This commit is contained in:
marauder2k7 2026-04-28 08:31:44 +01:00 committed by GitHub
commit c07234eb15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 2031 additions and 270 deletions

View file

@ -22,15 +22,68 @@
#include "platform/platform.h"
#include "core/stream/fileStream.h"
#include "platform/threads/threadPool.h"
//-----------------------------------------------------------------------------
// FileStream methods...
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
FileStream::FileStream()
static void writeBufferToFile(
Torque::FS::FileRef& file,
U32 buffHead,
U32 buffTail,
const U8* buffer)
{
if (!file || buffHead == FileStream::BUFFER_INVALID)
return;
// match FileStream::flush logic
if (buffHead != file->getPosition())
file->setPosition(buffHead, Torque::FS::File::Begin);
U32 blockHead;
FileStream::calcBlockHead(buffHead, &blockHead);
file->write((char*)buffer + (buffHead - blockHead), buffTail - buffHead + 1);
}
struct FileCloseWorkItem : public ThreadPool::WorkItem
{
Torque::FS::FileRef mFile;
public:
FileCloseWorkItem(Torque::FS::FileRef file)
: mFile(file)
{
}
protected:
void execute() override
{
if (!mFile)
return;
// When platforms free a file they
// remove the handle which causes the stall
// as they write metadata.
mFile->close();
}
};
void FileStream::dispatchAsyncClose()
{
if (!mFile)
return;
FileCloseWorkItem* job = new FileCloseWorkItem(mFile);
ThreadPool::GLOBAL().queueWorkItem(job);
}
//-----------------------------------------------------------------------------
FileStream::FileStream(AsyncMode flushMode)
{
mAsyncMode = flushMode;
dMemset(mBuffer, 0, sizeof(mBuffer));
// initialize the file stream
init();
@ -190,10 +243,13 @@ void FileStream::close()
if (mDirty)
flush();
// and close the file
mFile->close();
AssertFatal(mFile->getStatus() == Torque::FS::FileNode::Closed, "FileStream::close: close failed");
if (mAsyncMode == Background)
dispatchAsyncClose();
else
{
mFile->close();
AssertFatal(mFile->getStatus() == Torque::FS::FileNode::Closed, "FileStream::close: close failed");
}
mFile = NULL;
}

View file

@ -39,9 +39,17 @@ public:
BUFFER_INVALID = 0xffffffff // file offsets must all be less than this
};
enum AsyncMode
{
Blocking, // current behavior
Background // write-behind
};
typedef char Ch; //!< Character type. Only support char.
public:
FileStream(); // default constructor
AsyncMode mAsyncMode;
void dispatchAsyncClose();
FileStream(AsyncMode flushMode = Blocking); // default constructor
virtual ~FileStream(); // destructor
// This function will allocate a new FileStream and open it.
@ -64,7 +72,7 @@ public:
//rjson compatibility
bool Flush() { return flush(); }
FileStream* clone() const override;
static void calcBlockHead(const U32 i_position, U32* o_blockHead);
protected:
// more mandatory methods from Stream base class...
bool _read(const U32 i_numBytes, void *o_pBuffer) override;
@ -73,7 +81,7 @@ protected:
void init();
bool fillBuffer(const U32 i_startPosition);
void clearBuffer();
static void calcBlockHead(const U32 i_position, U32 *o_blockHead);
static void calcBlockBounds(const U32 i_position, U32 *o_blockHead, U32 *o_blockTail);
void setStatus();

View file

@ -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

View file

@ -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_

View file

