From 18e8833eebabfc3a846ee8a643e2e894720d35db Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Mon, 5 Feb 2018 10:27:42 +0100 Subject: [PATCH] Support gl_NumWorkgroups in HLSL. --- main.cpp | 11 +++ .../comp/num-workgroups-alone.comp | 16 +++++ .../comp/num-workgroups-with-builtins.comp | 23 +++++++ .../comp/num-workgroups-alone.comp | 16 +++++ .../comp/num-workgroups-with-builtins.comp | 23 +++++++ shaders-hlsl/comp/num-workgroups-alone.comp | 13 ++++ .../comp/num-workgroups-with-builtins.comp | 13 ++++ spirv_hlsl.cpp | 67 ++++++++++++++++++- spirv_hlsl.hpp | 14 ++++ 9 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp create mode 100644 reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp create mode 100644 reference/shaders-hlsl/comp/num-workgroups-alone.comp create mode 100644 reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp create mode 100644 shaders-hlsl/comp/num-workgroups-alone.comp create mode 100644 shaders-hlsl/comp/num-workgroups-with-builtins.comp diff --git a/main.cpp b/main.cpp index 49fc8653..e0e6873b 100644 --- a/main.cpp +++ b/main.cpp @@ -887,6 +887,17 @@ static int main_inner(int argc, char *argv[]) } } + if (args.hlsl) + { + auto *hlsl_compiler = static_cast(compiler.get()); + uint32_t new_builtin = hlsl_compiler->remap_num_workgroups_builtin(); + if (new_builtin) + { + hlsl_compiler->set_decoration(new_builtin, DecorationDescriptorSet, 0); + hlsl_compiler->set_decoration(new_builtin, DecorationBinding, 0); + } + } + string glsl; for (uint32_t i = 0; i < args.iterations; i++) { diff --git a/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp b/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp new file mode 100644 index 00000000..1e7dd542 --- /dev/null +++ b/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp @@ -0,0 +1,16 @@ +RWByteAddressBuffer _10 : register(u0); +cbuffer SPIRV_Cross_NumWorkgroups : register(b0) +{ + uint3 SPIRV_Cross_NumWorkgroups_count : packoffset(c0); +}; + +void comp_main() +{ + _10.Store3(0, SPIRV_Cross_NumWorkgroups_count); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp b/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp new file mode 100644 index 00000000..f44754e8 --- /dev/null +++ b/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp @@ -0,0 +1,23 @@ +RWByteAddressBuffer _10 : register(u0); +cbuffer SPIRV_Cross_NumWorkgroups : register(b0) +{ + uint3 SPIRV_Cross_NumWorkgroups_count : packoffset(c0); +}; + +static uint3 gl_WorkGroupID; +struct SPIRV_Cross_Input +{ + uint3 gl_WorkGroupID : SV_GroupID; +}; + +void comp_main() +{ + _10.Store3(0, SPIRV_Cross_NumWorkgroups_count + gl_WorkGroupID); +} + +[numthreads(1, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_WorkGroupID = stage_input.gl_WorkGroupID; + comp_main(); +} diff --git a/reference/shaders-hlsl/comp/num-workgroups-alone.comp b/reference/shaders-hlsl/comp/num-workgroups-alone.comp new file mode 100644 index 00000000..1e7dd542 --- /dev/null +++ b/reference/shaders-hlsl/comp/num-workgroups-alone.comp @@ -0,0 +1,16 @@ +RWByteAddressBuffer _10 : register(u0); +cbuffer SPIRV_Cross_NumWorkgroups : register(b0) +{ + uint3 SPIRV_Cross_NumWorkgroups_count : packoffset(c0); +}; + +void comp_main() +{ + _10.Store3(0, SPIRV_Cross_NumWorkgroups_count); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp b/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp new file mode 100644 index 00000000..f44754e8 --- /dev/null +++ b/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp @@ -0,0 +1,23 @@ +RWByteAddressBuffer _10 : register(u0); +cbuffer SPIRV_Cross_NumWorkgroups : register(b0) +{ + uint3 SPIRV_Cross_NumWorkgroups_count : packoffset(c0); +}; + +static uint3 gl_WorkGroupID; +struct SPIRV_Cross_Input +{ + uint3 gl_WorkGroupID : SV_GroupID; +}; + +void comp_main() +{ + _10.Store3(0, SPIRV_Cross_NumWorkgroups_count + gl_WorkGroupID); +} + +[numthreads(1, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_WorkGroupID = stage_input.gl_WorkGroupID; + comp_main(); +} diff --git a/shaders-hlsl/comp/num-workgroups-alone.comp b/shaders-hlsl/comp/num-workgroups-alone.comp new file mode 100644 index 00000000..10b5817c --- /dev/null +++ b/shaders-hlsl/comp/num-workgroups-alone.comp @@ -0,0 +1,13 @@ +#version 310 es +layout(local_size_x = 1) in; + +layout(std430, binding = 0) buffer SSBO +{ + uvec3 outdata; +}; + +void main() +{ + outdata = gl_NumWorkGroups; +} + diff --git a/shaders-hlsl/comp/num-workgroups-with-builtins.comp b/shaders-hlsl/comp/num-workgroups-with-builtins.comp new file mode 100644 index 00000000..d19a06c1 --- /dev/null +++ b/shaders-hlsl/comp/num-workgroups-with-builtins.comp @@ -0,0 +1,13 @@ +#version 310 es +layout(local_size_x = 1) in; + +layout(std430, binding = 0) buffer SSBO +{ + uvec3 outdata; +}; + +void main() +{ + outdata = gl_NumWorkGroups + gl_WorkGroupID; +} + diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index 9fbcccf6..794d7b74 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -588,6 +588,10 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() semantic = "SV_GroupID"; break; + case BuiltInNumWorkgroups: + // Handled specially. + break; + default: SPIRV_CROSS_THROW("Unsupported builtin in HLSL."); break; @@ -772,6 +776,15 @@ std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClas return "gl_VertexID"; case BuiltInInstanceId: return "gl_InstanceID"; + case BuiltInNumWorkgroups: + { + if (!num_workgroups_builtin) + SPIRV_CROSS_THROW("NumWorkgroups builtin is used, but remap_num_workgroups_builtin() was not called. Cannot emit code for this builtin."); + + auto &var = get(num_workgroups_builtin); + auto &type = get(var.basetype); + return sanitize_underscores(join(to_name(num_workgroups_builtin), "_", get_member_name(type.self, 0))); + } default: return CompilerGLSL::builtin_to_glsl(builtin, storage); } @@ -827,6 +840,10 @@ void CompilerHLSL::emit_builtin_variables() type = "uint"; break; + case BuiltInNumWorkgroups: + // Handled specially. + break; + default: SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin))); break; @@ -1106,7 +1123,7 @@ void CompilerHLSL::emit_resources() return name1.compare(name2) < 0; }; - if (!input_variables.empty() || active_input_builtins) + if (!input_variables.empty() || (active_input_builtins & ~(1ull << BuiltInNumWorkgroups))) { require_input = true; statement("struct SPIRV_Cross_Input"); @@ -1739,6 +1756,10 @@ void CompilerHLSL::emit_hlsl_entry_point() statement(builtin, " = int(stage_input.", builtin, ");"); break; + case BuiltInNumWorkgroups: + // Handled specially. + break; + default: statement(builtin, " = stage_input.", builtin, ";"); break; @@ -3659,6 +3680,50 @@ string CompilerHLSL::compile(std::vector vertex_attrib return compile(); } +uint32_t CompilerHLSL::remap_num_workgroups_builtin() +{ + update_active_builtins(); + if ((active_input_builtins & (1ull << BuiltInNumWorkgroups)) == 0) + return 0; + + // Create a new, fake UBO. + uint32_t offset = increase_bound_by(4); + + uint32_t uint_type_id = offset; + uint32_t block_type_id = offset + 1; + uint32_t block_pointer_type_id = offset + 2; + uint32_t variable_id = offset + 3; + + SPIRType uint_type; + uint_type.basetype = SPIRType::UInt; + uint_type.vecsize = 3; + uint_type.columns = 1; + set(uint_type_id, uint_type); + + SPIRType block_type; + block_type.basetype = SPIRType::Struct; + block_type.member_types.push_back(uint_type_id); + set(block_type_id, block_type); + set_decoration(block_type_id, DecorationBlock); + set_member_name(block_type_id, 0, "count"); + set_member_decoration(block_type_id, 0, DecorationOffset, 0); + + SPIRType block_pointer_type = block_type; + block_pointer_type.pointer = true; + block_pointer_type.storage = StorageClassUniform; + block_pointer_type.parent_type = block_type_id; + auto &ptr_type = set(block_pointer_type_id, block_pointer_type); + + // Preserve self. + ptr_type.self = block_type_id; + + set(variable_id, block_pointer_type_id, StorageClassUniform); + meta[variable_id].decoration.alias = "SPIRV_Cross_NumWorkgroups"; + + num_workgroups_builtin = variable_id; + return variable_id; +} + string CompilerHLSL::compile() { // Do not deal with ES-isms like precision, older extensions and such. diff --git a/spirv_hlsl.hpp b/spirv_hlsl.hpp index 9b326173..f759ab91 100644 --- a/spirv_hlsl.hpp +++ b/spirv_hlsl.hpp @@ -68,6 +68,18 @@ public: std::string compile(std::vector vertex_attributes); std::string compile() override; + // This is a special HLSL workaround for the NumWorkGroups builtin. + // This does not exist in HLSL, so the calling application must create a dummy cbuffer in + // which the application will store this builtin. + // The cbuffer layout will be: + // cbuffer SPIRV_Cross_NumWorkgroups : register(b#, space#) { uint3 SPIRV_Cross_NumWorkgroups_count; }; + // This must be called before compile(). + // The function returns 0 if NumWorkGroups builtin is not statically used in the shader from the current entry point. + // If non-zero, this returns the variable ID of a cbuffer which corresponds to + // the cbuffer declared above. By default, no binding or descriptor set decoration is set, + // so the calling application should declare explicit bindings on this ID before calling compile(). + uint32_t remap_num_workgroups_builtin(); + private: std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; std::string image_type_hlsl(const SPIRType &type); @@ -159,6 +171,8 @@ private: void emit_io_block(const SPIRVariable &var); std::string to_semantic(uint32_t vertex_location); + + uint32_t num_workgroups_builtin = 0; }; }