genericConstBuffer.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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. virtual 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 LinearColorF& 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_Float3x4 ||
  162. matrixType == GFXSCT_Float4x3 ||
  163. matrixType == GFXSCT_Float4x4,
  164. "GenericConstBuffer::set() - Invalid matrix type!" );
  165. internalSet( pd, matrixType, sizeof(MatrixF), &mat );
  166. }
  167. inline void set( const GenericConstBufferLayout::ParamDesc& pd, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType )
  168. {
  169. AssertFatal( matrixType == GFXSCT_Float2x2 ||
  170. matrixType == GFXSCT_Float3x3 ||
  171. matrixType == GFXSCT_Float3x4 ||
  172. matrixType == GFXSCT_Float4x3 ||
  173. matrixType == GFXSCT_Float4x4,
  174. "GenericConstBuffer::set() - Invalid matrix type!" );
  175. internalSet( pd, matrixType, sizeof(MatrixF)*arraySize, mat );
  176. }
  177. /// Gets the dirty buffer range and clears the dirty
  178. /// state at the same time.
  179. inline const U8* getDirtyBuffer( U32 *start, U32 *size );
  180. /// Gets the entire buffer ignoring dirty range
  181. inline const U8* getEntireBuffer();
  182. /// Sets the entire buffer as dirty or clears the dirty state.
  183. inline void setDirty( bool dirty );
  184. /// Returns true if the buffer has been modified since the
  185. /// last call to getDirtyBuffer or setDirty. The buffer is
  186. /// not dirty on initial creation.
  187. ///
  188. /// @see getDirtyBuffer
  189. /// @see setDirty
  190. inline bool isDirty() const { return mDirtyEnd != 0; }
  191. /// Returns true if have the same layout and hold the same
  192. /// data as the input buffer.
  193. inline bool isEqual( const GenericConstBuffer *buffer ) const;
  194. /// Returns our layout object.
  195. inline GenericConstBufferLayout* getLayout() const { return mLayout; }
  196. #ifdef TORQUE_DEBUG
  197. /// Helper function used to assert on unset constants.
  198. void assertUnassignedConstants( const char *shaderName );
  199. #endif
  200. protected:
  201. /// Returns a pointer to the raw buffer
  202. inline const U8* getBuffer() const { return mBuffer; }
  203. /// Called by the inlined set functions above to do the
  204. /// real dirty work of copying the data to the right location
  205. /// within the buffer.
  206. inline void internalSet( const GenericConstBufferLayout::ParamDesc &pd,
  207. const GFXShaderConstType constType,
  208. const U32 size,
  209. const void *data );
  210. /// The buffer layout.
  211. GenericConstBufferLayout *mLayout;
  212. /// The pointer to the contant store or
  213. /// NULL if the layout is empty.
  214. U8 *mBuffer;
  215. /// The byte offset to the start of the dirty
  216. /// range within the buffer or U32_MAX if the
  217. /// buffer is not dirty.
  218. U32 mDirtyStart;
  219. /// The btye offset to the end of the dirty
  220. /// range within the buffer or 0 if the buffer
  221. /// is not dirty.
  222. U32 mDirtyEnd;
  223. #ifdef TORQUE_DEBUG
  224. /// A vector used to keep track if a constant
  225. /// has beed assigned a value or not.
  226. ///
  227. /// @see assertUnassignedConstants
  228. Vector<bool> mWasAssigned;
  229. #endif
  230. };
  231. // NOTE: These inlines below are here to get the very best possible
  232. // performance when setting the device shader constants and can be
  233. // called 4000-8000 times per frame or more.
  234. //
  235. // You need a very good reason to consider changing them.
  236. inline void GenericConstBuffer::internalSet( const GenericConstBufferLayout::ParamDesc &pd,
  237. const GFXShaderConstType constType,
  238. const U32 size,
  239. const void *data )
  240. {
  241. // NOTE: We should have never gotten here if the buffer
  242. // was null as no valid shader constant could have been
  243. // assigned.
  244. //
  245. // If this happens its a bug in another part of the code.
  246. //
  247. AssertFatal( mBuffer, "GenericConstBuffer::internalSet - The buffer is NULL!" );
  248. if ( mLayout->set( pd, constType, size, data, mBuffer ) )
  249. {
  250. #ifdef TORQUE_DEBUG
  251. // Update the debug assignment tracking.
  252. mWasAssigned[ pd.index ] = true;
  253. #endif
  254. // Keep track of the dirty range so it can be queried
  255. // later in GenericConstBuffer::getDirtyBuffer.
  256. mDirtyStart = getMin( pd.offset, mDirtyStart );
  257. mDirtyEnd = getMax( pd.offset + pd.size, mDirtyEnd );
  258. }
  259. }
  260. inline void GenericConstBuffer::setDirty( bool dirty )
  261. {
  262. if ( !mBuffer )
  263. return;
  264. if ( dirty )
  265. {
  266. mDirtyStart = 0;
  267. mDirtyEnd = mLayout->getBufferSize();
  268. }
  269. else if ( !dirty )
  270. {
  271. mDirtyStart = U32_MAX;
  272. mDirtyEnd = 0;
  273. }
  274. }
  275. inline const U8* GenericConstBuffer::getDirtyBuffer( U32 *start, U32 *size )
  276. {
  277. AssertFatal( isDirty(), "GenericConstBuffer::getDirtyBuffer() - Buffer is not dirty!" );
  278. AssertFatal( mDirtyEnd > mDirtyStart, "GenericConstBuffer::getDirtyBuffer() - Dirty range is invalid!" );
  279. AssertFatal( mBuffer, "GenericConstBuffer::getDirtyBuffer() - Buffer is empty!" );
  280. // Use the area we calculated during internalSet.
  281. *size = mDirtyEnd - mDirtyStart;
  282. *start = mDirtyStart;
  283. const U8 *buffer = mBuffer + mDirtyStart;
  284. // Clear the dirty state while we're here.
  285. mDirtyStart = U32_MAX;
  286. mDirtyEnd = 0;
  287. return buffer;
  288. }
  289. inline const U8* GenericConstBuffer::getEntireBuffer()
  290. {
  291. AssertFatal(mBuffer, "GenericConstBuffer::getDirtyBuffer() - Buffer is empty!");
  292. return mBuffer;
  293. }
  294. inline bool GenericConstBuffer::isEqual( const GenericConstBuffer *buffer ) const
  295. {
  296. U32 bsize = mLayout->getBufferSize();
  297. if ( bsize != buffer->mLayout->getBufferSize() )
  298. return false;
  299. return dMemcmp( mBuffer, buffer->getBuffer(), bsize ) == 0;
  300. }
  301. #endif // _GENERICCONSTBUFFER_H_