@ -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(FileStream::AsyncMode::Background);
if (out.open(cachePath, Torque::FS::File::Write))
{
out.write(code->GetBufferSize(), code->GetBufferPointer());
}
}
}
if(code != NULL)
{
switch (shaderStage)

View file

@ -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<GFXShaderMacro>& ShaderData::_getMacros()
return mShaderMacros;
}
GFXShader* ShaderData::getShader( const Vector<GFXShaderMacro> &macros )
GFXShader* ShaderData::getShader( const Vector<GFXShaderMacro> &macros)
{
PROFILE_SCOPE( ShaderData_GetShader );
@ -217,6 +219,8 @@ GFXShader* ShaderData::getShader( const Vector<GFXShaderMacro> &macros )
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<GFXShaderMacro> &macros )
// 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<GFXShaderMacro> &macros )
return shader;
}
GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros)
{
F32 pixver = mPixVersion;
if ( mUseDevicePixVersion )
@ -257,30 +261,32 @@ GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
{
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;

View file

@ -80,10 +80,8 @@ protected:
/// them if the content has changed.
const Vector<GFXShaderMacro>& _getMacros();
/// Helper for converting an array of macros
/// into a formatted string.
void _stringizeMacros(const Vector<GFXShaderMacro>& macros,
String* outString);
// the instancing format.
GFXVertexFormat* mInstancingFormat;
/// Creates a new shader returning NULL on error.
GFXShader* _createShader(const Vector<GFXShaderMacro>& macros);
@ -106,8 +104,11 @@ public:
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 @@ public:
/// 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; }

View file

@ -98,6 +98,8 @@ public:
}
}
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
String getName() override { return "Accu Scale"; }
};
@ -118,6 +120,8 @@ public:
}
}
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
String getName() override { return "Accu Direction"; }
};
@ -138,6 +142,8 @@ public:
}
}
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
String getName() override { return "Accu Strength"; }
};
@ -158,6 +164,8 @@ public:
}
}
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
String getName() override { return "Accu Coverage"; }
};
@ -179,7 +187,9 @@ public:
}
}
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
String getName() override { return "Accu Specular"; }
};
#endif
#endif

View file

@ -37,5 +37,7 @@ public:
void processPix(Vector<ShaderComponent*>& componentList,
const MaterialFeatureData& fd) override;
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
String getName() override { return "Debug Viz"; }
};

View file

