Merge pull request #2152 from KhronosGroup/fix-2143

Land PR 2143
This commit is contained in:
Hans-Kristian Arntzen 2023-05-19 12:44:33 +02:00 committed by GitHub
commit 12542fc6fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 314 additions and 24 deletions

View File

@ -732,6 +732,7 @@ struct CLIArguments
bool hlsl_nonwritable_uav_texture_as_srv = false;
bool hlsl_enable_16bit_types = false;
bool hlsl_flatten_matrix_vertex_input_semantics = false;
bool hlsl_preserve_structured_buffers = false;
HLSLBindingFlags hlsl_binding_flags = 0;
bool vulkan_semantics = false;
bool flatten_multidimensional_arrays = false;
@ -839,6 +840,7 @@ static void print_help_hlsl()
"\t\tOpName reflection information must be intact.\n"
"\t[--hlsl-enable-16bit-types]:\n\t\tEnables native use of half/int16_t/uint16_t and ByteAddressBuffer interaction with these types. Requires SM 6.2.\n"
"\t[--hlsl-flatten-matrix-vertex-input-semantics]:\n\t\tEmits matrix vertex inputs with input semantics as if they were independent vectors, e.g. TEXCOORD{2,3,4} rather than matrix form TEXCOORD2_{0,1,2}.\n"
"\t[--hlsl-preserve-structured-buffers]:\n\t\tEmit SturucturedBuffer<T> rather than ByteAddressBuffer. Requires UserTypeGOOGLE to be emitted. Intended for DXC roundtrips.\n"
);
// clang-format on
}
@ -1421,6 +1423,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv;
hlsl_opts.enable_16bit_types = args.hlsl_enable_16bit_types;
hlsl_opts.flatten_matrix_vertex_input_semantics = args.hlsl_flatten_matrix_vertex_input_semantics;
hlsl_opts.preserve_structured_buffers = args.hlsl_preserve_structured_buffers;
hlsl->set_hlsl_options(hlsl_opts);
hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
if (args.hlsl_base_vertex_index_explicit_binding)
@ -1622,6 +1625,7 @@ static int main_inner(int argc, char *argv[])
cbs.add("--hlsl-enable-16bit-types", [&args](CLIParser &) { args.hlsl_enable_16bit_types = true; });
cbs.add("--hlsl-flatten-matrix-vertex-input-semantics",
[&args](CLIParser &) { args.hlsl_flatten_matrix_vertex_input_semantics = true; });
cbs.add("--hlsl-preserve-structured-buffers", [&args](CLIParser &) { args.hlsl_preserve_structured_buffers = true; });
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; });
cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });

View File

@ -0,0 +1,26 @@
struct Data
{
float4 Color;
};
StructuredBuffer<Data> Colors[2] : register(t0);
static float4 out_var_SV_Target;
struct SPIRV_Cross_Output
{
float4 out_var_SV_Target : SV_Target0;
};
void frag_main()
{
out_var_SV_Target = Colors[1][3u].Color;
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.out_var_SV_Target = out_var_SV_Target;
return stage_output;
}

View File

@ -0,0 +1,26 @@
struct Data
{
float4 Color;
};
StructuredBuffer<Data> Colors : register(t0);
static float4 out_var_SV_Target;
struct SPIRV_Cross_Output
{
float4 out_var_SV_Target : SV_Target0;
};
void frag_main()
{
out_var_SV_Target = Colors[3u].Color;
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.out_var_SV_Target = out_var_SV_Target;
return stage_output;
}

View File

@ -0,0 +1,26 @@
struct Data
{
float4 Color;
};
StructuredBuffer<Data> Colors[2] : register(t0);
static float4 out_var_SV_Target;
struct SPIRV_Cross_Output
{
float4 out_var_SV_Target : SV_Target0;
};
void frag_main()
{
out_var_SV_Target = Colors[1][3u].Color;
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.out_var_SV_Target = out_var_SV_Target;
return stage_output;
}

View File

