shaderData.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. #include "platform/platform.h"
  23. #include "materials/shaderData.h"
  24. #include "console/consoleTypes.h"
  25. #include "gfx/gfxDevice.h"
  26. #include "core/strings/stringUnit.h"
  27. #include "lighting/lightManager.h"
  28. #include "console/engineAPI.h"
  29. using namespace Torque;
  30. Vector<ShaderData*> ShaderData::smAllShaderData;
  31. IMPLEMENT_CONOBJECT( ShaderData );
  32. ConsoleDocClass( ShaderData,
  33. "@brief Special type of data block that stores information about a handwritten shader.\n\n"
  34. "To use hand written shaders, a ShaderData datablock must be used. This datablock "
  35. "refers only to the vertex and pixel shader filenames and a hardware target level. "
  36. "Shaders are API specific, so DirectX and OpenGL shaders must be explicitly identified.\n\n "
  37. "@tsexample\n"
  38. "// Used for the procedural clould system\n"
  39. "singleton ShaderData( CloudLayerShader )\n"
  40. "{\n"
  41. " DXVertexShaderFile = $Core::CommonShaderPath @ \"/cloudLayerV.hlsl\";\n"
  42. " DXPixelShaderFile = $Core::CommonShaderPath @ \"/cloudLayerP.hlsl\";\n"
  43. " OGLVertexShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerV.glsl\";\n"
  44. " OGLPixelShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerP.glsl\";\n"
  45. " pixVersion = 2.0;\n"
  46. "};\n"
  47. "@endtsexample\n\n"
  48. "@ingroup Shaders\n");
  49. ShaderData::ShaderData()
  50. {
  51. VECTOR_SET_ASSOCIATION( mShaderMacros );
  52. mUseDevicePixVersion = false;
  53. mPixVersion = 1.0;
  54. for( int i = 0; i < NumTextures; ++i)
  55. mRTParams[i] = false;
  56. }
  57. void ShaderData::initPersistFields()
  58. {
  59. addField("DXVertexShaderFile", TypeStringFilename, Offset(mDXVertexShaderName, ShaderData),
  60. "@brief %Path to the DirectX vertex shader file to use for this ShaderData.\n\n"
  61. "It must contain only one program and no pixel shader, just the vertex shader."
  62. "It can be either an HLSL or assembly level shader. HLSL's must have a "
  63. "filename extension of .hlsl, otherwise its assumed to be an assembly file.");
  64. addField("DXPixelShaderFile", TypeStringFilename, Offset(mDXPixelShaderName, ShaderData),
  65. "@brief %Path to the DirectX pixel shader file to use for this ShaderData.\n\n"
  66. "It must contain only one program and no vertex shader, just the pixel "
  67. "shader. It can be either an HLSL or assembly level shader. HLSL's "
  68. "must have a filename extension of .hlsl, otherwise its assumed to be an assembly file.");
  69. addField("OGLVertexShaderFile", TypeStringFilename, Offset(mOGLVertexShaderName, ShaderData),
  70. "@brief %Path to an OpenGL vertex shader file to use for this ShaderData.\n\n"
  71. "It must contain only one program and no pixel shader, just the vertex shader.");
  72. addField("OGLPixelShaderFile", TypeStringFilename, Offset(mOGLPixelShaderName, ShaderData),
  73. "@brief %Path to an OpenGL pixel shader file to use for this ShaderData.\n\n"
  74. "It must contain only one program and no vertex shader, just the pixel "
  75. "shader.");
  76. addField("useDevicePixVersion", TypeBool, Offset(mUseDevicePixVersion, ShaderData),
  77. "@brief If true, the maximum pixel shader version offered by the graphics card will be used.\n\n"
  78. "Otherwise, the script-defined pixel shader version will be used.\n\n");
  79. addField("pixVersion", TypeF32, Offset(mPixVersion, ShaderData),
  80. "@brief Indicates target level the shader should be compiled.\n\n"
  81. "Valid numbers at the time of this writing are 1.1, 1.4, 2.0, and 3.0. "
  82. "The shader will not run properly if the hardware does not support the "
  83. "level of shader compiled.");
  84. addField("defines", TypeRealString, Offset(mDefines, ShaderData),
  85. "@brief String of case-sensitive defines passed to the shader compiler.\n\n"
  86. "The string should be delimited by a semicolon, tab, or newline character."
  87. "@tsexample\n"
  88. "singleton ShaderData( FlashShader )\n"
  89. "{\n"
  90. "DXVertexShaderFile = $shaderGen::cachePath @ \"/postFx/flashV.hlsl\";\n"
  91. "DXPixelShaderFile = $shaderGen::cachePath @ \"/postFx/flashP.hlsl\";\n\n"
  92. " //Define setting the color of WHITE_COLOR.\n"
  93. "defines = \"WHITE_COLOR=float4(1.0,1.0,1.0,0.0)\";\n\n"
  94. "pixVersion = 2.0\n"
  95. "}\n"
  96. "@endtsexample\n\n"
  97. );
  98. addField("samplerNames", TypeRealString, Offset(mSamplerNames, ShaderData), NumTextures,
  99. "@brief Indicates names of samplers present in shader. Order is important.\n\n"
  100. "Order of sampler names are used to assert correct sampler register/location"
  101. "Other objects (GFXStateBlockData, PostEffect...) use index number to link samplers."
  102. );
  103. addField("rtParams", TypeBool, Offset(mRTParams, ShaderData), NumTextures, "");
  104. Parent::initPersistFields();
  105. // Make sure we get activation signals.
  106. LightManager::smActivateSignal.notify( &ShaderData::_onLMActivate );
  107. }
  108. bool ShaderData::onAdd()
  109. {
  110. if( !Parent::onAdd() )
  111. return false;
  112. mShaderMacros.clear();
  113. // Keep track of it.
  114. smAllShaderData.push_back( this );
  115. // NOTE: We initialize the shader on request.
  116. for(int i = 0; i < NumTextures; ++i)
  117. {
  118. if( mSamplerNames[i].isNotEmpty() && !mSamplerNames[i].startsWith("$") )
  119. mSamplerNames[i].insert(0, "$");
  120. }
  121. return true;
  122. }
  123. void ShaderData::onRemove()
  124. {
  125. // Remove it from the all shaders list.
  126. smAllShaderData.remove( this );
  127. Parent::onRemove();
  128. }
  129. const Vector<GFXShaderMacro>& ShaderData::_getMacros()
  130. {
  131. // If they have already been processed then
  132. // return the cached result.
  133. if ( mShaderMacros.size() != 0 || mDefines.isEmpty() )
  134. return mShaderMacros;
  135. mShaderMacros.clear();
  136. GFXShaderMacro macro;
  137. const U32 defineCount = StringUnit::getUnitCount( mDefines, ";\n\t" );
  138. for ( U32 i=0; i < defineCount; i++ )
  139. {
  140. String define = StringUnit::getUnit( mDefines, i, ";\n\t" );
  141. macro.name = StringUnit::getUnit( define, 0, "=" );
  142. macro.value = StringUnit::getUnit( define, 1, "=" );
  143. mShaderMacros.push_back( macro );
  144. }
  145. return mShaderMacros;
  146. }
  147. GFXShader* ShaderData::getShader( const Vector<GFXShaderMacro> &macros )
  148. {
  149. PROFILE_SCOPE( ShaderData_GetShader );
  150. // Combine the dynamic macros with our script defined macros.
  151. Vector<GFXShaderMacro> finalMacros;
  152. finalMacros.merge( _getMacros() );
  153. finalMacros.merge( macros );
  154. // Convert the final macro list to a string.
  155. String cacheKey;
  156. GFXShaderMacro::stringize( macros, &cacheKey );
  157. // Lookup the shader for this instance.
  158. ShaderCache::Iterator iter = mShaders.find( cacheKey );
  159. if ( iter != mShaders.end() )
  160. return iter->value;
  161. // Create the shader instance... if it fails then
  162. // bail out and return nothing to the caller.
  163. GFXShader *shader = _createShader( finalMacros );
  164. if ( !shader )
  165. return NULL;
  166. _checkDefinition(shader);
  167. // Store the shader in the cache and return it.
  168. mShaders.insertUnique( cacheKey, shader );
  169. return shader;
  170. }
  171. GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
  172. {
  173. F32 pixver = mPixVersion;
  174. if ( mUseDevicePixVersion )
  175. pixver = getMax( pixver, GFX->getPixelShaderVersion() );
  176. // Enable shader error logging.
  177. GFXShader::setLogging( true, true );
  178. GFXShader *shader = GFX->createShader();
  179. bool success = false;
  180. Vector<String> samplers;
  181. samplers.setSize(ShaderData::NumTextures);
  182. for(int i = 0; i < ShaderData::NumTextures; ++i)
  183. samplers[i] = mSamplerNames[i][0] == '$' ? mSamplerNames[i] : "$"+mSamplerNames[i];
  184. // Initialize the right shader type.
  185. switch( GFX->getAdapterType() )
  186. {
  187. case Direct3D11:
  188. {
  189. success = shader->init( mDXVertexShaderName,
  190. mDXPixelShaderName,
  191. pixver,
  192. macros,
  193. samplers);
  194. break;
  195. }
  196. case OpenGL:
  197. {
  198. success = shader->init( mOGLVertexShaderName,
  199. mOGLPixelShaderName,
  200. pixver,
  201. macros,
  202. samplers);
  203. break;
  204. }
  205. default:
  206. // Other device types are assumed to not support shaders.
  207. success = false;
  208. break;
  209. }
  210. #if defined(TORQUE_DEBUG)
  211. //Assert Sampler registers
  212. const Vector<GFXShaderConstDesc>& descs = shader->getShaderConstDesc();
  213. for(int i = 0; i < descs.size(); ++i)
  214. {
  215. if(descs[i].constType != GFXSCT_Sampler && descs[i].constType != GFXSCT_SamplerCube)
  216. continue;
  217. GFXShaderConstHandle *handle = shader->findShaderConstHandle(descs[i].name);
  218. if(!handle || !handle->isValid())
  219. continue;
  220. int reg = handle->getSamplerRegister();
  221. if( descs[i].name != samplers[reg] )
  222. {
  223. const char *err = avar("ShaderData(%s): samplerNames[%d] = \"%s\" are diferent to sampler in shader: %s : register(S%d)"
  224. ,getName(), reg, samplers[reg].c_str(), handle->getName().c_str(), reg);
  225. Con::printf(err);
  226. GFXAssertFatal(0, err);
  227. }
  228. }
  229. #endif
  230. // If we failed to load the shader then
  231. // cleanup and return NULL.
  232. if ( !success )
  233. SAFE_DELETE( shader );
  234. return shader;
  235. }
  236. void ShaderData::reloadShaders()
  237. {
  238. ShaderCache::Iterator iter = mShaders.begin();
  239. for ( ; iter != mShaders.end(); iter++ )
  240. iter->value->reload();
  241. }
  242. void ShaderData::reloadAllShaders()
  243. {
  244. Vector<ShaderData*>::iterator iter = smAllShaderData.begin();
  245. for ( ; iter != smAllShaderData.end(); iter++ )
  246. (*iter)->reloadShaders();
  247. }
  248. void ShaderData::_onLMActivate( const char *lm, bool activate )
  249. {
  250. // Only on activations do we do anything.
  251. if ( !activate )
  252. return;
  253. // Since the light manager usually swaps shadergen features
  254. // and changes system wide shader defines we need to completely
  255. // flush and rebuild all shaders.
  256. reloadAllShaders();
  257. }
  258. bool ShaderData::hasSamplerDef(const String &_samplerName, int &pos) const
  259. {
  260. String samplerName = _samplerName.startsWith("$") ? _samplerName : "$"+_samplerName;
  261. for(int i = 0; i < NumTextures; ++i)
  262. {
  263. if( mSamplerNames[i].equal(samplerName, String::NoCase ) )
  264. {
  265. pos = i;
  266. return true;
  267. }
  268. }
  269. pos = -1;
  270. return false;
  271. }
  272. bool ShaderData::_checkDefinition(GFXShader *shader)
  273. {
  274. bool error = false;
  275. Vector<String> samplers;
  276. samplers.reserve(NumTextures);
  277. bool rtParams[NumTextures];
  278. for(int i = 0; i < NumTextures; ++i)
  279. rtParams[i] = false;
  280. const Vector<GFXShaderConstDesc> &shaderConstDesc = shader->getShaderConstDesc();
  281. for(int i = 0; i < shaderConstDesc.size(); ++i)
  282. {
  283. const GFXShaderConstDesc &desc = shaderConstDesc[i];
  284. if(desc.constType == GFXSCT_Sampler)
  285. {
  286. samplers.push_back(desc.name );
  287. }
  288. }
  289. for(int i = 0; i < samplers.size(); ++i)
  290. {
  291. int pos;
  292. bool find = hasSamplerDef(samplers[i], pos);
  293. if(find && pos >= 0 && mRTParams[pos])
  294. {
  295. if( !shader->findShaderConstHandle( String::ToString("$rtParams%d", pos)) )
  296. {
  297. String errStr = String::ToString("ShaderData(%s) sampler[%d] used but rtParams%d not used in shader compilation. Possible error", shader->getPixelShaderFile().c_str(), pos, pos);
  298. Con::errorf(errStr);
  299. error = true;
  300. }
  301. }
  302. if(!find)
  303. {
  304. String errStr = String::ToString("ShaderData(%s) sampler %s not defined", shader->getPixelShaderFile().c_str(), samplers[i].c_str());
  305. Con::errorf(errStr);
  306. GFXAssertFatal(0, errStr);
  307. error = true;
  308. }
  309. }
  310. return !error;
  311. }
  312. DefineEngineMethod( ShaderData, reload, void, (),,
  313. "@brief Rebuilds all the vertex and pixel shader instances created from this ShaderData.\n\n"
  314. "@tsexample\n"
  315. "// Rebuild the shader instances from ShaderData CloudLayerShader\n"
  316. "CloudLayerShader.reload();\n"
  317. "@endtsexample\n\n")
  318. {
  319. object->reloadShaders();
  320. }