From 7c1e34f3b9ad2d249dcf01b6fa6a30cdc7911755 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Tue, 10 Dec 2019 12:00:55 +0100 Subject: [PATCH] GLSL: Fix array of input patch variables. Hoist out the hack to make array sizes unsized to a place where we can differentiate patch variables from control point variables. --- .../desktop-only/tesc/basic.desktop.sso.tesc | 2 +- .../tese/triangle.desktop.sso.tese | 2 +- .../opt/shaders/tese/patch-input-array.tese | 10 +++++ .../desktop-only/tesc/basic.desktop.sso.tesc | 2 +- .../tese/triangle.desktop.sso.tese | 2 +- reference/shaders/tese/patch-input-array.tese | 10 +++++ shaders/tese/patch-input-array.tese | 9 +++++ spirv_glsl.cpp | 37 +++++++++++++------ 8 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 reference/opt/shaders/tese/patch-input-array.tese create mode 100644 reference/shaders/tese/patch-input-array.tese create mode 100644 shaders/tese/patch-input-array.tese diff --git a/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc b/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc index 5e958256..c51699db 100644 --- a/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc +++ b/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc @@ -4,7 +4,7 @@ layout(vertices = 1) out; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese b/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese index 31027dae..c9bacd46 100644 --- a/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese +++ b/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese @@ -4,7 +4,7 @@ layout(triangles, cw, fractional_even_spacing) in; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/reference/opt/shaders/tese/patch-input-array.tese b/reference/opt/shaders/tese/patch-input-array.tese new file mode 100644 index 00000000..413d8b39 --- /dev/null +++ b/reference/opt/shaders/tese/patch-input-array.tese @@ -0,0 +1,10 @@ +#version 450 +layout(quads, ccw, equal_spacing) in; + +layout(location = 0) patch in float P[4]; + +void main() +{ + gl_Position = vec4(P[0], P[1], P[2], P[3]); +} + diff --git a/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc b/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc index 5e958256..c51699db 100644 --- a/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc +++ b/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc @@ -4,7 +4,7 @@ layout(vertices = 1) out; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese b/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese index 31027dae..c9bacd46 100644 --- a/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese +++ b/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese @@ -4,7 +4,7 @@ layout(triangles, cw, fractional_even_spacing) in; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/reference/shaders/tese/patch-input-array.tese b/reference/shaders/tese/patch-input-array.tese new file mode 100644 index 00000000..413d8b39 --- /dev/null +++ b/reference/shaders/tese/patch-input-array.tese @@ -0,0 +1,10 @@ +#version 450 +layout(quads, ccw, equal_spacing) in; + +layout(location = 0) patch in float P[4]; + +void main() +{ + gl_Position = vec4(P[0], P[1], P[2], P[3]); +} + diff --git a/shaders/tese/patch-input-array.tese b/shaders/tese/patch-input-array.tese new file mode 100644 index 00000000..741b2c3b --- /dev/null +++ b/shaders/tese/patch-input-array.tese @@ -0,0 +1,9 @@ +#version 450 + +layout(quads) in; +layout(location = 0) patch in float P[4]; + +void main() +{ + gl_Position = vec4(P[0], P[1], P[2], P[3]); +} diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index f4cfd4f2..f6a1b8b6 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -2104,9 +2104,32 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) else { add_resource_name(var.self); + + // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays. + // Opt for unsized as it's the more "correct" variant to use. + bool control_point_input_array = type.storage == StorageClassInput && + !type.array.empty() && !has_decoration(var.self, DecorationPatch) && + (get_entry_point().model == ExecutionModelTessellationControl || + get_entry_point().model == ExecutionModelTessellationEvaluation); + + uint32_t old_array_size = 0; + bool old_array_size_literal = true; + + if (control_point_input_array) + { + swap(type.array.back(), old_array_size); + swap(type.array_size_literal.back(), old_array_size_literal); + } + statement(layout_for_variable(var), to_qualifiers_glsl(var.self), variable_decl(type, to_name(var.self), var.self), ";"); + if (control_point_input_array) + { + swap(type.array.back(), old_array_size); + swap(type.array_size_literal.back(), old_array_size_literal); + } + // If a StorageClassOutput variable has an initializer, we need to initialize it in main(). if (var.storage == StorageClassOutput && var.initializer) { @@ -2478,7 +2501,6 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (emitted_builtins.get(BuiltInCullDistance)) statement("float gl_CullDistance[", cull_distance_size, "];"); - bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl; if (builtin_array) { // Make sure the array has a supported name in the code. @@ -2490,7 +2512,7 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (model == ExecutionModelTessellationControl && storage == StorageClassOutput) end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]")); else - end_scope_decl(join(to_name(block_var->self), tessellation ? "[gl_MaxPatchVertices]" : "[]")); + end_scope_decl(join(to_name(block_var->self), "[]")); } else end_scope_decl(); @@ -10794,14 +10816,6 @@ string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index) { assert(type.array.size() == type.array_size_literal.size()); - // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays. - // Opt for unsized as it's the more "correct" variant to use. - if (type.storage == StorageClassInput && - (get_entry_point().model == ExecutionModelTessellationControl || - get_entry_point().model == ExecutionModelTessellationEvaluation) && - index == uint32_t(type.array.size() - 1)) - return ""; - auto &size = type.array[index]; if (!type.array_size_literal[index]) return to_expression(size); @@ -12795,13 +12809,14 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn)); bool is_builtin = is_builtin_variable(*var) && (builtin == BuiltInPointSize || builtin == BuiltInPosition); bool is_tess = is_tessellation_shader(); + bool is_patch = has_decoration(var->self, DecorationPatch); // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it. // We must unroll the array load. // For builtins, we couldn't catch this case normally, // because this is resolved in the OpAccessChain in most cases. // If we load the entire array, we have no choice but to unroll here. - if (is_builtin || is_tess) + if (!is_patch && (is_builtin || is_tess)) { auto new_expr = join("_", target_id, "_unrolled"); statement(variable_decl(type, new_expr, target_id), ";");