@ -180,6 +180,8 @@ public:
void processPix( Vector<ShaderComponent*> &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<ShaderComponent*> &componentList,
const MaterialFeatureData &fd ) override;
U32 getShaderStages() override { return (GFXShaderStage::PIXEL_SHADER); }
Material::BlendOp getBlendOp() override{ return Material::None; }
@ -540,6 +543,8 @@ public:
void processPix( Vector<ShaderComponent*> &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 @@ public:
void processPix( Vector<ShaderComponent*> &componentList,
const MaterialFeatureData &fd ) override;
U32 getShaderStages() override { return ( GFXShaderStage::PIXEL_SHADER); }
String getName() override
{
return "Glow Mask";
@ -582,6 +590,8 @@ public:
void processPix( Vector<ShaderComponent*> &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 @@ public:
void processVert( Vector<ShaderComponent*> &componentList,
const MaterialFeatureData &fd ) override;
U32 getShaderStages() override { return (GFXShaderStage::VERTEX_SHADER); }
String getName() override
{
return "Particle Normal Generation Feature";
@ -672,6 +684,8 @@ public:
void processVert( Vector<ShaderComponent*> &componentList,
const MaterialFeatureData &fd ) override;
U32 getShaderStages() override { return (GFXShaderStage::VERTEX_SHADER); }
String getName() override { return "Hardware Skinning"; }
};

View file

@ -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(&register_node_features);
}
MODULE_END;
Var* ShaderFeatureNode::getObjTrans(Vector<ShaderComponent*>& componentList,
bool useInstancing,
MultiLine* meta)
{
Var* objTrans = (Var*)LangElement::find("objTrans");
if (objTrans)
return objTrans;
if (useInstancing)
{
ShaderConnector* vertStruct = dynamic_cast<ShaderConnector*>(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<LangElement*> 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<ShaderComponent*>& 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<ShaderComponent*>& 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<ShaderComponent*>& 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<Var*>(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<Var*>(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<ShaderComponent*>& 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<ShaderConnector*>(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<ShaderComponent*>& 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<ShaderComponent*>& 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<ShaderConnector*>(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<ShaderComponent*>& componentList, const MaterialFeatureData& fd)
{
const bool glsl = (GFX->getAdapterType() == OpenGL);
if (!glsl)
{
// grab connector position
ShaderConnector* connectComp = dynamic_cast<ShaderConnector*>(componentList[C_CONNECTOR]);
Var* outPosition = connectComp->getElement(RT_SVPOSITION);
outPosition->setName("vpos");
outPosition->setStructName("IN");
}
}
//--------------------------------------------------------
// Setup the default texcoord
//--------------------------------------------------------
void DefaultTexcoordFeature::processVert(Vector<ShaderComponent*>& componentList, const MaterialFeatureData& fd)
{
MultiLine* meta = new MultiLine;
getOutTexCoord("texCoord",
GFXSCT_Float2,
fd.features[MFT_TexAnim],
meta,
componentList);
output = meta;
}
void DefaultTexcoordFeature::processPix(Vector<ShaderComponent*>& 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<ShaderComponent*>& 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<ShaderComponent*>& 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;
}

View file

@ -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);
/// <summary>
/// This enum is so we can map to nodes in script.
/// </summary>
enum ShaderNodeFeature_enum
{
eSNF_VertexPosition,
eSNF_DefaultTexCoord,
eSNF_TextureFeature,
eSNF_NormalMapFeature,
};
DefineEnumType(ShaderNodeFeature_enum);
class ShaderFeatureNode : public ShaderFeature
{
public:
///
Var* getObjTrans( Vector<ShaderComponent*>& componentList,
bool useInstancing,
MultiLine* meta);
Var* getModelView(Vector<ShaderComponent*>& componentList,
bool useInstancing,
MultiLine* meta);
Var* getWorldView(Vector<ShaderComponent*>& componentList, bool useInstancing, MultiLine* meta);
void setupTextureSample(const String& samplerName,
GFXShaderConstType samplerType,
Vector<ShaderComponent*>& componentList,
MultiLine* meta,
LangElement* texCoord,
LangElement* compareValue,
bool useGather);
Var* getOutTexCoord( const char* name,
GFXShaderConstType type,
bool useTexAnim,
MultiLine* meta,
Vector<ShaderComponent*>& componentList);
LangElement* setupTexSpaceMat(Vector<ShaderComponent*>& 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<ShaderComponent*>& componentList,
const MaterialFeatureData& fd) override;
void processPix(Vector<ShaderComponent*>& componentList,
const MaterialFeatureData& fd) override;
String getName() override
{
return "NodeVertexPositionFeature";
}
};
class DefaultTexcoordFeature : public ShaderFeatureNode
{
void processVert(Vector<ShaderComponent*>& componentList,
const MaterialFeatureData& fd) override;
void processPix(Vector<ShaderComponent*>& componentList,
const MaterialFeatureData& fd) override;
String getName() override
{
return "DefaultTexCoord";
}
};
//--------------------------------------------------------
// TEXTURE SAMPLER FEATURE
//--------------------------------------------------------
/// <summary>
/// Parameters for the TextureFeature
/// </summary>
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"; }
/// <summary>
/// Texture features output variable is samplerName + "_col"
/// </summary>
/// <returns>The output variable for a texture feature.</returns>
const char* getOutputVar() const override { return samplerName + "_col"; }
static void persistedFields(Vector<FeatureParamField>& fields)
{
addParam(fields, "sampler", Offset(samplerName, TextureFeatureParams), TypeString);
addParam(fields, "samplerType", Offset(samplerType, TextureFeatureParams), TypeGFXShaderConstType);
addParam(fields, "samplerState", Offset(samplerState, TextureFeatureParams), TYPEID<GFXSamplerStateData>());
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<ShaderComponent*>& 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<TextureFeatureParams*>(args);
return new TextureFeature(params);
}
String getName() override
{
return "TextureSampler_" + params->samplerName + "_" + params->uvName;
}
};
//--------------------------------------------------------
// NORMAL MAPPING FEATURE
//--------------------------------------------------------
/// <summary>
/// Parameters for the NormalMapFeature
/// </summary>
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"; }
/// <summary>
/// Normal map feature writes the result into the input name
/// </summary>
/// <returns>The output variable for a normal map feature.</returns>
const char* getOutputVar() const override { return inputName; }
static void persistedFields(Vector<FeatureParamField>& 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<ShaderComponent*>& 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<NormalMapFeatureParams*>(args));
}
String getName() override
{
return "NormalMap_" + params->inputName;
}
};

View file

@ -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);
}

View file

@ -126,9 +126,11 @@ protected:
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<GFXShaderMacro> &macros );

View file

@ -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 NULL;
}
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<String>& 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)

