shadergen op classes

Added CastOp logic, prints out a cast operation
MatrixInitialization operation, takes input langelements and initializes a matrix
Other functions added to langelement
This commit is contained in:
marauder2k7 2025-11-28 18:05:03 +00:00
parent dfbea4540d
commit cff7a8060d
6 changed files with 514 additions and 104 deletions

View file

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

View file

@ -30,101 +30,107 @@
//**************************************************************************
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)
{
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<String, GFXShaderConstType> glslToType;
static HashMap<String, GFXShaderConstType> 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

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; }
};
//**************************************************************************
/*!
@ -54,13 +94,17 @@
//**************************************************************************
struct LangElement
{
static void buildTypeMaps();
static Vector<LangElement*> 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_

View file

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

View file

@ -22,10 +22,44 @@
#include "core/strings/stringFunctions.h"
#include <stdarg.h>
#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<Var*>(elem))
{
outVar = v;
outInfo = LangElement::getTypeInfo(LangElement::stringToConstType((const char*)v->type));
return outInfo != nullptr;
}
// INDEX OP: arrVar[index]
if (IndexOp* idx = dynamic_cast<IndexOp*>(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<Var*>(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<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* writeOut = NULL;
Var* curVar = dynamic_cast<Var*>(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");
}
}

View file

@ -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<String> mSwizzle; // "x", "y", "z", "w"
Vector<String> 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<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.
*/
//----------------------------------------------------------------------------
#endif // _SHADEROP_H_