@ -0,0 +1,26 @@
struct Data
{
float4 Color;
};
StructuredBuffer<Data> Colors : register(t0);
static float4 out_var_SV_Target;
struct SPIRV_Cross_Output
{
float4 out_var_SV_Target : SV_Target0;
};
void frag_main()
{
out_var_SV_Target = Colors[3u].Color;
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.out_var_SV_Target = out_var_SV_Target;
return stage_output;
}

View File

@ -0,0 +1,55 @@
; SPIR-V
; Version: 1.3
; Generator: Google spiregg; 0
; Bound: 25
; Schema: 0
OpCapability Shader
OpExtension "SPV_GOOGLE_hlsl_functionality1"
OpExtension "SPV_GOOGLE_user_type"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %out_var_SV_Target
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 660
OpName %type_StructuredBuffer_Data "type.StructuredBuffer.Data"
OpName %Data "Data"
OpMemberName %Data 0 "Color"
OpName %Colors "Colors"
OpName %out_var_SV_Target "out.var.SV_Target"
OpName %main "main"
OpDecorateString %out_var_SV_Target UserSemantic "SV_Target"
OpDecorate %out_var_SV_Target Location 0
OpDecorate %Colors DescriptorSet 0
OpDecorate %Colors Binding 0
OpMemberDecorate %Data 0 Offset 0
OpDecorate %_runtimearr_Data ArrayStride 16
OpMemberDecorate %type_StructuredBuffer_Data 0 Offset 0
OpMemberDecorate %type_StructuredBuffer_Data 0 NonWritable
OpDecorate %type_StructuredBuffer_Data BufferBlock
OpDecorateString %Colors UserTypeGOOGLE "structuredbuffer:<Data>"
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_0 = OpConstant %int 0
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%uint_2 = OpConstant %uint 2
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%Data = OpTypeStruct %v4float
%_runtimearr_Data = OpTypeRuntimeArray %Data
%type_StructuredBuffer_Data = OpTypeStruct %_runtimearr_Data
%_arr_type_StructuredBuffer_Data_uint_2 = OpTypeArray %type_StructuredBuffer_Data %uint_2
%_ptr_Uniform__arr_type_StructuredBuffer_Data_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_Data_uint_2
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%20 = OpTypeFunction %void
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%Colors = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_Data_uint_2 Uniform
%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %20
%22 = OpLabel
%23 = OpAccessChain %_ptr_Uniform_v4float %Colors %int_1 %int_0 %uint_3 %int_0
%24 = OpLoad %v4float %23
OpStore %out_var_SV_Target %24
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,52 @@
; SPIR-V
; Version: 1.3
; Generator: Google spiregg; 0
; Bound: 22
; Schema: 0
OpCapability Shader
OpExtension "SPV_GOOGLE_hlsl_functionality1"
OpExtension "SPV_GOOGLE_user_type"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %out_var_SV_Target
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 660
OpName %type_StructuredBuffer_Data "type.StructuredBuffer.Data"
OpName %Data "Data"
OpMemberName %Data 0 "Color"
OpName %Colors "Colors"
OpName %out_var_SV_Target "out.var.SV_Target"
OpName %main "main"
OpDecorateString %out_var_SV_Target UserSemantic "SV_Target"
OpDecorate %out_var_SV_Target Location 0
OpDecorate %Colors DescriptorSet 0
OpDecorate %Colors Binding 0
OpMemberDecorate %Data 0 Offset 0
OpDecorate %_runtimearr_Data ArrayStride 16
OpMemberDecorate %type_StructuredBuffer_Data 0 Offset 0
OpMemberDecorate %type_StructuredBuffer_Data 0 NonWritable
OpDecorate %type_StructuredBuffer_Data BufferBlock
OpDecorateString %Colors UserTypeGOOGLE "structuredbuffer:<Data>"
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%Data = OpTypeStruct %v4float
%_runtimearr_Data = OpTypeRuntimeArray %Data
%type_StructuredBuffer_Data = OpTypeStruct %_runtimearr_Data
%_ptr_Uniform_type_StructuredBuffer_Data = OpTypePointer Uniform %type_StructuredBuffer_Data
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%17 = OpTypeFunction %void
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%Colors = OpVariable %_ptr_Uniform_type_StructuredBuffer_Data Uniform
%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %17
%19 = OpLabel
%20 = OpAccessChain %_ptr_Uniform_v4float %Colors %int_0 %uint_3 %int_0
%21 = OpLoad %v4float %20
OpStore %out_var_SV_Target %21
OpReturn
OpFunctionEnd