View file

@ -36,7 +36,49 @@
class FeatureType;
class ShaderFeature;
typedef Delegate<ShaderFeature* (void*)> CreateShaderFeatureDelegate;
struct FeatureParamField
{
StringTableEntry paramName;
S32 offset;
S32 type;
U32 arraySize;
};
inline void addParam(Vector<FeatureParamField>& list,
const char* name,
S32 offset,
S32 consoleType,
U32 arraySize = 1)
{
FeatureParamField f = { name, offset, consoleType, arraySize };
list.push_back(f);
}
/// <summary>
/// Base class for all shader feature parameter structs.
/// </summary>
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<FeatureParamsBase* ()> 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<ShaderFeature* (FeatureParamsBase*)> CreateShaderFeatureDelegate;
/// <summary>
/// Used by the feature manager.
@ -60,9 +102,11 @@ protected:
bool mNeedsSort;
typedef Vector<FeatureInfo> FeatureInfoVector;
FeatureInfoVector mFeatures;
typedef Vector<FeatureParamInfo> FeatureParamInfoVector;
FeatureParamInfoVector mParamInfos;
static S32 QSORT_CALLBACK _featureInfoCompare( const FeatureInfo *a, const FeatureInfo *b );
public:
@ -87,7 +131,13 @@ public:
/// <returns>An instance of the shader feature using its static createFunction taking in the
/// argument struct.
/// </returns>
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<String>& args) const;
/// <summary>
/// Allows other systems to add features. index is
@ -114,4 +164,20 @@ public:
// Helper for accessing the feature manager singleton.
#define FEATUREMGR ManagedSingleton<FeatureMgr>::instance()
#define REGISTER_FEATURE_PARAMS(TYPE, STRUCT_TYPE) \
struct STRUCT_TYPE##_AutoRegister \
{ \
STRUCT_TYPE##_AutoRegister() \
{ \
Vector<FeatureParamField> fieldList; \
STRUCT_TYPE::persistedFields(fieldList); \
FEATUREMGR->registerFeatureParams( \
TYPE, \
fieldList.address(), \
fieldList.size(), \
Delegate<FeatureParamsBase*()>([]() -> FeatureParamsBase* { return new STRUCT_TYPE(); })\
); \
} \
} STRUCT_TYPE##_AutoRegisterInstance;
#endif // FEATUREMGR

View file

@ -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)
{

View file

@ -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 @@ protected:
{
const FeatureType* type;
S32 index;
void* argStruct;
FeatureParamsBase* argStruct;
};
/// The list of featurs.
@ -94,7 +97,7 @@ public:
/// 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 @@ public:
/// <param name="type">The shader feature type.</param>
/// <param name="index">The inedx the shader feature will be sorted in the set.</param>
/// <param name="argStruct">A struct representing arguments for a shader feature.</param>
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 );

View file

@ -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*> 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<String, GFXShaderConstType> glslToType;
static HashMap<String, GFXShaderConstType> hlslToType;
void LangElement::buildTypeMaps()
{
for (auto& info : ShaderTypes)
{
switch (constType)
{
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;
}
glslToType[info.glslName] = info.type;
hlslToType[info.hlslName] = info.type;
}
else // Assume DirectX/HLSL
}
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)
{
switch (constType)
if (!info->isSampler())
{
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 sampler but input const type is not a sampler");
return "unknown";
}
}
return "";
if (matrix)
{
if (!info->isMatrix())
{
Con::warnf("LangElement::Requested matrix but input const type is not a matrix");
return "unknown";
}
}
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<Var*>(elem))
{
outVar = v;
outInfo = getTypeInfo(stringToConstType((const char*)v->type));
return outInfo != nullptr;
}
// INDEX OP: arrVar[index]
if (IndexOp* idx = dynamic_cast<IndexOp*>(elem))
{
Var* arr = dynamic_cast<Var*>(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<CastOp*>(elem))
{
Var* castVar = dynamic_cast<Var*>(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
//--------------------------------------------------------------------------

View file

@ -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
};
/// <summary>
/// ShaderTypeInfo type helper for casts and other ops
/// </summary>
/// <param name="type">GFXShaderConstType enum type</param>
/// <param name="glslName">const char* type name for glsl</param>
/// <param name="hlslName">const char* type name for hlsl</param>
/// <param name="category">ShaderTypeCategory enum for category eg STC_Scalar</param>
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<LangElement*> 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 @@ public:
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_

View file

@ -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<const ShaderIncludeDependency*>( &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());
}
}

View file

@ -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 @@ public:
}
/// 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 @@ public:
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_
#endif // _SHADER_DEPENDENCY_H_

View file

@ -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;
}

View file

@ -237,6 +237,8 @@ public:
/// Allows the feature to add macros to vertex shader compiles.
virtual void processVertMacros( Vector<GFXShaderMacro> &macros, 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.

View file

@ -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<String> 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<GFXShaderMacro> &macros)
@ -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() );
dStrcpy( vertFile, vertShaderName, 256 );
dStrcpy( pixFile, pixShaderName, 256 );
// this needs to change - need to optimize down to ps v.1.1
*pixVersion = GFX->getPixelShaderVersion();
if ( !Con::getBoolVariable( "ShaderGen::GenNewShaders", true ) )
// loop through and see which stages this featureset is expecting to make.
for (U32 i = 0; i < features.getCount(); i++)
{
// 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 );
const FeatureType& type = features.getAt(i);
ShaderFeature* feat = FEATUREMGR->getByType(type);
stages |= feat->getShaderStages();
return;
}
// create vertex shader
//------------------------
FileStream* s = new FileStream();
if(!s->open(vertShaderName, Torque::FS::File::Write ))
for (U32 s = 0; s < (sizeof(gStageOrder) / sizeof(U32)); s++)
{
AssertFatal(false, "Failed to open Shader Stream" );
return;
U32 stage = gStageOrder[s];
// skip unused stages
if (!(stages & stage))
continue;
bool macrosOnly = !Con::getBoolVariable("ShaderGen::GenNewShaders", true);
bool skipPrint = false;
GFXShaderStage curStage = (GFXShaderStage)stage;
char fileName[256];
const char* postfix = _getStagePostfix(curStage);
String stageName;
if (curStage & GFXShaderStage::VERTEX_SHADER)
stageName += vertexFormat->getDescription();
// 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();
}
}
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;
}
skipPrint = true;
}
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;
}
}
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" );
delete s;
return;
}
mOutput = new MultiLine;
_processPixFeatures(macros);
_printPixShader( *s );
delete s;
LangElement::deleteElements();
}
void ShaderGen::_init()
@ -257,20 +356,20 @@ void ShaderGen::_processVertFeatures( Vector<GFXShaderMacro> &macros, bool macro
{
S32 index;
const FeatureType &type = features.getAt( i, &index );
void* args = features.getArguments(i);
FeatureParamsBase* args = features.getArguments(i);
ShaderFeature* feature = NULL;
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<GFXShaderMacro> &macros, bool macros
{
S32 index;
const FeatureType &type = features.getAt( i, &index );
void* args = features.getArguments(i);
FeatureParamsBase* args = features.getArguments(i);
ShaderFeature* feature = NULL;
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 = NULL;
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<const ShaderDependency *> 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<GFXShaderMacro> *macros, const Vector<String> &samplers )
GFXShader* ShaderGen::getShader(const MaterialFeatureData& featureData, const GFXVertexFormat* vertexFormat, const Vector<GFXShaderMacro>* macros, const Vector<String>& 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<GFXShaderMacro> 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);
GFXShader *shader = GFX->createShader();
shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, vertFile);
shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, pixFile);
if (!shader->init(pixVersion, shaderMacros, samplers, &mInstancingFormat))
ShaderDataMap::iterator dat = mProcShaderData.find(cacheKey);
if (dat != mProcShaderData.end())
{
delete shader;
return NULL;
// should we loop vertex shader features to build mInstancingFormat before sending it down to see old hob?
return dat->value->getShader(shaderMacros);
}
mProcShaders[cacheKey] = shader;
ShaderData* shaderData = new ShaderData;
return shader;
shaderData->setPixVersion(GFX->getPixelShaderVersion());
for (U32 samp = 0; samp < samplers.size(); samp++)
{
shaderData->setSamplerName(samplers[samp], samp);
}
generateShader(featureData, shaderData, vertexFormat, cacheKey, shaderMacros);
shaderData->setInstancingFormat(&mInstancingFormat);
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();
}
}

