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 <VE/VE_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 array_range = 1,
103  int* opt_idx = nullptr);
104 
105  /// Copy the data for uniform 'name' into the buffer. If name does not
106  /// exist in the buffer, or its type/array size doesn't match,
107  /// bind...() will return false. If its value is not different from the
108  /// current value in the block, it will not cause an upload.
109  /// Shader Storage Blocks can have open-ended arrays, and variables within
110  /// those arrays can specify their array index with 'array_index'.
111  bool bindInt(const UT_StringRef& name, int v,
112  int array_index = 0,
113  int* opt_idx = nullptr);
114  /// Bind a single float value.
115  bool bindFloat(const UT_StringRef& name, fpreal32 v,
116  int array_index = 0,
117  int* opt_idx = nullptr);
118  /// Bind a single double value. GPU must support native FP64 values.
119  bool bindDouble(const UT_StringRef& name, fpreal64 v,
120  int array_index = 0,
121  int* opt_idx = nullptr);
122  /// Bind a single handle value to a sampler. GPU must support bindless
123  /// textures.
124  bool bindUint64(const UT_StringRef& name,
125  uint64 v,
126  int array_index = 0,
127  int* opt_idx = nullptr);
128 
129  /// Set values for a fixed-length integer array.
130  bool bindInts(const UT_StringRef& name,
131  const int *valarray,
132  int array_size,
133  int array_index = 0,
134  int* opt_idx = nullptr);
135  /// Set values for a fixed-length float array.
136  bool bindFloats(const UT_StringRef& name,
137  const fpreal32 *valarray,
138  int array_size,
139  int array_index = 0,
140  int* opt_idx = nullptr);
141 
142  /// Set values for a fixed-length double array.
143  bool bindDoubles(const UT_StringRef& name,
144  const fpreal64 *valarray,
145  int array_size,
146  int array_index = 0,
147  int* opt_idx = nullptr);
148  /// Set values for a uint64 handle array.
149  bool bindUint64s(const UT_StringRef& name,
150  const uint64 *valarray,
151  int array_size,
152  int array_index = 0,
153  int* opt_idx = nullptr);
154 
155  /// vec3 is a little different, as it is padded to vec4 in uniform blocks.
156  /// SSBOs with std420 packing should use bindVector().
157 
158  /// bind a series of ivec3s, using std140 packing (padded to ivec4)
159  bool bindIntVector3(const UT_StringRef& name,
160  const int *valarray,
161  int array_size,
162  int array_index = 0,
163  int* opt_idx = nullptr);
164 
165  /// bind a series of vec3s, using std140 packing (padded to ivec4)
166  bool bindVector3(const UT_StringRef& name,
167  const fpreal32 *valarray,
168  int array_size,
169  int array_index = 0,
170  int* opt_idx = nullptr);
171 
172  /// bind a series of dvec3s, using std140 packing (padded to ivec4)
173  bool bindDVector3(const UT_StringRef& name,
174  const fpreal64 *valarray,
175  int array_size,
176  int array_index = 0,
177  int* opt_idx = nullptr);
178 
179  /// Bind a single vec2 uniform value.
180  bool bindVector(const UT_StringRef& name,
181  const UT_Vector2F &v,
182  int array_index = 0,
183  int* opt_idx = nullptr);
184  /// Bind a single vec3 uniform value.
185  bool bindVector(const UT_StringRef& name,
186  const UT_Vector3F &v,
187  int array_index = 0,
188  int* opt_idx = nullptr);
189  /// Bind a single vec4 uniform value.
190  bool bindVector(const UT_StringRef& name,
191  const UT_Vector4F &v,
192  int array_index = 0,
193  int* opt_idx = nullptr);
194 
195  /// Bind a single dvec2 uniform value.
196  bool bindVector(const UT_StringRef& name,
197  const UT_Vector2D &v,
198  int array_index = 0,
199  int* opt_idx = nullptr);
200 
201  /// Set a single dvec3 uniform value.
202  bool bindVector(const UT_StringRef& name,
203  const UT_Vector3D &v,
204  int array_index = 0,
205  int* opt_idx = nullptr);
206  /// Set a single dvec4 uniform value.
207  bool bindVector(const UT_StringRef& name,
208  const UT_Vector4D &v,
209  int array_index = 0,
210  int* opt_idx = nullptr);
211 
212  /// Bind a single ivec2 uniform value.
213  bool bindVector(const UT_StringRef& name,
214  const UT_Vector2i &v,
215  int array_index = 0,
216  int* opt_idx = nullptr);
217 
218  /// Set a single ivec3 uniform value.
219  bool bindVector(const UT_StringRef& name,
220  const UT_Vector3i &v,
221  int array_index = 0,
222  int* opt_idx = nullptr);
223  /// Set a single ivec4 uniform value.
224  bool bindVector(const UT_StringRef& name,
225  const UT_Vector4i &v,
226  int array_index = 0,
227  int* opt_idx = nullptr);
228 
229  /// Set a single 2x2 matrix value.
230  bool bindMatrix(const UT_StringRef& name,
231  const UT_Matrix2F &m,
232  int array_index = 0,
233  int* opt_idx = nullptr);
234  /// Set a single 3x3 matrix value.
235  bool bindMatrix(const UT_StringRef& name,
236  const UT_Matrix3F &m,
237  int array_index = 0,
238  int* opt_idx = nullptr);
239 
240  /// Set a single 4x4 matrix value.
241  bool bindMatrix(const UT_StringRef& name,
242  const UT_Matrix4F &m,
243  int array_index = 0,
244  int* opt_idx = nullptr);
245 
246  /// Set a single 2x2 matrix value (dmat2).
247  bool bindMatrix(const UT_StringRef& name,
248  const UT_Matrix2D &m,
249  int array_index = 0,
250  int* opt_idx = nullptr);
251 
252  /// Set a single 3x3 matrix value (dmat3).
253  bool bindMatrix(const UT_StringRef& name,
254  const UT_Matrix3D &m,
255  int array_index = 0,
256  int* opt_idx = nullptr);
257 
258  /// Set a single 4x4 matrix value (dmat4).
259  bool bindMatrix(const UT_StringRef& name,
260  const UT_Matrix4D &m,
261  int array_index = 0,
262  int* opt_idx = nullptr);
263 
264 protected:
265  virtual const RV_Uniform *getUniform(
266  const UT_StringRef& name,
267  int* opt_idx) = 0;
268 
269  // Virtual Interface for child classes
270 
271  /// Copy array of data into the CPU buffer
272  virtual void copyToBuffer(
273  const void *data,
274  int size, int offset,
275  const char* name)
276  = 0;
277 
278  /// Copy data into the CPU buffer with a specified stride.
279  /// incoming data is tightly packed, with padding added in
280  /// the buffer to match stride
281  virtual void copyToBufferStride(
282  const void *data,
283  int len,
284  int size,
285  int stride,
286  int offset,
287  const char* name)
288  = 0;
289 
290  // Protected ctor and dtor so base class can't be instantiated
291  // And static asserts so it MUST be inherited by BLOCK_T
293  { }
294 
296  { }
297 
298 };
299 
300 // Class Representing a Shader variable block, either UBO or SSBO
301 //
302 // Manages buffer and provides interface for querying, and setting
303 // uniforms. Requires DescriptorBinding description to initialize,
304 // but only manages buffer. Must be bound into Descriptor Set separately
305 //
307 {
308 public:
310 
311  /// Create the shader block (either a UBO or SSBO) for the binding in a set.
312  static RV_ShaderBlock* create(
313  RV_Instance* inst,
314  const RV_VKDescriptorBinding& binding_layout,
315  const char* name = nullptr,
316  uint32_t array_size = 0);
317 
318  /// Create the shader block (either a UBO or SSBO) for the binding in a set.
319  static RV_ShaderBlock* createCPUMapped(
320  RV_Instance* inst,
321  const RV_VKDescriptorBinding& binding_layout,
322  const char* name = nullptr,
323  uint32_t array_size = 0,
324  bool cpu_mapped = false);
325 
326  ~RV_ShaderBlock() override;
327 
328  /// Return the buffer object that backs this UBO or SSBO
329  RV_VKBuffer* getBufferObject() { return myBufferObject.get(); }
330 
331  /// Return the ptr to the CPU copy of buffer data, which must be downloaded
332  /// with downloadBuffer to see the most recent value
333  const void* getCPUBuffer() { return myData; }
334 
335  /// commits any changes to the buffer object, creating the buffer object
336  /// if required.
337  bool uploadBuffer(RV_Render* r);
338 
339  /// Fetches the contents of the GL buffer into the main mem block contained
340  /// by this class.
341  void downloadBuffer(RV_Render *r);
342 
343  /// returns the size of the buffer for UBO blocks and the
344  /// non-dynamically-sized part of the buffer for SSBOs
345  int getFixedSize() { return myFixedSize; }
346 
347  /// returns the size of the buffer for UBO blocks and the
348  /// dynamically-sized part of the buffer for SSBOs
349  exint getSize() const;
350 
351  // Whether this block requires uploading to the GPU.
352  bool isDirty() const { return myDirtyFlag; }
353 
354  /// compare whether this block is compatible with a shader's binding
355  bool isCompatible(const RV_VKDescriptorBinding& binding) const;
356 
357  /// get the binding location of the binding used to create this block
358  int getBindingNum() const { return myBindingNum; }
359 
360  /// Copy a bunch of bytes to the buffer. If size=0, it assumes the full
361  /// buffer size (or remaining size if ofset!=-0)
362  bool fillBuffer(const void *data, int offset=0, int size=0);
363 
364 
365  /// Array length of variably sized arrays for SSBOs.
366  int getArrayLength() const { return myArrayLength; }
367 
368  /// Offset in buffer of variably sized arrays for SSBOs.
369  int getArrayOffset() const { return myUniforms.last().offset; }
370 
371  /// Copy a bunch of bytes to the variable array component of the SSBO
372  bool uploadArray(RV_Render* r,
373  const void* data,
374  exint size,
375  exint offset = 0);
376 
377  /// Download bytes from the buffer variable array component of the SSBO
378  bool downloadArray(RV_Render* r,
379  void* data,
380  exint size,
381  exint offset = 0);
382 
383  /// Copy a bunch of bytes to the variable array component of the SSBO
384  /// where data can be any type used to construct a span
385  template<typename T>
387  const T &data,
388  exint offset = 0)
389  {
390  // `T` must be a `UT_Span` or convertable into a `UT_Span`
392  return uploadArray(r, span.data(), span.size_bytes(), offset);
393  }
394 
395  /// Download bytes from the buffer variable array component of the SSBO
396  /// where data can be any type used to construct a span
397  template<typename T>
399  T &data,
400  exint offset = 0)
401  {
402  // `T` must be a `UT_Span` or convertable into a `UT_Span`
404  return downloadArray(r, span.data(), span.size_bytes(), offset);
405  }
406 
407  // See `RV_ShaderBindFuncs` for bind functions
408 
409  // Debug Print functions
410  void print(RV_ShaderProgram *opt_shr = nullptr) const;
411 
412 private:
413  // Debug Print functions
414  void printMemberValue(
415  UT_WorkBuffer &out_msg,
416  const RV_Uniform& u,
417  int base_offset,
418  RV_ShaderProgram *opt_shr = nullptr) const;
419  void printMemberList(
420  const UT_Array<RV_Uniform>& u,
421  int indent, int base_offset,
422  RV_ShaderProgram *opt_shr = nullptr) const;
423 
424  int getUniformIndex(const UT_StringRef& name);
425  const RV_Uniform* getUniform(const UT_StringRef& name, int* opt_idx) override;
426 
427  /// Copy array of data into the CPU buffer
428  void copyToBuffer(
429  const void *data,
430  int size,
431  int offset,
432  const char* name) override;
433 
434  /// Copy data into the CPU buffer with a specified stride.
435  /// incoming data is tightly packed, with padding added in
436  /// the buffer to match stride
437  void copyToBufferStride(
438  const void *data,
439  int len,
440  int size,
441  int stride,
442  int offset,
443  const char* name) override;
444 
446  RV_VKBufferPtr buffer_object,
447  void *buffer,
448  int size,
449  const char *instance_name,
450  int32 binding_num,
451  const UT_Array<RV_Uniform> &uniforms,
452  uint32_t array_length,
453  bool is_storage);
454 
455  /// Buffer Data
456  UT_UniquePtr<RV_VKBuffer> myBufferObject;
457  void *myData;
458  bool myDirtyFlag;
459  bool myIsStorage;
460 
461  // Uniform Reflection
462  UT_StringHolder myInstanceName;
463  int myBindingNum = -1;
464  UT_Array<RV_Uniform> myUniforms;
465 
466  UT_StringMap<int> myUniformsIndexMap;
467  UT_StringMap<int> myUniformsInstanceIndexMap;
468 
469  // Size of the fixed part of the buffer
470  int myFixedSize;
471 
472  // Size of the fully allocated buffer
473  int mySize;
474 
475  // for buffer storage objects, which can have a non-array section at the
476  // beginning of the block (fixed), followed by array data at the end
477  // (variable). myArrayLength determines the number of entries in the array.
478 
479  int myVariableSize;
480  int myArrayLength;
481 
482 
483  // =====================
484  // WIP: caching builtin uniforms offsets for faster upload
485 public:
486  bool bindUniform(int idx,
488  const void* data, exint data_size,
489  int array_index = 0);
490 
491  // Bring in interface version of `bindUniform` so it isn't hidden
493 
495  friend GR_Uniforms;
496 };
497 
498 /// Class Representing the Push Constants used by the pipeline
499 /// Will be owned by directly by the RV_Render, and gets holds
500 /// a ptr to the RV_Render owning it
501 ///
502 /// Does not have its own layout, instead uses the layout of the
503 /// shader bound to RV_Render at the time 'bind' is called
505 {
506 public:
508  ~RV_PushConstants() override;
509 
510  /// Write all bound values to the push constant memory
511  bool upload(RV_Render* r);
512 
513  /// Whether this block requires uploading to the GPU.
514  bool isDirty() const { return myDirtyFlag; }
515  /// Force the block to be re-uploaded to the GPU, even if not dirtied
516  void forceDirty() { myDirtyFlag = true; }
517 
518  /// Copy a bunch of bytes to the buffer. If size=0, it assumes the full
519  /// buffer size (or remaining size if ofset!=-0)
520  bool fillBuffer(const void *data, int offset=0, int size=0);
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
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:55
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
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:284
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
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
virtual ~RV_ShaderBindFuncs()
Handle to the main interface of Vulkan.
Definition: RV_Instance.h:38
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: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:81
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