diff --git a/reference/shaders/asm/vert/global-builtin.sso.asm.vert b/reference/shaders/asm/vert/global-builtin.sso.asm.vert new file mode 100644 index 00000000..75788270 --- /dev/null +++ b/reference/shaders/asm/vert/global-builtin.sso.asm.vert @@ -0,0 +1,35 @@ +#version 450 + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +struct VSOut +{ + float a; + vec4 pos; +}; + +struct VSOut_1 +{ + float a; +}; + +layout(location = 0) out VSOut_1 _entryPointOutput; + +VSOut _main() +{ + VSOut vout; + vout.a = 40.0; + vout.pos = vec4(1.0); + return vout; +} + +void main() +{ + VSOut flattenTemp = _main(); + _entryPointOutput.a = flattenTemp.a; + gl_Position = flattenTemp.pos; +} + diff --git a/shaders/asm/vert/global-builtin.sso.asm.vert b/shaders/asm/vert/global-builtin.sso.asm.vert new file mode 100644 index 00000000..d7306deb --- /dev/null +++ b/shaders/asm/vert/global-builtin.sso.asm.vert @@ -0,0 +1,68 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 40 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %_entryPointOutput %_entryPointOutput_pos + OpSource HLSL 500 + OpName %main "main" + OpName %VSOut "VSOut" + OpMemberName %VSOut 0 "a" + OpMemberName %VSOut 1 "pos" + OpName %_main_ "@main(" + OpName %vout "vout" + OpName %flattenTemp "flattenTemp" + OpName %VSOut_0 "VSOut" + OpMemberName %VSOut_0 0 "a" + OpName %_entryPointOutput "@entryPointOutput" + OpName %_entryPointOutput_pos "@entryPointOutput_pos" + OpDecorate %_entryPointOutput Location 0 + OpDecorate %_entryPointOutput_pos BuiltIn Position + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %VSOut = OpTypeStruct %float %v4float + %9 = OpTypeFunction %VSOut +%_ptr_Function_VSOut = OpTypePointer Function %VSOut + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float_40 = OpConstant %float 40 +%_ptr_Function_float = OpTypePointer Function %float + %int_1 = OpConstant %int 1 + %float_1 = OpConstant %float 1 + %21 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %VSOut_0 = OpTypeStruct %float +%_ptr_Output_VSOut_0 = OpTypePointer Output %VSOut_0 +%_entryPointOutput = OpVariable %_ptr_Output_VSOut_0 Output +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_pos = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel +%flattenTemp = OpVariable %_ptr_Function_VSOut Function + %28 = OpFunctionCall %VSOut %_main_ + OpStore %flattenTemp %28 + %32 = OpAccessChain %_ptr_Function_float %flattenTemp %int_0 + %33 = OpLoad %float %32 + %35 = OpAccessChain %_ptr_Output_float %_entryPointOutput %int_0 + OpStore %35 %33 + %38 = OpAccessChain %_ptr_Function_v4float %flattenTemp %int_1 + %39 = OpLoad %v4float %38 + OpStore %_entryPointOutput_pos %39 + OpReturn + OpFunctionEnd + %_main_ = OpFunction %VSOut None %9 + %11 = OpLabel + %vout = OpVariable %_ptr_Function_VSOut Function + %18 = OpAccessChain %_ptr_Function_float %vout %int_0 + OpStore %18 %float_40 + %23 = OpAccessChain %_ptr_Function_v4float %vout %int_1 + OpStore %23 %21 + %24 = OpLoad %VSOut %vout + OpReturnValue %24 + OpFunctionEnd diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 48cb5fd4..c2ec16cc 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -1784,7 +1784,12 @@ void CompilerGLSL::fixup_image_load_store_access() void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model) { + uint64_t emitted_builtins = 0; + uint64_t global_builtins = 0; + const SPIRVariable *block_var = nullptr; bool emitted_block = false; + bool builtin_array = false; + for (auto &id : ids) { if (id.get_type() != TypeVariable) @@ -1801,6 +1806,13 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (m.builtin) builtins |= 1ull << m.builtin_type; } + else if (var.storage == storage && !block && is_builtin_variable(var)) + { + // While we're at it, collect all declared global builtins (HLSL mostly ...). + auto &m = meta[var.self].decoration; + if (m.builtin) + global_builtins |= 1ull << m.builtin_type; + } if (!builtins) continue; @@ -1808,42 +1820,58 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (emitted_block) SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block."); - if (storage == StorageClassOutput) - statement("out gl_PerVertex"); - else - statement("in gl_PerVertex"); - - begin_scope(); - if (builtins & (1ull << BuiltInPosition)) - statement("vec4 gl_Position;"); - if (builtins & (1ull << BuiltInPointSize)) - statement("float gl_PointSize;"); - if (builtins & (1ull << BuiltInClipDistance)) - statement("float gl_ClipDistance[];"); // TODO: Do we need a fixed array size here? - if (builtins & (1ull << BuiltInCullDistance)) - statement("float gl_CullDistance[];"); // TODO: Do we need a fixed array size here? - - bool builtin_array = !type.array.empty(); - bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl; - if (builtin_array) - { - // Make sure the array has a supported name in the code. - if (storage == StorageClassOutput) - set_name(var.self, "gl_out"); - else if (storage == StorageClassInput) - set_name(var.self, "gl_in"); - - if (model == ExecutionModelTessellationControl && storage == StorageClassOutput) - end_scope_decl(join(to_name(var.self), "[", get_entry_point().output_vertices, "]")); - else - end_scope_decl(join(to_name(var.self), tessellation ? "[gl_MaxPatchVertices]" : "[]")); - } - else - end_scope_decl(); - statement(""); - + emitted_builtins = builtins; emitted_block = true; + builtin_array = !type.array.empty(); + block_var = &var; } + + global_builtins &= + (1ull << BuiltInPosition) | + (1ull << BuiltInPointSize) | + (1ull << BuiltInClipDistance) | + (1ull << BuiltInCullDistance); + + // Try to collect all other declared builtins. + if (!emitted_block) + emitted_builtins = global_builtins; + + // Can't declare an empty interface block. + if (!emitted_builtins) + return; + + if (storage == StorageClassOutput) + statement("out gl_PerVertex"); + else + statement("in gl_PerVertex"); + + begin_scope(); + if (emitted_builtins & (1ull << BuiltInPosition)) + statement("vec4 gl_Position;"); + 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? + if (emitted_builtins & (1ull << BuiltInCullDistance)) + statement("float gl_CullDistance[];"); // TODO: Do we need a fixed array size here? + + bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl; + if (builtin_array) + { + // Make sure the array has a supported name in the code. + if (storage == StorageClassOutput) + set_name(block_var->self, "gl_out"); + else if (storage == StorageClassInput) + set_name(block_var->self, "gl_in"); + + 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]" : "[]")); + } + else + end_scope_decl(); + statement(""); } void CompilerGLSL::declare_undefined_values()