View file

@ -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 @@ public:
/// 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<GFXShaderMacro> &macros);
Vector<GFXShaderMacro>& macros);
// Returns a shader that implements the features listed by dat.
GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros, const Vector<String> &samplers );
@ -191,10 +193,15 @@ protected:
FeatureInitSignal mFeatureInitSignal;
bool mRegisteredWithGFX;
Torque::FS::FileSystemRef mMemFS;
/// Map of cache string -> shaders
typedef Map<String, GFXShaderRef> ShaderMap;
ShaderMap mProcShaders;
/// <summary>
/// Map of shaderdata, string should be built up of stage files
/// </summary>
typedef HashMap<String, SimObjectPtr<ShaderData>> ShaderDataMap;
ShaderDataMap mProcShaderData;
typedef HashMap<String, bool> FileCacheSet; // we use a hashmap because it is quicker for finding.
FileCacheSet mFileCache;
ShaderGen();
@ -215,7 +222,7 @@ protected:
/// 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<GFXShaderMacro> &macros, bool macrosOnly = false );
void _printPixShader( Stream &stream );

View file

@ -22,7 +22,7 @@
#include "core/strings/stringFunctions.h"
#include <stdarg.h>
#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<Var*>(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<Var*>(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<IndexOp*>(initElem) || dynamic_cast<CastOp*>(initElem)) // if we are a cast or index, write out.
{
count += initInfo->cols;
initElem->print(stream);
}
else if(dynamic_cast<Var*>(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(" )");
}

View file

@ -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 @@ public:
};
//----------------------------------------------------------------------------
/*!
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<String> mSwizzle; // "x", "y", "z", "w"
Vector<String> mFillValues; // "0", "0", "0", "1"
public:
CastOp(Var* in1, GFXShaderConstType type);
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<String>& 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<LangElement*> mInitialVals;
public:
MatrixInitializeOp(Var* matrixVar, const Vector<LangElement*>& 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_

View file

@ -1092,7 +1092,7 @@ TSShape* assimpLoadShape(const Torque::Path &path)
// Cache the model to a DTS file for faster loading next time.
cachedPath.setExtension("cached.dts");
// Cache the model to a DTS file for faster loading next time.
FileStream dtsStream;
FileStream dtsStream(FileStream::AsyncMode::Background);
if (dtsStream.open(cachedPath.getFullPath(), Torque::FS::File::Write))
{
Con::printf("Writing cached shape to %s", cachedPath.getFullPath().c_str());

View file

@ -803,7 +803,7 @@ TSShape* loadColladaShape(const Torque::Path &path)
{
// Cache the Collada model to a DTS file for faster loading next time.
cachedPath.setExtension("cached.dts");
FileStream dtsStream;
FileStream dtsStream(FileStream::AsyncMode::Background);
if (dtsStream.open(cachedPath.getFullPath(), Torque::FS::File::Write))
{
Torque::FS::FileSystemRef ref = Torque::FS::GetFileSystem(daePath);