shaderGen.cpp
Engine/source/shaderGen/shaderGen.cpp
Public Variables
Detailed Description
Public Variables
MODULE_END
MODULE_INIT
MODULE_SHUTDOWN
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 "shaderGen/shaderGen.h" 26 27#include "shaderGen/conditionerFeature.h" 28#include "core/stream/fileStream.h" 29#include "shaderGen/featureMgr.h" 30#include "shaderGen/shaderOp.h" 31#include "gfx/gfxDevice.h" 32#include "core/memVolume.h" 33#include "core/module.h" 34 35#ifdef TORQUE_D3D11 36#include "shaderGen/HLSL/customFeatureHLSL.h" 37#endif 38#ifdef TORQUE_OPENGL 39#include "shaderGen/GLSL/customFeatureGLSL.h" 40#endif 41 42MODULE_BEGIN( ShaderGen ) 43 44 MODULE_INIT_BEFORE( GFX ) 45 MODULE_SHUTDOWN_AFTER( GFX ) 46 47 MODULE_INIT 48 { 49 ManagedSingleton< ShaderGen >::createSingleton(); 50 } 51 52 MODULE_SHUTDOWN 53 { 54 ManagedSingleton< ShaderGen >::deleteSingleton(); 55 } 56 57MODULE_END; 58 59String ShaderGen::smCommonShaderPath("shaders/common"); 60 61ShaderGen::ShaderGen() 62{ 63 mInit = false; 64 GFXDevice::getDeviceEventSignal().notify(this, &ShaderGen::_handleGFXEvent); 65 mOutput = NULL; 66} 67 68ShaderGen::~ShaderGen() 69{ 70 GFXDevice::getDeviceEventSignal().remove(this, &ShaderGen::_handleGFXEvent); 71 _uninit(); 72} 73 74void ShaderGen::registerInitDelegate(GFXAdapterType adapterType, ShaderGenInitDelegate& initDelegate) 75{ 76 mInitDelegates[(U32)adapterType] = initDelegate; 77} 78 79bool ShaderGen::_handleGFXEvent(GFXDevice::GFXDeviceEventType event) 80{ 81 switch (event) 82 { 83 case GFXDevice::deInit : 84 initShaderGen(); 85 break; 86 case GFXDevice::deDestroy : 87 { 88 flushProceduralShaders(); 89 } 90 break; 91 default : 92 break; 93 } 94 return true; 95} 96 97void ShaderGen::initShaderGen() 98{ 99 if (mInit) 100 return; 101 102 const GFXAdapterType adapterType = GFX->getAdapterType(); 103 if (!mInitDelegates[adapterType]) 104 return; 105 106 smCommonShaderPath = String(Con::getVariable("$Core::CommonShaderPath", "shaders/common")); 107 108 mInitDelegates[adapterType](this); 109 mFeatureInitSignal.trigger( adapterType ); 110 mInit = true; 111 112 String shaderPath = Con::getVariable( "$shaderGen::cachePath"); 113 if (!shaderPath.equal( "shadergen:" ) && !shaderPath.isEmpty() ) 114 { 115 // this is necessary, especially under Windows with UAC enabled 116 if (!Torque::FS::VerifyWriteAccess(shaderPath)) 117 { 118 // we don't have write access so enable the virtualized memory store 119 Con::warnf("ShaderGen: Write permission unavailable, switching to virtualized memory storage"); 120 shaderPath.clear(); 121 } 122 123 } 124 125 if ( shaderPath.equal( "shadergen:" ) || shaderPath.isEmpty() ) 126 { 127 // If we didn't get a path then we're gonna cache the shaders to 128 // a virtualized memory file system. 129 mMemFS = new Torque::Mem::MemFileSystem( "shadergen:/" ); 130 Torque::FS::Mount( "shadergen", mMemFS ); 131 } 132 else 133 Torque::FS::Mount( "shadergen", shaderPath + "/" ); 134 135 // Delete the auto-generated conditioner include file. 136 Torque::FS::Remove( "shadergen:/" + ConditionerFeature::ConditionerIncludeFileName ); 137} 138 139void ShaderGen::generateShader( const MaterialFeatureData &featureData, 140 char *vertFile, 141 char *pixFile, 142 F32 *pixVersion, 143 const GFXVertexFormat *vertexFormat, 144 const char* cacheName, 145 Vector<GFXShaderMacro> ¯os) 146{ 147 PROFILE_SCOPE( ShaderGen_GenerateShader ); 148 149 mFeatureData = featureData; 150 mVertexFormat = vertexFormat; 151 152 _uninit(); 153 _init(); 154 155 char vertShaderName[256]; 156 char pixShaderName[256]; 157 158 // Note: We use a postfix of _V/_P here so that it sorts the matching 159 // vert and pixel shaders together when listed alphabetically. 160 dSprintf( vertShaderName, sizeof(vertShaderName), "shadergen:/%s_V.%s", cacheName, mFileEnding.c_str() ); 161 dSprintf( pixShaderName, sizeof(pixShaderName), "shadergen:/%s_P.%s", cacheName, mFileEnding.c_str() ); 162 163 dStrcpy( vertFile, vertShaderName, 256 ); 164 dStrcpy( pixFile, pixShaderName, 256 ); 165 166 // this needs to change - need to optimize down to ps v.1.1 167 *pixVersion = GFX->getPixelShaderVersion(); 168 169 if ( !Con::getBoolVariable( "ShaderGen::GenNewShaders", true ) ) 170 { 171 // If we are not regenerating the shader we will return here. 172 // But we must fill in the shader macros first! 173 174 _processVertFeatures( macros, true ); 175 _processPixFeatures( macros, true ); 176 177 return; 178 } 179 180 // create vertex shader 181 //------------------------ 182 FileStream* s = new FileStream(); 183 if(!s->open(vertShaderName, Torque::FS::File::Write )) 184 { 185 AssertFatal(false, "Failed to open Shader Stream" ); 186 return; 187 } 188 189 mOutput = new MultiLine; 190 mInstancingFormat.clear(); 191 _processVertFeatures(macros); 192 _printVertShader( *s ); 193 delete s; 194 195 ((ShaderConnector*)mComponents[C_CONNECTOR])->reset(); 196 LangElement::deleteElements(); 197 198 // create pixel shader 199 //------------------------ 200 s = new FileStream(); 201 if(!s->open(pixShaderName, Torque::FS::File::Write )) 202 { 203 AssertFatal(false, "Failed to open Shader Stream" ); 204 return; 205 } 206 207 mOutput = new MultiLine; 208 _processPixFeatures(macros); 209 _printPixShader( *s ); 210 211 delete s; 212 LangElement::deleteElements(); 213} 214 215void ShaderGen::_init() 216{ 217 _createComponents(); 218} 219 220void ShaderGen::_uninit() 221{ 222 for( U32 i=0; i<mComponents.size(); i++ ) 223 { 224 delete mComponents[i]; 225 mComponents[i] = NULL; 226 } 227 mComponents.setSize(0); 228 229 LangElement::deleteElements(); 230 231 Var::reset(); 232} 233 234void ShaderGen::_createComponents() 235{ 236 ShaderComponent* vertComp = mComponentFactory->createVertexInputConnector( *mVertexFormat ); 237 mComponents.push_back(vertComp); 238 239 ShaderComponent* vertPixelCon = mComponentFactory->createVertexPixelConnector(); 240 mComponents.push_back(vertPixelCon); 241 242 ShaderComponent* vertParamDef = mComponentFactory->createVertexParamsDef(); 243 mComponents.push_back(vertParamDef); 244 245 ShaderComponent* pixParamDef = mComponentFactory->createPixelParamsDef(); 246 mComponents.push_back(pixParamDef); 247} 248 249//---------------------------------------------------------------------------- 250// Process features 251//---------------------------------------------------------------------------- 252void ShaderGen::_processVertFeatures( Vector<GFXShaderMacro> ¯os, bool macrosOnly ) 253{ 254 const FeatureSet &features = mFeatureData.features; 255 256 for( U32 i=0; i < features.getCount(); i++ ) 257 { 258 S32 index; 259 const FeatureType &type = features.getAt( i, &index ); 260 ShaderFeature* feature = FEATUREMGR->getByType( type ); 261 if ( feature ) 262 { 263 feature->setProcessIndex( index ); 264 265 feature->processVertMacros( macros, mFeatureData ); 266 267 if ( macrosOnly ) 268 continue; 269 270 feature->setInstancingFormat( &mInstancingFormat ); 271 272 feature->mVertexFormat = mVertexFormat; 273 274 feature->processVert( mComponents, mFeatureData ); 275 276 String line; 277 if ( index > -1 ) 278 line = String::ToString( " // %s %d\r\n", feature->getName().c_str(), index ); 279 else 280 line = String::ToString( " // %s\r\n", feature->getName().c_str() ); 281 mOutput->addStatement( new GenOp( line ) ); 282 283 if ( feature->getOutput() ) 284 mOutput->addStatement( feature->getOutput() ); 285 286 feature->reset(); 287 mOutput->addStatement( new GenOp( " \r\n" ) ); 288 } 289 } 290 291 ShaderConnector *connect = dynamic_cast<ShaderConnector *>( mComponents[C_CONNECTOR] ); 292 connect->sortVars(); 293} 294 295void ShaderGen::_processPixFeatures( Vector<GFXShaderMacro> ¯os, bool macrosOnly ) 296{ 297 const FeatureSet &features = mFeatureData.features; 298 299 for( U32 i=0; i < features.getCount(); i++ ) 300 { 301 S32 index; 302 const FeatureType &type = features.getAt( i, &index ); 303 ShaderFeature* feature = FEATUREMGR->getByType( type ); 304 if ( feature ) 305 { 306 feature->setProcessIndex( index ); 307 308 feature->processPixMacros( macros, mFeatureData ); 309 310 if ( macrosOnly ) 311 continue; 312 313 feature->setInstancingFormat( &mInstancingFormat ); 314 feature->processPix( mComponents, mFeatureData ); 315 316 String line; 317 if ( index > -1 ) 318 line = String::ToString( " // %s %d\r\n", feature->getName().c_str(), index ); 319 else 320 line = String::ToString( " // %s\r\n", feature->getName().c_str() ); 321 mOutput->addStatement( new GenOp( line ) ); 322 323 if ( feature->getOutput() ) 324 mOutput->addStatement( feature->getOutput() ); 325 326 feature->reset(); 327 mOutput->addStatement( new GenOp( " \r\n" ) ); 328 } 329 } 330 331 ShaderConnector *connect = dynamic_cast<ShaderConnector *>( mComponents[C_CONNECTOR] ); 332 connect->sortVars(); 333} 334 335void ShaderGen::_printFeatureList(Stream &stream) 336{ 337 mPrinter->printLine(stream, "// Features:"); 338 339 const FeatureSet &features = mFeatureData.features; 340 341 for( U32 i=0; i < features.getCount(); i++ ) 342 { 343 S32 index; 344 const FeatureType &type = features.getAt( i, &index ); 345 ShaderFeature* feature = FEATUREMGR->getByType( type ); 346 if ( feature ) 347 { 348 String line; 349 if ( index > -1 ) 350 line = String::ToString( "// %s %d", feature->getName().c_str(), index ); 351 else 352 line = String::ToString( "// %s", feature->getName().c_str() ); 353 354 mPrinter->printLine( stream, line ); 355 } 356 } 357 358 mPrinter->printLine(stream, ""); 359} 360 361void ShaderGen::_printDependencies(Stream &stream) 362{ 363 Vector<const ShaderDependency*> dependencies; 364 365 for( U32 i=0; i < FEATUREMGR->getFeatureCount(); i++ ) 366 { 367 const FeatureInfo &info = FEATUREMGR->getAt( i ); 368 if ( mFeatureData.features.hasFeature( *info.type ) ) 369 dependencies.merge( info.feature->getDependencies() ); 370 } 371 372 // Do a quick loop removing any duplicate dependancies. 373 for( U32 i=0; i < dependencies.size(); ) 374 { 375 bool dup = false; 376 377 for( U32 j=0; j < dependencies.size(); j++ ) 378 { 379 if ( j != i && 380 *dependencies[i] == *dependencies[j] ) 381 { 382 dup = true; 383 break; 384 } 385 } 386 387 if ( dup ) 388 dependencies.erase( i ); 389 else 390 i++; 391 } 392 393 // Print dependencies 394 if( dependencies.size() > 0 ) 395 { 396 mPrinter->printLine(stream, "// Dependencies:"); 397 398 for( S32 i = 0; i < dependencies.size(); i++ ) 399 dependencies[i]->print( stream ); 400 401 mPrinter->printLine(stream, ""); 402 } 403} 404 405void ShaderGen::_printFeatures( Stream &stream ) 406{ 407 mOutput->print( stream ); 408} 409 410void ShaderGen::_printVertShader( Stream &stream ) 411{ 412 mPrinter->printShaderHeader(stream); 413 414 _printDependencies(stream); // TODO: Split into vert and pix dependencies? 415 _printFeatureList(stream); 416 417 // print out structures 418 mComponents[C_VERT_STRUCT]->print( stream, true ); 419 mComponents[C_CONNECTOR]->print( stream, true ); 420 421 mPrinter->printMainComment(stream); 422 423 mComponents[C_VERT_MAIN]->print( stream, true ); 424 mComponents[C_VERT_STRUCT]->printOnMain( stream, true ); 425 426 // print out the function 427 _printFeatures( stream ); 428 429 mPrinter->printVertexShaderCloser(stream); 430} 431 432void ShaderGen::_printPixShader( Stream &stream ) 433{ 434 mPrinter->printShaderHeader(stream); 435 436 _printDependencies(stream); // TODO: Split into vert and pix dependencies? 437 _printFeatureList(stream); 438 439 mComponents[C_CONNECTOR]->print( stream, false ); 440 441 mPrinter->printPixelShaderOutputStruct(stream, mFeatureData); 442 mPrinter->printMainComment(stream); 443 444 mComponents[C_PIX_MAIN]->print( stream, false ); 445 mComponents[C_CONNECTOR]->printOnMain( stream, false ); 446 447 // print out the function 448 _printFeatures( stream ); 449 450 mPrinter->printPixelShaderCloser(stream); 451} 452 453GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros, const Vector<String> &samplers ) 454{ 455 PROFILE_SCOPE( ShaderGen_GetShader ); 456 457 const FeatureSet &features = featureData.codify(); 458 459 // Build a description string from the features 460 // and vertex format combination ( and macros ). 461 String shaderDescription = vertexFormat->getDescription() + features.getDescription(); 462 if ( macros && !macros->empty() ) 463 { 464 String macroStr; 465 GFXShaderMacro::stringize( *macros, ¯oStr ); 466 shaderDescription += macroStr; 467 } 468 469 // Generate a single 64bit hash from the description string. 470 // 471 // Don't get paranoid! This has 1 in 18446744073709551616 472 // chance for collision... it won't happen in this lifetime. 473 // 474 U64 hash = Torque::hash64( (const U8*)shaderDescription.c_str(), shaderDescription.length(), 0 ); 475 hash = convertHostToLEndian(hash); 476 U32 high = (U32)( hash >> 32 ); 477 U32 low = (U32)( hash & 0x00000000FFFFFFFF ); 478 String cacheKey = String::ToString( "%x%x", high, low ); 479 // return shader if exists 480 GFXShader *match = mProcShaders[cacheKey]; 481 if ( match ) 482 return match; 483 484 // if not, then create it 485 char vertFile[256]; 486 char pixFile[256]; 487 F32 pixVersion; 488 489 Vector<GFXShaderMacro> shaderMacros; 490 shaderMacros.push_back( GFXShaderMacro( "TORQUE_SHADERGEN" ) ); 491 if ( macros ) 492 shaderMacros.merge( *macros ); 493 generateShader( featureData, vertFile, pixFile, &pixVersion, vertexFormat, cacheKey, shaderMacros ); 494 495 GFXShader *shader = GFX->createShader(); 496 if (!shader->init(vertFile, pixFile, pixVersion, shaderMacros, samplers, &mInstancingFormat)) 497 { 498 delete shader; 499 return NULL; 500 } 501 502 mProcShaders[cacheKey] = shader; 503 504 return shader; 505} 506 507void ShaderGen::flushProceduralShaders() 508{ 509 // The shaders are reference counted, so we 510 // just need to clear the map. 511 mProcShaders.clear(); 512} 513