shaderGen.cpp

Engine/source/shaderGen/shaderGen.cpp

More...

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> &macros)
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> &macros, 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> &macros, 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, &macroStr );
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