Torque3D Documentation / _generateds / genericConstBuffer.h

genericConstBuffer.h

Engine/source/gfx/genericConstBuffer.h

More...

Classes:

class

This class manages shader constant data in a system memory buffer.

class

This class defines the memory layout for a GenericConstBuffer.

class

Describes the parameters we contain.

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#ifndef _GENERICCONSTBUFFER_H_
 25#define _GENERICCONSTBUFFER_H_
 26
 27#ifndef _TORQUE_STRING_H_
 28#include "core/util/str.h"
 29#endif
 30#ifndef _TDICTIONARY_H_
 31#include "core/util/tDictionary.h"
 32#endif
 33#ifndef _TVECTOR_H_
 34#include "core/util/tVector.h"
 35#endif
 36#ifndef _ALIGNEDARRAY_H_
 37#include "core/util/tAlignedArray.h"
 38#endif
 39#ifndef _COLOR_H_
 40#include "core/color.h"
 41#endif
 42#ifndef _MMATRIX_H_
 43#include "math/mMatrix.h"
 44#endif
 45#ifndef _MPOINT2_H_
 46#include "math/mPoint2.h"
 47#endif
 48#ifndef _GFXENUMS_H_
 49#include "gfx/gfxEnums.h"
 50#endif
 51
 52class Stream;
 53
 54
 55/// This class defines the memory layout for a GenericConstBuffer.
 56class GenericConstBufferLayout 
 57{   
 58public:
 59   /// Describes the parameters we contain
 60   struct ParamDesc
 61   {
 62      ParamDesc()
 63         :  name(),
 64            offset( 0 ),
 65            size( 0 ),
 66            constType( GFXSCT_Float ),
 67            arraySize( 0 ),
 68            alignValue( 0 ),
 69            index( 0 )
 70      {
 71      }
 72
 73      void clear()
 74      {
 75         name = String::EmptyString;
 76         offset = 0;
 77         size = 0;
 78         constType = GFXSCT_Float;
 79         arraySize = 0;
 80         alignValue = 0;
 81         index = 0;
 82      }
 83
 84      /// Parameter name
 85      String name;
 86
 87      /// Offset into the memory block
 88      U32 offset;
 89
 90      /// Size of the block
 91      U32 size;
 92
 93      /// Type of data
 94      GFXShaderConstType constType;
 95
 96      // For arrays, how many elements
 97      U32 arraySize;
 98
 99      // Array element alignment value
100      U32 alignValue;
101
102      /// 0 based index of this param, in order of addParameter calls.
103      U32 index;
104   };
105
106   GenericConstBufferLayout();
107   virtual ~GenericConstBufferLayout() {}
108
109   /// Add a parameter to the buffer
110   virtual void addParameter(const String& name, const GFXShaderConstType constType, const U32 offset, const U32 size, const U32 arraySize, const U32 alignValue);
111
112   /// Get the size of the buffer
113   inline U32 getBufferSize() const { return mBufferSize; }
114
115   /// Get the number of parameters
116   inline U32 getParameterCount() const { return mParams.size(); }
117
118   /// Returns the ParamDesc of a parameter 
119   bool getDesc(const String& name, ParamDesc& param) const;
120
121   /// Returns the ParamDesc of a parameter 
122   bool getDesc(const U32 index, ParamDesc& param) const;
123
124   /// Set a parameter, given a base pointer
125   virtual bool set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer);
126
127   /// Save this layout to a stream
128   bool write(Stream* s);
129
130   /// Load this layout from a stream
131   bool read(Stream* s);
132
133   /// Restore to initial state.
134   void clear();
135
136protected:
137
138   /// Set a matrix, given a base pointer.
139   virtual bool setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer);
140
141   /// Vector of parameter descriptions.
142   typedef Vector<ParamDesc> Params;
143   
144   /// Vector of parameter descriptions.
145   Params mParams;
146   U32 mBufferSize;
147   U32 mCurrentIndex;
148
149   // This if for debugging shader reloading and can be removed later.
150   U32 mTimesCleared;
151};
152
153
154/// This class manages shader constant data in a system memory buffer.  It is
155/// used by device specific classes for batching together many constant changes 
156/// which are then copied to the device thru a single API call.
157///
158/// @see GenericConstBufferLayout
159///
160class GenericConstBuffer
161{
162public:
163   GenericConstBuffer(GenericConstBufferLayout* layout);
164   ~GenericConstBuffer();
165
166   /// @name Set shader constant values
167   /// @{
168   /// Actually set shader constant values
169   /// @param name Name of the constant, this should be a name contained in the array returned in getShaderConstDesc,
170   /// if an invalid name is used, its ignored, but it's not an error.
171   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const F32 f) { internalSet(pd, GFXSCT_Float, sizeof(F32), &f); }
172   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point2F& fv) { internalSet(pd, GFXSCT_Float2, sizeof(Point2F), &fv); }
173   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point3F& fv) { internalSet(pd, GFXSCT_Float3, sizeof(Point3F), &fv); }
174   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point4F& fv) { internalSet(pd, GFXSCT_Float4, sizeof(Point4F), &fv); }
175   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const PlaneF& fv) { internalSet(pd, GFXSCT_Float4, sizeof(PlaneF), &fv); }
176   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const LinearColorF& fv) { internalSet(pd, GFXSCT_Float4, sizeof(Point4F), &fv); }
177   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const S32 f) { internalSet(pd, GFXSCT_Int, sizeof(S32), &f); }
178   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point2I& fv) { internalSet(pd, GFXSCT_Int2, sizeof(Point2I), &fv); }
179   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point3I& fv) { internalSet(pd, GFXSCT_Int3, sizeof(Point3I), &fv); }
180   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point4I& fv) { internalSet(pd, GFXSCT_Int4, sizeof(Point4I), &fv); }
181   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<F32>& fv) { internalSet(pd, GFXSCT_Float, fv.getElementSize() * fv.size(), fv.getBuffer()); }
182   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<Point2F>& fv) { internalSet(pd, GFXSCT_Float2, fv.getElementSize() * fv.size(), fv.getBuffer()); }
183   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<Point3F>& fv) { internalSet(pd, GFXSCT_Float3, fv.getElementSize() * fv.size(), fv.getBuffer()); }
184   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<Point4F>& fv) { internalSet(pd, GFXSCT_Float4, fv.getElementSize() * fv.size(), fv.getBuffer()); }
185   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<S32>& fv) { internalSet(pd, GFXSCT_Int, fv.getElementSize() * fv.size(), fv.getBuffer()); }
186   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<Point2I>& fv) { internalSet(pd, GFXSCT_Int2, fv.getElementSize() * fv.size(), fv.getBuffer()); }
187   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<Point3I>& fv) { internalSet(pd, GFXSCT_Int3, fv.getElementSize() * fv.size(), fv.getBuffer()); }
188   inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray<Point4I>& fv) { internalSet(pd, GFXSCT_Int4, fv.getElementSize() * fv.size(), fv.getBuffer()); }
189
190   inline void set( const GenericConstBufferLayout::ParamDesc& pd, const MatrixF& mat, const GFXShaderConstType matrixType )
191   {
192      AssertFatal(   matrixType == GFXSCT_Float2x2 || 
193                     matrixType == GFXSCT_Float3x3 || 
194                     matrixType == GFXSCT_Float3x4 || 
195                     matrixType == GFXSCT_Float4x3 || 
196                     matrixType == GFXSCT_Float4x4, 
197         "GenericConstBuffer::set() - Invalid matrix type!" );
198
199      internalSet( pd, matrixType, sizeof(MatrixF), &mat );
200   }
201
202   inline void set( const GenericConstBufferLayout::ParamDesc& pd, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType )
203   {
204      AssertFatal(   matrixType == GFXSCT_Float2x2 || 
205                     matrixType == GFXSCT_Float3x3 || 
206                     matrixType == GFXSCT_Float3x4 ||
207                     matrixType == GFXSCT_Float4x3 ||  
208                     matrixType == GFXSCT_Float4x4, 
209         "GenericConstBuffer::set() - Invalid matrix type!" );
210
211      internalSet( pd, matrixType, sizeof(MatrixF)*arraySize, mat );
212   }
213
214   /// Gets the dirty buffer range and clears the dirty
215   /// state at the same time.
216   inline const U8* getDirtyBuffer( U32 *start, U32 *size );
217
218   /// Gets the entire buffer ignoring dirty range
219   inline const U8* getEntireBuffer();
220
221   /// Sets the entire buffer as dirty or clears the dirty state.
222   inline void setDirty( bool dirty );
223
224   /// Returns true if the buffer has been modified since the 
225   /// last call to getDirtyBuffer or setDirty.  The buffer is
226   /// not dirty on initial creation.
227   ///
228   /// @see getDirtyBuffer
229   /// @see setDirty
230   inline bool isDirty() const { return mDirtyEnd != 0; }
231
232   /// Returns true if have the same layout and hold the same 
233   /// data as the input buffer.
234   inline bool isEqual( const GenericConstBuffer *buffer ) const;
235
236   /// Returns our layout object.
237   inline GenericConstBufferLayout* getLayout() const { return mLayout; }
238
239   #ifdef TORQUE_DEBUG
240   
241      /// Helper function used to assert on unset constants.
242      void assertUnassignedConstants( const char *shaderName );
243
244   #endif
245
246protected:
247
248   /// Returns a pointer to the raw buffer
249   inline const U8* getBuffer() const { return mBuffer; }
250
251   /// Called by the inlined set functions above to do the
252   /// real dirty work of copying the data to the right location
253   /// within the buffer.
254   inline void internalSet(   const GenericConstBufferLayout::ParamDesc &pd, 
255                              const GFXShaderConstType constType, 
256                              const U32 size, 
257                              const void *data );
258
259   /// The buffer layout.
260   GenericConstBufferLayout *mLayout;
261
262   /// The pointer to the contant store or
263   /// NULL if the layout is empty.
264   U8 *mBuffer;
265
266   /// The byte offset to the start of the dirty
267   /// range within the buffer or U32_MAX if the
268   /// buffer is not dirty.
269   U32 mDirtyStart;
270
271   /// The btye offset to the end of the dirty
272   /// range within the buffer or 0 if the buffer
273   /// is not dirty.
274   U32 mDirtyEnd;
275
276
277   #ifdef TORQUE_DEBUG
278   
279      /// A vector used to keep track if a constant 
280      /// has beed assigned a value or not.
281      ///
282      /// @see assertUnassignedConstants
283      Vector<bool> mWasAssigned;
284
285   #endif
286};
287
288
289// NOTE: These inlines below are here to get the very best possible
290// performance when setting the device shader constants and can be
291// called 4000-8000 times per frame or more.
292//
293// You need a very good reason to consider changing them.
294
295inline void GenericConstBuffer::internalSet( const GenericConstBufferLayout::ParamDesc &pd, 
296                                             const GFXShaderConstType constType, 
297                                             const U32 size, 
298                                             const void *data )
299{   
300   // NOTE: We should have never gotten here if the buffer 
301   // was null as no valid shader constant could have been 
302   // assigned.
303   //
304   // If this happens its a bug in another part of the code.
305   //
306   AssertFatal( mBuffer, "GenericConstBuffer::internalSet - The buffer is NULL!" );
307
308   if ( mLayout->set( pd, constType, size, data, mBuffer ) )
309   {
310      #ifdef TORQUE_DEBUG
311         
312         // Update the debug assignment tracking.
313         mWasAssigned[ pd.index ] = true;
314
315      #endif
316
317      // Keep track of the dirty range so it can be queried
318      // later in GenericConstBuffer::getDirtyBuffer.
319      mDirtyStart = getMin( pd.offset, mDirtyStart );
320      mDirtyEnd = getMax( pd.offset + pd.size, mDirtyEnd );
321   }
322}
323
324inline void GenericConstBuffer::setDirty( bool dirty )
325{ 
326   if ( !mBuffer )
327      return;
328
329   if ( dirty )
330   {
331      mDirtyStart = 0;
332      mDirtyEnd = mLayout->getBufferSize();
333   }
334   else if ( !dirty )
335   {
336      mDirtyStart = U32_MAX;
337      mDirtyEnd = 0;
338   }
339}
340
341inline const U8* GenericConstBuffer::getDirtyBuffer( U32 *start, U32 *size )
342{
343   AssertFatal( isDirty(), "GenericConstBuffer::getDirtyBuffer() - Buffer is not dirty!" );
344   AssertFatal( mDirtyEnd > mDirtyStart, "GenericConstBuffer::getDirtyBuffer() - Dirty range is invalid!" );
345   AssertFatal( mBuffer, "GenericConstBuffer::getDirtyBuffer() - Buffer is empty!" );
346
347   // Use the area we calculated during internalSet.
348   *size = mDirtyEnd - mDirtyStart;
349   *start = mDirtyStart;
350   const U8 *buffer = mBuffer + mDirtyStart;
351
352   // Clear the dirty state while we're here.
353   mDirtyStart = U32_MAX;
354   mDirtyEnd = 0;
355
356   return buffer;
357}
358
359inline const U8* GenericConstBuffer::getEntireBuffer()
360{
361   AssertFatal(mBuffer, "GenericConstBuffer::getDirtyBuffer() - Buffer is empty!");
362
363   return mBuffer;
364}
365
366inline bool GenericConstBuffer::isEqual( const GenericConstBuffer *buffer ) const
367{      
368   U32 bsize = mLayout->getBufferSize();
369   if ( bsize != buffer->mLayout->getBufferSize() )
370      return false;
371
372   return dMemcmp( mBuffer, buffer->getBuffer(), bsize ) == 0;
373}
374
375#endif // _GENERICCONSTBUFFER_H_
376