genericConstBuffer.h 13 KB

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