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