diff --git a/reference/opt/shaders-hlsl/frag/clip-cull-distance.frag b/reference/opt/shaders-hlsl/frag/clip-cull-distance.frag new file mode 100644 index 00000000..52f1ac30 --- /dev/null +++ b/reference/opt/shaders-hlsl/frag/clip-cull-distance.frag @@ -0,0 +1,30 @@ +static float gl_ClipDistance[2]; +static float gl_CullDistance[1]; +static float FragColor; + +struct SPIRV_Cross_Input +{ + float2 gl_ClipDistance0 : SV_ClipDistance0; + float gl_CullDistance0 : SV_CullDistance0; +}; + +struct SPIRV_Cross_Output +{ + float FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = (gl_ClipDistance[0] + gl_CullDistance[0]) + gl_ClipDistance[1]; +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + gl_ClipDistance[0] = stage_input.gl_ClipDistance0.x; + gl_ClipDistance[1] = stage_input.gl_ClipDistance0.y; + gl_CullDistance[0] = stage_input.gl_CullDistance0.x; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/opt/shaders-hlsl/vert/clip-cull-distance.vert b/reference/opt/shaders-hlsl/vert/clip-cull-distance.vert new file mode 100644 index 00000000..7e0d104a --- /dev/null +++ b/reference/opt/shaders-hlsl/vert/clip-cull-distance.vert @@ -0,0 +1,28 @@ +static float4 gl_Position; +static float gl_ClipDistance[2]; +static float gl_CullDistance[1]; +struct SPIRV_Cross_Output +{ + float4 gl_Position : SV_Position; + float2 gl_ClipDistance0 : SV_ClipDistance0; + float gl_CullDistance0 : SV_CullDistance0; +}; + +void vert_main() +{ + gl_Position = 1.0f.xxxx; + gl_ClipDistance[0] = 0.0f; + gl_ClipDistance[1] = 0.0f; + gl_CullDistance[0] = 4.0f; +} + +SPIRV_Cross_Output main() +{ + vert_main(); + SPIRV_Cross_Output stage_output; + stage_output.gl_Position = gl_Position; + stage_output.gl_ClipDistance0.x = gl_ClipDistance[0]; + stage_output.gl_ClipDistance0.y = gl_ClipDistance[1]; + stage_output.gl_CullDistance0.x = gl_CullDistance[0]; + return stage_output; +} diff --git a/reference/opt/shaders/desktop-only/frag/clip-cull-distance.desktop.frag b/reference/opt/shaders/desktop-only/frag/clip-cull-distance.desktop.frag new file mode 100644 index 00000000..3cc32055 --- /dev/null +++ b/reference/opt/shaders/desktop-only/frag/clip-cull-distance.desktop.frag @@ -0,0 +1,12 @@ +#version 450 + +in float gl_ClipDistance[4]; +in float gl_CullDistance[3]; + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = gl_ClipDistance[0] + gl_CullDistance[0]; +} + diff --git a/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert b/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert new file mode 100644 index 00000000..a7c5d761 --- /dev/null +++ b/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert @@ -0,0 +1,20 @@ +#version 450 + +out gl_PerVertex +{ + vec4 gl_Position; + float gl_PointSize; + float gl_ClipDistance[4]; + float gl_CullDistance[3]; +}; + +void main() +{ + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_ClipDistance[2] = 0.0; + gl_ClipDistance[3] = 0.0; + gl_CullDistance[1] = 4.0; +} + diff --git a/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.vert b/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.vert index 566809db..2f3d49f5 100644 --- a/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.vert +++ b/reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.vert @@ -1,11 +1,15 @@ #version 450 +out float gl_ClipDistance[4]; +out float gl_CullDistance[3]; + void main() { - gl_Position = vec4(10.0); - gl_ClipDistance[0] = 1.0; - gl_ClipDistance[1] = 4.0; - gl_CullDistance[0] = 4.0; - gl_CullDistance[1] = 9.0; + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_ClipDistance[2] = 0.0; + gl_ClipDistance[3] = 0.0; + gl_CullDistance[1] = 4.0; } diff --git a/reference/shaders-hlsl/frag/clip-cull-distance.frag b/reference/shaders-hlsl/frag/clip-cull-distance.frag new file mode 100644 index 00000000..52f1ac30 --- /dev/null +++ b/reference/shaders-hlsl/frag/clip-cull-distance.frag @@ -0,0 +1,30 @@ +static float gl_ClipDistance[2]; +static float gl_CullDistance[1]; +static float FragColor; + +struct SPIRV_Cross_Input +{ + float2 gl_ClipDistance0 : SV_ClipDistance0; + float gl_CullDistance0 : SV_CullDistance0; +}; + +struct SPIRV_Cross_Output +{ + float FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = (gl_ClipDistance[0] + gl_CullDistance[0]) + gl_ClipDistance[1]; +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + gl_ClipDistance[0] = stage_input.gl_ClipDistance0.x; + gl_ClipDistance[1] = stage_input.gl_ClipDistance0.y; + gl_CullDistance[0] = stage_input.gl_CullDistance0.x; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-hlsl/vert/clip-cull-distance.vert b/reference/shaders-hlsl/vert/clip-cull-distance.vert new file mode 100644 index 00000000..7e0d104a --- /dev/null +++ b/reference/shaders-hlsl/vert/clip-cull-distance.vert @@ -0,0 +1,28 @@ +static float4 gl_Position; +static float gl_ClipDistance[2]; +static float gl_CullDistance[1]; +struct SPIRV_Cross_Output +{ + float4 gl_Position : SV_Position; + float2 gl_ClipDistance0 : SV_ClipDistance0; + float gl_CullDistance0 : SV_CullDistance0; +}; + +void vert_main() +{ + gl_Position = 1.0f.xxxx; + gl_ClipDistance[0] = 0.0f; + gl_ClipDistance[1] = 0.0f; + gl_CullDistance[0] = 4.0f; +} + +SPIRV_Cross_Output main() +{ + vert_main(); + SPIRV_Cross_Output stage_output; + stage_output.gl_Position = gl_Position; + stage_output.gl_ClipDistance0.x = gl_ClipDistance[0]; + stage_output.gl_ClipDistance0.y = gl_ClipDistance[1]; + stage_output.gl_CullDistance0.x = gl_CullDistance[0]; + return stage_output; +} diff --git a/reference/shaders/desktop-only/frag/clip-cull-distance.desktop.frag b/reference/shaders/desktop-only/frag/clip-cull-distance.desktop.frag new file mode 100644 index 00000000..3cc32055 --- /dev/null +++ b/reference/shaders/desktop-only/frag/clip-cull-distance.desktop.frag @@ -0,0 +1,12 @@ +#version 450 + +in float gl_ClipDistance[4]; +in float gl_CullDistance[3]; + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = gl_ClipDistance[0] + gl_CullDistance[0]; +} + diff --git a/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert b/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert new file mode 100644 index 00000000..a7c5d761 --- /dev/null +++ b/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert @@ -0,0 +1,20 @@ +#version 450 + +out gl_PerVertex +{ + vec4 gl_Position; + float gl_PointSize; + float gl_ClipDistance[4]; + float gl_CullDistance[3]; +}; + +void main() +{ + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_ClipDistance[2] = 0.0; + gl_ClipDistance[3] = 0.0; + gl_CullDistance[1] = 4.0; +} + diff --git a/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.vert b/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.vert index 566809db..2f3d49f5 100644 --- a/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.vert +++ b/reference/shaders/desktop-only/vert/clip-cull-distance.desktop.vert @@ -1,11 +1,15 @@ #version 450 +out float gl_ClipDistance[4]; +out float gl_CullDistance[3]; + void main() { - gl_Position = vec4(10.0); - gl_ClipDistance[0] = 1.0; - gl_ClipDistance[1] = 4.0; - gl_CullDistance[0] = 4.0; - gl_CullDistance[1] = 9.0; + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_ClipDistance[2] = 0.0; + gl_ClipDistance[3] = 0.0; + gl_CullDistance[1] = 4.0; } diff --git a/shaders-hlsl/frag/clip-cull-distance.frag b/shaders-hlsl/frag/clip-cull-distance.frag new file mode 100644 index 00000000..625a7dab --- /dev/null +++ b/shaders-hlsl/frag/clip-cull-distance.frag @@ -0,0 +1,12 @@ +#version 450 + +in float gl_ClipDistance[2]; +in float gl_CullDistance[1]; + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = gl_ClipDistance[0] + gl_CullDistance[0] + gl_ClipDistance[1]; +} + diff --git a/shaders-hlsl/vert/clip-cull-distance.vert b/shaders-hlsl/vert/clip-cull-distance.vert new file mode 100644 index 00000000..34f65fc1 --- /dev/null +++ b/shaders-hlsl/vert/clip-cull-distance.vert @@ -0,0 +1,11 @@ +#version 450 +out float gl_ClipDistance[2]; +out float gl_CullDistance[1]; + +void main() +{ + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_CullDistance[0] = 4.0; +} diff --git a/shaders/desktop-only/frag/clip-cull-distance.desktop.frag b/shaders/desktop-only/frag/clip-cull-distance.desktop.frag new file mode 100644 index 00000000..5212fd64 --- /dev/null +++ b/shaders/desktop-only/frag/clip-cull-distance.desktop.frag @@ -0,0 +1,12 @@ +#version 450 + +in float gl_ClipDistance[4]; +in float gl_CullDistance[3]; + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = gl_ClipDistance[0] + gl_CullDistance[0]; +} + diff --git a/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert b/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert new file mode 100644 index 00000000..1489cc7a --- /dev/null +++ b/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert @@ -0,0 +1,13 @@ +#version 450 +out float gl_ClipDistance[4]; +out float gl_CullDistance[3]; + +void main() +{ + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_ClipDistance[2] = 0.0; + gl_ClipDistance[3] = 0.0; + gl_CullDistance[1] = 4.0; +} diff --git a/shaders/desktop-only/vert/clip-cull-distance.desktop.vert b/shaders/desktop-only/vert/clip-cull-distance.desktop.vert index 9e4a0b7a..1489cc7a 100644 --- a/shaders/desktop-only/vert/clip-cull-distance.desktop.vert +++ b/shaders/desktop-only/vert/clip-cull-distance.desktop.vert @@ -1,10 +1,13 @@ #version 450 +out float gl_ClipDistance[4]; +out float gl_CullDistance[3]; void main() { - gl_Position = vec4(10.0); - gl_ClipDistance[0] = 1.0; - gl_ClipDistance[1] = 4.0; - gl_CullDistance[0] = 4.0; - gl_CullDistance[1] = 9.0; + gl_Position = vec4(1.0); + gl_ClipDistance[0] = 0.0; + gl_ClipDistance[1] = 0.0; + gl_ClipDistance[2] = 0.0; + gl_ClipDistance[3] = 0.0; + gl_CullDistance[1] = 4.0; } diff --git a/spirv_cross.cpp b/spirv_cross.cpp index 021d2a6f..9378cefa 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -3749,6 +3749,30 @@ bool Compiler::get_common_basic_type(const SPIRType &type, SPIRType::BaseType &b } } +void Compiler::ActiveBuiltinHandler::handle_builtin(const SPIRType &type, BuiltIn builtin) +{ + // If used, we will need to explicitly declare a new array size for these builtins. + + if (builtin == BuiltInClipDistance) + { + if (!type.array_size_literal[0]) + SPIRV_CROSS_THROW("Array size for ClipDistance must be a literal."); + uint32_t array_size = type.array[0]; + if (array_size == 0) + SPIRV_CROSS_THROW("Array size for ClipDistance must not be unsized."); + compiler.clip_distance_count = array_size; + } + else if (builtin == BuiltInCullDistance) + { + if (!type.array_size_literal[0]) + SPIRV_CROSS_THROW("Array size for CullDistance must be a literal."); + uint32_t array_size = type.array[0]; + if (array_size == 0) + SPIRV_CROSS_THROW("Array size for CullDistance must not be unsized."); + compiler.cull_distance_count = array_size; + } +} + bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length) { const auto add_if_builtin = [&](uint32_t id) { @@ -3761,6 +3785,7 @@ bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args auto &flags = type.storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins; flags |= 1ull << compiler.meta[id].decoration.builtin_type; + handle_builtin(type, compiler.meta[id].decoration.builtin_type); } }; @@ -3846,7 +3871,10 @@ bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args { auto &decorations = compiler.meta[type->self].members[index]; if (decorations.builtin) + { flags |= 1ull << decorations.builtin_type; + handle_builtin(compiler.get(type->member_types[index]), decorations.builtin_type); + } } type = &compiler.get(type->member_types[index]); @@ -3871,6 +3899,8 @@ void Compiler::update_active_builtins() { active_input_builtins = 0; active_output_builtins = 0; + cull_distance_count = 0; + clip_distance_count = 0; ActiveBuiltinHandler handler(*this); traverse_all_reachable_opcodes(get(entry_point), handler); } diff --git a/spirv_cross.hpp b/spirv_cross.hpp index 66c65b4d..69079232 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -715,6 +715,8 @@ protected: bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override; Compiler &compiler; + + void handle_builtin(const SPIRType &type, spv::BuiltIn builtin); }; bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const; @@ -735,6 +737,9 @@ protected: uint64_t active_input_builtins = 0; uint64_t active_output_builtins = 0; + uint32_t clip_distance_count = 0; + uint32_t cull_distance_count = 0; + // Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader. void update_active_builtins(); bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage); diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index edda4f7f..284c2c33 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -1871,9 +1871,9 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (emitted_builtins & (1ull << BuiltInPointSize)) statement("float gl_PointSize;"); if (emitted_builtins & (1ull << BuiltInClipDistance)) - statement("float gl_ClipDistance[];"); // TODO: Do we need a fixed array size here? + statement("float gl_ClipDistance[", clip_distance_count, "];"); if (emitted_builtins & (1ull << BuiltInCullDistance)) - statement("float gl_CullDistance[];"); // TODO: Do we need a fixed array size here? + statement("float gl_CullDistance[", cull_distance_count, "];"); bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl; if (builtin_array) @@ -1927,7 +1927,7 @@ void CompilerGLSL::emit_resources() emit_pls(); // Emit custom gl_PerVertex for SSO compatibility. - if (options.separate_shader_objects && !options.es) + if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment) { switch (execution.model) { @@ -1946,6 +1946,18 @@ void CompilerGLSL::emit_resources() break; } } + else + { + // Need to redeclare clip/cull distance with explicit size to use them. + // SPIR-V mandates these builtins have a size declared. + const char *storage = execution.model == ExecutionModelFragment ? "in" : "out"; + if (clip_distance_count != 0) + statement(storage, " float gl_ClipDistance[", clip_distance_count, "];"); + if (cull_distance_count != 0) + statement(storage, " float gl_CullDistance[", cull_distance_count, "];"); + if (clip_distance_count != 0 || cull_distance_count != 0) + statement(""); + } bool emitted = false; diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 5444df5c..bfe6b339 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -509,6 +509,40 @@ void CompilerHLSL::emit_builtin_outputs_in_struct() semantic = legacy ? "DEPTH" : "SV_Depth"; break; + case BuiltInClipDistance: + // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors. + for (uint32_t clip = 0; clip < clip_distance_count; clip += 4) + { + uint32_t to_declare = clip_distance_count - clip; + if (to_declare > 4) + to_declare = 4; + + uint32_t semantic_index = clip / 4; + + static const char *types[] = { "float", "float2", "float3", "float4" }; + statement(types[to_declare - 1], " ", + builtin_to_glsl(builtin, StorageClassOutput), + semantic_index, " : SV_ClipDistance", semantic_index, ";"); + } + break; + + case BuiltInCullDistance: + // HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors. + for (uint32_t cull = 0; cull < cull_distance_count; cull += 4) + { + uint32_t to_declare = cull_distance_count - cull; + if (to_declare > 4) + to_declare = 4; + + uint32_t semantic_index = cull / 4; + + static const char *types[] = { "float", "float2", "float3", "float4" }; + statement(types[to_declare - 1], " ", + builtin_to_glsl(builtin, StorageClassOutput), + semantic_index, " : SV_CullDistance", semantic_index, ";"); + } + break; + case BuiltInPointSize: // If point_size_compat is enabled, just ignore PointSize. // PointSize does not exist in HLSL, but some code bases might want to be able to use these shaders, @@ -598,6 +632,40 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() // Handled specially. break; + case BuiltInClipDistance: + // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors. + for (uint32_t clip = 0; clip < clip_distance_count; clip += 4) + { + uint32_t to_declare = clip_distance_count - clip; + if (to_declare > 4) + to_declare = 4; + + uint32_t semantic_index = clip / 4; + + static const char *types[] = { "float", "float2", "float3", "float4" }; + statement(types[to_declare - 1], " ", + builtin_to_glsl(builtin, StorageClassInput), + semantic_index, " : SV_ClipDistance", semantic_index, ";"); + } + break; + + case BuiltInCullDistance: + // HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors. + for (uint32_t cull = 0; cull < cull_distance_count; cull += 4) + { + uint32_t to_declare = cull_distance_count - cull; + if (to_declare > 4) + to_declare = 4; + + uint32_t semantic_index = cull / 4; + + static const char *types[] = { "float", "float2", "float3", "float4" }; + statement(types[to_declare - 1], " ", + builtin_to_glsl(builtin, StorageClassInput), + semantic_index, " : SV_CullDistance", semantic_index, ";"); + } + break; + default: SPIRV_CROSS_THROW("Unsupported builtin in HLSL."); break; @@ -807,6 +875,7 @@ void CompilerHLSL::emit_builtin_variables() const char *type = nullptr; auto builtin = static_cast(i); + uint32_t array_size = 0; switch (builtin) { @@ -855,6 +924,16 @@ void CompilerHLSL::emit_builtin_variables() // Handled specially. break; + case BuiltInClipDistance: + array_size = clip_distance_count; + type = "float"; + break; + + case BuiltInCullDistance: + array_size = cull_distance_count; + type = "float"; + break; + default: SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin))); break; @@ -865,7 +944,12 @@ void CompilerHLSL::emit_builtin_variables() // need to distinguish that when we add support for that. if (type) - statement("static ", type, " ", builtin_to_glsl(builtin, storage), ";"); + { + if (array_size) + statement("static ", type, " ", builtin_to_glsl(builtin, storage), "[", array_size, "];"); + else + statement("static ", type, " ", builtin_to_glsl(builtin, storage), ";"); + } } } @@ -1843,7 +1927,16 @@ void CompilerHLSL::emit_hlsl_entry_point() break; case BuiltInNumWorkgroups: - // Handled specially. + break; + + case BuiltInClipDistance: + for (uint32_t clip = 0; clip < clip_distance_count; clip++) + statement("gl_ClipDistance[", clip, "] = stage_input.gl_ClipDistance", clip / 4, ".", "xyzw"[clip & 3], ";"); + break; + + case BuiltInCullDistance: + for (uint32_t cull = 0; cull < cull_distance_count; cull++) + statement("gl_CullDistance[", cull, "] = stage_input.gl_CullDistance", cull / 4, ".", "xyzw"[cull & 3], ";"); break; default: @@ -1938,8 +2031,25 @@ void CompilerHLSL::emit_hlsl_entry_point() if (i == BuiltInPointSize) continue; - auto builtin = builtin_to_glsl(static_cast(i), StorageClassOutput); - statement("stage_output.", builtin, " = ", builtin, ";"); + switch (static_cast(i)) + { + case BuiltInClipDistance: + for (uint32_t clip = 0; clip < clip_distance_count; clip++) + statement("stage_output.gl_ClipDistance", clip / 4, ".", "xyzw"[clip & 3], " = gl_ClipDistance[", clip, "];"); + break; + + case BuiltInCullDistance: + for (uint32_t cull = 0; cull < cull_distance_count; cull++) + statement("stage_output.gl_CullDistance", cull / 4, ".", "xyzw"[cull & 3], " = gl_CullDistance[", cull, "];"); + break; + + default: + { + auto builtin_expr = builtin_to_glsl(static_cast(i), StorageClassOutput); + statement("stage_output.", builtin_expr, " = ", builtin_expr, ";"); + break; + } + } } for (auto &id : ids)