diff --git a/reference/shaders-hlsl/frag/spec-constant.frag b/reference/shaders-hlsl/frag/spec-constant.frag new file mode 100644 index 00000000..63873d29 --- /dev/null +++ b/reference/shaders-hlsl/frag/spec-constant.frag @@ -0,0 +1,77 @@ +const float a = 1.0f; +const float b = 2.0f; +const int c = 3; +const int d = 4; +const uint e = 5u; +const uint f = 6u; +const bool g = false; +const bool h = true; + +struct Foo +{ + float elems[(d + 2)]; +}; + +static float4 FragColor; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + float t0 = a; + float t1 = b; + uint c0 = (uint(c) + 0u); + int c1 = (-c); + int c2 = (~c); + int c3 = (c + d); + int c4 = (c - d); + int c5 = (c * d); + int c6 = (c / d); + uint c7 = (e / f); + int c8 = (c % d); + uint c9 = (e % f); + int c10 = (c >> d); + uint c11 = (e >> f); + int c12 = (c << d); + int c13 = (c | d); + int c14 = (c ^ d); + int c15 = (c & d); + bool c16 = (g || h); + bool c17 = (g && h); + bool c18 = (!g); + bool c19 = (g == h); + bool c20 = (g != h); + bool c21 = (c == d); + bool c22 = (c != d); + bool c23 = (c < d); + bool c24 = (e < f); + bool c25 = (c > d); + bool c26 = (e > f); + bool c27 = (c <= d); + bool c28 = (e <= f); + bool c29 = (c >= d); + bool c30 = (e >= f); + int c31 = c8 + c3; + int c32 = int(e + 0u); + bool c33 = (c != int(0u)); + bool c34 = (e != 0u); + int c35 = int(g); + uint c36 = uint(g); + float c37 = float(g); + float _113 = t0 + t1; + float vec0[(c + 3)][8]; + float vec1[(c + 2)]; + Foo foo; + FragColor = ((float4(_113, _113, _113, _113) + float4(vec0[0][0], vec0[0][0], vec0[0][0], vec0[0][0])) + float4(vec1[0], vec1[0], vec1[0], vec1[0])) + float4(foo.elems[c], foo.elems[c], foo.elems[c], foo.elems[c]); +} + +SPIRV_Cross_Output main() +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/shaders-hlsl/frag/spec-constant.frag b/shaders-hlsl/frag/spec-constant.frag new file mode 100644 index 00000000..2002c127 --- /dev/null +++ b/shaders-hlsl/frag/spec-constant.frag @@ -0,0 +1,77 @@ +#version 310 es +precision mediump float; + +layout(location = 0) out vec4 FragColor; +layout(constant_id = 1) const float a = 1.0; +layout(constant_id = 2) const float b = 2.0; +layout(constant_id = 3) const int c = 3; +layout(constant_id = 4) const int d = 4; +layout(constant_id = 5) const uint e = 5u; +layout(constant_id = 6) const uint f = 6u; +layout(constant_id = 7) const bool g = false; +layout(constant_id = 8) const bool h = true; +// glslang doesn't seem to support partial spec constants or composites yet, so only test the basics. + +struct Foo +{ + float elems[d + 2]; +}; + +void main() +{ + float t0 = a; + float t1 = b; + + uint c0 = uint(c); // OpIAdd with different types. + // FConvert, float-to-double. + int c1 = -c; // SNegate + int c2 = ~c; // OpNot + int c3 = c + d; // OpIAdd + int c4 = c - d; // OpISub + int c5 = c * d; // OpIMul + int c6 = c / d; // OpSDiv + uint c7 = e / f; // OpUDiv + int c8 = c % d; // OpSMod + uint c9 = e % f; // OpUMod + // TODO: OpSRem, any way to access this in GLSL? + int c10 = c >> d; // OpShiftRightArithmetic + uint c11 = e >> f; // OpShiftRightLogical + int c12 = c << d; // OpShiftLeftLogical + int c13 = c | d; // OpBitwiseOr + int c14 = c ^ d; // OpBitwiseXor + int c15 = c & d; // OpBitwiseAnd + // VectorShuffle, CompositeExtract, CompositeInsert, not testable atm. + bool c16 = g || h; // OpLogicalOr + bool c17 = g && h; // OpLogicalAnd + bool c18 = !g; // OpLogicalNot + bool c19 = g == h; // OpLogicalEqual + bool c20 = g != h; // OpLogicalNotEqual + // OpSelect not testable atm. + bool c21 = c == d; // OpIEqual + bool c22 = c != d; // OpINotEqual + bool c23 = c < d; // OpSLessThan + bool c24 = e < f; // OpULessThan + bool c25 = c > d; // OpSGreaterThan + bool c26 = e > f; // OpUGreaterThan + bool c27 = c <= d; // OpSLessThanEqual + bool c28 = e <= f; // OpULessThanEqual + bool c29 = c >= d; // OpSGreaterThanEqual + bool c30 = e >= f; // OpUGreaterThanEqual + // OpQuantizeToF16 not testable atm. + + int c31 = c8 + c3; + + int c32 = int(e); // OpIAdd with different types. + bool c33 = bool(c); // int -> bool + bool c34 = bool(e); // uint -> bool + int c35 = int(g); // bool -> int + uint c36 = uint(g); // bool -> uint + float c37 = float(g); // bool -> float + + // Flexible sized arrays with spec constants and spec constant ops. + float vec0[c + 3][8]; + float vec1[c + 2]; + + Foo foo; + FragColor = vec4(t0 + t1) + vec0[0][0] + vec1[0] + foo.elems[c]; +} diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 5b5ec822..268d029e 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -583,10 +583,35 @@ void CompilerHLSL::emit_builtin_variables() } } +void CompilerHLSL::emit_specialization_constants() +{ + bool emitted = false; + for (auto &id : ids) + { + if (id.get_type() == TypeConstant) + { + auto &c = id.get(); + if (!c.specialization) + continue; + + auto &type = get(c.constant_type); + auto name = to_name(c.self); + + statement("const ", variable_decl(type, name), " = ", constant_expression(c), ";"); + emitted = true; + } + } + + if (emitted) + statement(""); +} + void CompilerHLSL::emit_resources() { auto &execution = get_entry_point(); + emit_specialization_constants(); + // Output all basic struct types which are not Block or BufferBlock as these are declared inplace // when such variables are instantiated. for (auto &id : ids) diff --git a/spirv_hlsl.hpp b/spirv_hlsl.hpp index 73bcbbae..580b0a05 100644 --- a/spirv_hlsl.hpp +++ b/spirv_hlsl.hpp @@ -80,6 +80,7 @@ private: void emit_uniform(const SPIRVariable &var) override; void emit_modern_uniform(const SPIRVariable &var); void emit_legacy_uniform(const SPIRVariable &var); + void emit_specialization_constants(); std::string layout_for_member(const SPIRType &type, uint32_t index) override; std::string to_interpolation_qualifiers(uint64_t flags) override; std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;