shaderData.cpp
Engine/source/materials/shaderData.cpp
Public Functions
ConsoleDocClass(ShaderData , "@brief Special type of data block that stores information about <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> handwritten <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shader.\n\n</a>" "To use hand written shaders, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classshaderdata/">ShaderData</a> datablock must be used. This datablock " "refers only <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the vertex and pixel shader filenames and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> hardware target level. " "Shaders are API specific, so DirectX and <a href="/coding/file/gfxenums_8h/#gfxenums_8h_1a56a87c3b5eae9ccbc914a79dfcd0e5f8adfde619af40503997cc57fc8af21825c">OpenGL</a> shaders must be explicitly <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">identified.\n\n</a> " " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the procedural clould <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">system\n</a>" "singleton <a href="/coding/class/classshaderdata/">ShaderData</a>(CloudLayerShader)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " DXVertexShaderFile=$Core::CommonShaderPath @ \"/cloudLayerV.hlsl\";\n" " DXPixelShaderFile = $Core::CommonShaderPath @ \"/cloudLayerP.hlsl\";\n" " OGLVertexShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerV.glsl\";\n" " OGLPixelShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerP.glsl\";\n" " pixVersion = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Shaders\n</a>" )
DefineEngineMethod(ShaderData , reload , void , () , "@brief Rebuilds all the vertex and pixel shader instances created from this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShaderData.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Rebuild the shader instances from <a href="/coding/class/classshaderdata/">ShaderData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">CloudLayerShader\n</a>" "CloudLayerShader.reload();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" )
Detailed Description
Public Functions
ConsoleDocClass(ShaderData , "@brief Special type of data block that stores information about <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> handwritten <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shader.\n\n</a>" "To use hand written shaders, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classshaderdata/">ShaderData</a> datablock must be used. This datablock " "refers only <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the vertex and pixel shader filenames and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> hardware target level. " "Shaders are API specific, so DirectX and <a href="/coding/file/gfxenums_8h/#gfxenums_8h_1a56a87c3b5eae9ccbc914a79dfcd0e5f8adfde619af40503997cc57fc8af21825c">OpenGL</a> shaders must be explicitly <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">identified.\n\n</a> " " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the procedural clould <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">system\n</a>" "singleton <a href="/coding/class/classshaderdata/">ShaderData</a>(CloudLayerShader)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " DXVertexShaderFile=$Core::CommonShaderPath @ \"/cloudLayerV.hlsl\";\n" " DXPixelShaderFile = $Core::CommonShaderPath @ \"/cloudLayerP.hlsl\";\n" " OGLVertexShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerV.glsl\";\n" " OGLPixelShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerP.glsl\";\n" " pixVersion = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Shaders\n</a>" )
DefineEngineMethod(ShaderData , reload , void , () , "@brief Rebuilds all the vertex and pixel shader instances created from this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShaderData.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Rebuild the shader instances from <a href="/coding/class/classshaderdata/">ShaderData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">CloudLayerShader\n</a>" "CloudLayerShader.reload();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" )
IMPLEMENT_CONOBJECT(ShaderData )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "materials/shaderData.h" 26 27#include "console/consoleTypes.h" 28#include "gfx/gfxDevice.h" 29#include "core/strings/stringUnit.h" 30#include "lighting/lightManager.h" 31#include "console/engineAPI.h" 32 33using namespace Torque; 34 35 36Vector<ShaderData*> ShaderData::smAllShaderData; 37 38 39IMPLEMENT_CONOBJECT( ShaderData ); 40 41ConsoleDocClass( ShaderData, 42 "@brief Special type of data block that stores information about a handwritten shader.\n\n" 43 44 "To use hand written shaders, a ShaderData datablock must be used. This datablock " 45 "refers only to the vertex and pixel shader filenames and a hardware target level. " 46 "Shaders are API specific, so DirectX and OpenGL shaders must be explicitly identified.\n\n " 47 48 "@tsexample\n" 49 "// Used for the procedural clould system\n" 50 "singleton ShaderData( CloudLayerShader )\n" 51 "{\n" 52 " DXVertexShaderFile = $Core::CommonShaderPath @ \"/cloudLayerV.hlsl\";\n" 53 " DXPixelShaderFile = $Core::CommonShaderPath @ \"/cloudLayerP.hlsl\";\n" 54 " OGLVertexShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerV.glsl\";\n" 55 " OGLPixelShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerP.glsl\";\n" 56 " pixVersion = 2.0;\n" 57 "};\n" 58 "@endtsexample\n\n" 59 60 "@ingroup Shaders\n"); 61 62ShaderData::ShaderData() 63{ 64 VECTOR_SET_ASSOCIATION( mShaderMacros ); 65 66 mUseDevicePixVersion = false; 67 mPixVersion = 1.0; 68 69 for( int i = 0; i < NumTextures; ++i) 70 mRTParams[i] = false; 71} 72 73void ShaderData::initPersistFields() 74{ 75 addField("DXVertexShaderFile", TypeStringFilename, Offset(mDXVertexShaderName, ShaderData), 76 "@brief %Path to the DirectX vertex shader file to use for this ShaderData.\n\n" 77 "It must contain only one program and no pixel shader, just the vertex shader." 78 "It can be either an HLSL or assembly level shader. HLSL's must have a " 79 "filename extension of .hlsl, otherwise its assumed to be an assembly file."); 80 81 addField("DXPixelShaderFile", TypeStringFilename, Offset(mDXPixelShaderName, ShaderData), 82 "@brief %Path to the DirectX pixel shader file to use for this ShaderData.\n\n" 83 "It must contain only one program and no vertex shader, just the pixel " 84 "shader. It can be either an HLSL or assembly level shader. HLSL's " 85 "must have a filename extension of .hlsl, otherwise its assumed to be an assembly file."); 86 87 addField("OGLVertexShaderFile", TypeStringFilename, Offset(mOGLVertexShaderName, ShaderData), 88 "@brief %Path to an OpenGL vertex shader file to use for this ShaderData.\n\n" 89 "It must contain only one program and no pixel shader, just the vertex shader."); 90 91 addField("OGLPixelShaderFile", TypeStringFilename, Offset(mOGLPixelShaderName, ShaderData), 92 "@brief %Path to an OpenGL pixel shader file to use for this ShaderData.\n\n" 93 "It must contain only one program and no vertex shader, just the pixel " 94 "shader."); 95 96 addField("useDevicePixVersion", TypeBool, Offset(mUseDevicePixVersion, ShaderData), 97 "@brief If true, the maximum pixel shader version offered by the graphics card will be used.\n\n" 98 "Otherwise, the script-defined pixel shader version will be used.\n\n"); 99 100 addField("pixVersion", TypeF32, Offset(mPixVersion, ShaderData), 101 "@brief Indicates target level the shader should be compiled.\n\n" 102 "Valid numbers at the time of this writing are 1.1, 1.4, 2.0, and 3.0. " 103 "The shader will not run properly if the hardware does not support the " 104 "level of shader compiled."); 105 106 addField("defines", TypeRealString, Offset(mDefines, ShaderData), 107 "@brief String of case-sensitive defines passed to the shader compiler.\n\n" 108 "The string should be delimited by a semicolon, tab, or newline character." 109 110 "@tsexample\n" 111 "singleton ShaderData( FlashShader )\n" 112 "{\n" 113 "DXVertexShaderFile = $shaderGen::cachePath @ \"/postFx/flashV.hlsl\";\n" 114 "DXPixelShaderFile = $shaderGen::cachePath @ \"/postFx/flashP.hlsl\";\n\n" 115 " //Define setting the color of WHITE_COLOR.\n" 116 "defines = \"WHITE_COLOR=float4(1.0,1.0,1.0,0.0)\";\n\n" 117 "pixVersion = 2.0\n" 118 "}\n" 119 "@endtsexample\n\n" 120 ); 121 122 addField("samplerNames", TypeRealString, Offset(mSamplerNames, ShaderData), NumTextures, 123 "@brief Indicates names of samplers present in shader. Order is important.\n\n" 124 "Order of sampler names are used to assert correct sampler register/location" 125 "Other objects (GFXStateBlockData, PostEffect...) use index number to link samplers." 126 ); 127 128 addField("rtParams", TypeBool, Offset(mRTParams, ShaderData), NumTextures, ""); 129 130 Parent::initPersistFields(); 131 132 // Make sure we get activation signals. 133 LightManager::smActivateSignal.notify( &ShaderData::_onLMActivate ); 134} 135 136bool ShaderData::onAdd() 137{ 138 if( !Parent::onAdd() ) 139 return false; 140 141 mShaderMacros.clear(); 142 143 // Keep track of it. 144 smAllShaderData.push_back( this ); 145 146 // NOTE: We initialize the shader on request. 147 148 for(int i = 0; i < NumTextures; ++i) 149 { 150 if( mSamplerNames[i].isNotEmpty() && !mSamplerNames[i].startsWith("$") ) 151 mSamplerNames[i].insert(0, "$"); 152 } 153 154 return true; 155} 156 157void ShaderData::onRemove() 158{ 159 // Remove it from the all shaders list. 160 smAllShaderData.remove( this ); 161 162 Parent::onRemove(); 163} 164 165const Vector<GFXShaderMacro>& ShaderData::_getMacros() 166{ 167 // If they have already been processed then 168 // return the cached result. 169 if ( mShaderMacros.size() != 0 || mDefines.isEmpty() ) 170 return mShaderMacros; 171 172 mShaderMacros.clear(); 173 GFXShaderMacro macro; 174 const U32 defineCount = StringUnit::getUnitCount( mDefines, ";\n\t" ); 175 for ( U32 i=0; i < defineCount; i++ ) 176 { 177 String define = StringUnit::getUnit( mDefines, i, ";\n\t" ); 178 179 macro.name = StringUnit::getUnit( define, 0, "=" ); 180 macro.value = StringUnit::getUnit( define, 1, "=" ); 181 mShaderMacros.push_back( macro ); 182 } 183 184 return mShaderMacros; 185} 186 187GFXShader* ShaderData::getShader( const Vector<GFXShaderMacro> ¯os ) 188{ 189 PROFILE_SCOPE( ShaderData_GetShader ); 190 191 // Combine the dynamic macros with our script defined macros. 192 Vector<GFXShaderMacro> finalMacros; 193 finalMacros.merge( _getMacros() ); 194 finalMacros.merge( macros ); 195 196 // Convert the final macro list to a string. 197 String cacheKey; 198 GFXShaderMacro::stringize( macros, &cacheKey ); 199 200 // Lookup the shader for this instance. 201 ShaderCache::Iterator iter = mShaders.find( cacheKey ); 202 if ( iter != mShaders.end() ) 203 return iter->value; 204 205 // Create the shader instance... if it fails then 206 // bail out and return nothing to the caller. 207 GFXShader *shader = _createShader( finalMacros ); 208 if ( !shader ) 209 return NULL; 210 211 _checkDefinition(shader); 212 213 // Store the shader in the cache and return it. 214 mShaders.insertUnique( cacheKey, shader ); 215 return shader; 216} 217 218GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> ¯os ) 219{ 220 F32 pixver = mPixVersion; 221 if ( mUseDevicePixVersion ) 222 pixver = getMax( pixver, GFX->getPixelShaderVersion() ); 223 224 // Enable shader error logging. 225 GFXShader::setLogging( true, true ); 226 227 GFXShader *shader = GFX->createShader(); 228 bool success = false; 229 230 Vector<String> samplers; 231 samplers.setSize(ShaderData::NumTextures); 232 for(int i = 0; i < ShaderData::NumTextures; ++i) 233 samplers[i] = mSamplerNames[i][0] == '$' ? mSamplerNames[i] : "$"+mSamplerNames[i]; 234 235 // Initialize the right shader type. 236 switch( GFX->getAdapterType() ) 237 { 238 case Direct3D11: 239 { 240 success = shader->init( mDXVertexShaderName, 241 mDXPixelShaderName, 242 pixver, 243 macros, 244 samplers); 245 break; 246 } 247 248 case OpenGL: 249 { 250 success = shader->init( mOGLVertexShaderName, 251 mOGLPixelShaderName, 252 pixver, 253 macros, 254 samplers); 255 break; 256 } 257 258 default: 259 // Other device types are assumed to not support shaders. 260 success = false; 261 break; 262 } 263 264#if defined(TORQUE_DEBUG) 265 //Assert Sampler registers 266 const Vector<GFXShaderConstDesc>& descs = shader->getShaderConstDesc(); 267 for(int i = 0; i < descs.size(); ++i) 268 { 269 if(descs[i].constType != GFXSCT_Sampler && descs[i].constType != GFXSCT_SamplerCube) 270 continue; 271 272 GFXShaderConstHandle *handle = shader->findShaderConstHandle(descs[i].name); 273 if(!handle || !handle->isValid()) 274 continue; 275 276 int reg = handle->getSamplerRegister(); 277 if( descs[i].name != samplers[reg] ) 278 { 279 const char *err = avar("ShaderData(%s): samplerNames[%d] = \"%s\" are diferent to sampler in shader: %s : register(S%d)" 280 ,getName(), reg, samplers[reg].c_str(), handle->getName().c_str(), reg); 281 Con::printf(err); 282 GFXAssertFatal(0, err); 283 } 284 } 285#endif 286 287 // If we failed to load the shader then 288 // cleanup and return NULL. 289 if ( !success ) 290 SAFE_DELETE( shader ); 291 292 return shader; 293} 294 295void ShaderData::reloadShaders() 296{ 297 ShaderCache::Iterator iter = mShaders.begin(); 298 for ( ; iter != mShaders.end(); iter++ ) 299 iter->value->reload(); 300} 301 302void ShaderData::reloadAllShaders() 303{ 304 Vector<ShaderData*>::iterator iter = smAllShaderData.begin(); 305 for ( ; iter != smAllShaderData.end(); iter++ ) 306 (*iter)->reloadShaders(); 307} 308 309void ShaderData::_onLMActivate( const char *lm, bool activate ) 310{ 311 // Only on activations do we do anything. 312 if ( !activate ) 313 return; 314 315 // Since the light manager usually swaps shadergen features 316 // and changes system wide shader defines we need to completely 317 // flush and rebuild all shaders. 318 319 reloadAllShaders(); 320} 321 322bool ShaderData::hasSamplerDef(const String &_samplerName, int &pos) const 323{ 324 String samplerName = _samplerName.startsWith("$") ? _samplerName : "$"+_samplerName; 325 for(int i = 0; i < NumTextures; ++i) 326 { 327 if( mSamplerNames[i].equal(samplerName, String::NoCase ) ) 328 { 329 pos = i; 330 return true; 331 } 332 } 333 334 pos = -1; 335 return false; 336} 337 338bool ShaderData::_checkDefinition(GFXShader *shader) 339{ 340 bool error = false; 341 Vector<String> samplers; 342 samplers.reserve(NumTextures); 343 bool rtParams[NumTextures]; 344 for(int i = 0; i < NumTextures; ++i) 345 rtParams[i] = false; 346 347 const Vector<GFXShaderConstDesc> &shaderConstDesc = shader->getShaderConstDesc(); 348 349 for(int i = 0; i < shaderConstDesc.size(); ++i) 350 { 351 const GFXShaderConstDesc &desc = shaderConstDesc[i]; 352 if(desc.constType == GFXSCT_Sampler) 353 { 354 samplers.push_back(desc.name ); 355 } 356 } 357 358 for(int i = 0; i < samplers.size(); ++i) 359 { 360 int pos; 361 bool find = hasSamplerDef(samplers[i], pos); 362 363 if(find && pos >= 0 && mRTParams[pos]) 364 { 365 if( !shader->findShaderConstHandle( String::ToString("$rtParams%d", pos)) ) 366 { 367 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); 368 Con::errorf(errStr); 369 error = true; 370 } 371 } 372 373 if(!find) 374 { 375 String errStr = String::ToString("ShaderData(%s) sampler %s not defined", shader->getPixelShaderFile().c_str(), samplers[i].c_str()); 376 Con::errorf(errStr); 377 GFXAssertFatal(0, errStr); 378 error = true; 379 } 380 } 381 382 return !error; 383} 384 385DefineEngineMethod( ShaderData, reload, void, (),, 386 "@brief Rebuilds all the vertex and pixel shader instances created from this ShaderData.\n\n" 387 388 "@tsexample\n" 389 "// Rebuild the shader instances from ShaderData CloudLayerShader\n" 390 "CloudLayerShader.reload();\n" 391 "@endtsexample\n\n") 392{ 393 object->reloadShaders(); 394} 395