genericConstBuffer.h 13 KB

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