mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-27 16:19:34 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
507
Engine/source/shaderGen/shaderGen.cpp
Normal file
507
Engine/source/shaderGen/shaderGen.cpp
Normal file
|
|
@ -0,0 +1,507 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "shaderGen/shaderGen.h"
|
||||
|
||||
#include "shaderGen/conditionerFeature.h"
|
||||
#include "core/stream/fileStream.h"
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "shaderGen/shaderOp.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "core/memVolume.h"
|
||||
#include "core/module.h"
|
||||
|
||||
|
||||
MODULE_BEGIN( ShaderGen )
|
||||
|
||||
MODULE_INIT_BEFORE( GFX )
|
||||
MODULE_SHUTDOWN_AFTER( GFX )
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
ManagedSingleton< ShaderGen >::createSingleton();
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
ManagedSingleton< ShaderGen >::deleteSingleton();
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
|
||||
ShaderGen::ShaderGen()
|
||||
{
|
||||
mInit = false;
|
||||
GFXDevice::getDeviceEventSignal().notify(this, &ShaderGen::_handleGFXEvent);
|
||||
mOutput = NULL;
|
||||
}
|
||||
|
||||
ShaderGen::~ShaderGen()
|
||||
{
|
||||
GFXDevice::getDeviceEventSignal().remove(this, &ShaderGen::_handleGFXEvent);
|
||||
_uninit();
|
||||
}
|
||||
|
||||
void ShaderGen::registerInitDelegate(GFXAdapterType adapterType, ShaderGenInitDelegate& initDelegate)
|
||||
{
|
||||
mInitDelegates[(U32)adapterType] = initDelegate;
|
||||
}
|
||||
|
||||
bool ShaderGen::_handleGFXEvent(GFXDevice::GFXDeviceEventType event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case GFXDevice::deInit :
|
||||
initShaderGen();
|
||||
break;
|
||||
case GFXDevice::deDestroy :
|
||||
{
|
||||
flushProceduralShaders();
|
||||
}
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShaderGen::initShaderGen()
|
||||
{
|
||||
if (mInit)
|
||||
return;
|
||||
|
||||
const GFXAdapterType adapterType = GFX->getAdapterType();
|
||||
if (!mInitDelegates[adapterType])
|
||||
return;
|
||||
|
||||
mInitDelegates[adapterType](this);
|
||||
mFeatureInitSignal.trigger( adapterType );
|
||||
mInit = true;
|
||||
|
||||
String shaderPath = Con::getVariable( "$shaderGen::cachePath");
|
||||
#if defined(TORQUE_SHADERGEN) && ( defined(TORQUE_OS_XENON) || defined(TORQUE_OS_PS3) )
|
||||
// If this is a console build, and TORQUE_SHADERGEN is defined
|
||||
// (signifying that new shaders should be generated) then clear the shader
|
||||
// path so that the MemFileSystem is used instead.
|
||||
shaderPath.clear();
|
||||
#endif
|
||||
|
||||
if (!shaderPath.equal( "shadergen:" ) && !shaderPath.isEmpty() )
|
||||
{
|
||||
// this is necessary, especially under Windows with UAC enabled
|
||||
if (!Torque::FS::VerifyWriteAccess(shaderPath))
|
||||
{
|
||||
// we don't have write access so enable the virtualized memory store
|
||||
Con::warnf("ShaderGen: Write permission unavailable, switching to virtualized memory storage");
|
||||
shaderPath.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( shaderPath.equal( "shadergen:" ) || shaderPath.isEmpty() )
|
||||
{
|
||||
// If we didn't get a path then we're gonna cache the shaders to
|
||||
// a virtualized memory file system.
|
||||
mMemFS = new Torque::Mem::MemFileSystem( "shadergen:/" );
|
||||
Torque::FS::Mount( "shadergen", mMemFS );
|
||||
}
|
||||
else
|
||||
Torque::FS::Mount( "shadergen", shaderPath + "/" );
|
||||
|
||||
// Delete the auto-generated conditioner include file.
|
||||
Torque::FS::Remove( "shadergen:/" + ConditionerFeature::ConditionerIncludeFileName );
|
||||
}
|
||||
|
||||
void ShaderGen::generateShader( const MaterialFeatureData &featureData,
|
||||
char *vertFile,
|
||||
char *pixFile,
|
||||
F32 *pixVersion,
|
||||
const GFXVertexFormat *vertexFormat,
|
||||
const char* cacheName,
|
||||
Vector<GFXShaderMacro> ¯os )
|
||||
{
|
||||
PROFILE_SCOPE( ShaderGen_GenerateShader );
|
||||
|
||||
mFeatureData = featureData;
|
||||
mVertexFormat = vertexFormat;
|
||||
|
||||
_uninit();
|
||||
_init();
|
||||
|
||||
char vertShaderName[256];
|
||||
char pixShaderName[256];
|
||||
|
||||
// Note: We use a postfix of _V/_P here so that it sorts the matching
|
||||
// vert and pixel shaders together when listed alphabetically.
|
||||
dSprintf( vertShaderName, sizeof(vertShaderName), "shadergen:/%s_V.%s", cacheName, mFileEnding.c_str() );
|
||||
dSprintf( pixShaderName, sizeof(pixShaderName), "shadergen:/%s_P.%s", cacheName, mFileEnding.c_str() );
|
||||
|
||||
dStrcpy( vertFile, vertShaderName );
|
||||
dStrcpy( pixFile, pixShaderName );
|
||||
|
||||
// this needs to change - need to optimize down to ps v.1.1
|
||||
*pixVersion = GFX->getPixelShaderVersion();
|
||||
|
||||
if ( !Con::getBoolVariable( "ShaderGen::GenNewShaders", true ) )
|
||||
{
|
||||
// If we are not regenerating the shader we will return here.
|
||||
// But we must fill in the shader macros first!
|
||||
|
||||
_processVertFeatures( macros, true );
|
||||
_processPixFeatures( macros, true );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// create vertex shader
|
||||
//------------------------
|
||||
FileStream* s = new FileStream();
|
||||
if(!s->open(vertShaderName, Torque::FS::File::Write ))
|
||||
{
|
||||
AssertFatal(false, "Failed to open Shader Stream" );
|
||||
return;
|
||||
}
|
||||
|
||||
mOutput = new MultiLine;
|
||||
mInstancingFormat.clear();
|
||||
_processVertFeatures(macros);
|
||||
_printVertShader( *s );
|
||||
delete s;
|
||||
|
||||
((ShaderConnector*)mComponents[C_CONNECTOR])->reset();
|
||||
LangElement::deleteElements();
|
||||
|
||||
// create pixel shader
|
||||
//------------------------
|
||||
s = new FileStream();
|
||||
if(!s->open(pixShaderName, Torque::FS::File::Write ))
|
||||
{
|
||||
AssertFatal(false, "Failed to open Shader Stream" );
|
||||
return;
|
||||
}
|
||||
|
||||
mOutput = new MultiLine;
|
||||
_processPixFeatures(macros);
|
||||
_printPixShader( *s );
|
||||
|
||||
delete s;
|
||||
LangElement::deleteElements();
|
||||
}
|
||||
|
||||
void ShaderGen::_init()
|
||||
{
|
||||
_createComponents();
|
||||
}
|
||||
|
||||
void ShaderGen::_uninit()
|
||||
{
|
||||
for( U32 i=0; i<mComponents.size(); i++ )
|
||||
{
|
||||
delete mComponents[i];
|
||||
mComponents[i] = NULL;
|
||||
}
|
||||
mComponents.setSize(0);
|
||||
|
||||
LangElement::deleteElements();
|
||||
|
||||
Var::reset();
|
||||
}
|
||||
|
||||
void ShaderGen::_createComponents()
|
||||
{
|
||||
ShaderComponent* vertComp = mComponentFactory->createVertexInputConnector( *mVertexFormat );
|
||||
mComponents.push_back(vertComp);
|
||||
|
||||
ShaderComponent* vertPixelCon = mComponentFactory->createVertexPixelConnector();
|
||||
mComponents.push_back(vertPixelCon);
|
||||
|
||||
ShaderComponent* vertParamDef = mComponentFactory->createVertexParamsDef();
|
||||
mComponents.push_back(vertParamDef);
|
||||
|
||||
ShaderComponent* pixParamDef = mComponentFactory->createPixelParamsDef();
|
||||
mComponents.push_back(pixParamDef);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Process features
|
||||
//----------------------------------------------------------------------------
|
||||
void ShaderGen::_processVertFeatures( Vector<GFXShaderMacro> ¯os, bool macrosOnly )
|
||||
{
|
||||
const FeatureSet &features = mFeatureData.features;
|
||||
|
||||
for( U32 i=0; i < features.getCount(); i++ )
|
||||
{
|
||||
S32 index;
|
||||
const FeatureType &type = features.getAt( i, &index );
|
||||
ShaderFeature* feature = FEATUREMGR->getByType( type );
|
||||
if ( feature )
|
||||
{
|
||||
feature->setProcessIndex( index );
|
||||
|
||||
feature->processVertMacros( macros, mFeatureData );
|
||||
|
||||
if ( macrosOnly )
|
||||
continue;
|
||||
|
||||
feature->mInstancingFormat = &mInstancingFormat;
|
||||
feature->processVert( mComponents, mFeatureData );
|
||||
|
||||
String line;
|
||||
if ( index > -1 )
|
||||
line = String::ToString( " // %s %d\r\n", feature->getName().c_str(), index );
|
||||
else
|
||||
line = String::ToString( " // %s\r\n", feature->getName().c_str() );
|
||||
mOutput->addStatement( new GenOp( line ) );
|
||||
|
||||
if ( feature->getOutput() )
|
||||
mOutput->addStatement( feature->getOutput() );
|
||||
|
||||
feature->reset();
|
||||
mOutput->addStatement( new GenOp( " \r\n" ) );
|
||||
}
|
||||
}
|
||||
|
||||
ShaderConnector *connect = dynamic_cast<ShaderConnector *>( mComponents[C_CONNECTOR] );
|
||||
connect->sortVars();
|
||||
}
|
||||
|
||||
void ShaderGen::_processPixFeatures( Vector<GFXShaderMacro> ¯os, bool macrosOnly )
|
||||
{
|
||||
const FeatureSet &features = mFeatureData.features;
|
||||
|
||||
for( U32 i=0; i < features.getCount(); i++ )
|
||||
{
|
||||
S32 index;
|
||||
const FeatureType &type = features.getAt( i, &index );
|
||||
ShaderFeature* feature = FEATUREMGR->getByType( type );
|
||||
if ( feature )
|
||||
{
|
||||
feature->setProcessIndex( index );
|
||||
|
||||
feature->processPixMacros( macros, mFeatureData );
|
||||
|
||||
if ( macrosOnly )
|
||||
continue;
|
||||
|
||||
feature->mInstancingFormat = &mInstancingFormat;
|
||||
feature->processPix( mComponents, mFeatureData );
|
||||
|
||||
String line;
|
||||
if ( index > -1 )
|
||||
line = String::ToString( " // %s %d\r\n", feature->getName().c_str(), index );
|
||||
else
|
||||
line = String::ToString( " // %s\r\n", feature->getName().c_str() );
|
||||
mOutput->addStatement( new GenOp( line ) );
|
||||
|
||||
if ( feature->getOutput() )
|
||||
mOutput->addStatement( feature->getOutput() );
|
||||
|
||||
feature->reset();
|
||||
mOutput->addStatement( new GenOp( " \r\n" ) );
|
||||
}
|
||||
}
|
||||
|
||||
ShaderConnector *connect = dynamic_cast<ShaderConnector *>( mComponents[C_CONNECTOR] );
|
||||
connect->sortVars();
|
||||
}
|
||||
|
||||
void ShaderGen::_printFeatureList(Stream &stream)
|
||||
{
|
||||
mPrinter->printLine(stream, "// Features:");
|
||||
|
||||
const FeatureSet &features = mFeatureData.features;
|
||||
|
||||
for( U32 i=0; i < features.getCount(); i++ )
|
||||
{
|
||||
S32 index;
|
||||
const FeatureType &type = features.getAt( i, &index );
|
||||
ShaderFeature* feature = FEATUREMGR->getByType( type );
|
||||
if ( feature )
|
||||
{
|
||||
String line;
|
||||
if ( index > -1 )
|
||||
line = String::ToString( "// %s %d", feature->getName().c_str(), index );
|
||||
else
|
||||
line = String::ToString( "// %s", feature->getName().c_str() );
|
||||
|
||||
mPrinter->printLine( stream, line );
|
||||
}
|
||||
}
|
||||
|
||||
mPrinter->printLine(stream, "");
|
||||
}
|
||||
|
||||
void ShaderGen::_printDependencies(Stream &stream)
|
||||
{
|
||||
Vector<const ShaderDependency *> dependencies;
|
||||
|
||||
for( U32 i=0; i < FEATUREMGR->getFeatureCount(); i++ )
|
||||
{
|
||||
const FeatureInfo &info = FEATUREMGR->getAt( i );
|
||||
if ( mFeatureData.features.hasFeature( *info.type ) )
|
||||
dependencies.merge( info.feature->getDependencies() );
|
||||
}
|
||||
|
||||
// Do a quick loop removing any duplicate dependancies.
|
||||
for( U32 i=0; i < dependencies.size(); )
|
||||
{
|
||||
bool dup = false;
|
||||
|
||||
for( U32 j=0; j < dependencies.size(); j++ )
|
||||
{
|
||||
if ( j != i &&
|
||||
*dependencies[i] == *dependencies[j] )
|
||||
{
|
||||
dup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( dup )
|
||||
dependencies.erase( i );
|
||||
else
|
||||
i++;
|
||||
}
|
||||
|
||||
// Print dependencies
|
||||
if( dependencies.size() > 0 )
|
||||
{
|
||||
mPrinter->printLine(stream, "// Dependencies:");
|
||||
|
||||
for( int i = 0; i < dependencies.size(); i++ )
|
||||
dependencies[i]->print( stream );
|
||||
|
||||
mPrinter->printLine(stream, "");
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderGen::_printFeatures( Stream &stream )
|
||||
{
|
||||
mOutput->print( stream );
|
||||
}
|
||||
|
||||
void ShaderGen::_printVertShader( Stream &stream )
|
||||
{
|
||||
mPrinter->printShaderHeader(stream);
|
||||
|
||||
_printDependencies(stream); // TODO: Split into vert and pix dependencies?
|
||||
_printFeatureList(stream);
|
||||
|
||||
// print out structures
|
||||
mComponents[C_VERT_STRUCT]->print( stream );
|
||||
mComponents[C_CONNECTOR]->print( stream );
|
||||
|
||||
mPrinter->printMainComment(stream);
|
||||
|
||||
mComponents[C_VERT_MAIN]->print( stream );
|
||||
|
||||
|
||||
// print out the function
|
||||
_printFeatures( stream );
|
||||
|
||||
mPrinter->printVertexShaderCloser(stream);
|
||||
}
|
||||
|
||||
void ShaderGen::_printPixShader( Stream &stream )
|
||||
{
|
||||
mPrinter->printShaderHeader(stream);
|
||||
|
||||
_printDependencies(stream); // TODO: Split into vert and pix dependencies?
|
||||
_printFeatureList(stream);
|
||||
|
||||
mComponents[C_CONNECTOR]->print( stream );
|
||||
|
||||
mPrinter->printPixelShaderOutputStruct(stream, mFeatureData);
|
||||
mPrinter->printMainComment(stream);
|
||||
|
||||
mComponents[C_PIX_MAIN]->print( stream );
|
||||
|
||||
// print out the function
|
||||
_printFeatures( stream );
|
||||
|
||||
mPrinter->printPixelShaderCloser(stream);
|
||||
}
|
||||
|
||||
GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros )
|
||||
{
|
||||
PROFILE_SCOPE( ShaderGen_GetShader );
|
||||
|
||||
const FeatureSet &features = featureData.codify();
|
||||
|
||||
// Build a description string from the features
|
||||
// and vertex format combination ( and macros ).
|
||||
String shaderDescription = vertexFormat->getDescription() + features.getDescription();
|
||||
if ( macros && !macros->empty() )
|
||||
{
|
||||
String macroStr;
|
||||
GFXShaderMacro::stringize( *macros, ¯oStr );
|
||||
shaderDescription += macroStr;
|
||||
}
|
||||
|
||||
// Generate a single 64bit hash from the description string.
|
||||
//
|
||||
// Don't get paranoid! This has 1 in 18446744073709551616
|
||||
// chance for collision... it won't happen in this lifetime.
|
||||
//
|
||||
U64 hash = Torque::hash64( (const U8*)shaderDescription.c_str(), shaderDescription.length(), 0 );
|
||||
hash = convertHostToLEndian(hash);
|
||||
U32 high = (U32)( hash >> 32 );
|
||||
U32 low = (U32)( hash & 0x00000000FFFFFFFF );
|
||||
String cacheKey = String::ToString( "%x%x", high, low );
|
||||
|
||||
// return shader if exists
|
||||
GFXShader *match = mProcShaders[cacheKey];
|
||||
if ( match )
|
||||
return match;
|
||||
|
||||
// if not, then create it
|
||||
char vertFile[256];
|
||||
char pixFile[256];
|
||||
F32 pixVersion;
|
||||
|
||||
Vector<GFXShaderMacro> shaderMacros;
|
||||
shaderMacros.push_back( GFXShaderMacro( "TORQUE_SHADERGEN" ) );
|
||||
if ( macros )
|
||||
shaderMacros.merge( *macros );
|
||||
generateShader( featureData, vertFile, pixFile, &pixVersion, vertexFormat, cacheKey, shaderMacros );
|
||||
|
||||
GFXShader *shader = GFX->createShader();
|
||||
shader->mInstancingFormat.copy( mInstancingFormat ); // TODO: Move to init() below!
|
||||
if ( !shader->init( vertFile, pixFile, pixVersion, shaderMacros ) )
|
||||
{
|
||||
delete shader;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mProcShaders[cacheKey] = shader;
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void ShaderGen::flushProceduralShaders()
|
||||
{
|
||||
// The shaders are reference counted, so we
|
||||
// just need to clear the map.
|
||||
mProcShaders.clear();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue