diff --git a/Engine/source/shaderGen/featureMgr.h b/Engine/source/shaderGen/featureMgr.h index 51daf6667..239b92828 100644 --- a/Engine/source/shaderGen/featureMgr.h +++ b/Engine/source/shaderGen/featureMgr.h @@ -62,6 +62,7 @@ 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"; } }; diff --git a/Engine/source/shaderGen/langElement.cpp b/Engine/source/shaderGen/langElement.cpp index ce74e303e..e0e197c9b 100644 --- a/Engine/source/shaderGen/langElement.cpp +++ b/Engine/source/shaderGen/langElement.cpp @@ -30,101 +30,107 @@ //************************************************************************** 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) - { - 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; - } - } - else // Assume DirectX/HLSL - { - switch (constType) - { - 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; - } - } + // ---- 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 }, - return ""; + // ---- 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) + { + glslToType[info.glslName] = info.type; + hlslToType[info.hlslName] = info.type; + } } -const char* LangElement::samplerTypeToString(GFXShaderConstType constType) +const ShaderTypeInfo* LangElement::getTypeInfo(GFXShaderConstType type) { - if (constType < GFXSCT_Sampler) - return ""; - - // Determine shader language based on GFXAdapterAPI - if (GFX->getAdapterType() == OpenGL) - { - switch (constType) - { - case GFXSCT_Sampler: return "sampler2D"; break; - case GFXSCT_SamplerCube: return "samplerCube"; break; - case GFXSCT_SamplerTextureArray: return "sampler2DArray"; break; - case GFXSCT_SamplerCubeArray: return "samplerCubeArray"; break; - default: return "unknown"; break; - } - } - else // Assume DirectX/HLSL - { - switch (constType) - { - case GFXSCT_Sampler: return "Texture2D"; break; - case GFXSCT_SamplerCube: return "TextureCube"; break; - case GFXSCT_SamplerTextureArray: return "Texture2DArray"; break; - case GFXSCT_SamplerCubeArray: return "TextureCubeArray"; break; - default: return "unknown"; break; - } - } - - return ""; + 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()) + { + Con::warnf("LangElement::Requested sampler but input const type is not a sampler"); + return "unknown"; + } + } + + 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; +} //-------------------------------------------------------------------------- // Constructor diff --git a/Engine/source/shaderGen/langElement.h b/Engine/source/shaderGen/langElement.h index 89897f5a8..48c6afcb2 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; } +}; //************************************************************************** /*! @@ -54,13 +94,17 @@ //************************************************************************** struct LangElement { + static void buildTypeMaps(); static Vector elementList; static LangElement * find( const char *name ); static void deleteElements(); + static const ShaderTypeInfo* getTypeInfo(GFXShaderConstType type); U8 name[32]; - static const char* constTypeToString(GFXShaderConstType constType); - static const char* samplerTypeToString(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 ){}; @@ -186,6 +230,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_ + + diff --git a/Engine/source/shaderGen/shaderGen.cpp b/Engine/source/shaderGen/shaderGen.cpp index 1f30654c6..16db02946 100644 --- a/Engine/source/shaderGen/shaderGen.cpp +++ b/Engine/source/shaderGen/shaderGen.cpp @@ -133,6 +133,9 @@ void ShaderGen::initShaderGen() // Delete the auto-generated conditioner include file. Torque::FS::Remove( "shadergen:/" + ConditionerFeature::ConditionerIncludeFileName ); + + // build our type maps. + LangElement::buildTypeMaps(); } void ShaderGen::generateShader( const MaterialFeatureData &featureData, diff --git a/Engine/source/shaderGen/shaderOp.cpp b/Engine/source/shaderGen/shaderOp.cpp index b160615aa..80e467080 100644 --- a/Engine/source/shaderGen/shaderOp.cpp +++ b/Engine/source/shaderGen/shaderOp.cpp @@ -22,10 +22,44 @@ #include "core/strings/stringFunctions.h" #include - +#include "gfx/gfxDevice.h" #include "shaderOp.h" +bool resolveSourceType(LangElement* elem, Var*& outVar, const ShaderTypeInfo*& outInfo) +{ + outVar = nullptr; + outInfo = nullptr; + + // DIRECT VAR + if (Var* v = dynamic_cast(elem)) + { + outVar = v; + outInfo = LangElement::getTypeInfo(LangElement::stringToConstType((const char*)v->type)); + return outInfo != nullptr; + } + + // INDEX OP: arrVar[index] + if (IndexOp* idx = dynamic_cast(elem)) + { + Var* arr = idx->arrVar; + if (!arr) + return false; + + const ShaderTypeInfo* arrInfo = LangElement::getTypeInfo(LangElement::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; + } + + return false; +} + + //************************************************************************** // Shader Operations //************************************************************************** @@ -85,6 +119,7 @@ void EchoOp::print( Stream &stream ) //************************************************************************** IndexOp::IndexOp( Var* var, U32 index ) : Parent( NULL, NULL ) { + arrVar = var; // need to keep hold of it for casts. mInput[0] = var; mIndex = index; } @@ -180,18 +215,260 @@ 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]; - WRITESTR(mConstType); - WRITESTR("( "); - mInput[0]->print(stream); - WRITESTR(" )"); + 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 || (srcInfo->type == dstInfo->type)) + { + srcElem->print(stream); // print something.... + return; + } + + 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* writeOut = NULL; + Var* curVar = dynamic_cast(mInitialVals[elem]); + if (curVar) // is a var + { + const ShaderTypeInfo* curInfo = getTypeInfo(stringToConstType((const char*)curVar->type)); + if (!curInfo) // no info, cant do it cleanly. + return; + + const U32 curSize = curInfo->cols; + + // if we are an array + if (curVar->arraySize > 1) + { + for (U32 arr = 0; arr < curVar->arraySize; arr++) + { + writeOut = new IndexOp(curVar, arr); + if (curSize != cols) + { + CastOp* cast = new CastOp(writeOut, (GFXShaderConstType)(GFXSCT_Float + (cols - 1))); + cast->print(stream); + count += cols; + } + else + { + writeOut->print(stream); + count += curSize; + } + + if (count < matSize) + { + WRITESTR(",\r\n"); + } + } + } + else + { + if (curSize != cols) + { + CastOp* cast = new CastOp(curVar, (GFXShaderConstType)(GFXSCT_Float + (cols - 1))); + cast->print(stream); + count += cols; + } + else + { + curVar->print(stream); + count += curSize; + } + + if (count < matSize) + { + WRITESTR(",\r\n"); + } + } + } + else + { + // Non-var LangElement, assume it produces correct vector + mInitialVals[elem]->print(stream); + count += cols; + + if (count < matSize) + WRITESTR(",\r\n"); + } + } + + // If not enough elements → pad with zeros + while (count < matSize) + { + WRITESTR("0"); + count++; + + if (count < matSize) + { + WRITESTR(",\r\n"); + } + } + + + if (glsl) + { + WRITESTR(")\r\n"); + } + else + { + WRITESTR("}\r\n"); + } +} + diff --git a/Engine/source/shaderGen/shaderOp.h b/Engine/source/shaderGen/shaderOp.h index 6b8966250..8a42168dd 100644 --- a/Engine/source/shaderGen/shaderOp.h +++ b/Engine/source/shaderGen/shaderOp.h @@ -45,7 +45,7 @@ */ //************************************************************************** - +bool resolveSourceType(LangElement* elem, Var*& outVar, const ShaderTypeInfo*& outInfo); ///************************************************************************** /// Shader operation base class @@ -117,8 +117,8 @@ class IndexOp : public ShaderOp { typedef ShaderOp Parent; U32 mIndex; - public: + Var* arrVar; IndexOp( Var* var, U32 index ); void print( Stream &stream ) override; }; @@ -161,14 +161,86 @@ 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; + GFXShaderConstType mTargetType; + Vector mSwizzle; // "x", "y", "z", "w" + Vector mFillValues; // "0", "0", "0", "1" public: - CastOp(Var* in1, GFXShaderConstType type); + 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: + MatrixInitializeOp(Var* matrixVar, const Vector& inputs) + : Parent(matrixVar, nullptr) + { + mInitialVals = inputs; + mInput[0] = matrixVar; + } + void print(Stream& stream) override; }; +//---------------------------------------------------------------------------- +/*! + Matrix multiplication operation. +*/ +//---------------------------------------------------------------------------- #endif // _SHADEROP_H_