From fb3f92a3ff8d0735a209e4eb440ba31cf4c12688 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 22 Feb 2018 14:36:50 +0100 Subject: [PATCH] Overhaul clip/cull distance support in GLSL. --- .../frag/clip-cull-distance.desktop.frag | 12 ++++++++ .../vert/clip-cull-distance.desktop.sso.vert | 20 +++++++++++++ .../vert/clip-cull-distance.desktop.vert | 14 +++++---- .../frag/clip-cull-distance.desktop.frag | 12 ++++++++ .../vert/clip-cull-distance.desktop.sso.vert | 20 +++++++++++++ .../vert/clip-cull-distance.desktop.vert | 14 +++++---- .../frag/clip-cull-distance.desktop.frag | 12 ++++++++ .../vert/clip-cull-distance.desktop.sso.vert | 13 ++++++++ .../vert/clip-cull-distance.desktop.vert | 13 ++++---- spirv_cross.cpp | 30 +++++++++++++++++++ spirv_cross.hpp | 5 ++++ spirv_glsl.cpp | 18 +++++++++-- 12 files changed, 165 insertions(+), 18 deletions(-) create mode 100644 reference/opt/shaders/desktop-only/frag/clip-cull-distance.desktop.frag create mode 100644 reference/opt/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert create mode 100644 reference/shaders/desktop-only/frag/clip-cull-distance.desktop.frag create mode 100644 reference/shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert create mode 100644 shaders/desktop-only/frag/clip-cull-distance.desktop.frag create mode 100644 shaders/desktop-only/vert/clip-cull-distance.desktop.sso.vert 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/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/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;