Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify NaN propagation for multiplication #779

Merged
merged 2 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libprojectM/MilkdropPreset/MilkdropShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ void MilkdropShader::TranspileHLSLShader(const PresetState& presetState, std::st
// Then generate GLSL from the resulting parser tree
if (!generator.Generate(&tree, M4::GLSLGenerator::Target_FragmentShader,
MilkdropStaticShaders::Get()->GetGlslGeneratorVersion(),
"PS"))
"PS", M4::GLSLGenerator::Options(M4::GLSLGenerator::Flag_AlternateNanPropagation)))
{
throw Renderer::ShaderException("Error translating HLSL " + shaderTypeString + " shader: GLSL generating failed.\nSource:\n" + sourcePreprocessed);
}
Expand Down
40 changes: 35 additions & 5 deletions vendor/hlslparser/src/GLSLGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ GLSLGenerator::GLSLGenerator() :
m_modfFunction[0] = 0;
m_acosFunction[0] = 0;
m_asinFunction[0] = 0;
m_altMultFunction[0] = 0;
m_outputPosition = false;
m_outputTargets = 0;
}
Expand Down Expand Up @@ -170,6 +171,7 @@ bool GLSLGenerator::Generate(HLSLTree* tree, Target target, Version version, con
ChooseUniqueName( "modf", m_modfFunction, sizeof( m_modfFunction ) );
ChooseUniqueName( "acos", m_acosFunction, sizeof( m_acosFunction ) );
ChooseUniqueName( "asin", m_asinFunction, sizeof( m_asinFunction ) );
ChooseUniqueName( "mult", m_altMultFunction, sizeof( m_altMultFunction ) );

for (int i = 0; i < s_numReservedWords; ++i)
{
Expand Down Expand Up @@ -422,6 +424,19 @@ bool GLSLGenerator::Generate(HLSLTree* tree, Target target, Version version, con
m_writer.WriteLine(0, "vec4 %s(vec4 x) { vec4 ret; ret.x = %s(x.x); ret.y = %s(x.y); ret.z = %s(x.z); ret.w = %s(x.w); return ret; }", m_asinFunction, m_asinFunction, m_asinFunction, m_asinFunction, m_asinFunction);
}

if (m_options.flags & Flag_AlternateNanPropagation) {
/* Implement alternate functions that propagate NaNs like shader model 3 and DX9. */
m_writer.WriteLine(0, "float %s(float x, float y) { if (x == 0.0 || y == 0.0) { return 0.0; } else { return (x * y); } }", m_altMultFunction);
m_writer.WriteLine(0, "vec2 %s(vec2 x, vec2 y) { return vec2(%s(x.x, y.x), %s(x.y, y.y)); }", m_altMultFunction, m_altMultFunction, m_altMultFunction);
m_writer.WriteLine(0, "vec3 %s(vec3 x, vec3 y) { return vec3(%s(x.x, y.x), %s(x.y, y.y), %s(x.z, y.z)); }", m_altMultFunction, m_altMultFunction, m_altMultFunction, m_altMultFunction);
m_writer.WriteLine(0, "vec4 %s(vec4 x, vec4 y) { return vec4(%s(x.x, y.x), %s(x.y, y.y), %s(x.z, y.z), %s(x.w, y.w)); }", m_altMultFunction, m_altMultFunction, m_altMultFunction, m_altMultFunction, m_altMultFunction);
// For matrix multiplication just perform the multiplication
m_writer.WriteLine(0, "mat2 %s(mat2 x, mat2 y) { return x * y; }", m_altMultFunction);
m_writer.WriteLine(0, "mat3 %s(mat3 x, mat3 y) { return x * y; }", m_altMultFunction);
m_writer.WriteLine(0, "mat4 %s(mat4 x, mat4 y) { return x * y; }", m_altMultFunction);

}

m_writer.WriteLine(0, "vec2 %s(float x) { return vec2(x, x); }", m_scalarSwizzle2Function);
m_writer.WriteLine(0, "ivec2 %s(int x) { return ivec2(x, x); }", m_scalarSwizzle2Function);

Expand Down Expand Up @@ -735,11 +750,26 @@ void GLSLGenerator::OutputExpression(HLSLExpression* expression, const HLSLType*
OutputExpression(binaryExpression->expression2, dstType2);
m_writer.Write(")))");
} else {
m_writer.Write("(");
OutputExpression(binaryExpression->expression1, dstType1);
m_writer.Write("%s", op);
OutputExpression(binaryExpression->expression2, dstType2);
m_writer.Write(")");
bool handled = false;
if (m_options.flags & Flag_AlternateNanPropagation) {
if (binaryExpression->binaryOp == HLSLBinaryOp_Mul) {
// Punt to function that does not follow IEEE 754 NaN propagation rules
m_writer.Write("%s(", m_altMultFunction);
OutputExpression(binaryExpression->expression1, dstType1);
m_writer.Write(",", op);
OutputExpression(binaryExpression->expression2, dstType2);
m_writer.Write(")");
handled = true;
}
}

if (!handled) {
m_writer.Write("(");
OutputExpression(binaryExpression->expression1, dstType1);
m_writer.Write("%s", op);
OutputExpression(binaryExpression->expression2, dstType2);
m_writer.Write(")");
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions vendor/hlslparser/src/GLSLGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class GLSLGenerator
Flag_EmulateConstantBuffer = 1 << 1,
Flag_PackMatrixRowMajor = 1 << 2,
Flag_LowerMatrixMultiplication = 1 << 3,
Flag_AlternateNanPropagation = 1 << 4,
};

struct Options
Expand All @@ -55,6 +56,12 @@ class GLSLGenerator
flags = 0;
constantBufferPrefix = "";
}

Options(unsigned int _flags)
{
flags = _flags;
constantBufferPrefix = "";
}
};

GLSLGenerator();
Expand Down Expand Up @@ -160,6 +167,7 @@ class GLSLGenerator
char m_modfFunction[64];
char m_acosFunction[64];
char m_asinFunction[64];
char m_altMultFunction[64];

bool m_error;

Expand Down
4 changes: 2 additions & 2 deletions vendor/hlslparser/src/HLSLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,8 @@ const Intrinsic _intrinsic[] =
INTRINSIC_FLOAT2_FUNCTION( "step" ),
INTRINSIC_FLOAT2_FUNCTION( "reflect" ),

INTRINSIC_FLOAT1_FUNCTION("isnan"),
INTRINSIC_FLOAT1_FUNCTION("isinf"),
Intrinsic("isnan", HLSLBaseType_Bool, HLSLBaseType_Float),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware of any presets that use these functions, but in trying to identify NaNs and Infs in shaders I found that the return type was declared incorrectly here. Changing this line results in the resulting shader correctly casting the output where necessary.

Intrinsic("isinf", HLSLBaseType_Bool, HLSLBaseType_Float),

Intrinsic("asuint", HLSLBaseType_Uint, HLSLBaseType_Float),

Expand Down