diff --git a/Engine/source/core/util/hashFunction.cpp b/Engine/source/core/util/hashFunction.cpp index 69206dc300..dbc30e2870 100644 --- a/Engine/source/core/util/hashFunction.cpp +++ b/Engine/source/core/util/hashFunction.cpp @@ -31,6 +31,8 @@ #include "core/util/hashFunction.h" +#include "core/util/endian.h" + namespace Torque { @@ -268,4 +270,21 @@ U64 hash64( const U8 *k, U32 length, U64 initval ) return c; } +// Generate a single 64bit hash from the input string. +// +// Don't get paranoid! This has 1 in 18446744073709551616 +// chance for collision... it won't happen in this lifetime. +// +String getStringHash64(const String& in) +{ + String cacheKey = in; + cacheKey.replace("\n", " "); + U64 hash = hash64((const U8*)cacheKey.c_str(), cacheKey.length(), 0); + hash = convertHostToLEndian(hash); + U32 high = (U32)(hash >> 32); + U32 low = (U32)(hash & 0x00000000FFFFFFFF); + cacheKey = String::ToString("%x%x", high, low); + return cacheKey; +} + } // namespace diff --git a/Engine/source/core/util/hashFunction.h b/Engine/source/core/util/hashFunction.h index 02ecd019b2..f3a57cc9ab 100644 --- a/Engine/source/core/util/hashFunction.h +++ b/Engine/source/core/util/hashFunction.h @@ -34,6 +34,8 @@ extern U32 hash(const U8 *k, U32 length, U32 initval); extern U64 hash64(const U8 *k, U32 length, U64 initval); +extern String getStringHash64(const String& in); + } #endif // _HASHFUNCTION_H_ diff --git a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp index 6259be3304..4a919cffd3 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp @@ -681,6 +681,24 @@ bool GFXD3D11Shader::_init() return true; } +static String buildMacroHash(const D3D_SHADER_MACRO* defines) +{ + String combined; + + if (!defines) + return ""; + + for (const D3D_SHADER_MACRO* m = defines; m->Name != nullptr; ++m) + { + combined += m->Name; + combined += "="; + combined += m->Definition ? m->Definition : ""; + combined += ";"; + } + + return Torque::getStringHash64(combined); +} + bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, GFXShaderStage shaderStage, const D3D_SHADER_MACRO *defines) @@ -706,8 +724,40 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, Con::printf( "Compiling Shader: '%s'", filePath.getFullPath().c_str() ); #endif + String macroHash = buildMacroHash(defines); + + Torque::Path cachePath = filePath; + cachePath.setExtension("tso"); + cachePath.setFileName(cachePath.getFileName() + "_" + macroHash); + + if (Torque::FS::IsFile(cachePath)) + { + Torque::FS::FileNodeRef rawFile = Torque::FS::GetFileNode(filePath); + Torque::FS::FileNodeRef cachedFile = Torque::FS::GetFileNode(cachePath); + + if (rawFile != NULL && cachedFile != NULL) + { + if (cachedFile->getModifiedTime() >= rawFile->getModifiedTime()) + { + + FileStream fs; + if (fs.open(cachePath, Torque::FS::File::Read)) + { + U32 size = fs.getStreamSize(); + + D3DCreateBlob(size, &code); + fs.read(size, code->GetBufferPointer()); + + res = 1; + } + } + } + } + + bool loadedFromCache = (code != NULL); + // Is it an HLSL shader? - if(filePath.getExtension().equal("hlsl", String::NoCase)) + if(filePath.getExtension().equal("hlsl", String::NoCase) && !loadedFromCache) { // Set this so that the D3DInclude::Open will have this // information for relative paths. @@ -788,6 +838,20 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, AssertISV(SUCCEEDED(res), "Unable to compile shader!"); + // succeeded write out a cache + if (!loadedFromCache) + { + if (SUCCEEDED(res) && code) + { + // Save cache + FileStream out; + if (out.open(cachePath, Torque::FS::File::Write)) + { + out.write(code->GetBufferSize(), code->GetBufferPointer()); + } + } + } + if(code != NULL) { switch (shaderStage) diff --git a/Engine/source/gfx/gfxAPI.cpp b/Engine/source/gfx/gfxAPI.cpp index be9564732e..be05be46f9 100644 --- a/Engine/source/gfx/gfxAPI.cpp +++ b/Engine/source/gfx/gfxAPI.cpp @@ -180,3 +180,37 @@ ImplementEnumType( GFXBlendOp, { GFXBlendOpMax, "GFXBlendOpMax" } EndImplementEnumType; + +ImplementEnumType(GFXShaderConstType, + "The shader const types.\n" + "@ingroup GFX") + + { GFXSCT_Uknown, "GFXSCT_Uknown" }, + { GFXSCT_ConstBuffer, "GFXSCT_ConstBuffer" }, + { GFXSCT_Float, "GFXSCT_Float" }, + { GFXSCT_Float2, "GFXSCT_Float2" }, + { GFXSCT_Float3, "GFXSCT_Float3" }, + { GFXSCT_Float4, "GFXSCT_Float4" }, + { GFXSCT_Float2x2, "GFXSCT_Float2x2" }, + { GFXSCT_Float3x3, "GFXSCT_Float3x3" }, + { GFXSCT_Float3x4, "GFXSCT_Float3x4" }, + { GFXSCT_Float4x3, "GFXSCT_Float4x3" }, + { GFXSCT_Float4x4, "GFXSCT_Float4x4" }, + { GFXSCT_Int, "GFXSCT_Int" }, + { GFXSCT_Int2, "GFXSCT_Int2" }, + { GFXSCT_Int3, "GFXSCT_Int3" }, + { GFXSCT_Int4, "GFXSCT_Int4" }, + { GFXSCT_UInt, "GFXSCT_UInt" }, + { GFXSCT_UInt2, "GFXSCT_UInt2" }, + { GFXSCT_UInt3, "GFXSCT_UInt3" }, + { GFXSCT_UInt4, "GFXSCT_UInt4" }, + { GFXSCT_Bool, "GFXSCT_Bool" }, + { GFXSCT_Bool2, "GFXSCT_Bool2" }, + { GFXSCT_Bool3, "GFXSCT_Bool3" }, + { GFXSCT_Bool4, "GFXSCT_Bool4" }, + { GFXSCT_Sampler, "GFXSCT_Sampler" }, + { GFXSCT_SamplerCube, "GFXSCT_SamplerCube" }, + { GFXSCT_SamplerCubeArray, "GFXSCT_SamplerCubeArray" }, + { GFXSCT_SamplerTextureArray, "GFXSCT_SamplerTextureArray" } + +EndImplementEnumType; diff --git a/Engine/source/gfx/gfxAPI.h b/Engine/source/gfx/gfxAPI.h index 2c7f420d05..00f2191667 100644 --- a/Engine/source/gfx/gfxAPI.h +++ b/Engine/source/gfx/gfxAPI.h @@ -44,6 +44,7 @@ DefineEnumType( GFXTextureFilterType ); DefineEnumType( GFXCullMode ); DefineEnumType( GFXStencilOp ); DefineEnumType( GFXBlendOp ); +DefineEnumType(GFXShaderConstType); DefineEnumType( GFXAdapterType ); DECLARE_STRUCT( GFXVideoMode ); @@ -57,5 +58,6 @@ DefineConsoleType( TypeGFXTextureFilterType, GFXTextureFilterType ); DefineConsoleType( TypeGFXCullMode, GFXCullMode ); DefineConsoleType( TypeGFXStencilOp, GFXStencilOp ); DefineConsoleType( TypeGFXBlendOp, GFXBlendOp ); +DefineConsoleType( TypeGFXShaderConstType, GFXShaderConstType); #endif // !_GFXAPI_H_ diff --git a/Engine/source/gfx/gfxShader.cpp b/Engine/source/gfx/gfxShader.cpp index 62f6aff967..af4930d63b 100644 --- a/Engine/source/gfx/gfxShader.cpp +++ b/Engine/source/gfx/gfxShader.cpp @@ -42,8 +42,12 @@ GFXShader::GFXShader() GFXShader::~GFXShader() { - Torque::FS::RemoveChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged ); - Torque::FS::RemoveChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged ); + if (!mVertexFile.isEmpty()) + Torque::FS::RemoveChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged ); + if (!mPixelFile.isEmpty()) + Torque::FS::RemoveChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged ); + if (!mGeometryFile.isEmpty()) + Torque::FS::RemoveChangeNotification(mGeometryFile, this, &GFXShader::_onFileChanged); SAFE_DELETE(mInstancingFormat); } diff --git a/Engine/source/gfx/gfxShader.h b/Engine/source/gfx/gfxShader.h index edb20a1278..720d76290c 100644 --- a/Engine/source/gfx/gfxShader.h +++ b/Engine/source/gfx/gfxShader.h @@ -77,7 +77,9 @@ enum GFXShaderStage GEOMETRY_SHADER = BIT(2), DOMAIN_SHADER = BIT(3), HULL_SHADER = BIT(4), - COMPUTE_SHADER = BIT(5) + COMPUTE_SHADER = BIT(5), + ALL_STAGES = VERTEX_SHADER | PIXEL_SHADER | GEOMETRY_SHADER | + DOMAIN_SHADER | HULL_SHADER | COMPUTE_SHADER }; /// Instances of this struct are returned GFXShaderConstBuffer diff --git a/Engine/source/materials/shaderData.cpp b/Engine/source/materials/shaderData.cpp index 85b6d14467..8e987e4dcc 100644 --- a/Engine/source/materials/shaderData.cpp +++ b/Engine/source/materials/shaderData.cpp @@ -78,6 +78,8 @@ ShaderData::ShaderData() mOGLVertexShaderName = StringTable->EmptyString(); mOGLPixelShaderName = StringTable->EmptyString(); mOGLGeometryShaderName = StringTable->EmptyString(); + + mInstancingFormat = NULL; } void ShaderData::initPersistFields() @@ -204,7 +206,7 @@ const Vector& ShaderData::_getMacros() return mShaderMacros; } -GFXShader* ShaderData::getShader( const Vector ¯os ) +GFXShader* ShaderData::getShader( const Vector ¯os) { PROFILE_SCOPE( ShaderData_GetShader ); @@ -217,6 +219,8 @@ GFXShader* ShaderData::getShader( const Vector ¯os ) String cacheKey; GFXShaderMacro::stringize( macros, &cacheKey ); + cacheKey = Torque::getStringHash64(cacheKey); + // Lookup the shader for this instance. ShaderCache::Iterator iter = mShaders.find( cacheKey ); if ( iter != mShaders.end() ) @@ -224,7 +228,7 @@ GFXShader* ShaderData::getShader( const Vector ¯os ) // Create the shader instance... if it fails then // bail out and return nothing to the caller. - GFXShader *shader = _createShader( finalMacros ); + GFXShader *shader = _createShader( finalMacros); if ( !shader ) return NULL; @@ -235,7 +239,7 @@ GFXShader* ShaderData::getShader( const Vector ¯os ) return shader; } -GFXShader* ShaderData::_createShader( const Vector ¯os ) +GFXShader* ShaderData::_createShader( const Vector ¯os) { F32 pixver = mPixVersion; if ( mUseDevicePixVersion ) @@ -257,30 +261,32 @@ GFXShader* ShaderData::_createShader( const Vector ¯os ) { case Direct3D11: { - if (mDXVertexShaderName != String::EmptyString) + if (mDXVertexShaderName != StringTable->EmptyString()) shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, mDXVertexShaderName); - if (mDXPixelShaderName != String::EmptyString) + if (mDXPixelShaderName != StringTable->EmptyString()) shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, mDXPixelShaderName); - if (mDXGeometryShaderName != String::EmptyString) + if (mDXGeometryShaderName != StringTable->EmptyString()) shader->setShaderStageFile(GFXShaderStage::GEOMETRY_SHADER, mDXGeometryShaderName); success = shader->init( pixver, macros, - samplers); + samplers, + mInstancingFormat); break; } case OpenGL: { - if(mOGLVertexShaderName != String::EmptyString) + if(mOGLVertexShaderName != StringTable->EmptyString()) shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, mOGLVertexShaderName); - if (mOGLPixelShaderName != String::EmptyString) + if (mOGLPixelShaderName != StringTable->EmptyString()) shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, mOGLPixelShaderName); - if (mOGLGeometryShaderName != String::EmptyString) + if (mOGLGeometryShaderName != StringTable->EmptyString()) shader->setShaderStageFile(GFXShaderStage::GEOMETRY_SHADER, mOGLGeometryShaderName); success = shader->init( pixver, macros, - samplers); + samplers, + mInstancingFormat); break; } @@ -348,6 +354,33 @@ void ShaderData::_onLMActivate( const char *lm, bool activate ) reloadAllShaders(); } +void ShaderData::setShaderStageFile(GFXShaderStage stage, String fileName) +{ + const bool isGL = GFX->getAdapterType() == GFXAdapterType::OpenGL; + switch (stage) + { + case VERTEX_SHADER: + isGL ? mOGLVertexShaderName = StringTable->insert(fileName) : mDXVertexShaderName = StringTable->insert(fileName); + break; + case PIXEL_SHADER: + isGL ? mOGLPixelShaderName = StringTable->insert(fileName) : mDXPixelShaderName = StringTable->insert(fileName); + break; + case GEOMETRY_SHADER: + isGL ? mOGLGeometryShaderName = StringTable->insert(fileName) : mDXGeometryShaderName = StringTable->insert(fileName); + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + case ALL_STAGES: + break; + default: + break; + } +} + bool ShaderData::hasSamplerDef(const String &_samplerName, int &pos) const { String samplerName = _samplerName.startsWith("$") ? _samplerName : "$"+_samplerName; diff --git a/Engine/source/materials/shaderData.h b/Engine/source/materials/shaderData.h index 2fa63271fa..9b9af2a154 100644 --- a/Engine/source/materials/shaderData.h +++ b/Engine/source/materials/shaderData.h @@ -80,10 +80,8 @@ class ShaderData : public SimObject /// them if the content has changed. const Vector& _getMacros(); - /// Helper for converting an array of macros - /// into a formatted string. - void _stringizeMacros(const Vector& macros, - String* outString); + // the instancing format. + GFXVertexFormat* mInstancingFormat; /// Creates a new shader returning NULL on error. GFXShader* _createShader(const Vector& macros); @@ -106,8 +104,11 @@ class ShaderData : public SimObject void setSamplerName(const String& name, int idx) { mSamplerNames[idx] = name; } String getSamplerName(int idx) const { return mSamplerNames[idx]; } + void setShaderStageFile(GFXShaderStage stage, String fileName); + bool hasSamplerDef(const String& samplerName, int& pos) const; bool hasRTParamsDef(const int pos) const { return mRTParams[pos]; } + void setInstancingFormat(GFXVertexFormat* instancingFormat) { mInstancingFormat = instancingFormat; } ShaderData(); @@ -122,6 +123,7 @@ class ShaderData : public SimObject /// all loaded ShaderData objects in the system. static void reloadAllShaders(); + void setPixVersion(F32 pixVersion) { mPixVersion = pixVersion; } /// Returns the required pixel shader version for this shader. F32 getPixVersion() const { return mPixVersion; } diff --git a/Engine/source/shaderGen/HLSL/accuFeatureHLSL.h b/Engine/source/shaderGen/HLSL/accuFeatureHLSL.h index 5f4682178f..1912ecbb8d 100644 --- a/Engine/source/shaderGen/HLSL/accuFeatureHLSL.h +++ b/Engine/source/shaderGen/HLSL/accuFeatureHLSL.h @@ -98,6 +98,8 @@ class AccuScaleFeature : public ShaderFeatureHLSL } } + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Accu Scale"; } }; @@ -118,6 +120,8 @@ class AccuDirectionFeature : public ShaderFeatureHLSL } } + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Accu Direction"; } }; @@ -138,6 +142,8 @@ class AccuStrengthFeature : public ShaderFeatureHLSL } } + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Accu Strength"; } }; @@ -158,6 +164,8 @@ class AccuCoverageFeature : public ShaderFeatureHLSL } } + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Accu Coverage"; } }; @@ -179,7 +187,9 @@ class AccuSpecularFeature : public ShaderFeatureHLSL } } + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Accu Specular"; } }; -#endif \ No newline at end of file +#endif diff --git a/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.h b/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.h index 53c0151e95..05ffc69a73 100644 --- a/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.h +++ b/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.h @@ -37,5 +37,7 @@ class DebugVizHLSL : public ShaderFeatureHLSL void processPix(Vector& componentList, const MaterialFeatureData& fd) override; + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Debug Viz"; } }; diff --git a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.h b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.h index 627f1019a5..f5988c0224 100644 --- a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.h +++ b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.h @@ -180,6 +180,8 @@ class RenderTargetZeroHLSL : public ShaderFeatureHLSL void processPix( Vector &componentList, const MaterialFeatureData &fd ) override; + + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } U32 getOutputTargets( const MaterialFeatureData &fd ) const override { return mOutputTargetMask; } }; @@ -306,6 +308,7 @@ class DiffuseFeatureHLSL : public ShaderFeatureHLSL public: void processPix( Vector &componentList, const MaterialFeatureData &fd ) override; + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } Material::BlendOp getBlendOp() override{ return Material::None; } @@ -540,6 +543,8 @@ class AlphaTestHLSL : public ShaderFeatureHLSL void processPix( Vector &componentList, const MaterialFeatureData &fd ) override; + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + Material::BlendOp getBlendOp() override { return Material::None; } String getName() override @@ -558,6 +563,9 @@ class GlowMaskHLSL : public ShaderFeatureHLSL void processPix( Vector &componentList, const MaterialFeatureData &fd ) override; + + U32 getShaderStages() override { return ( GFXShaderStage::PIXEL_SHADER); } + String getName() override { return "Glow Mask"; @@ -582,6 +590,8 @@ class HDROutHLSL : public ShaderFeatureHLSL void processPix( Vector &componentList, const MaterialFeatureData &fd ) override; + U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); } + Material::BlendOp getBlendOp() override { return Material::None; } String getName() override { return "HDR Output"; } @@ -626,6 +636,8 @@ class ParticleNormalFeatureHLSL : public ShaderFeatureHLSL void processVert( Vector &componentList, const MaterialFeatureData &fd ) override; + U32 getShaderStages() override { return (GFXShaderStage::VERTEX_SHADER); } + String getName() override { return "Particle Normal Generation Feature"; @@ -672,6 +684,8 @@ class HardwareSkinningFeatureHLSL : public ShaderFeatureHLSL void processVert( Vector &componentList, const MaterialFeatureData &fd ) override; + U32 getShaderStages() override { return (GFXShaderStage::VERTEX_SHADER); } + String getName() override { return "Hardware Skinning"; } }; diff --git a/Engine/source/shaderGen/NODE/shaderGenNodes.cpp b/Engine/source/shaderGen/NODE/shaderGenNodes.cpp new file mode 100644 index 0000000000..5ae6de5669 --- /dev/null +++ b/Engine/source/shaderGen/NODE/shaderGenNodes.cpp @@ -0,0 +1,533 @@ +#include "platform/platform.h" +#include "shaderGen/shaderGen.h" + +#include "shaderGen/NODE/shaderGenNodes.h" +#include "shaderGen/langElement.h" +#include "shaderGen/shaderOp.h" +#include "shaderGen/shaderGenVars.h" +#include "gfx/gfxDevice.h" +#include "materials/matInstance.h" +#include "materials/processedMaterial.h" +#include "materials/materialFeatureTypes.h" +#include "core/util/autoPtr.h" + +#include "core/module.h" +#include "materials/materialFeatureTypes.h" + + +ImplementFeatureType(SNF_VertexPosition, U32(-1), -1, false); +ImplementFeatureType(SNF_DefaultTexCoord, U32(-1), -1, false); +ImplementFeatureType(SNF_TextureFeature, U32(-1), -1, false); +ImplementFeatureType(SNF_NormalMapFeature, U32(-1), -1, false); + +ImplementEnumType(ShaderNodeFeature_enum, "Shader node features. Each of thes relates to a specific node for generating a shader.\n\n") + { ShaderNodeFeature_enum::eSNF_VertexPosition, "SNF_VertexPosition", "Setup vertex position." }, + { ShaderNodeFeature_enum::eSNF_DefaultTexCoord, "SNF_DefaultTexCoord", "Setup the default texcoord." }, + { ShaderNodeFeature_enum::eSNF_TextureFeature, "SNF_TextureFeature", "Sample a Texture - Params: (string,string,GFXSamplerStateData,bool)." }, + { ShaderNodeFeature_enum::eSNF_NormalMapFeature,"SNF_NormalMapFeature", "Convert a texture to a normalmap - Params: (string,float,bool,bool)." }, +EndImplementEnumType; + +namespace +{ + void register_node_features(GFXAdapterType type) + { + FEATUREMGR->registerFeature(SNF_VertexPosition, new NodeVertexPositionFeature); + FEATUREMGR->registerFeature(SNF_DefaultTexCoord, new DefaultTexcoordFeature); + FEATUREMGR->registerFeature(SNF_TextureFeature, new TextureFeature, TextureFeature::createFunction); + FEATUREMGR->registerFeature(SNF_NormalMapFeature, new NormalMapFeature, NormalMapFeature::createFunction); + + REGISTER_FEATURE_PARAMS(SNF_TextureFeature, TextureFeatureParams); + REGISTER_FEATURE_PARAMS(SNF_NormalMapFeature, NormalMapFeatureParams); + } + +}; + +MODULE_BEGIN(ShaderGenNodes) + +MODULE_INIT_AFTER(ShaderGen) +MODULE_INIT_AFTER(ShaderGenFeatureMgr) + +MODULE_INIT +{ + SHADERGEN->getFeatureInitSignal().notify(®ister_node_features); +} + +MODULE_END; + +Var* ShaderFeatureNode::getObjTrans(Vector& componentList, + bool useInstancing, + MultiLine* meta) +{ + Var* objTrans = (Var*)LangElement::find("objTrans"); + if (objTrans) + return objTrans; + + if (useInstancing) + { + ShaderConnector* vertStruct = dynamic_cast(componentList[C_VERT_STRUCT]); + Var* instObjTrans = vertStruct->getElement(RT_TEXCOORD, 4, 4); + instObjTrans->setStructName("IN"); + instObjTrans->setName("inst_objectTrans"); + + mInstancingFormat->addElement("objTrans", GFXDeclType_Float4, instObjTrans->constNum + 0); + mInstancingFormat->addElement("objTrans", GFXDeclType_Float4, instObjTrans->constNum + 1); + mInstancingFormat->addElement("objTrans", GFXDeclType_Float4, instObjTrans->constNum + 2); + mInstancingFormat->addElement("objTrans", GFXDeclType_Float4, instObjTrans->constNum + 3); + + objTrans = new Var; + objTrans->setType(GFXSCT_Float4x4); + objTrans->setName("objTrans"); + + Vector matrixVars; + matrixVars.push_back(instObjTrans); + meta->addStatement(new GenOp(" @ = @;", new DecOp(objTrans), new MatrixInitializeOp(objTrans, matrixVars))); + } + else + { + objTrans = new Var; + objTrans->setType(GFXSCT_Float4x4); + objTrans->setName("objTrans"); + objTrans->uniform = true; + objTrans->constSortPos = cspPrimitive; + } + + return objTrans; +} + +Var* ShaderFeatureNode::getModelView( Vector& componentList, + bool useInstancing, + MultiLine* meta) +{ + Var* modelview = (Var*)LangElement::find("modelview"); + if (modelview) + return modelview; + + if (useInstancing) + { + Var* objTrans = getObjTrans(componentList, useInstancing, meta); + + Var* viewProj = (Var*)LangElement::find("viewProj"); + if (!viewProj) + { + viewProj = new Var; + viewProj->setType(GFXSCT_Float4x4); + viewProj->setName("viewProj"); + viewProj->uniform = true; + viewProj->constSortPos = cspPass; + } + + modelview = new Var; + modelview->setType(GFXSCT_Float4x4); + modelview->setName("modelview"); + meta->addStatement(new GenOp(" @ = @; // Instancing!\r\n", new DecOp(modelview), new MatrixMultiplyOp(viewProj, objTrans))); + } + else + { + modelview = new Var; + modelview->setType(GFXSCT_Float4x4); + modelview->setName("modelview"); + modelview->uniform = true; + modelview->constSortPos = cspPrimitive; + } + + return modelview; +} + +Var* ShaderFeatureNode::getWorldView( Vector& componentList, + bool useInstancing, + MultiLine* meta) +{ + Var* worldView = (Var*)LangElement::find("worldViewOnly"); + if (worldView) + return worldView; + + if (useInstancing) + { + Var* objTrans = getObjTrans(componentList, useInstancing, meta); + + Var* worldToCamera = (Var*)LangElement::find("worldToCamera"); + if (!worldToCamera) + { + worldToCamera = new Var; + worldToCamera->setType(GFXSCT_Float4x4); + worldToCamera->setName("worldToCamera"); + worldToCamera->uniform = true; + worldToCamera->constSortPos = cspPass; + } + + worldView = new Var; + worldView->setType(GFXSCT_Float4x4); + worldView->setName("worldViewOnly"); + + meta->addStatement(new GenOp(" @ = @; // Instancing!\r\n", new DecOp(worldView), new MatrixMultiplyOp(worldToCamera, objTrans) )); + } + else + { + worldView = new Var; + worldView->setType(GFXSCT_Float4x4); + worldView->setName("worldViewOnly"); + worldView->uniform = true; + worldView->constSortPos = cspPrimitive; + } + + return worldView; +} + +void ShaderFeatureNode::setupTextureSample( const String& samplerName, + GFXShaderConstType samplerType, + Vector& componentList, + MultiLine* meta, + LangElement* texCoord, + LangElement* compareValue, + bool useGather) +{ + const bool isGL = (GFX->getAdapterType() == OpenGL); + const bool isComparison = (compareValue != NULL); + + // ---- Create or find texture/sampler vars ---- + String texVarName = samplerName + "_tex"; + String sampVarName = samplerName; + String resultVarName = samplerName + "_col"; + + + Var* samplerVar = dynamic_cast(LangElement::find(sampVarName)); + Var* textureVar = NULL; + + // The sampled color variable (e.g. "samplerName_col") should always be new but just in case + Var* sampledColor = (Var*)LangElement::find(resultVarName); + if (!sampledColor) + { + sampledColor->setType(GFXSCT_Float4); + sampledColor->setName(resultVarName); // The result var will be named like the sampler + meta->addStatement(new GenOp(" @", new DecOp(sampledColor))); + } + else + { + meta->addStatement(new GenOp(" @",sampledColor)); + } + + if (isGL) + { + // ---------------- GLSL Sampling ---------------- + if (!samplerVar) + { + samplerVar = new Var; + samplerVar->setType(LangElement::constTypeToString(samplerType, true)); + samplerVar->setName(sampVarName); + samplerVar->uniform = true; + samplerVar->sampler = true; + samplerVar->constNum = Var::getTexUnitNum(); + } + + if (isComparison) + { + if (useGather) + meta->addStatement(new GenOp( + " = textureGather(@, @, @);\r\n", + samplerVar, texCoord, compareValue)); + else + meta->addStatement(new GenOp( + " = texture(@, @, @);\r\n", + samplerVar, texCoord, compareValue)); + } + else + { + if (useGather) + meta->addStatement(new GenOp( + " = textureGather(@, @);\r\n", + samplerVar, texCoord)); + else + meta->addStatement(new GenOp( + " = texture(@, @);\r\n", + samplerVar, texCoord)); + } + } + else + { + // ---------------- HLSL Sampling ---------------- + if (!samplerVar) + { + samplerVar = new Var; + samplerVar->setType(isComparison ? "SamplerComparisonState" : "SamplerState"); + samplerVar->setName(sampVarName); + samplerVar->uniform = true; + samplerVar->sampler = true; + samplerVar->constNum = Var::getTexUnitNum(); + } + + textureVar = dynamic_cast(LangElement::find(texVarName)); + if (!textureVar) + { + textureVar = new Var; + textureVar->setType(LangElement::constTypeToString(samplerType, true)); // Texture2D, TextureCube, etc. + textureVar->setName(texVarName); + textureVar->uniform = true; + textureVar->texture = true; + textureVar->constNum = samplerVar->constNum; + } + + if (isComparison) + { + if (useGather) + meta->addStatement(new GenOp( + " = @.SampleCmpGather(@, @, @);\r\n", + textureVar, samplerVar, texCoord, compareValue)); + else + meta->addStatement(new GenOp( + " = @.SampleCmp(@, @, @);\r\n", + textureVar, samplerVar, texCoord, compareValue)); + } + else + { + if (useGather) + meta->addStatement(new GenOp( + " = @.Gather(@, @);\r\n", + textureVar, samplerVar, texCoord)); + else + meta->addStatement(new GenOp( + " = @.Sample(@, @);\r\n", + textureVar, samplerVar, texCoord)); + } + } +} + +Var* ShaderFeatureNode::getOutTexCoord(const char* name, GFXShaderConstType type, bool useTexAnim, MultiLine* meta, Vector& componentList) +{ + String outTexName = String::ToString("out_%s", name); + Var* texCoord = (Var*)LangElement::find(outTexName); + if (!texCoord) + { + Var* inTex = getVertTexCoord(name); + AssertFatal(inTex, "ShaderFeatureNode::getOutTexCoord - Unknown vertex input coord!"); + + ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); + + texCoord = connectComp->getElement(RT_TEXCOORD); + texCoord->setName(outTexName); + texCoord->setStructName("OUT"); + texCoord->setType(type); + + // Statement allows for casting of different types which + // eliminates vector truncation problems. + meta->addStatement(new GenOp(" @ = (@)@;\r\n", texCoord, new TypeOp(type), inTex)); + + } + + return texCoord; +} + +LangElement* ShaderFeatureNode::setupTexSpaceMat(Vector& componentList, Var** texSpaceMat) +{ + return nullptr; +} + +LangElement* ShaderFeatureNode::assignColor(LangElement* elem, Material::BlendOp blend, LangElement* lerpElem, ShaderFeature::OutputTarget outputTarget) +{ + // search for color var + Var* color = (Var*)LangElement::find(getOutputTargetVarName(outputTarget)); + + if (!color) + { + // create color var + color = new Var; + color->setType("fragout"); + color->setName(getOutputTargetVarName(outputTarget)); + color->setStructName("OUT"); + + return new GenOp("@ = @", color, elem); + } + + switch (blend) + { + case Material::Add: + return new GenOp("@ += @", color, elem); + break; + + case Material::Sub: + return new GenOp("@ -= @", color, elem); + break; + + case Material::Mul: + return new GenOp("@ *= @", color, elem); + break; + + case Material::PreMul: + return new GenOp("@.rgb = @.rgb + (@.rgb*(1.0-@.a))", color, elem, color, elem); + break; + + case Material::AddAlpha: + return new GenOp("@ += @ * @.a", color, elem, elem); + break; + + case Material::LerpAlpha: + if (!lerpElem) + lerpElem = elem; + return new GenOp("@.rgb = lerp( @.rgb, (@).rgb, (@).a )", color, color, elem, lerpElem); + break; + + case Material::ToneMap: + return new GenOp("@ = 1.0 - exp(-1.0 * @ * @)", color, color, elem); + break; + + case Material::None: + return new GenOp("@ = @", color, elem); + break; + + default: + AssertFatal(false, "Unrecognized color blendOp"); + // Fallthru + } + + return NULL; +} + +//-------------------------------------------------------- +// Vertex position. +//-------------------------------------------------------- + +void NodeVertexPositionFeature::processVert(Vector& componentList, const MaterialFeatureData& fd) +{ + // First check for an input position from a previous feature + // then look for the default vertex position. + Var* inPosition = (Var*)LangElement::find("inPosition"); + if (!inPosition) + inPosition = (Var*)LangElement::find("position"); + + const bool glsl = (GFX->getAdapterType() == OpenGL); + + // grab connector position + ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); + Var* outPosition = connectComp->getElement( glsl ? RT_POSITION : RT_SVPOSITION); + + if (glsl) + { + outPosition->setName("gl_Position"); + } + else + { + outPosition->setName("hpos"); + outPosition->setStructName("OUT"); + } + + MultiLine* meta = new MultiLine; + + Var* modelview = getModelView(componentList, fd.features[MFT_UseInstancing], meta); + + meta->addStatement(new GenOp(" @ = @;\r\n", outPosition, new MatrixMultiplyOp( modelview, new CastOp(inPosition, GFXSCT_Float4, "x;y;z")))); + + output = meta; +} + +void NodeVertexPositionFeature::processPix(Vector& componentList, const MaterialFeatureData& fd) +{ + const bool glsl = (GFX->getAdapterType() == OpenGL); + + if (!glsl) + { + // grab connector position + ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); + Var* outPosition = connectComp->getElement(RT_SVPOSITION); + outPosition->setName("vpos"); + outPosition->setStructName("IN"); + } +} + +//-------------------------------------------------------- +// Setup the default texcoord +//-------------------------------------------------------- + +void DefaultTexcoordFeature::processVert(Vector& componentList, const MaterialFeatureData& fd) +{ + MultiLine* meta = new MultiLine; + getOutTexCoord("texCoord", + GFXSCT_Float2, + fd.features[MFT_TexAnim], + meta, + componentList); + output = meta; +} + +void DefaultTexcoordFeature::processPix(Vector& componentList, const MaterialFeatureData& fd) +{ + // grab connector texcoord register + Var* inTex = getInTexCoord("texCoord", GFXSCT_Float2, componentList); + if (!inTex) + return; +} + +//-------------------------------------------------------- +// TEXTURE SAMPLER FEATURE +//-------------------------------------------------------- + +void TextureFeature::processPix(Vector& componentList, const MaterialFeatureData& fd) +{ + // find the uv var. + Var* inTex = getInTexCoord(params->uvName, GFXSCT_Float2, componentList); + if (!inTex) + return; + + MultiLine* meta = new MultiLine; + + // Sample texture + setupTextureSample( + params->samplerName, // name of the output variable. + params->samplerType, // or GFXSCT_SamplerCube, etc. + componentList, + meta, + inTex, + NULL, // compareValue (for SampleCmp) + params->useGather // enable gather if desired + ); + + output = meta; +} + +ShaderFeature::Resources TextureFeature::getResources(const MaterialFeatureData& fd) +{ + Resources res; + res.numTex = 1; + res.numTexReg = 1; + + return res; +} + +//-------------------------------------------------------- +// NORMAL MAPPING FEATURE +//-------------------------------------------------------- + +void NormalMapFeature::processPix(Vector& componentList, const MaterialFeatureData& fd) +{ + String colorVarName = params->inputName; + Var* sampledColor = (Var*)LangElement::find(colorVarName); + + if (!sampledColor) + { + Con::warnf("NormalMapFeature: sampler %s not sampled yet!", params->inputName.c_str()); + return; // TextureFeature must run first + } + + + MultiLine* meta = new MultiLine; + + // TEMP float4 for base decoded normal + Var* tempNorm = new Var; + tempNorm->setName(params->inputName + "_normTemp"); + tempNorm->setType(GFXSCT_Float4); + LangElement* tempNormDecl = new DecOp(tempNorm); + + // sampledColor is the result of the textureFeature. + meta->addStatement(expandNormalMap(sampledColor, tempNormDecl, tempNorm, fd)); + + meta->addStatement( + new GenOp(" @.xy *= @(@, @);\r\n", tempNorm, new TypeOp(GFXSCT_Float2), params->flipX ? -1.0f : 1.0f, params->flipY ? -1.0f : 1.0f)); + + meta->addStatement(new GenOp(" @.xyz = normalize( @( @.xy * @, @.z ) );\r\n", + tempNorm, new TypeOp(GFXSCT_Float3), tempNorm, params->strength, tempNorm)); + + // write back into our known variable. + meta->addStatement(new GenOp(" @ = @;\r\n", sampledColor, tempNorm)); + + output = meta; + +} + diff --git a/Engine/source/shaderGen/NODE/shaderGenNodes.h b/Engine/source/shaderGen/NODE/shaderGenNodes.h new file mode 100644 index 0000000000..d93f3ca808 --- /dev/null +++ b/Engine/source/shaderGen/NODE/shaderGenNodes.h @@ -0,0 +1,241 @@ +#pragma once + +#ifndef _SHADERFEATURE_H_ +#include "shaderGen/shaderFeature.h" +#endif + +#ifndef _FEATUREMGR_H_ +#include "shaderGen/featureMgr.h" +#endif + +#ifndef _FEATURETYPE_H_ +#include "shaderGen/featureType.h" +#endif + +#ifndef __GFXSTATEBLOCKDATA_H_ +#include "gfx/sim/gfxStateBlockData.h" +#endif + +#ifndef _GFXAPI_H_ +#include "gfx/gfxAPI.h" +#endif + +DeclareFeatureType(SNF_VertexPosition); +DeclareFeatureType(SNF_DefaultTexCoord); +DeclareFeatureType(SNF_TextureFeature); +DeclareFeatureType(SNF_NormalMapFeature); + +/// +/// This enum is so we can map to nodes in script. +/// +enum ShaderNodeFeature_enum +{ + eSNF_VertexPosition, + eSNF_DefaultTexCoord, + eSNF_TextureFeature, + eSNF_NormalMapFeature, +}; + +DefineEnumType(ShaderNodeFeature_enum); + +class ShaderFeatureNode : public ShaderFeature +{ +public: + + /// + Var* getObjTrans( Vector& componentList, + bool useInstancing, + MultiLine* meta); + + Var* getModelView(Vector& componentList, + bool useInstancing, + MultiLine* meta); + + Var* getWorldView(Vector& componentList, bool useInstancing, MultiLine* meta); + + void setupTextureSample(const String& samplerName, + GFXShaderConstType samplerType, + Vector& componentList, + MultiLine* meta, + LangElement* texCoord, + LangElement* compareValue, + bool useGather); + + Var* getOutTexCoord( const char* name, + GFXShaderConstType type, + bool useTexAnim, + MultiLine* meta, + Vector& componentList); + + LangElement* setupTexSpaceMat(Vector& componentList, Var** texSpaceMat) override; + + LangElement* assignColor(LangElement* elem, Material::BlendOp blend, LangElement* lerpElem = NULL, ShaderFeature::OutputTarget outputTarget = ShaderFeature::DefaultTarget) override; +}; + +class NodeVertexPositionFeature : public ShaderFeatureNode +{ + void processVert(Vector& componentList, + const MaterialFeatureData& fd) override; + + void processPix(Vector& componentList, + const MaterialFeatureData& fd) override; + + String getName() override + { + return "NodeVertexPositionFeature"; + } +}; + +class DefaultTexcoordFeature : public ShaderFeatureNode +{ + void processVert(Vector& componentList, + const MaterialFeatureData& fd) override; + + void processPix(Vector& componentList, + const MaterialFeatureData& fd) override; + + String getName() override + { + return "DefaultTexCoord"; + } +}; + +//-------------------------------------------------------- +// TEXTURE SAMPLER FEATURE +//-------------------------------------------------------- + +/// +/// Parameters for the TextureFeature +/// +struct TextureFeatureParams : public FeatureParamsBase +{ + String samplerName; + GFXShaderConstType samplerType; + GFXSamplerStateData samplerState; + String uvName; + bool useGather; + + TextureFeatureParams() + { + samplerName = "defaultSampler"; + samplerType = GFXSCT_Sampler; + uvName = "texCoord"; + useGather = false; + + } + + const char* getFeatureParamTypeName() const override { return "TextureFeatureParams"; } + + /// + /// Texture features output variable is samplerName + "_col" + /// + /// The output variable for a texture feature. + const char* getOutputVar() const override { return samplerName + "_col"; } + + static void persistedFields(Vector& fields) + { + addParam(fields, "sampler", Offset(samplerName, TextureFeatureParams), TypeString); + addParam(fields, "samplerType", Offset(samplerType, TextureFeatureParams), TypeGFXShaderConstType); + addParam(fields, "samplerState", Offset(samplerState, TextureFeatureParams), TYPEID()); + addParam(fields, "uvName", Offset(uvName, TextureFeatureParams), TypeString); + addParam(fields, "useGather", Offset(useGather, TextureFeatureParams), TypeBool); + } +}; + +class TextureFeature : public ShaderFeatureNode +{ +private: + /// Parameters that this feature can use to change the shadergen output. + TextureFeatureParams* params; +public: + /// default constructor + TextureFeature() + { + params = new TextureFeatureParams(); + } + /// Constructor that takes params as an argument + TextureFeature(TextureFeatureParams* inParams) + { + params = inParams; + } + + void processPix(Vector& componentList, + const MaterialFeatureData& fd) override; + + ShaderFeature::Resources getResources(const MaterialFeatureData& fd) override; + + // create a static function on the feature class + static ShaderFeature* createFunction(FeatureParamsBase* args) + { + TextureFeatureParams* params = static_cast(args); + return new TextureFeature(params); + } + + String getName() override + { + return "TextureSampler_" + params->samplerName + "_" + params->uvName; + } +}; + +//-------------------------------------------------------- +// NORMAL MAPPING FEATURE +//-------------------------------------------------------- + +/// +/// Parameters for the NormalMapFeature +/// +struct NormalMapFeatureParams : public FeatureParamsBase +{ + String inputName; // name of the sampled normal texture (Var* from TextureFeature) + F32 strength; // normal strength multiplier + bool flipX; + bool flipY; + + NormalMapFeatureParams() + { + inputName = "normalSampler"; + strength = 1.0f; + flipX = false; + flipY = false; + } + + const char* getFeatureParamTypeName() const override { return "NormalMapFeatureParams"; } + + /// + /// Normal map feature writes the result into the input name + /// + /// The output variable for a normal map feature. + const char* getOutputVar() const override { return inputName; } + + static void persistedFields(Vector& fields) + { + addParam(fields, "input", Offset(inputName, NormalMapFeatureParams), TypeString); + addParam(fields, "strength", Offset(strength, NormalMapFeatureParams), TypeF32); + addParam(fields, "flipX", Offset(flipX, NormalMapFeatureParams), TypeBool); + addParam(fields, "flipY", Offset(flipY, NormalMapFeatureParams), TypeBool); + } +}; + +class NormalMapFeature : public ShaderFeatureNode +{ +private: + NormalMapFeatureParams* params; + +public: + NormalMapFeature() { params = new NormalMapFeatureParams(); } + NormalMapFeature(NormalMapFeatureParams* p) { params = p; } + + void processPix(Vector& componentList, const MaterialFeatureData& fd) override; + + // normal map feature does not need any resources as these were created from the texture feature. + + static ShaderFeature* createFunction(FeatureParamsBase* args) + { + return new NormalMapFeature(static_cast(args)); + } + + String getName() override + { + return "NormalMap_" + params->inputName; + } +}; diff --git a/Engine/source/shaderGen/conditionerFeature.cpp b/Engine/source/shaderGen/conditionerFeature.cpp index 1de0b76814..76e2b82306 100644 --- a/Engine/source/shaderGen/conditionerFeature.cpp +++ b/Engine/source/shaderGen/conditionerFeature.cpp @@ -227,7 +227,7 @@ void ConditionerFeature::printFooterComment( MethodType methodType, const String meta->addStatement( new GenOp( "\r\n\r\n" ) ); } -void ConditionerMethodDependency::print( Stream &s ) const +void ConditionerMethodDependency::print( Stream &s, GFXShaderStage stage) const { mConditioner->_printMethod(mMethodType, mConditioner->getShaderMethodName(mMethodType), s); } diff --git a/Engine/source/shaderGen/conditionerFeature.h b/Engine/source/shaderGen/conditionerFeature.h index b834418d7e..5de418bb60 100644 --- a/Engine/source/shaderGen/conditionerFeature.h +++ b/Engine/source/shaderGen/conditionerFeature.h @@ -126,9 +126,11 @@ class ConditionerMethodDependency : public ShaderDependency public: ConditionerMethodDependency( ConditionerFeature *conditioner, const ConditionerFeature::MethodType methodType ) : - mConditioner(conditioner), mMethodType(methodType) {} + mConditioner(conditioner), mMethodType(methodType) { + stages = (GFXShaderStage::VERTEX_SHADER | GFXShaderStage::PIXEL_SHADER); + } - void print( Stream &s ) const override; + void print( Stream &s, GFXShaderStage stage ) const override; // Auto insert information into a macro virtual void createMethodMacro( const String &methodName, Vector ¯os ); diff --git a/Engine/source/shaderGen/featureMgr.cpp b/Engine/source/shaderGen/featureMgr.cpp index 7e742bf587..560c8ab6bd 100644 --- a/Engine/source/shaderGen/featureMgr.cpp +++ b/Engine/source/shaderGen/featureMgr.cpp @@ -51,6 +51,7 @@ FeatureMgr::FeatureMgr() : mNeedsSort( false ) { VECTOR_SET_ASSOCIATION( mFeatures ); + VECTOR_SET_ASSOCIATION( mParamInfos ); } FeatureMgr::~FeatureMgr() @@ -96,7 +97,7 @@ ShaderFeature* FeatureMgr::getByType( const FeatureType &type ) return NULL; } -ShaderFeature* FeatureMgr::createFeature(const FeatureType& type, void* argStruct) +ShaderFeature* FeatureMgr::createFeature(const FeatureType& type, FeatureParamsBase* argStruct) { FeatureInfoVector::iterator iter = mFeatures.begin(); @@ -114,6 +115,64 @@ ShaderFeature* FeatureMgr::createFeature(const FeatureType& type, void* argStruc return nullptr; } +void FeatureMgr::registerFeatureParams(const FeatureType& type, const FeatureParamField* fields, U32 fieldCount, CreateFeatureParams createFn) +{ + // Replace if already exists + for (U32 i = 0; i < mParamInfos.size(); ++i) + { + if (*mParamInfos[i].type == type) + { + mParamInfos.erase(i); + break; + } + } + + mParamInfos.increment(); + mParamInfos.last().type = &type; + mParamInfos.last().fields = fields; + mParamInfos.last().fieldCount = fieldCount; + mParamInfos.last().createFn = createFn; + +} + +FeatureParamsBase* FeatureMgr::createFeatureParams(const FeatureType& type) const +{ + for (U32 i = 0; i < mParamInfos.size(); ++i) + { + if (*mParamInfos[i].type == type) + return mParamInfos[i].createFn(); + } + return nullptr; +} + +void FeatureMgr::applyFeatureParams(const FeatureType& type, + FeatureParamsBase* params, + const Vector& args) const +{ + const FeatureParamInfo* info = nullptr; + for (U32 i = 0; i < mParamInfos.size(); ++i) + { + if (*mParamInfos[i].type == type) + { + info = &mParamInfos[i]; + break; + } + } + + if (!info || !params) + return; + + for (U32 i = 0; i < info->fieldCount; ++i) + { + const FeatureParamField& f = info->fields[i]; + const char* val = args[i].c_str(); + + void* fieldPtr = (U8*)params + f.offset; + // no array support yet. + Con::setData(f.type, fieldPtr, 0, 1, &val); + } +} + void FeatureMgr::registerFeature( const FeatureType &type, ShaderFeature *feature, CreateShaderFeatureDelegate featureDelegate) diff --git a/Engine/source/shaderGen/featureMgr.h b/Engine/source/shaderGen/featureMgr.h index 0b4eeecf13..239b92828e 100644 --- a/Engine/source/shaderGen/featureMgr.h +++ b/Engine/source/shaderGen/featureMgr.h @@ -36,7 +36,49 @@ class FeatureType; class ShaderFeature; -typedef Delegate CreateShaderFeatureDelegate; +struct FeatureParamField +{ + StringTableEntry paramName; + S32 offset; + S32 type; + U32 arraySize; +}; + +inline void addParam(Vector& list, + const char* name, + S32 offset, + S32 consoleType, + U32 arraySize = 1) +{ + FeatureParamField f = { name, offset, consoleType, arraySize }; + list.push_back(f); +} + +/// +/// Base class for all shader feature parameter structs. +/// +class FeatureParamsBase +{ +public: + virtual ~FeatureParamsBase() {} + + virtual const char* getOutputVar() const { return "default"; } + // For debug or script reflection, you can override to serialize/print parameters + virtual const char* getFeatureParamTypeName() const { return "FeatureParamsBase"; } +}; + +typedef Delegate CreateFeatureParams; + +/// Metadata for a parameter struct type. +struct FeatureParamInfo +{ + const FeatureType* type; // Matches feature + const FeatureParamField* fields; + U32 fieldCount; + CreateFeatureParams createFn; // makes a new param struct +}; + +typedef Delegate CreateShaderFeatureDelegate; /// /// Used by the feature manager. @@ -60,9 +102,11 @@ class FeatureMgr bool mNeedsSort; typedef Vector FeatureInfoVector; - FeatureInfoVector mFeatures; + typedef Vector FeatureParamInfoVector; + FeatureParamInfoVector mParamInfos; + static S32 QSORT_CALLBACK _featureInfoCompare( const FeatureInfo *a, const FeatureInfo *b ); public: @@ -87,7 +131,13 @@ class FeatureMgr /// An instance of the shader feature using its static createFunction taking in the /// argument struct. /// - ShaderFeature* createFeature(const FeatureType& type, void* argStruct); + ShaderFeature* createFeature(const FeatureType& type, FeatureParamsBase* argStruct); + + void registerFeatureParams(const FeatureType& type, const FeatureParamField* fields, U32 fieldCount, CreateFeatureParams createFn); + + FeatureParamsBase* createFeatureParams(const FeatureType& type) const; + + void applyFeatureParams(const FeatureType& type, FeatureParamsBase* params, const Vector& args) const; /// /// Allows other systems to add features. index is @@ -114,4 +164,20 @@ class FeatureMgr // Helper for accessing the feature manager singleton. #define FEATUREMGR ManagedSingleton::instance() +#define REGISTER_FEATURE_PARAMS(TYPE, STRUCT_TYPE) \ + struct STRUCT_TYPE##_AutoRegister \ + { \ + STRUCT_TYPE##_AutoRegister() \ + { \ + Vector fieldList; \ + STRUCT_TYPE::persistedFields(fieldList); \ + FEATUREMGR->registerFeatureParams( \ + TYPE, \ + fieldList.address(), \ + fieldList.size(), \ + Delegate([]() -> FeatureParamsBase* { return new STRUCT_TYPE(); })\ + ); \ + } \ + } STRUCT_TYPE##_AutoRegisterInstance; + #endif // FEATUREMGR diff --git a/Engine/source/shaderGen/featureSet.cpp b/Engine/source/shaderGen/featureSet.cpp index f295536bee..a6af95c556 100644 --- a/Engine/source/shaderGen/featureSet.cpp +++ b/Engine/source/shaderGen/featureSet.cpp @@ -82,7 +82,7 @@ const FeatureType& FeatureSet::getAt( U32 index, S32 *outIndex ) const return *mFeatures[index].type; } -void* FeatureSet::getArguments(U32 index) const +FeatureParamsBase* FeatureSet::getArguments(U32 index) const { if (mFeatures[index].argStruct) return mFeatures[index].argStruct; @@ -146,7 +146,7 @@ void FeatureSet::setFeature( const FeatureType &type, bool set, S32 index ) mDescription.clear(); } -void FeatureSet::addFeature( const FeatureType &type, S32 index, void* argStruct ) +void FeatureSet::addFeature( const FeatureType &type, S32 index, FeatureParamsBase* argStruct ) { if (!argStruct) { diff --git a/Engine/source/shaderGen/featureSet.h b/Engine/source/shaderGen/featureSet.h index b494492fd3..299fbe2004 100644 --- a/Engine/source/shaderGen/featureSet.h +++ b/Engine/source/shaderGen/featureSet.h @@ -29,6 +29,9 @@ #ifndef _TVECTOR_H_ #include "core/util/tVector.h" #endif +#ifndef _FEATUREMGR_H_ +#include "shaderGen/featureMgr.h" +#endif class FeatureType; @@ -42,7 +45,7 @@ class FeatureSet { const FeatureType* type; S32 index; - void* argStruct; + FeatureParamsBase* argStruct; }; /// The list of featurs. @@ -94,7 +97,7 @@ class FeatureSet /// the feature index when it was added. const FeatureType& getAt( U32 index, S32 *outIndex = NULL ) const; - void* getArguments(U32 index) const; + FeatureParamsBase* getArguments(U32 index) const; /// Returns true if this handle has this feature. bool hasFeature( const FeatureType &type, S32 index = -1 ) const; @@ -108,7 +111,7 @@ class FeatureSet /// The shader feature type. /// The inedx the shader feature will be sorted in the set. /// A struct representing arguments for a shader feature. - void addFeature( const FeatureType &type, S32 index = -1, void* argStruct = nullptr ); + void addFeature( const FeatureType &type, S32 index = -1, FeatureParamsBase* argStruct = nullptr ); /// void removeFeature( const FeatureType &type ); diff --git a/Engine/source/shaderGen/langElement.cpp b/Engine/source/shaderGen/langElement.cpp index 461a6d43c1..7148e85f35 100644 --- a/Engine/source/shaderGen/langElement.cpp +++ b/Engine/source/shaderGen/langElement.cpp @@ -23,6 +23,7 @@ #include "core/strings/stringFunctions.h" #include "core/util/str.h" #include "gfx/gfxDevice.h" +#include "shaderGen/shaderOp.h" #include "langElement.h" //************************************************************************** @@ -30,69 +31,158 @@ //************************************************************************** Vector LangElement::elementList( __FILE__, __LINE__ ); -const char* LangElement::constTypeToString(GFXShaderConstType constType) +static const ShaderTypeInfo ShaderTypes[] = { - // Determine shader language based on GFXAdapterAPI - if (GFX->getAdapterType() == OpenGL) + // ---- FLOATS ---- + { GFXSCT_Float, "float", "float", STC_Scalar, 1, 1 }, + { GFXSCT_Float2, "vec2", "float2", STC_Vector, 1, 2 }, + { GFXSCT_Float3, "vec3", "float3", STC_Vector, 1, 3 }, + { GFXSCT_Float4, "vec4", "float4", STC_Vector, 1, 4 }, + + // ---- MATRICES ---- + { GFXSCT_Float2x2, "mat2", "float2x2", STC_Matrix, 2, 2 }, + { GFXSCT_Float3x3, "mat3", "float3x3", STC_Matrix, 3, 3 }, + { GFXSCT_Float3x4, "mat3x4", "float3x4", STC_Matrix, 3, 4 }, + { GFXSCT_Float4x3, "mat4x3", "float4x3", STC_Matrix, 4, 3 }, + { GFXSCT_Float4x4, "mat4", "float4x4", STC_Matrix, 4, 4 }, + + // ---- INT ---- + { GFXSCT_Int, "int", "int", STC_Scalar, 1, 1 }, + { GFXSCT_Int2, "ivec2", "int2", STC_Vector, 1, 2 }, + { GFXSCT_Int3, "ivec3", "int3", STC_Vector, 1, 3 }, + { GFXSCT_Int4, "ivec4", "int4", STC_Vector, 1, 4 }, + + // ---- UINT ---- + { GFXSCT_UInt, "uint", "uint", STC_Scalar, 1, 1 }, + { GFXSCT_UInt2, "uvec2", "uint2", STC_Vector, 1, 2 }, + { GFXSCT_UInt3, "uvec3", "uint3", STC_Vector, 1, 3 }, + { GFXSCT_UInt4, "uvec4", "uint4", STC_Vector, 1, 4 }, + + // ---- BOOL ---- + { GFXSCT_Bool, "bool", "bool", STC_Scalar, 1, 1 }, + { GFXSCT_Bool2, "bvec2", "bool2", STC_Vector, 1, 2 }, + { GFXSCT_Bool3, "bvec3", "bool3", STC_Vector, 1, 3 }, + { GFXSCT_Bool4, "bvec4", "bool4", STC_Vector, 1, 4 }, + + // ---- SAMPLERS ---- + { GFXSCT_Sampler, "sampler2D", "Texture2D", STC_Sampler, 0, 0 }, + { GFXSCT_SamplerCube, "samplerCube", "TextureCube", STC_Sampler, 0, 0 }, + { GFXSCT_SamplerTextureArray, "sampler2DArray", "Texture2DArray", STC_Sampler, 0, 0 }, + { GFXSCT_SamplerCubeArray, "samplerCubeArray", "TextureCubeArray", STC_Sampler, 0, 0 }, +}; + +static HashMap glslToType; +static HashMap hlslToType; + +void LangElement::buildTypeMaps() +{ + for (auto& info : ShaderTypes) { - switch (constType) + glslToType[info.glslName] = info.type; + hlslToType[info.hlslName] = info.type; + } +} + +const ShaderTypeInfo* LangElement::getTypeInfo(GFXShaderConstType type) +{ + for (auto& info : ShaderTypes) + if (info.type == type) + return &info; + return nullptr; +} + +const char* LangElement::constTypeToString(GFXShaderConstType constType, bool sampler, bool matrix) +{ + const ShaderTypeInfo* info = getTypeInfo(constType); + if (!info) + return "unknown"; + + if (sampler) + { + if (!info->isSampler()) { - case GFXSCT_Float: return "float"; break; - case GFXSCT_Float2: return "vec2"; break; - case GFXSCT_Float3: return "vec3"; break; - case GFXSCT_Float4: return "vec4"; break; - case GFXSCT_Float2x2: return "mat2"; break; - case GFXSCT_Float3x3: return "mat3"; break; - case GFXSCT_Float3x4: return "mat3x4"; break; - case GFXSCT_Float4x3: return "mat4x3"; break; - case GFXSCT_Float4x4: return "mat4"; break; - case GFXSCT_Int: return "int"; break; - case GFXSCT_Int2: return "ivec2"; break; - case GFXSCT_Int3: return "ivec3"; break; - case GFXSCT_Int4: return "ivec4"; break; - case GFXSCT_UInt: return "uint"; break; - case GFXSCT_UInt2: return "uvec2"; break; - case GFXSCT_UInt3: return "uvec3"; break; - case GFXSCT_UInt4: return "uvec4"; break; - case GFXSCT_Bool: return "bool"; break; - case GFXSCT_Bool2: return "bvec2"; break; - case GFXSCT_Bool3: return "bvec3"; break; - case GFXSCT_Bool4: return "bvec4"; break; - default: return "unknown"; break; + Con::warnf("LangElement::Requested sampler but input const type is not a sampler"); + return "unknown"; } } - else // Assume DirectX/HLSL + + if (matrix) { - switch (constType) + if (!info->isMatrix()) { - case GFXSCT_Float: return "float"; break; - case GFXSCT_Float2: return "float2"; break; - case GFXSCT_Float3: return "float3"; break; - case GFXSCT_Float4: return "float4"; break; - case GFXSCT_Float2x2: return "float2x2"; break; - case GFXSCT_Float3x3: return "float3x3"; break; - case GFXSCT_Float3x4: return "float3x4"; break; - case GFXSCT_Float4x3: return "float4x3"; break; - case GFXSCT_Float4x4: return "float4x4"; break; - case GFXSCT_Int: return "int"; break; - case GFXSCT_Int2: return "int2"; break; - case GFXSCT_Int3: return "int3"; break; - case GFXSCT_Int4: return "int4"; break; - case GFXSCT_UInt: return "uint"; break; - case GFXSCT_UInt2: return "uint2"; break; - case GFXSCT_UInt3: return "uint3"; break; - case GFXSCT_UInt4: return "uint4"; break; - case GFXSCT_Bool: return "bool"; break; - case GFXSCT_Bool2: return "bool2"; break; - case GFXSCT_Bool3: return "bool3"; break; - case GFXSCT_Bool4: return "bool4"; break; - default: return "unknown"; break; + Con::warnf("LangElement::Requested matrix but input const type is not a matrix"); + return "unknown"; } } - return ""; + return (GFX->getAdapterType() == OpenGL) + ? info->glslName + : info->hlslName; +} + +GFXShaderConstType LangElement::stringToConstType(const char* name) +{ + bool glsl = (GFX->getAdapterType() == OpenGL); + + auto& map = glsl ? glslToType : hlslToType; + auto it = map.find(name); + + if (it != map.end()) + return it->value; + + return GFXSCT_Uknown; +} + +bool LangElement::resolveSourceType(LangElement* elem, Var*& outVar, const ShaderTypeInfo*& outInfo) +{ + outVar = nullptr; + outInfo = nullptr; + + // DIRECT VAR + if (Var* v = dynamic_cast(elem)) + { + outVar = v; + outInfo = getTypeInfo(stringToConstType((const char*)v->type)); + return outInfo != nullptr; + } + + // INDEX OP: arrVar[index] + if (IndexOp* idx = dynamic_cast(elem)) + { + Var* arr = dynamic_cast(idx->mInput[0]); + if (!arr) + return false; + + const ShaderTypeInfo* arrInfo = getTypeInfo(stringToConstType((const char*)arr->type)); + if (!arrInfo) + return false; + + // array element type = same as var type but no array dimension + outVar = arr; + outInfo = arrInfo; + return true; + } + + // CAST OP: cast var + if (CastOp* cast = dynamic_cast(elem)) + { + Var* castVar = dynamic_cast(cast->mInput[0]); + if (!castVar) + return false; + + const ShaderTypeInfo* castInfo = getTypeInfo(cast->mTargetType);// get the casts target type. + if (!castInfo) + return false; + + outVar = castVar; // we should probably return null as we should just write the castop langelement, not a var. + outInfo = castInfo; + return true; + } + + return false; } + //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- diff --git a/Engine/source/shaderGen/langElement.h b/Engine/source/shaderGen/langElement.h index c6f25b77ab..f5d4f9206d 100644 --- a/Engine/source/shaderGen/langElement.h +++ b/Engine/source/shaderGen/langElement.h @@ -36,6 +36,46 @@ #define WRITESTR( a ){ stream.write( dStrlen(a), a ); } +//************************************************************************** +/*! + These structs are helpers for unifying both sides of shadergen, the setup + allows us to create other shaderops such as constructors for vars, cast + operations and also checks to make sure mathops can be executed cleanly. +*/ +//************************************************************************** + +enum ShaderTypeCategory +{ + STC_Scalar, + STC_Vector, + STC_Matrix, + STC_Sampler +}; + +/// +/// ShaderTypeInfo type helper for casts and other ops +/// +/// GFXShaderConstType enum type +/// const char* type name for glsl +/// const char* type name for hlsl +/// ShaderTypeCategory enum for category eg STC_Scalar +struct ShaderTypeInfo +{ + GFXShaderConstType type; + + const char* glslName; + const char* hlslName; + + ShaderTypeCategory category; + + U32 rows; // for matrices (otherwise 1) + U32 cols; // vector size for scalars/vectors, column count for matrices + + bool isSampler() const { return category == STC_Sampler; } + bool isVector() const { return category == STC_Vector; } + bool isMatrix() const { return category == STC_Matrix; } + bool isScalar() const { return category == STC_Scalar; } +}; //************************************************************************** /*! @@ -52,14 +92,21 @@ //************************************************************************** // Language element //************************************************************************** +struct Var; // forward declaration struct LangElement { + static void buildTypeMaps(); static Vector elementList; static LangElement * find( const char *name ); static void deleteElements(); - + static const ShaderTypeInfo* getTypeInfo(GFXShaderConstType type); + static bool resolveSourceType(LangElement* elem, Var*& outVar, const ShaderTypeInfo*& outInfo); + U8 name[32]; - static const char* constTypeToString(GFXShaderConstType constType); + + static const char* constTypeToString(GFXShaderConstType constType, bool sampler = false, bool matrix = false); + static GFXShaderConstType stringToConstType(const char* name); + LangElement(); virtual ~LangElement() {}; virtual void print( Stream &stream ){}; @@ -77,6 +124,8 @@ enum ConstantSortPosition cspPotentialPrimitive, /// Updated one per pass cspPass, + /// Set once per scene + cspScene, /// Count var, do not use csp_Count }; @@ -185,6 +234,13 @@ class MultiLine : public LangElement void print( Stream &stream ) override; }; - +class LiteralStr : public LangElement { +public: + LiteralStr(const char* s) : mStr(s) {} + void print(Stream& stream) override { WRITESTR(mStr.c_str()); } + String mStr; +}; #endif // _LANG_ELEMENT_H_ + + diff --git a/Engine/source/shaderGen/shaderDependency.cpp b/Engine/source/shaderGen/shaderDependency.cpp index 22d30572fa..e14948904d 100644 --- a/Engine/source/shaderGen/shaderDependency.cpp +++ b/Engine/source/shaderGen/shaderDependency.cpp @@ -30,6 +30,7 @@ ShaderIncludeDependency::ShaderIncludeDependency( const Torque::Path &pathToInclude ) : mIncludePath( pathToInclude ) { + stages = (GFXShaderStage::VERTEX_SHADER | GFXShaderStage::PIXEL_SHADER); } bool ShaderIncludeDependency::operator==( const ShaderDependency &cmpTo ) const @@ -39,9 +40,12 @@ bool ShaderIncludeDependency::operator==( const ShaderDependency &cmpTo ) const static_cast( &cmpTo )->mIncludePath == mIncludePath ); } -void ShaderIncludeDependency::print( Stream &s ) const +void ShaderIncludeDependency::print( Stream &s , GFXShaderStage stage) const { // Print the include... all shaders support #includes. - String include = String::ToString( "#include \"%s\"\r\n", mIncludePath.getFullPath().c_str() ); - s.write( include.length(), include.c_str() ); + if (stages & stage) + { + String include = String::ToString("#include \"%s\"\r\n", mIncludePath.getFullPath().c_str()); + s.write(include.length(), include.c_str()); + } } diff --git a/Engine/source/shaderGen/shaderDependency.h b/Engine/source/shaderGen/shaderDependency.h index 63a6de48b5..967d5cadad 100644 --- a/Engine/source/shaderGen/shaderDependency.h +++ b/Engine/source/shaderGen/shaderDependency.h @@ -26,7 +26,9 @@ #ifndef _PATH_H_ #include "core/util/path.h" #endif - +#ifndef _GFXSHADER_H_ +#include "gfx/gfxShader.h" +#endif class Stream; @@ -35,6 +37,7 @@ class Stream; class ShaderDependency { public: + U32 stages; virtual ~ShaderDependency() {} /// Compare this dependency to another one. @@ -44,7 +47,7 @@ class ShaderDependency } /// Print the dependency into the header of a shader. - virtual void print( Stream &s ) const = 0; + virtual void print( Stream &s, GFXShaderStage stage) const = 0; }; @@ -60,7 +63,7 @@ class ShaderIncludeDependency : public ShaderDependency ShaderIncludeDependency( const Torque::Path &pathToInclude ); bool operator==( const ShaderDependency &cmpTo ) const override; - void print( Stream &s ) const override; + void print( Stream &s, GFXShaderStage stage) const override; }; -#endif // _SHADER_DEPENDENCY_H_ \ No newline at end of file +#endif // _SHADER_DEPENDENCY_H_ diff --git a/Engine/source/shaderGen/shaderFeature.cpp b/Engine/source/shaderGen/shaderFeature.cpp index 00bbd7c9d7..eb9fb472ae 100644 --- a/Engine/source/shaderGen/shaderFeature.cpp +++ b/Engine/source/shaderGen/shaderFeature.cpp @@ -27,74 +27,74 @@ #include "shaderGen/shaderOp.h" -void ShaderFeature::addDependency( const ShaderDependency *dependsOn ) +void ShaderFeature::addDependency(const ShaderDependency* dependsOn) { - for ( U32 i = 0; i < mDependencies.size(); i++ ) + for (U32 i = 0; i < mDependencies.size(); i++) { - if ( *mDependencies[i] == *dependsOn ) + if (*mDependencies[i] == *dependsOn) return; } - mDependencies.push_back( dependsOn ); + mDependencies.push_back(dependsOn); } -ShaderFeature::Resources ShaderFeature::getResources( const MaterialFeatureData &fd ) +ShaderFeature::Resources ShaderFeature::getResources(const MaterialFeatureData& fd) { - Resources temp; - return temp; + Resources temp; + return temp; } -const char* ShaderFeature::getOutputTargetVarName( OutputTarget target ) const +const char* ShaderFeature::getOutputTargetVarName(OutputTarget target) const { const char* targName = "col"; - switch(target) + switch (target) { - case DefaultTarget: - targName = "col"; - break; + case DefaultTarget: + targName = "col"; + break; - case RenderTarget1: + case RenderTarget1: targName = "col1"; - break; + break; - case RenderTarget2: - targName = "col2"; - break; + case RenderTarget2: + targName = "col2"; + break; - case RenderTarget3: - targName = "col3"; - break; + case RenderTarget3: + targName = "col3"; + break; - case RenderTarget4: - targName = "col4"; - break; + case RenderTarget4: + targName = "col4"; + break; - case RenderTarget5: - targName = "col5"; - break; + case RenderTarget5: + targName = "col5"; + break; } return targName; } -Var* ShaderFeature::findOrCreateLocal( const char *name, - const char *type, - MultiLine *multi ) +Var* ShaderFeature::findOrCreateLocal(const char* name, + const char* type, + MultiLine* multi) { - Var *outVar = (Var*)LangElement::find( name ); - if ( !outVar ) + Var* outVar = (Var*)LangElement::find(name); + if (!outVar) { outVar = new Var; - outVar->setType( type ); - outVar->setName( name ); - multi->addStatement( new GenOp( " @;\r\n", new DecOp( outVar ) ) ); + outVar->setType(type); + outVar->setName(name); + multi->addStatement(new GenOp(" @;\r\n", new DecOp(outVar))); } return outVar; } -void ShaderFeature::setInstancingFormat(GFXVertexFormat *format) +void ShaderFeature::setInstancingFormat(GFXVertexFormat* format) { mInstancingFormat = format; } diff --git a/Engine/source/shaderGen/shaderFeature.h b/Engine/source/shaderGen/shaderFeature.h index 9bed4e7ac6..c19bab55bf 100644 --- a/Engine/source/shaderGen/shaderFeature.h +++ b/Engine/source/shaderGen/shaderFeature.h @@ -237,6 +237,8 @@ class ShaderFeature /// Allows the feature to add macros to vertex shader compiles. virtual void processVertMacros( Vector ¯os, const MaterialFeatureData &fd ) {}; + virtual U32 getShaderStages() { return (GFXShaderStage::VERTEX_SHADER | GFXShaderStage::PIXEL_SHADER); } + /// Identifies what type of blending a feature uses. This is used to /// group features with the same blend operation together in a multipass /// situation. diff --git a/Engine/source/shaderGen/shaderGen.cpp b/Engine/source/shaderGen/shaderGen.cpp index 07781aea0f..2907fbb21d 100644 --- a/Engine/source/shaderGen/shaderGen.cpp +++ b/Engine/source/shaderGen/shaderGen.cpp @@ -30,6 +30,7 @@ #include "gfx/gfxDevice.h" #include "core/memVolume.h" #include "core/module.h" +#include "console/persistenceManager.h" #ifdef TORQUE_D3D11 #include "shaderGen/HLSL/customFeatureHLSL.h" @@ -38,6 +39,31 @@ #include "shaderGen/GLSL/customFeatureGLSL.h" #endif +static const U32 gStageOrder[] = +{ + GFXShaderStage::VERTEX_SHADER, + GFXShaderStage::HULL_SHADER, + GFXShaderStage::DOMAIN_SHADER, + GFXShaderStage::GEOMETRY_SHADER, + GFXShaderStage::PIXEL_SHADER, + GFXShaderStage::COMPUTE_SHADER +}; + +static const char* _getStagePostfix(GFXShaderStage stage) +{ + switch (stage) + { + case GFXShaderStage::VERTEX_SHADER: return "_V"; + case GFXShaderStage::HULL_SHADER: return "_H"; + case GFXShaderStage::DOMAIN_SHADER: return "_D"; + case GFXShaderStage::GEOMETRY_SHADER: return "_G"; + case GFXShaderStage::PIXEL_SHADER: return "_P"; + case GFXShaderStage::COMPUTE_SHADER: return "_C"; + } + + return "_U"; // Unknown +} + MODULE_BEGIN( ShaderGen ) MODULE_INIT_BEFORE( GFX ) @@ -68,6 +94,16 @@ ShaderGen::~ShaderGen() { GFXDevice::getDeviceEventSignal().remove(this, &ShaderGen::_handleGFXEvent); _uninit(); + + mFileCache.clear(); + + for (ShaderDataMap::Pair data : mProcShaderData) + { + if (data.value->isProperlyAdded() && !data.value->isDeleted()) + data.value->unregisterObject(); + } + + mProcShaderData.clear(); } void ShaderGen::registerInitDelegate(GFXAdapterType adapterType, ShaderGenInitDelegate& initDelegate) @@ -99,6 +135,8 @@ void ShaderGen::initShaderGen() return; const GFXAdapterType adapterType = GFX->getAdapterType(); + const bool isGl = adapterType == GFXAdapterType::OpenGL; + if (!mInitDelegates[adapterType]) return; @@ -133,12 +171,23 @@ void ShaderGen::initShaderGen() // Delete the auto-generated conditioner include file. Torque::FS::Remove( "shadergen:/" + ConditionerFeature::ConditionerIncludeFileName ); + + Vector fileList; + String pattern = "*."; + pattern += isGl ? "glsl" : "hlsl"; + S32 numShaderFiles = Torque::FS::FindByPattern("shadergen:/", pattern, false, fileList); + for (U32 i = 0; i < numShaderFiles; i++) + { + Torque::Path filePath = fileList[i]; + mFileCache[filePath.getFileName()] = true; + } + + // build our type maps. + LangElement::buildTypeMaps(); } -void ShaderGen::generateShader( const MaterialFeatureData &featureData, - char *vertFile, - char *pixFile, - F32 *pixVersion, +void ShaderGen::generateShader( const MaterialFeatureData& featureData, + ShaderData* shaderData, const GFXVertexFormat *vertexFormat, const char* cacheName, Vector ¯os) @@ -151,65 +200,115 @@ void ShaderGen::generateShader( const MaterialFeatureData &featureData, _uninit(); _init(); - char vertShaderName[256]; - char pixShaderName[256]; + const FeatureSet& features = mFeatureData.features; + U32 stages = 0; - // 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() ); + // loop through and see which stages this featureset is expecting to make. + for (U32 i = 0; i < features.getCount(); i++) + { - dStrcpy( vertFile, vertShaderName, 256 ); - dStrcpy( pixFile, pixShaderName, 256 ); + const FeatureType& type = features.getAt(i); + ShaderFeature* feat = FEATUREMGR->getByType(type); + stages |= feat->getShaderStages(); - // this needs to change - need to optimize down to ps v.1.1 - *pixVersion = GFX->getPixelShaderVersion(); + } - if ( !Con::getBoolVariable( "ShaderGen::GenNewShaders", true ) ) + for (U32 s = 0; s < (sizeof(gStageOrder) / sizeof(U32)); s++) { - // If we are not regenerating the shader we will return here. - // But we must fill in the shader macros first! + U32 stage = gStageOrder[s]; - _processVertFeatures( macros, true ); - _processPixFeatures( macros, true ); + // skip unused stages + if (!(stages & stage)) + continue; - return; - } + bool macrosOnly = !Con::getBoolVariable("ShaderGen::GenNewShaders", true); + bool skipPrint = false; + GFXShaderStage curStage = (GFXShaderStage)stage; - // create vertex shader - //------------------------ - FileStream* s = new FileStream(); - if(!s->open(vertShaderName, Torque::FS::File::Write )) - { - AssertFatal(false, "Failed to open Shader Stream" ); - return; - } + char fileName[256]; + const char* postfix = _getStagePostfix(curStage); + String stageName; - mOutput = new MultiLine; - mInstancingFormat.clear(); - _processVertFeatures(macros); - _printVertShader( *s ); - delete s; + if (curStage & GFXShaderStage::VERTEX_SHADER) + stageName += vertexFormat->getDescription(); - ((ShaderConnector*)mComponents[C_CONNECTOR])->reset(); - LangElement::deleteElements(); + // build our filename. + for (U32 i = 0; i < features.getCount(); i++) + { + const FeatureType& type = features.getAt(i); + if (stage & FEATUREMGR->getByType(type)->getShaderStages()) + { + stageName += type.getName(); + } + } - // create pixel shader - //------------------------ - s = new FileStream(); - if(!s->open(pixShaderName, Torque::FS::File::Write )) - { - AssertFatal(false, "Failed to open Shader Stream" ); - delete s; - return; - } + stageName = Torque::getStringHash64(stageName); + stageName += postfix; + + FileCacheSet::iterator file = mFileCache.find(stageName); + if (file != mFileCache.end()) + { + // set the shaderdata file for this stage, shaderdata ptr needs to be passed in here. + dSprintf(fileName, sizeof(fileName), "shadergen:/%s.%s", stageName.c_str(), mFileEnding.c_str()); + shaderData->setShaderStageFile(curStage, fileName); + if (!(curStage & GFXShaderStage::VERTEX_SHADER)) + { + continue; + } - mOutput = new MultiLine; - _processPixFeatures(macros); - _printPixShader( *s ); + skipPrint = true; + } - delete s; - LangElement::deleteElements(); + mFileCache[stageName] = true; + + dSprintf(fileName, sizeof(fileName), "shadergen:/%s.%s", stageName.c_str(), mFileEnding.c_str()); + + shaderData->setShaderStageFile(curStage, fileName); + + + FileStream* stream = new FileStream(); + if (!skipPrint) + { + if (!stream->open(fileName, Torque::FS::File::Write)) + { + AssertFatal(false, "Failed to open Shader Stream"); + return; + } + } + + switch (curStage) + { + case VERTEX_SHADER: + mOutput = new MultiLine; + mInstancingFormat.clear(); + _processVertFeatures(macros, macrosOnly); + if(!skipPrint || macrosOnly) _printVertShader(*stream); + delete stream; + ((ShaderConnector*)mComponents[C_CONNECTOR])->reset(); + LangElement::deleteElements(); + break; + case PIXEL_SHADER: + mOutput = new MultiLine; + _processPixFeatures(macros, macrosOnly); + if (!skipPrint || macrosOnly)_printPixShader(*stream); + delete stream; + LangElement::deleteElements(); + break; + case GEOMETRY_SHADER: + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + case ALL_STAGES: + break; + default: + break; + } + + } } void ShaderGen::_init() @@ -257,20 +356,20 @@ void ShaderGen::_processVertFeatures( Vector ¯os, bool macro { S32 index; const FeatureType &type = features.getAt( i, &index ); - void* args = features.getArguments(i); + FeatureParamsBase* args = features.getArguments(i); ShaderFeature* feature = nullptr; if(args) feature = FEATUREMGR->createFeature(type, args); else feature = FEATUREMGR->getByType( type ); - if ( feature ) + if ( feature && (feature->getShaderStages() & GFXShaderStage::VERTEX_SHADER)) { feature->setProcessIndex( index ); feature->processVertMacros( macros, mFeatureData ); - if ( macrosOnly ) + if (macrosOnly) continue; feature->setInstancingFormat( &mInstancingFormat ); @@ -306,13 +405,13 @@ void ShaderGen::_processPixFeatures( Vector ¯os, bool macros { S32 index; const FeatureType &type = features.getAt( i, &index ); - void* args = features.getArguments(i); + FeatureParamsBase* args = features.getArguments(i); ShaderFeature* feature = nullptr; if (args) feature = FEATUREMGR->createFeature(type, args); else feature = FEATUREMGR->getByType(type); - if ( feature ) + if ( feature && (feature->getShaderStages() & GFXShaderStage::PIXEL_SHADER)) { feature->setProcessIndex( index ); @@ -353,7 +452,7 @@ void ShaderGen::_printFeatureList(Stream &stream) { S32 index; const FeatureType &type = features.getAt( i, &index ); - void* args = features.getArguments(i); + FeatureParamsBase* args = features.getArguments(i); ShaderFeature* feature = nullptr; if (args) feature = FEATUREMGR->createFeature(type, args); @@ -374,7 +473,7 @@ void ShaderGen::_printFeatureList(Stream &stream) mPrinter->printLine(stream, ""); } -void ShaderGen::_printDependencies(Stream &stream) +void ShaderGen::_printDependencies(Stream &stream, GFXShaderStage stage) { Vector dependencies; @@ -412,7 +511,7 @@ void ShaderGen::_printDependencies(Stream &stream) mPrinter->printLine(stream, "// Dependencies:"); for( S32 i = 0; i < dependencies.size(); i++ ) - dependencies[i]->print( stream ); + dependencies[i]->print( stream, stage); mPrinter->printLine(stream, ""); } @@ -427,7 +526,7 @@ void ShaderGen::_printVertShader( Stream &stream ) { mPrinter->printShaderHeader(stream); - _printDependencies(stream); // TODO: Split into vert and pix dependencies? + _printDependencies(stream, GFXShaderStage::VERTEX_SHADER); // TODO: Split into vert and pix dependencies? _printFeatureList(stream); // print out structures @@ -449,7 +548,7 @@ void ShaderGen::_printPixShader( Stream &stream ) { mPrinter->printShaderHeader(stream); - _printDependencies(stream); // TODO: Split into vert and pix dependencies? + _printDependencies(stream, GFXShaderStage::PIXEL_SHADER); // TODO: Split into vert and pix dependencies? _printFeatureList(stream); mComponents[C_CONNECTOR]->print( stream, false ); @@ -466,60 +565,48 @@ void ShaderGen::_printPixShader( Stream &stream ) mPrinter->printPixelShaderCloser(stream); } -GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ) +GFXShader* ShaderGen::getShader(const MaterialFeatureData& featureData, const GFXVertexFormat* vertexFormat, const Vector* macros, const Vector& samplers) { - PROFILE_SCOPE( ShaderGen_GetShader ); + PROFILE_SCOPE(ShaderGen_GetShader); - const FeatureSet &features = featureData.codify(); + const FeatureSet& features = featureData.codify(); // Build a description string from the features // and vertex format combination ( and macros ). String shaderDescription = vertexFormat->getDescription() + features.getDescription(); - // 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. - // - shaderDescription.replace("\n", " "); - 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; + + String cacheKey = Torque::getStringHash64(shaderDescription); Vector shaderMacros; - shaderMacros.push_back( GFXShaderMacro( "TORQUE_SHADERGEN" ) ); - if ( macros ) - shaderMacros.merge( *macros ); - generateShader( featureData, vertFile, pixFile, &pixVersion, vertexFormat, cacheKey, shaderMacros ); + shaderMacros.push_back(GFXShaderMacro("TORQUE_SHADERGEN")); + if (macros) + shaderMacros.merge(*macros); + + ShaderDataMap::iterator dat = mProcShaderData.find(cacheKey); + if (dat != mProcShaderData.end()) + { + // should we loop vertex shader features to build mInstancingFormat before sending it down to see old hob? + return dat->value->getShader(shaderMacros); + } - GFXShader *shader = GFX->createShader(); - shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, vertFile); - shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, pixFile); + ShaderData* shaderData = new ShaderData; - if (!shader->init(pixVersion, shaderMacros, samplers, &mInstancingFormat)) + shaderData->setPixVersion(GFX->getPixelShaderVersion()); + + for (U32 samp = 0; samp < samplers.size(); samp++) { - delete shader; - return NULL; + shaderData->setSamplerName(samplers[samp], samp); } - mProcShaders[cacheKey] = shader; + generateShader(featureData, shaderData, vertexFormat, cacheKey, shaderMacros); + + shaderData->setInstancingFormat(&mInstancingFormat); - return shader; + mProcShaderData.insert(cacheKey, shaderData); + return shaderData->getShader(shaderMacros); } void ShaderGen::flushProceduralShaders() { - // The shaders are reference counted, so we - // just need to clear the map. - mProcShaders.clear(); + } diff --git a/Engine/source/shaderGen/shaderGen.h b/Engine/source/shaderGen/shaderGen.h index 8ff8ef0f61..f19306772a 100644 --- a/Engine/source/shaderGen/shaderGen.h +++ b/Engine/source/shaderGen/shaderGen.h @@ -46,6 +46,10 @@ #ifndef _MATERIALFEATUREDATA_H_ #include "materials/materialFeatureData.h" #endif +#ifndef _SHADERDATA_H_ +#include "materials/shaderData.h" +#endif // !_SHADERDATA_H_ + /// Base class used by shaderGen to be API agnostic. Subclasses implement the various methods /// in an API specific way. @@ -145,13 +149,11 @@ class ShaderGen /// the vertex and pixel shader files. pixVersion is also filled in by /// this function. /// @param assignNum used to assign a specific number as the filename - void generateShader( const MaterialFeatureData &featureData, - char *vertFile, - char *pixFile, - F32 *pixVersion, - const GFXVertexFormat *vertexFormat, + void generateShader( const MaterialFeatureData& featureData, + ShaderData* shaderData, + const GFXVertexFormat* vertexFormat, const char* cacheName, - Vector ¯os); + Vector& macros); // Returns a shader that implements the features listed by dat. GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ); @@ -191,10 +193,15 @@ class ShaderGen FeatureInitSignal mFeatureInitSignal; bool mRegisteredWithGFX; Torque::FS::FileSystemRef mMemFS; - - /// Map of cache string -> shaders - typedef Map ShaderMap; - ShaderMap mProcShaders; + + /// + /// Map of shaderdata, string should be built up of stage files + /// + typedef HashMap> ShaderDataMap; + ShaderDataMap mProcShaderData; + + typedef HashMap FileCacheSet; // we use a hashmap because it is quicker for finding. + FileCacheSet mFileCache; ShaderGen(); @@ -215,7 +222,7 @@ class ShaderGen /// print out the processed features to the file stream void _printFeatures( Stream &stream ); - void _printDependencies( Stream &stream ); + void _printDependencies( Stream &stream, GFXShaderStage stage); void _processPixFeatures( Vector ¯os, bool macrosOnly = false ); void _printPixShader( Stream &stream ); diff --git a/Engine/source/shaderGen/shaderOp.cpp b/Engine/source/shaderGen/shaderOp.cpp index b160615aa3..3becd8fed4 100644 --- a/Engine/source/shaderGen/shaderOp.cpp +++ b/Engine/source/shaderGen/shaderOp.cpp @@ -22,7 +22,7 @@ #include "core/strings/stringFunctions.h" #include - +#include "gfx/gfxDevice.h" #include "shaderOp.h" @@ -83,7 +83,7 @@ void EchoOp::print( Stream &stream ) //************************************************************************** // Index operation //************************************************************************** -IndexOp::IndexOp( Var* var, U32 index ) : Parent( NULL, NULL ) +IndexOp::IndexOp( Var* var, U32 index ) : Parent(var, NULL ) { mInput[0] = var; mIndex = index; @@ -180,18 +180,338 @@ void GenOp::print( Stream &stream ) } } -CastOp::CastOp(Var* in1, GFXShaderConstType type) : Parent(in1, NULL) +//---------------------------------------------------------------------------- +// TYPE OPERATION +//---------------------------------------------------------------------------- + +TypeOp::TypeOp(GFXShaderConstType type) : Parent(NULL, NULL) { - mInput[0] = in1; - mConstType = constTypeToString(type); + mType = type; +} + +TypeOp::~TypeOp() +{ +} + +//---------------------------------------------------------------------------- +// Print +//---------------------------------------------------------------------------- + +void TypeOp::print(Stream& stream) +{ + WRITESTR(LangElement::constTypeToString(mType)); +} + +//---------------------------------------------------------------------------- +// CAST OPERATION +//---------------------------------------------------------------------------- + +CastOp::CastOp(LangElement* srcVar, GFXShaderConstType type, const char* swizzleStr, const char* fillStr) : Parent(srcVar, NULL) +{ + mInput[0] = srcVar; + mTargetType = type; + parseStringList(swizzleStr, mSwizzle); + parseStringList(fillStr, mFillValues); } void CastOp::print(Stream& stream) { - Var* var = dynamic_cast(mInput[0]); + LangElement* srcElem = mInput[0]; + + Var* srcVar = nullptr; + const ShaderTypeInfo* srcInfo = nullptr; + + if (!resolveSourceType(srcElem, srcVar, srcInfo)) + { + // fallback: at least print something + srcElem->print(stream); + return; + } + + const ShaderTypeInfo* dstInfo = getTypeInfo(mTargetType); + + // no info? types match? nothing to do. + if (!srcInfo || !dstInfo) + { + srcElem->print(stream); // print something.... + return; + } + + const bool glsl = (GFX->getAdapterType() == OpenGL); + const char* dstName = glsl ? dstInfo->glslName : dstInfo->hlslName; + + U32 srcSize = srcInfo->cols; + U32 dstSize = dstInfo->cols; + + // scalar -> vector + if (srcSize == 1 && dstSize > 1) + { + WRITESTR(dstName); + WRITESTR("("); + srcElem->print(stream); + + for (U32 i = 1; i < dstSize; i++) + { + WRITESTR(", "); + WRITESTR(mFillValues[i].c_str()); + } + + WRITESTR(")"); + return; + } + + // vector -> scalar + if (srcSize > 1 && dstSize == 1) + { + srcElem->print(stream); + WRITESTR("."); + WRITESTR(mSwizzle[0].c_str()); + return; + } + + // vector -> vector narrowing + if (srcSize > dstSize) + { + WRITESTR(dstName); + WRITESTR("("); + srcElem->print(stream); + WRITESTR("."); + + for (U32 i = 0; i < dstSize; i++) + { + WRITESTR(mSwizzle[i].c_str()); + } + + WRITESTR(")"); + return; + } + + // vector -> vector widening + if (srcSize <= dstSize) + { + WRITESTR(dstName); + WRITESTR("("); + srcElem->print(stream); + if (mSwizzle.size() < srcSize) + { + WRITESTR("."); + + for (U32 i = 0; i < mSwizzle.size(); i++) + { + WRITESTR(mSwizzle[i].c_str()); + } + } + + for (U32 i = getMin((U32)mSwizzle.size(), srcSize); i < dstSize; i++) + { + WRITESTR(", "); + WRITESTR(mFillValues[i].c_str()); + } + + WRITESTR(")"); + return; + } + + // fallback + srcElem->print(stream); +} + +//---------------------------------------------------------------------------- +// MATRIX INITIALIZE OPERATION +//---------------------------------------------------------------------------- + +void MatrixInitializeOp::print(Stream& stream) +{ + Var* matVar = dynamic_cast(mInput[0]); + if (!matVar) + return; + + const ShaderTypeInfo* matInfo = getTypeInfo(stringToConstType((const char*)matVar->type)); + if (!matInfo || !matInfo->isMatrix()) + return; + + // full size of the mat. + const bool glsl = (GFX->getAdapterType() == OpenGL); + const U32 rows = matInfo->rows; + const U32 cols = matInfo->cols; + const U32 matSize = rows * cols; + + if (glsl) + { + WRITESTR(matInfo->glslName); + WRITESTR("(\r\n"); + } + else + { + WRITESTR("{\r\n"); + } + + U32 count = 0; + for (U32 elem = 0; elem < mInitialVals.size(); elem++) + { + LangElement* initElem = mInitialVals[elem]; + Var* initVar = nullptr; + const ShaderTypeInfo* initInfo = nullptr; + + if (!resolveSourceType(initElem, initVar, initInfo)) + { + return; + } + + if (dynamic_cast(initElem) || dynamic_cast(initElem)) // if we are a cast or index, write out. + { + count += initInfo->cols; + initElem->print(stream); + } + else if(dynamic_cast(initElem)) // we are a var (hopefully) + { + const U32 varSize = initInfo->cols; + const bool cast = cols != varSize; + + if (initVar->arraySize > 1) + { + for (U32 arr = 0; arr < initVar->arraySize; arr++) + { + initElem = new IndexOp(initVar, arr); + if (cast) + { + CastOp* castOp = new CastOp(initElem, (GFXShaderConstType)(GFXSCT_Float + (cols - 1))); + castOp->print(stream); + count += cols; + } + else + { + initElem->print(stream); + count += varSize; + } + + if (count < matSize) + { + WRITESTR(",\r\n"); + } + } + } + else + { + if (cast) + { + CastOp* castOp = new CastOp(initElem, (GFXShaderConstType)(GFXSCT_Float + (cols - 1))); + castOp->print(stream); + count += cols; + } + else + { + initElem->print(stream); + count += varSize; + } + + if (count < matSize) + { + WRITESTR(",\r\n"); + } + } + } + } + + // If not enough elements → pad with identity + while (count < matSize) + { + U32 row = count / cols; + U32 col = count % cols; + + if (row == col) + { + WRITESTR("1"); + } + else + { + WRITESTR("0"); + } + + count++; + + if (count < matSize) + { + WRITESTR(",\r\n"); + } + } + + + if (glsl) + { + WRITESTR(")\r\n"); + } + else + { + WRITESTR("}\r\n"); + } +} + +MatrixMultiplyOp::MatrixMultiplyOp(LangElement* left, LangElement* right) : Parent(left, right) +{ + mInput[0] = left; + mInput[1] = right; +} + +void MatrixMultiplyOp::print(Stream& stream) +{ + LangElement* leftElem = mInput[0]; + Var* leftVar = nullptr; + const ShaderTypeInfo* leftInfo = nullptr; + + if (!resolveSourceType(leftElem, leftVar, leftInfo)) + { + return; + } + + LangElement* rightElem = mInput[1]; + Var* rightVar = nullptr; + const ShaderTypeInfo* rightInfo = nullptr; + + if (!resolveSourceType(rightElem, rightVar, rightInfo)) + { + return; + } + + if (leftInfo->isMatrix() && rightInfo->isVector()) + { + if (rightInfo->cols != leftInfo->cols) + { + rightElem = new CastOp(rightVar, (GFXShaderConstType)(GFXSCT_Float + (leftInfo->cols - 1))); + } + } + + if (leftInfo->isVector() && rightInfo->isMatrix()) + { + if (rightInfo->cols != leftInfo->cols) + { + leftElem = new CastOp(leftVar, (GFXShaderConstType)(GFXSCT_Float + (rightInfo->cols - 1))); + } + } + + else if (leftInfo->isMatrix() && rightInfo->isMatrix()) + { + if (leftInfo->cols != rightInfo->rows) + Con::warnf("MatrixMultiplyOp: incompatible matrices: (%dx%d) × (%dx%d)", + leftInfo->rows, leftInfo->cols, + rightInfo->rows, rightInfo->cols); + } + + const bool glsl = (GFX->getAdapterType() == OpenGL); + + if (!glsl) + { + WRITESTR("mul("); + leftElem->print(stream); + WRITESTR(", "); + rightElem->print(stream); + WRITESTR(")"); + } + else + { + leftElem->print(stream); + WRITESTR(" * "); + rightElem->print(stream); + } - WRITESTR(mConstType); - WRITESTR("( "); - mInput[0]->print(stream); - WRITESTR(" )"); } diff --git a/Engine/source/shaderGen/shaderOp.h b/Engine/source/shaderGen/shaderOp.h index 6b8966250c..d7035d496e 100644 --- a/Engine/source/shaderGen/shaderOp.h +++ b/Engine/source/shaderGen/shaderOp.h @@ -52,10 +52,8 @@ ///************************************************************************** class ShaderOp : public LangElement { -protected: - LangElement * mInput[2]; - public: + LangElement* mInput[2]; ShaderOp( LangElement *in1, LangElement *in2 ); }; @@ -117,7 +115,6 @@ class IndexOp : public ShaderOp { typedef ShaderOp Parent; U32 mIndex; - public: IndexOp( Var* var, U32 index ); void print( Stream &stream ) override; @@ -161,14 +158,95 @@ class GenOp : public ShaderOp }; +//---------------------------------------------------------------------------- +/*! + Like the name suggests, prints out the type as a string, for working between + glsl and hlsl. +*/ +//---------------------------------------------------------------------------- +class TypeOp : public ShaderOp +{ + typedef ShaderOp Parent; + GFXShaderConstType mType; +public: + TypeOp(GFXShaderConstType type); + ~TypeOp(); + void print(Stream& stream) override; +}; + +//---------------------------------------------------------------------------- +/*! + Casting operation to cast a var from one type to another. +*/ +//---------------------------------------------------------------------------- class CastOp : public ShaderOp { typedef ShaderOp Parent; - const char* mConstType; + Vector mSwizzle; // "x", "y", "z", "w" + Vector mFillValues; // "0", "0", "0", "1" +public: + GFXShaderConstType mTargetType; + CastOp( LangElement* srcVar, + GFXShaderConstType type, + const char* swizzleStr = "x;y;z;w", + const char* fillStr = "0;0;0;1"); + + void print(Stream& stream) override; + + void parseStringList(const char* src, Vector& out) + { + out.clear(); + const char* p = src; + + while (*p) + { + const char* start = p; + while (*p && *p != ';') + p++; + + out.push_back(String(start, p - start)); + + if (*p == ';') + p++; + } + } +}; + +//---------------------------------------------------------------------------- +/*! + Matrix initialize operation, initializes a matrix with the input + vars as a vector. +*/ +//---------------------------------------------------------------------------- + +class MatrixInitializeOp : public ShaderOp +{ + typedef ShaderOp Parent; + Vector mInitialVals; public: - CastOp(Var* in1, GFXShaderConstType type); + MatrixInitializeOp(Var* matrixVar, const Vector& inputs) + : Parent(matrixVar, nullptr) + { + mInitialVals = inputs; + mInput[0] = matrixVar; + } + void print(Stream& stream) override; }; +//---------------------------------------------------------------------------- +/*! + Matrix multiplication operation. +*/ +//---------------------------------------------------------------------------- + +class MatrixMultiplyOp : public ShaderOp +{ + typedef ShaderOp Parent; +public: + MatrixMultiplyOp(LangElement* left, LangElement* right); + + void print(Stream& stream) override; +}; #endif // _SHADEROP_H_