View File

@ -1663,6 +1663,7 @@ struct Meta
std::string alias;
std::string qualified_alias;
std::string hlsl_semantic;
std::string user_type;
Bitset decoration_flags;
spv::BuiltIn builtin_type = spv::BuiltInMax;
uint32_t location = 0;

View File

@ -370,6 +370,10 @@ void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string
dec.hlsl_semantic = argument;
break;
case DecorationUserTypeGOOGLE:
dec.user_type = argument;
break;
default:
break;
}
@ -659,6 +663,9 @@ const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) cons
case DecorationHlslSemanticGOOGLE:
return dec.hlsl_semantic;
case DecorationUserTypeGOOGLE:
return dec.user_type;
default:
return empty_string;
}

View File

@ -9858,6 +9858,9 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
bool pending_array_enclose = false;
bool dimension_flatten = false;
// If we are translating access to a structured buffer, the first subscript '._m0' must be hidden
bool hide_first_subscript = count > 1 && is_user_type_structured(base);
const auto append_index = [&](uint32_t index, bool is_literal, bool is_ptr_chain = false) {
AccessChainFlags mod_flags = flags;
if (!is_literal)
@ -10044,32 +10047,40 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
if (index >= type->member_types.size())
SPIRV_CROSS_THROW("Member index is out of bounds!");
BuiltIn builtin = BuiltInMax;
if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base))
if (hide_first_subscript)
{
if (access_chain_is_arrayed)
{
expr += ".";
expr += builtin_to_glsl(builtin, type->storage);
}
else
expr = builtin_to_glsl(builtin, type->storage);
// First "._m0" subscript has been hidden, subsequent fields must be emitted even for structured buffers
hide_first_subscript = false;
}
else
{
// If the member has a qualified name, use it as the entire chain
string qual_mbr_name = get_member_qualified_name(type_id, index);
if (!qual_mbr_name.empty())
expr = qual_mbr_name;
else if (flatten_member_reference)
expr += join("_", to_member_name(*type, index));
BuiltIn builtin = BuiltInMax;
if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base))
{
if (access_chain_is_arrayed)
{
expr += ".";
expr += builtin_to_glsl(builtin, type->storage);
}
else
expr = builtin_to_glsl(builtin, type->storage);
}
else
{
// Any pointer de-refences for values are handled in the first access chain.
// For pointer chains, the pointer-ness is resolved through an array access.
// The only time this is not true is when accessing array of SSBO/UBO.
// This case is explicitly handled.
expr += to_member_reference(base, *type, index, ptr_chain || i != 0);
// If the member has a qualified name, use it as the entire chain
string qual_mbr_name = get_member_qualified_name(type_id, index);
if (!qual_mbr_name.empty())
expr = qual_mbr_name;
else if (flatten_member_reference)
expr += join("_", to_member_name(*type, index));
else
{
// Any pointer de-refences for values are handled in the first access chain.
// For pointer chains, the pointer-ness is resolved through an array access.
// The only time this is not true is when accessing array of SSBO/UBO.
// This case is explicitly handled.
expr += to_member_reference(base, *type, index, ptr_chain || i != 0);
}
}
}
@ -15587,6 +15598,11 @@ bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) cons
return false; // GLSL itself does not need to translate array builtin types to non-array builtin types
}
bool CompilerGLSL::is_user_type_structured(uint32_t /*id*/) const
{
return false; // GLSL itself does not have structured user type, but HLSL does with StructuredBuffer and RWStructuredBuffer resources.
}
bool CompilerGLSL::check_atomic_image(uint32_t id)
{
auto &type = expression_type(id);

View File

@ -477,6 +477,8 @@ protected:
virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const;
virtual bool is_user_type_structured(uint32_t id) const;
void emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id,
SmallVector<uint32_t> chain);

View File

