HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RV_ShaderBlock.h
Go to the documentation of this file.
1 
2 /*
3  * PROPRIETARY INFORMATION. This software is proprietary to
4  * Side Effects Software Inc., and is not to be reproduced,
5  * transmitted, or disclosed in any way without written permission.
6  *
7  * NAME: RV_ShaderBlock.h ( RV Library, C++)
8  *
9  * COMMENTS:
10  * Class to handle Shader SSBO and UBO blocks
11  */
12 
13 #ifndef RV_ShaderBlock_h
14 #define RV_ShaderBlock_h
15 
16 
17 #include <typeinfo>
18 
19 #include "RV_API.h"
20 
21 #include <utility>
22 
23 #include <UT/UT_Array.h>
24 #include <UT/UT_Map.h>
25 #include <UT/UT_Matrix2.h>
26 #include <UT/UT_Matrix3.h>
27 #include <UT/UT_Matrix4.h>
28 #include <UT/UT_Span.h>
29 #include <UT/UT_String.h>
30 #include <UT/UT_StringMap.h>
31 #include <UT/UT_WorkBuffer.h>
32 #include <UT/UT_Vector2.h>
33 #include <UT/UT_Vector3.h>
34 #include <UT/UT_Vector4.h>
35 #include <UT/UT_VectorTypes.h>
36 
37 #include "RV_VK.h"
38 #include "RV_VKBuffer.h"
39 #include "RV_Instance.h"
40 #include "RV_VKDescriptorSet.h"
41 #include "RV_VKShaderModule.h"
42 
43 
44 class RV_Render;
45 class RV_ShaderProgram;
46 class GR_Uniforms;
47 
48 #if 0
49 struct UniformLocation
50 {
51  // name lookup
52  UniformLocation(const char* name)
53  : owned_stringref(name), name(&owned_stringref)
54  {
55  }
56  UniformLocation(const UT_StringRef& name)
57  : name(&name)
58  {
59  }
60 
61  // index lookup
62  UniformLocation(int idx)
63  : owned_idx(idx), idx(&owned_idx)
64  {
65  }
66 
67  // name lookup and store index
68  UniformLocation(const char* name, int* idx)
69  : owned_stringref(name), name(&owned_stringref), idx(idx)
70  {
71  }
72  UniformLocation(const UT_StringRef& name, int* idx)
73  : name(&name), idx(idx)
74  {
75  }
76 
77  UT_StringRef owned_stringref;
78  const UT_StringRef* name = nullptr;
79  int owned_idx;
80  int* idx = nullptr;
81 };
82 #endif
83 
84 // Helper class to hold type-checked bind functions for the RV_Uniform class
85 // and RV_PushConstants
86 // Must be inherited by a child class to be used
87 // Relies on the child class implementing:
88 // - getUniform(): to return the uniform
89 // - copyToBuffer(): to set data of the uniform if checks pass
90 // - copyToBufferStride(): to set uniforms that need to have
91 // padding between elements (e.g. vec3 arrays, mat3)
92 
93 /// Helper tie-in class for binding functions for UBOs and SSBOs
95 {
96 public:
97  /// Set the value of the uniform 'name' with a block of memory
98  bool bindUniform(const UT_StringRef& name,
100  const void* data, exint data_size,
101  int array_index = 0,
102  int* opt_idx = nullptr);
103 
104  /// Copy the data for uniform 'name' into the buffer. If name does not
105  /// exist in the buffer, or its type/array size doesn't match,
106  /// bind...() will return false. If its value is not different from the
107  /// current value in the block, it will not cause an upload.
108  /// Shader Storage Blocks can have open-ended arrays, and variables within
109  /// those arrays can specify their array index with 'array_index'.
110  bool bindInt(const UT_StringRef& name, int v,
111  int array_index = 0,
112  int* opt_idx = nullptr);
113  /// Bind a single float value.
114  bool bindFloat(const UT_StringRef& name, fpreal32 v,
115  int array_index = 0,
116  int* opt_idx = nullptr);
117  /// Bind a single double value. GPU must support native FP64 values.
118  bool bindDouble(const UT_StringRef& name, fpreal64 v,
119  int array_index = 0,
120  int* opt_idx = nullptr);
121  /// Bind a single handle value to a sampler. GPU must support bindless
122  /// textures.
123  bool bindUint64(const UT_StringRef& name,
124  uint64 v,
125  int array_index = 0,
126  int* opt_idx = nullptr);
127 
128  /// Set values for a fixed-length integer array.
129  bool bindInts(const UT_StringRef& name,
130  const int *valarray,
131  int array_size,
132  int array_index = 0,
133  int* opt_idx = nullptr);
134  /// Set values for a fixed-length float array.
135  bool bindFloats(const UT_StringRef& name,
136  const fpreal32 *valarray,
137  int array_size,
138  int array_index = 0,
139  int* opt_idx = nullptr);
140 
141  /// Set values for a fixed-length double array.
142  bool bindDoubles(const UT_StringRef& name,
143  const fpreal64 *valarray,
144  int array_size,
145  int array_index = 0,
146  int* opt_idx = nullptr);
147  /// Set values for a uint64 handle array.
148  bool bindUint64s(const UT_StringRef& name,
149  const uint64 *valarray,
150  int array_size,
151  int array_index = 0,
152  int* opt_idx = nullptr);
153 
154  /// vec3 is a little different, as it is padded to vec4 in uniform blocks.
155  /// SSBOs with std420 packing should use bindVector().
156 
157  /// bind a series of ivec3s, using std140 packing (padded to ivec4)
158  bool bindIntVector3(const UT_StringRef& name,
159  const int *valarray,
160  int array_size,
161  int array_index = 0,
162  int* opt_idx = nullptr);
163 
164  /// bind a series of vec3s, using std140 packing (padded to ivec4)
165  bool bindVector3(const UT_StringRef& name,
166  const fpreal32 *valarray,
167  int array_size,
168  int array_index = 0,
169  int* opt_idx = nullptr);
170 
171  /// bind a series of dvec3s, using std140 packing (padded to ivec4)
172  bool bindDVector3(const UT_StringRef& name,
173  const fpreal64 *valarray,
174  int array_size,
175  int array_index = 0,
176  int* opt_idx = nullptr);
177 
178  /// Bind a single vec2 uniform value.
179  bool bindVector(const UT_StringRef& name,
180  const UT_Vector2F &v,
181  int array_index = 0,
182  int* opt_idx = nullptr);
183  /// Bind a single vec3 uniform value.
184  bool bindVector(const UT_StringRef& name,
185  const UT_Vector3F &v,
186  int array_index = 0,
187  int* opt_idx = nullptr);
188  /// Bind a single vec4 uniform value.
189  bool bindVector(const UT_StringRef& name,
190  const UT_Vector4F &v,
191  int array_index = 0,
192  int* opt_idx = nullptr);
193 
194  /// Bind a single dvec2 uniform value.
195  bool bindVector(const UT_StringRef& name,
196  const UT_Vector2D &v,
197  int array_index = 0,
198  int* opt_idx = nullptr);
199 
200  /// Set a single dvec3 uniform value.
201  bool bindVector(const UT_StringRef& name,
202  const UT_Vector3D &v,
203  int array_index = 0,
204  int* opt_idx = nullptr);
205  /// Set a single dvec4 uniform value.
206  bool bindVector(const UT_StringRef& name,
207  const UT_Vector4D &v,
208  int array_index = 0,
209  int* opt_idx = nullptr);
210 
211  /// Bind a single ivec2 uniform value.
212  bool bindVector(const UT_StringRef& name,
213  const UT_Vector2i &v,
214  int array_index = 0,
215  int* opt_idx = nullptr);
216 
217  /// Set a single ivec3 uniform value.
218  bool bindVector(const UT_StringRef& name,
219  const UT_Vector3i &v,
220  int array_index = 0,
221  int* opt_idx = nullptr);
222  /// Set a single ivec4 uniform value.
223  bool bindVector(const UT_StringRef& name,
224  const UT_Vector4i &v,
225  int array_index = 0,
226  int* opt_idx = nullptr);
227 
228  /// Set a single 2x2 matrix value.
229  bool bindMatrix(const UT_StringRef& name,
230  const UT_Matrix2F &m,
231  int array_index = 0,
232  int* opt_idx = nullptr);
233  /// Set a single 3x3 matrix value.
234  bool bindMatrix(const UT_StringRef& name,
235  const UT_Matrix3F &m,
236  int array_index = 0,
237  int* opt_idx = nullptr);
238 
239  /// Set a single 4x4 matrix value.
240  bool bindMatrix(const UT_StringRef& name,
241  const UT_Matrix4F &m,
242  int array_index = 0,
243  int* opt_idx = nullptr);
244 
245  /// Set a single 2x2 matrix value (dmat2).
246  bool bindMatrix(const UT_StringRef& name,
247  const UT_Matrix2D &m,
248  int array_index = 0,
249  int* opt_idx = nullptr);
250 
251  /// Set a single 3x3 matrix value (dmat3).
252  bool bindMatrix(const UT_StringRef& name,
253  const UT_Matrix3D &m,
254  int array_index = 0,
255  int* opt_idx = nullptr);
256 
257  /// Set a single 4x4 matrix value (dmat4).
258  bool bindMatrix(const UT_StringRef& name,
259  const UT_Matrix4D &m,
260  int array_index = 0,
261  int* opt_idx = nullptr);
262 
263 protected:
264  virtual const RV_Uniform *getUniform(
265  const UT_StringRef& name,
266  int* opt_idx) const = 0;
267 
268  // Virtual Interface for child classes
269 
270  /// Copy array of data into the CPU buffer
271  virtual void copyToBuffer(
272  const void *data,
273  int size, int offset,
274  const char* name)
275  = 0;
276 
277  /// Copy data into the CPU buffer with a specified stride.
278  /// incoming data is tightly packed, with padding added in
279  /// the buffer to match stride
280  virtual void copyToBufferStride(
281  const void *data,
282  int len,
283  int size,
284  int stride,
285  int offset,
286  const char* name)
287  = 0;
288 
289  // Protected ctor and dtor so base class can't be instantiated
290  // And static asserts so it MUST be inherited by BLOCK_T
292  { }
293 
295  { }
296 
297 };
298 
299 // Class Representing a Shader variable block, either UBO or SSBO
300 //
301 // Manages buffer and provides interface for querying, and setting
302 // uniforms. Requires DescriptorBinding description to initialize,
303 // but only manages buffer. Must be bound into Descriptor Set separately
304 //
306 {
307 public:
309 
310  /// Create the shader block (either a UBO or SSBO) for the binding in a set.
311  static RV_ShaderBlock* create(
312  RV_Instance* inst,
313  const RV_VKDescriptorBinding& binding_layout,
314  const char* name = nullptr,
315  uint32_t array_size = 0);
316 
317  ~RV_ShaderBlock() override;
318 
319  /// Return the buffer object that backs this UBO or SSBO
320  RV_VKBuffer* getBufferObject() { return myBufferObject.get(); }
321 
322  /// Return the ptr to the CPU copy of buffer data, which must be downloaded
323  /// with downloadBuffer to see the most recent value
324  const void* getCPUBuffer() { return myData; }
325 
326  /// commits any changes to the buffer object, creating the buffer object
327  /// if required.
328  bool uploadBuffer(RV_Render* r);
329 
330  /// Fetches the contents of the GL buffer into the main mem block contained
331  /// by this class.
332  void downloadBuffer(RV_Render *r);
333 
334  // Whether this block requires uploading to the GPU.
335  bool isDirty() const { return myDirtyFlag; }
336 
337  /// compare whether this block is compatible with a shader's binding
338  bool isCompatible(const RV_VKDescriptorBinding& binding) const;
339 
340  /// Copy a bunch of bytes to the buffer. If size=0, it assumes the full
341  /// buffer size (or remaining size if ofset!=-0)
342  bool fillBuffer(const void *data, int offset=0, int size=0);
343 
344 
345  /// Array length of variably sized arrays for SSBOs.
346  int getArrayLength() const { return myArrayLength; }
347 
348  /// Offset in buffer of variably sized arrays for SSBOs.
349  int getArrayOffset() const { return myUniforms.last().offset; }
350 
351  /// Copy a bunch of bytes to the variable array component of the SSBO
352  bool uploadArray(RV_Render* r,
353  const void* data,
354  exint size,
355  exint offset = 0);
356 
357  /// Download bytes from the buffer variable array component of the SSBO
358  bool downloadArray(RV_Render* r,
359  void* data,
360  exint size,
361  exint offset = 0);
362 
363  /// Copy a bunch of bytes to the variable array component of the SSBO
364  /// where data can be any type used to construct a span
365  template<typename T>
367  const T &data,
368  exint offset = 0)
369  {
370  // `T` must be a `UT_Span` or convertable into a `UT_Span`
372  return uploadArray(r, span.data(), span.size_bytes(), offset);
373  }
374 
375  /// Download bytes from the buffer variable array component of the SSBO
376  /// where data can be any type used to construct a span
377  template<typename T>
379  T &data,
380  exint offset = 0)
381  {
382  // `T` must be a `UT_Span` or convertable into a `UT_Span`
384  return downloadArray(r, span.data(), span.size_bytes(), offset);
385  }
386 
387  // See `RV_ShaderBindFuncs` for bind functions
388 
389  // Debug Print functions
390  void print(RV_ShaderProgram *opt_shr = nullptr) const;
391 
392 private:
393  // Debug Print functions
394  void printMemberValue(
395  UT_WorkBuffer &out_msg,
396  const RV_Uniform& u,
397  int base_offset,
398  RV_ShaderProgram *opt_shr = nullptr) const;
399  void printMemberList(
400  const UT_Array<RV_Uniform>& u,
401  int indent, int base_offset,
402  RV_ShaderProgram *opt_shr = nullptr) const;
403 
404  int getUniformIndex(const UT_StringRef& name) const;
405 
406  const RV_Uniform* getUniform(const UT_StringRef& name, int* opt_idx) const override;
407 
408  /// Copy array of data into the CPU buffer
409  void copyToBuffer(
410  const void *data,
411  int size,
412  int offset,
413  const char* name) override;
414 
415  /// Copy data into the CPU buffer with a specified stride.
416  /// incoming data is tightly packed, with padding added in
417  /// the buffer to match stride
418  void copyToBufferStride(
419  const void *data,
420  int len,
421  int size,
422  int stride,
423  int offset,
424  const char* name) override;
425 
427  RV_VKBuffer *buffer_object,
428  void *buffer,
429  int size,
430  const char *instance_name,
431  const UT_Array<RV_Uniform> &uniforms,
432  uint32_t array_length,
433  bool is_storage);
434 
435  /// Buffer Data
436  UT_UniquePtr<RV_VKBuffer> myBufferObject;
437  void *myData;
438  bool myDirtyFlag;
439  bool myIsStorage;
440 
441  // Uniform Reflection
442  UT_StringHolder myInstanceName;
443  UT_Array<RV_Uniform> myUniforms;
444  UT_StringMap<int> myUniformsIndexMap;
445 
446  // TODO: does instance name need to be a built in part of the block?? -- I would think not
447  UT_StringMap<int> myUniformsInstanceIndexMap;
448 
449  // Size of the fixed part of the buffer
450  int myFixedSize;
451 
452  // Size of the fully allocated buffer
453  int mySize;
454 
455  // for buffer storage objects, which can have a non-array section at the
456  // beginning of the block (fixed), followed by array data at the end
457  // (variable). myArrayLength determines the number of entries in the array.
458 
459  int myVariableSize;
460  int myArrayLength;
461 
462 
463  // =====================
464  // WIP: caching builtin uniforms offsets for faster upload
465 public:
466  bool bindUniform(int idx,
468  const void* data, exint data_size,
469  int array_index = 0);
470 
471  // Bring in interface version of `bindUniform` so it isn't hidden
473 
475  friend GR_Uniforms;
476 };
477 
478 /// Class Representing the Push Constants used by the pipeline
479 /// Will be owned by directly by the RV_Render, and gets holds
480 /// a ptr to the RV_Render owning it
481 ///
482 /// Does not have its own layout, instead uses the layout of the
483 /// shader bound to RV_Render at the time 'bind' is called
485 {
486 public:
488  ~RV_PushConstants() override;
489 
490  /// Write all bound values to the push constant memory
491  bool upload(RV_Render* r);
492 
493  /// Whether this block requires uploading to the GPU.
494  bool isDirty() const { return myDirtyFlag; }
495  /// Force the block to be re-uploaded to the GPU, even if not dirtied
496  void forceDirty() { myDirtyFlag = true; }
497 
498  /// Copy a bunch of bytes to the buffer. If size=0, it assumes the full
499  /// buffer size (or remaining size if ofset!=-0)
500  bool fillBuffer(const void *data, int offset=0, int size=0);
501 
502 private:
503  const RV_Uniform* getUniform(const UT_StringRef& name, int* opt_idx)
504  const override;
505 
506  /// Copy array of data into the CPU buffer
507  void copyToBuffer(
508  const void *data,
509  int size,
510  int offset,
511  const char* name) override;
512 
513  /// Copy data into the CPU buffer with a specified stride.
514  /// incoming data is tightly packed, with padding added in
515  /// the buffer to match stride
516  void copyToBufferStride(
517  const void *data,
518  int len,
519  int size,
520  int stride,
521  int offset,
522  const char* name) override;
523 
524  bool myDirtyFlag = true;
525  RV_Render* myR;
526  void* myData;
527  int mySize;
528 };
529 
530 #endif
virtual const RV_Uniform * getUniform(const UT_StringRef &name, int *opt_idx) const =0
bool bindUniform(const UT_StringRef &name, RV_UniformType type, const void *data, exint data_size, int array_index=0, int *opt_idx=nullptr)
Set the value of the uniform 'name' with a block of memory.
Helper tie-in class for binding functions for UBOs and SSBOs.
constexpr span< ElementType, Extent > make_span(span< ElementType, Extent > s) noexcept
Definition: UT_Span.h:559
bool isDirty() const
const GLdouble * v
Definition: glcorearb.h:837
~RV_PushConstants() override
void forceDirty()
Force the block to be re-uploaded to the GPU, even if not dirtied.
friend RV_ShaderBindFuncs
Definition: span.h:73
int64 exint
Definition: SYS_Types.h:125
const void * getCPUBuffer()
unsigned long long uint64
Definition: SYS_Types.h:117
float fpreal32
Definition: SYS_Types.h:200
RV_VKBuffer * getBufferObject()
Return the buffer object that backs this UBO or SSBO.
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
double fpreal64
Definition: SYS_Types.h:201
bool uploadArray(RV_Render *r, const T &data, exint offset=0)
int getArrayOffset() const
Offset in buffer of variably sized arrays for SSBOs.
bool fillBuffer(const void *data, int offset=0, int size=0)
GLintptr offset
Definition: glcorearb.h:665
Definition: core.h:760
virtual void copyToBuffer(const void *data, int size, int offset, const char *name)=0
Copy array of data into the CPU buffer.
RV_UniformType
Definition: RV_Type.h:262
int getArrayLength() const
Array length of variably sized arrays for SSBOs.
RV_PushConstants(RV_Render *r)
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:872
#define RV_API
Definition: RV_API.h:10
bool downloadArray(RV_Render *r, T &data, exint offset=0)
GLuint const GLchar * name
Definition: glcorearb.h:786
virtual ~RV_ShaderBindFuncs()
Handle to the main interface of Vulkan.
Definition: RV_Instance.h:36
GLsizeiptr size
Definition: glcorearb.h:664
virtual void copyToBufferStride(const void *data, int len, int size, int stride, int offset, const char *name)=0
constexpr size_type size_bytes() const noexcept
Definition: span.h:186
bool upload(RV_Render *r)
Write all bound values to the push constant memory.
GLboolean r
Definition: glcorearb.h:1222
A vulkan buffer object.
Definition: RV_VKBuffer.h:80
bool isDirty() const
Whether this block requires uploading to the GPU.
type
Definition: core.h:1059
FMT_INLINE void print(format_string< T...> fmt, T &&...args)
Definition: core.h:2976
Type info for a single variable in a shader.
constexpr pointer data() const noexcept
Definition: span.h:189
UT_Array< int > myBuiltinArrayIdxToLocalIdx
Definition: format.h:895