BsMaterial.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #pragma once
  5. #include "BsCorePrerequisites.h"
  6. #include "BsResource.h"
  7. #include "BsGpuParam.h"
  8. #include "BsMaterialProxy.h"
  9. #include "BsVector2.h"
  10. #include "BsVector3.h"
  11. #include "BsVector4.h"
  12. #include "BsMatrix3.h"
  13. #include "BsMatrix4.h"
  14. namespace BansheeEngine
  15. {
  16. /**
  17. * @brief Type of material dirty flags
  18. */
  19. enum class MaterialDirtyFlag
  20. {
  21. Material = 0x01, /**< Internal material data is dirty. */
  22. Proxy = 0x02, /**< Active proxy needs to be updated. */
  23. Params = 0x04 /**< Parameters are dirty. */
  24. };
  25. /**
  26. * @brief Helper class containing parameters for all types
  27. * of GPU programs used in a pass.
  28. */
  29. class BS_CORE_EXPORT PassParameters
  30. {
  31. public:
  32. GpuParamsPtr mVertParams;
  33. GpuParamsPtr mFragParams;
  34. GpuParamsPtr mGeomParams;
  35. GpuParamsPtr mHullParams;
  36. GpuParamsPtr mDomainParams;
  37. GpuParamsPtr mComputeParams;
  38. /**
  39. * @brief Returns a set of GPU parameters based on an index.
  40. *
  41. * @note Useful when needing to iterate over all sets of GPU parameters.
  42. */
  43. GpuParamsPtr& getParamByIdx(UINT32 idx)
  44. {
  45. GpuParamsPtr* paramArray[] = {&mVertParams, &mFragParams, &mGeomParams, &mHullParams, &mDomainParams, &mComputeParams};
  46. return *paramArray[idx];
  47. }
  48. /**
  49. * @brief Sets GPU parameters based on an index.
  50. *
  51. * @note Useful when needing to iterate over all sets of GPU parameters.
  52. */
  53. void setParamByIdx(UINT32 idx, const GpuParamsPtr& params)
  54. {
  55. GpuParamsPtr* paramArray[] = {&mVertParams, &mFragParams, &mGeomParams, &mHullParams, &mDomainParams, &mComputeParams};
  56. (*paramArray[idx]) = params;
  57. }
  58. /**
  59. * @brief Returns the total number of stored sets of
  60. * GPU parameters in this object.
  61. */
  62. UINT32 getNumParams() const { return 6; }
  63. };
  64. /**
  65. * @brief Material represents a shader and parameters used to set up
  66. * that shader. It provides a simple interface for manipulating the
  67. * parameters.
  68. */
  69. class BS_CORE_EXPORT Material : public Resource
  70. {
  71. public:
  72. /**
  73. * @brief Data used to described a structure defined within a shader.
  74. */
  75. struct StructData
  76. {
  77. StructData()
  78. :size(0), data(nullptr)
  79. { }
  80. StructData(UINT32 _size)
  81. :size(_size)
  82. {
  83. data = std::shared_ptr<void>(bs_alloc<ScratchAlloc>(_size), &bs_free<ScratchAlloc>);
  84. }
  85. /**
  86. * @brief Writes the specified data to the internal buffer. Caller
  87. * must ensure size of the provided buffer is correct.
  88. */
  89. void write(void* _data)
  90. {
  91. memcpy(data.get(), _data, size);
  92. }
  93. std::shared_ptr<void> data;
  94. UINT32 size;
  95. };
  96. ~Material();
  97. /**
  98. * @brief Sets a shader that will be used by the material. Best technique within the
  99. * provided shader will be used for the material.
  100. *
  101. * @note Shader must be set before doing any other operations with the material.
  102. *
  103. * After setting the shader if change any systems that a shader technique is
  104. * dependent upon (render system, renderer, etc), you will need to call this
  105. * method again on all your Materials to make sure technique used is updated.
  106. */
  107. void setShader(ShaderPtr shader);
  108. /**
  109. * @brief Returns the currently active shader.
  110. */
  111. ShaderPtr getShader() const { return mShader; }
  112. /** @brief Assigns a texture to the shader parameter with the specified name. */
  113. void setTexture(const String& name, const HTexture& value) { return getParamTexture(name).set(value); }
  114. /** @brief Assigns a sampler state to the shader parameter with the specified name. */
  115. void setSamplerState(const String& name, const HSamplerState& value) { return getParamSamplerState(name).set(value); }
  116. /**
  117. * @brief Assigns a float value to the shader parameter with the specified name.
  118. *
  119. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  120. */
  121. void setFloat(const String& name, float value, UINT32 arrayIdx = 0) { return getParamFloat(name).set(value, arrayIdx); }
  122. /**
  123. * @brief Assigns a color to the shader parameter with the specified name.
  124. *
  125. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  126. */
  127. void setColor(const String& name, const Color& value, UINT32 arrayIdx = 0);
  128. /**
  129. * @brief Assigns a 2D vector to the shader parameter with the specified name.
  130. *
  131. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  132. */
  133. void setVec2(const String& name, const Vector2& value, UINT32 arrayIdx = 0) { return getParamVec2(name).set(value, arrayIdx); }
  134. /**
  135. * @brief Assigns a 3D vector to the shader parameter with the specified name.
  136. *
  137. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  138. */
  139. void setVec3(const String& name, const Vector3& value, UINT32 arrayIdx = 0) { return getParamVec3(name).set(value, arrayIdx); }
  140. /**
  141. * @brief Assigns a 4D vector to the shader parameter with the specified name.
  142. *
  143. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  144. */
  145. void setVec4(const String& name, const Vector4& value, UINT32 arrayIdx = 0) { return getParamVec4(name).set(value, arrayIdx); }
  146. /**
  147. * @brief Assigns a 3x3 matrix to the shader parameter with the specified name.
  148. *
  149. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  150. */
  151. void setMat3(const String& name, const Matrix3& value, UINT32 arrayIdx = 0) { return getParamMat3(name).set(value, arrayIdx); }
  152. /**
  153. * @brief Assigns a 4x4 matrix to the shader parameter with the specified name.
  154. *
  155. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  156. */
  157. void setMat4(const String& name, const Matrix4& value, UINT32 arrayIdx = 0) { return getParamMat4(name).set(value, arrayIdx); }
  158. /**
  159. * @brief Assigns a structure to the shader parameter with the specified name.
  160. *
  161. * Structure is provided as a raw buffer and caller must ensure structure in buffer
  162. * matches what the shader expects.
  163. *
  164. * Optionally if the parameter is an array you may provide an array index to assign the value to.
  165. */
  166. void setStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx = 0) { return getParamStruct(name).set(value, size, arrayIdx); }
  167. /**
  168. * @brief Assign a parameter block buffer with the specified name.
  169. *
  170. * @note Parameter block buffers can be used as quick way of setting multiple parameters on a material at once, or
  171. * potentially sharing parameters between multiple materials. This reduces driver overhead as the parameters
  172. * in the buffers need only be set once and then reused multiple times.
  173. */
  174. void setParamBlockBuffer(const String& name, const GpuParamBlockBufferPtr& paramBlock);
  175. /** @brief Returns a texture assigned with the parameter with the specified name. */
  176. HTexture getTexture(const String& name) const { return getParamTexture(name).get(); }
  177. /** @brief Returns a sampler state assigned with the parameter with the specified name. */
  178. HSamplerState getSamplerState(const String& name) const { return getParamSamplerState(name).get(); }
  179. /**
  180. * @brief Returns a float value assigned with the parameter with the specified name.
  181. *
  182. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  183. */
  184. float getFloat(const String& name, UINT32 arrayIdx = 0) const { return getParamFloat(name).get(arrayIdx); }
  185. /**
  186. * @brief Returns a 2D vector assigned with the parameter with the specified name.
  187. *
  188. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  189. */
  190. Vector2 getVec2(const String& name, UINT32 arrayIdx = 0) const { return getParamVec2(name).get(arrayIdx); }
  191. /**
  192. * @brief Returns a 3D vector assigned with the parameter with the specified name.
  193. *
  194. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  195. */
  196. Vector3 getVec3(const String& name, UINT32 arrayIdx = 0) const { return getParamVec3(name).get(arrayIdx); }
  197. /**
  198. * @brief Returns a 4D vector assigned with the parameter with the specified name.
  199. *
  200. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  201. */
  202. Vector4 getVec4(const String& name, UINT32 arrayIdx = 0) const { return getParamVec4(name).get(arrayIdx); }
  203. /**
  204. * @brief Returns a 3x3 matrix assigned with the parameter with the specified name.
  205. *
  206. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  207. */
  208. Matrix3 getMat3(const String& name, UINT32 arrayIdx = 0) const { return getParamMat3(name).get(arrayIdx); }
  209. /**
  210. * @brief Returns a 4x4 matrix assigned with the parameter with the specified name.
  211. *
  212. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  213. */
  214. Matrix4 getMat4(const String& name, UINT32 arrayIdx = 0) const { return getParamMat4(name).get(arrayIdx); }
  215. /**
  216. * @brief Returns a buffer representing a structure assigned to the parameter with the specified name.
  217. *
  218. * Optionally if the parameter is an array you may provide an array index you which to retrieve.
  219. */
  220. StructData getStructData(const String& name, UINT32 arrayIdx = 0) const;
  221. /**
  222. * @brief Returns a float GPU parameter. This parameter may be used for
  223. * more efficiently getting/setting GPU parameter values than calling
  224. * Material::get* / Material::set* methods.
  225. *
  226. * @note Expected behavior is that you would retrieve this parameter when
  227. * initially constructing the material, and then use it throughout material
  228. * lifetime to assign and retrieve parameter values.
  229. *
  230. * If material shader changes this handle will be invalidated.
  231. */
  232. GpuParamFloat getParamFloat(const String& name) const;
  233. /**
  234. * @brief Returns a 2D vector GPU parameter. This parameter may be used for
  235. * more efficiently getting/setting GPU parameter values than calling
  236. * Material::get* / Material::set* methods.
  237. *
  238. * @note Expected behavior is that you would retrieve this parameter when
  239. * initially constructing the material, and then use it throughout material
  240. * lifetime to assign and retrieve parameter values.
  241. *
  242. * If material shader changes this handle will be invalidated.
  243. */
  244. GpuParamVec2 getParamVec2(const String& name) const;
  245. /**
  246. * @brief Returns a 3D vector GPU parameter. This parameter may be used for
  247. * more efficiently getting/setting GPU parameter values than calling
  248. * Material::get* / Material::set* methods.
  249. *
  250. * @note Expected behavior is that you would retrieve this parameter when
  251. * initially constructing the material, and then use it throughout material
  252. * lifetime to assign and retrieve parameter values.
  253. *
  254. * If material shader changes this handle will be invalidated.
  255. */
  256. GpuParamVec3 getParamVec3(const String& name) const;
  257. /**
  258. * @brief Returns a 4D vector GPU parameter. This parameter may be used for
  259. * more efficiently getting/setting GPU parameter values than calling
  260. * Material::get* / Material::set* methods.
  261. *
  262. * @note Expected behavior is that you would retrieve this parameter when
  263. * initially constructing the material, and then use it throughout material
  264. * lifetime to assign and retrieve parameter values.
  265. *
  266. * If material shader changes this handle will be invalidated.
  267. */
  268. GpuParamVec4 getParamVec4(const String& name) const;
  269. /**
  270. * @brief Returns a 3x3 matrix GPU parameter. This parameter may be used for
  271. * more efficiently getting/setting GPU parameter values than calling
  272. * Material::get* / Material::set* methods.
  273. *
  274. * @note Expected behavior is that you would retrieve this parameter when
  275. * initially constructing the material, and then use it throughout material
  276. * lifetime to assign and retrieve parameter values.
  277. *
  278. * If material shader changes this handle will be invalidated.
  279. */
  280. GpuParamMat3 getParamMat3(const String& name) const;
  281. /**
  282. * @brief Returns a 4x4 matrix GPU parameter. This parameter may be used for
  283. * more efficiently getting/setting GPU parameter values than calling
  284. * Material::get* / Material::set* methods.
  285. *
  286. * @note Expected behavior is that you would retrieve this parameter when
  287. * initially constructing the material, and then use it throughout material
  288. * lifetime to assign and retrieve parameter values.
  289. *
  290. * If material shader changes this handle will be invalidated.
  291. */
  292. GpuParamMat4 getParamMat4(const String& name) const;
  293. /**
  294. * @brief Returns a structure GPU parameter. This parameter may be used for
  295. * more efficiently getting/setting GPU parameter values than calling
  296. * Material::get* / Material::set* methods.
  297. *
  298. * @note Expected behavior is that you would retrieve this parameter when
  299. * initially constructing the material, and then use it throughout material
  300. * lifetime to assign and retrieve parameter values.
  301. *
  302. * If material shader changes this handle will be invalidated.
  303. */
  304. GpuParamStruct getParamStruct(const String& name) const;
  305. /**
  306. * @brief Returns a texture GPU parameter. This parameter may be used for
  307. * more efficiently getting/setting GPU parameter values than calling
  308. * Material::get* / Material::set* methods.
  309. *
  310. * @note Expected behavior is that you would retrieve this parameter when
  311. * initially constructing the material, and then use it throughout material
  312. * lifetime to assign and retrieve parameter values.
  313. *
  314. * If material shader changes this handle will be invalidated.
  315. */
  316. GpuParamTexture getParamTexture(const String& name) const;
  317. /**
  318. * @brief Returns a sampler state GPU parameter. This parameter may be used for
  319. * more efficiently getting/setting GPU parameter values than calling
  320. * Material::get* / Material::set* methods.
  321. *
  322. * @note Expected behavior is that you would retrieve this parameter when
  323. * initially constructing the material, and then use it throughout material
  324. * lifetime to assign and retrieve parameter values.
  325. *
  326. * If material shader changes this handle will be invalidated.
  327. */
  328. GpuParamSampState getParamSamplerState(const String& name) const;
  329. /**
  330. * @brief Returns the number of passes that are used
  331. * by the shader contained in the material.
  332. */
  333. UINT32 getNumPasses() const;
  334. /**
  335. * @brief Retrieves a specific shader pass.
  336. */
  337. PassPtr getPass(UINT32 passIdx) const;
  338. /**
  339. * @brief Returns a set of parameters for all GPU programs
  340. * in the specified shader pass.
  341. */
  342. PassParametersPtr getPassParameters(UINT32 passIdx) const;
  343. /**
  344. * @brief Creates a new empty material.
  345. *
  346. * @note Make sure you call Material::setShader before using it.
  347. */
  348. static HMaterial create();
  349. /**
  350. * @brief Creates a new material with the specified shader.
  351. */
  352. static HMaterial create(ShaderPtr shader);
  353. /************************************************************************/
  354. /* CORE PROXY */
  355. /************************************************************************/
  356. /**
  357. * @brief Checks is the core dirty flag set. This is used by external systems
  358. * to know when internal data has changed and core thread potentially needs to be notified.
  359. *
  360. * @note Sim thread only.
  361. */
  362. bool _isCoreDirty(MaterialDirtyFlag flag) const;
  363. /**
  364. * @brief Marks the core dirty flag as clean.
  365. *
  366. * @note Sim thread only.
  367. */
  368. void _markCoreClean(MaterialDirtyFlag flag);
  369. /**
  370. * @brief Gets the currently active proxy of this material.
  371. */
  372. MaterialProxyPtr _getActiveProxy() const { return mActiveProxy; }
  373. /**
  374. * @brief Sets an active proxy for this material.
  375. */
  376. void _setActiveProxy(const MaterialProxyPtr& proxy) { mActiveProxy = proxy; }
  377. /**
  378. * @brief Returns updated GPU parameters since the last time the parameters were marked clean.
  379. */
  380. Vector<MaterialProxy::ParamsBindInfo> _getDirtyProxyParams();
  381. /**
  382. * @brief Creates a new core proxy from the currently set material data. Core proxies ensure
  383. * that the core thread has all the necessary material data, while avoiding the need
  384. * to manage Material itself on the core thread.
  385. *
  386. * @note Sim thread only.
  387. * You generally need to update the core thread with a new proxy whenever core
  388. * dirty flag is set.
  389. */
  390. MaterialProxyPtr _createProxy();
  391. protected:
  392. /**
  393. * @copydoc Resource::destroy_internal
  394. */
  395. void destroy_internal();
  396. /**
  397. * @brief Allows you to retrieve a handle to a parameter that you can then use for quickly
  398. * setting and retrieving parameter data. This allows you to set/get parameter data
  399. * without all the cost of extra lookups otherwise required.
  400. *
  401. * @note All of these handles will be invalidated if material shader ever changes. It is up to the
  402. * caller to keep track of that.
  403. */
  404. template <typename T>
  405. void getParam(const String& name, TGpuDataParam<T>& output) const
  406. {
  407. throwIfNotInitialized();
  408. auto iterFind = mValidParams.find(name);
  409. if(iterFind == mValidParams.end())
  410. {
  411. LOGWRN("Material doesn't have a parameter named " + name);
  412. return;
  413. }
  414. const String& gpuVarName = iterFind->second;
  415. GpuParamsPtr params = findParamsWithName(gpuVarName);
  416. params->getParam<T>(gpuVarName, output);
  417. }
  418. private:
  419. friend class MaterialManager;
  420. ShaderPtr mShader;
  421. TechniquePtr mBestTechnique;
  422. INT32 mCoreDirtyFlags;
  423. Set<String> mValidShareableParamBlocks;
  424. Map<String, String> mValidParams; // Also maps Shader param name -> gpu variable name
  425. Vector<PassParametersPtr> mParametersPerPass;
  426. Vector<GpuParamBlockBufferPtr> mParamBuffers;
  427. MaterialProxyPtr mActiveProxy;
  428. Material();
  429. /**
  430. * @brief Throw an exception if no shader is set, or no acceptable
  431. * technique was found.
  432. */
  433. void throwIfNotInitialized() const;
  434. /**
  435. * @brief Marks the core data as dirty.
  436. */
  437. void markCoreDirty() { mCoreDirtyFlags = 0xFFFFFFFF; }
  438. /**
  439. * @brief Retrieves a list of all shader GPU parameters, and the GPU program variable names they map to.
  440. */
  441. const Map<String, String>& getValidParamNames() const { return mValidParams; }
  442. /**
  443. * @brief Initializes the material by using the best technique from the currently set shader. Shader
  444. * must contain the technique that matches the current renderer and render system.
  445. */
  446. void initBestTechnique();
  447. /**
  448. * @brief Constructs a map containing all data parameters (e.g. float, vector3, color).
  449. * Map contains parameter names and descriptions.
  450. */
  451. Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<GpuParamDescPtr>& paramDescs) const;
  452. /**
  453. * @brief Constructs a list containing all object parameter (e.g. texture, sampler state) names.
  454. */
  455. Set<String> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs) const;
  456. /**
  457. * @brief Constructs a list containing all shareable parameter block names. Shareable blocks may be shared between
  458. * different GPU programs, passes or even materials.
  459. */
  460. Set<String> determineValidShareableParamBlocks(const Vector<GpuParamDescPtr>& paramDescs) const;
  461. /**
  462. * @brief Constructs a map that maps parameter names to a parameter block.
  463. */
  464. Map<String, String> determineParameterToBlockMapping(const Vector<GpuParamDescPtr>& paramDescs);
  465. /**
  466. * @brief Checks are the specified two parameters equal
  467. *
  468. * @param paramA The parameter a to compare.
  469. * @param paramB The parameter b to compare.
  470. * @param ignoreBufferOffsets (optional) If true, parameter offsets into the parameter buffer will be ignored
  471. * when comparing.
  472. */
  473. bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets = false) const;
  474. /**
  475. * @brief Frees all parameter block buffers.
  476. */
  477. void freeParamBuffers();
  478. /**
  479. * @brief Finds a set of GPU parameters containing a data (e.g. float, vector2) parameter with the provided name.
  480. */
  481. GpuParamsPtr findParamsWithName(const String& name) const;
  482. /**
  483. * @brief Finds a set of GPU parameters containing a texture parameter with the provided name.
  484. */
  485. GpuParamsPtr findTexWithName(const String& name) const;
  486. /**
  487. * @brief Finds a set of GPU parameters containing a sampler state parameter with the provided name.
  488. */
  489. GpuParamsPtr findSamplerStateWithName(const String& name) const;
  490. /************************************************************************/
  491. /* RTTI */
  492. /************************************************************************/
  493. public:
  494. friend class MaterialRTTI;
  495. static RTTITypeBase* getRTTIStatic();
  496. virtual RTTITypeBase* getRTTI() const;
  497. };
  498. }