@ -2603,11 +2603,30 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
bool is_coherent = flags.get(DecorationCoherent) && !is_readonly;
bool is_interlocked = interlocked_resources.count(var.self) > 0;
const char *type_name = "ByteAddressBuffer ";
if (!is_readonly)
type_name = is_interlocked ? "RasterizerOrderedByteAddressBuffer " : "RWByteAddressBuffer ";
auto to_structuredbuffer_subtype_name = [this](const SPIRType &parent_type) -> std::string
{
if (parent_type.basetype == SPIRType::Struct && parent_type.member_types.size() == 1)
{
// Use type of first struct member as a StructuredBuffer will have only one '._m0' field in SPIR-V
const auto &member0_type = this->get<SPIRType>(parent_type.member_types.front());
return this->type_to_glsl(member0_type);
}
else
{
// Otherwise, this StructuredBuffer only has a basic subtype, e.g. StructuredBuffer<int>
return this->type_to_glsl(parent_type);
}
};
std::string type_name;
if (is_user_type_structured(var.self))
type_name = join(is_readonly ? "" : is_interlocked ? "RasterizerOrdered" : "RW", "StructuredBuffer<", to_structuredbuffer_subtype_name(type), ">");
else
type_name = is_readonly ? "ByteAddressBuffer" : is_interlocked ? "RasterizerOrderedByteAddressBuffer" : "RWByteAddressBuffer";
add_resource_name(var.self);
statement(is_coherent ? "globallycoherent " : "", type_name, to_name(var.self), type_to_array_glsl(type),
statement(is_coherent ? "globallycoherent " : "", type_name, " ", to_name(var.self), type_to_array_glsl(type),
to_resource_binding(var), ";");
}
else
@ -4969,6 +4988,12 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
auto *backing_variable = maybe_get_backing_variable(ops[2]);
if (backing_variable != nullptr && is_user_type_structured(backing_variable->self))
{
CompilerGLSL::emit_instruction(instruction);
return;
}
string base;
if (to_plain_buffer_length != 0)
base = access_chain(ops[2], &ops[3], to_plain_buffer_length, get<SPIRType>(ops[0]));
@ -6693,3 +6718,17 @@ bool CompilerHLSL::builtin_translates_to_nonarray(spv::BuiltIn builtin) const
{
return (builtin == BuiltInSampleMask);
}
bool CompilerHLSL::is_user_type_structured(uint32_t id) const
{
if (hlsl_options.preserve_structured_buffers)
{
// Compare left hand side of string only as these user types can contain more meta data such as their subtypes,
// e.g. "structuredbuffer:int"
const std::string &user_type = get_decoration_string(id, DecorationUserTypeGOOGLE);
return user_type.compare(0, 16, "structuredbuffer") == 0 ||
user_type.compare(0, 18, "rwstructuredbuffer") == 0 ||
user_type.compare(0, 33, "rasterizerorderedstructuredbuffer") == 0;
}
return false;
}

View File

@ -145,6 +145,11 @@ public:
// Rather than emitting main() for the entry point, use the name in SPIR-V.
bool use_entry_point_name = false;
// Preserve (RW)StructuredBuffer types if the input source was HLSL.
// This relies on UserTypeGOOGLE to encode the buffer type either as "structuredbuffer" or "rwstructuredbuffer"
// whereas the type can be extended with an optional subtype, e.g. "structuredbuffer:int".
bool preserve_structured_buffers = false;
};
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
@ -398,6 +403,9 @@ private:
// Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but SV_Coverage is a scalar in HLSL.
bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override;
// Returns true if the specified ID has a UserTypeGOOGLE decoration for StructuredBuffer or RWStructuredBuffer resources.
bool is_user_type_structured(uint32_t id) const override;
std::vector<TypeID> composite_selection_workaround_types;
std::string get_inner_entry_point_name() const;

View File

@ -515,6 +515,8 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati
hlsl_args.append('--hlsl-flatten-matrix-vertex-input-semantics')
if '.relax-nan.' in shader:
hlsl_args.append('--relax-nan-checks')
if '.structured.' in shader:
hlsl_args.append('--hlsl-preserve-structured-buffers')
subprocess.check_call(hlsl_args)