BsParamBlocks.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsCorePrerequisites.h"
  5. #include "RenderAPI/BsGpuParamDesc.h"
  6. #include "RenderAPI/BsGpuParams.h"
  7. #include "RenderAPI/BsRenderAPI.h"
  8. #include "RenderAPI/BsGpuParamBlockBuffer.h"
  9. namespace bs { namespace ct
  10. {
  11. /** @addtogroup Renderer-Internal
  12. * @{
  13. */
  14. /** Wrapper for a single parameter in a parameter block buffer. */
  15. template<class T>
  16. class ParamBlockParam
  17. {
  18. public:
  19. ParamBlockParam() { }
  20. ParamBlockParam(const GpuParamDataDesc& paramDesc)
  21. :mParamDesc(paramDesc)
  22. { }
  23. /**
  24. * Sets the parameter in the provided parameter block buffer. Caller is responsible for ensuring the param block
  25. * buffer contains this parameter.
  26. */
  27. void set(const SPtr<GpuParamBlockBuffer>& paramBlock, const T& value, UINT32 arrayIdx = 0) const
  28. {
  29. #if BS_DEBUG_MODE
  30. if (arrayIdx >= mParamDesc.arraySize)
  31. {
  32. BS_EXCEPT(InvalidParametersException, "Array index out of range. Array size: " +
  33. toString(mParamDesc.arraySize) + ". Requested size: " + toString(arrayIdx));
  34. }
  35. #endif
  36. UINT32 elementSizeBytes = mParamDesc.elementSize * sizeof(UINT32);
  37. UINT32 sizeBytes = std::min(elementSizeBytes, (UINT32)sizeof(T)); // Truncate if it doesn't fit within parameter size
  38. bool transposeMatrices = RenderAPI::instance().getAPIInfo().isFlagSet(RenderAPIFeatureFlag::ColumnMajorMatrices);
  39. if (TransposePolicy<T>::transposeEnabled(transposeMatrices))
  40. {
  41. auto transposed = TransposePolicy<T>::transpose(value);
  42. paramBlock->write((mParamDesc.cpuMemOffset + arrayIdx * mParamDesc.arrayElementStride) * sizeof(UINT32),
  43. &transposed, sizeBytes);
  44. }
  45. else
  46. paramBlock->write((mParamDesc.cpuMemOffset + arrayIdx * mParamDesc.arrayElementStride) * sizeof(UINT32),
  47. &value, sizeBytes);
  48. // Set unused bytes to 0
  49. if (sizeBytes < elementSizeBytes)
  50. {
  51. UINT32 diffSize = elementSizeBytes - sizeBytes;
  52. paramBlock->zeroOut((mParamDesc.cpuMemOffset + arrayIdx * mParamDesc.arrayElementStride) * sizeof(UINT32) +
  53. sizeBytes, diffSize);
  54. }
  55. }
  56. /**
  57. * Gets the parameter in the provided parameter block buffer. Caller is responsible for ensuring the param block
  58. * buffer contains this parameter.
  59. */
  60. T get(const SPtr<GpuParamBlockBuffer>& paramBlock, UINT32 arrayIdx = 0) const
  61. {
  62. #if BS_DEBUG_MODE
  63. if (arrayIdx >= mParamDesc.arraySize)
  64. {
  65. LOGERR("Array index out of range. Array size: " + toString(mParamDesc.arraySize) + ". Requested size: " +
  66. toString(arrayIdx));
  67. return T();
  68. }
  69. #endif
  70. UINT32 elementSizeBytes = mParamDesc.elementSize * sizeof(UINT32);
  71. UINT32 sizeBytes = std::min(elementSizeBytes, (UINT32)sizeof(T));
  72. T value;
  73. paramBlock->read((mParamDesc.cpuMemOffset + arrayIdx * mParamDesc.arrayElementStride) * sizeof(UINT32), &value,
  74. sizeBytes);
  75. return value;
  76. }
  77. protected:
  78. GpuParamDataDesc mParamDesc;
  79. };
  80. /** Base class for all parameter blocks. */
  81. struct BS_CORE_EXPORT ParamBlock
  82. {
  83. virtual ~ParamBlock();
  84. virtual void initialize() = 0;
  85. };
  86. /**
  87. * Takes care of initializing param block definitions in a delayed manner since they depend on engine systems yet
  88. * are usually used as global variables which are initialized before engine systems are ready.
  89. */
  90. class BS_CORE_EXPORT ParamBlockManager : public Module<ParamBlockManager>
  91. {
  92. public:
  93. ParamBlockManager();
  94. /** Registers a new param block, and initializes it when ready. */
  95. static void registerBlock(ParamBlock* paramBlock);
  96. /** Removes the param block from the initialization list. */
  97. static void unregisterBlock(ParamBlock* paramBlock);
  98. private:
  99. static Vector<ParamBlock*> sToInitialize;
  100. };
  101. /**
  102. * Starts a new custom parameter block. Custom parameter blocks allow you to create C++ structures that map directly
  103. * to GPU program buffers (for example uniform buffer in OpenGL or constant buffer in DX). Must be followed by
  104. * BS_PARAM_BLOCK_END.
  105. */
  106. #define BS_PARAM_BLOCK_BEGIN(Name) \
  107. struct Name : ParamBlock \
  108. { \
  109. Name() \
  110. { \
  111. ParamBlockManager::registerBlock(this); \
  112. } \
  113. \
  114. SPtr<GpuParamBlockBuffer> createBuffer() const { return GpuParamBlockBuffer::create(mBlockSize); } \
  115. \
  116. private: \
  117. friend class ParamBlockManager; \
  118. \
  119. void initialize() override \
  120. { \
  121. mParams = getEntries(); \
  122. RenderAPI& rapi = RenderAPI::instance(); \
  123. \
  124. GpuParamBlockDesc blockDesc = rapi.generateParamBlockDesc(#Name, mParams); \
  125. mBlockSize = blockDesc.blockSize * sizeof(UINT32); \
  126. \
  127. initEntries(); \
  128. } \
  129. \
  130. struct META_FirstEntry {}; \
  131. static void META_GetPrevEntries(Vector<GpuParamDataDesc>& params, META_FirstEntry id) { } \
  132. void META_InitPrevEntry(const Vector<GpuParamDataDesc>& params, UINT32 idx, META_FirstEntry id) { } \
  133. \
  134. typedef META_FirstEntry
  135. /**
  136. * Registers a new entry in a parameter block. Must be called in between BS_PARAM_BLOCK_BEGIN and BS_PARAM_BLOCK_END calls.
  137. */
  138. #define BS_PARAM_BLOCK_ENTRY_ARRAY(Type, Name, NumElements) \
  139. META_Entry_##Name; \
  140. \
  141. struct META_NextEntry_##Name {}; \
  142. static void META_GetPrevEntries(Vector<GpuParamDataDesc>& params, META_NextEntry_##Name id) \
  143. { \
  144. META_GetPrevEntries(params, META_Entry_##Name()); \
  145. \
  146. params.push_back(GpuParamDataDesc()); \
  147. GpuParamDataDesc& newEntry = params.back(); \
  148. newEntry.name = #Name; \
  149. newEntry.type = (GpuParamDataType)TGpuDataParamInfo<Type>::TypeId; \
  150. newEntry.arraySize = NumElements; \
  151. newEntry.elementSize = sizeof(Type); \
  152. } \
  153. \
  154. void META_InitPrevEntry(const Vector<GpuParamDataDesc>& params, UINT32 idx, META_NextEntry_##Name id) \
  155. { \
  156. META_InitPrevEntry(params, idx - 1, META_Entry_##Name()); \
  157. Name = ParamBlockParam<Type>(params[idx]); \
  158. } \
  159. \
  160. public: \
  161. ParamBlockParam<Type> Name; \
  162. \
  163. private: \
  164. typedef META_NextEntry_##Name
  165. /**
  166. * Registers a new entry in a parameter block. Must be called in between BS_PARAM_BLOCK_BEGIN and BS_PARAM_BLOCK_END calls.
  167. */
  168. #define BS_PARAM_BLOCK_ENTRY(Type, Name) BS_PARAM_BLOCK_ENTRY_ARRAY(Type, Name, 1)
  169. /** Ends parameter block definition. See BS_PARAM_BLOCK_BEGIN. */
  170. #define BS_PARAM_BLOCK_END \
  171. META_LastEntry; \
  172. \
  173. static Vector<GpuParamDataDesc> getEntries() \
  174. { \
  175. Vector<GpuParamDataDesc> entries; \
  176. META_GetPrevEntries(entries, META_LastEntry()); \
  177. return entries; \
  178. } \
  179. \
  180. void initEntries() \
  181. { \
  182. META_InitPrevEntry(mParams, (UINT32)mParams.size() - 1, META_LastEntry()); \
  183. } \
  184. \
  185. Vector<GpuParamDataDesc> mParams; \
  186. UINT32 mBlockSize; \
  187. };
  188. /** @} */
  189. }}