Improve handling of block name declaration in GLSL.
HLSL UAVs are a bit annoying because they can share block types, so reflection becomes rather awkward. Sometimes we will need to make some nasty fallbacks, so add a reflection interface which lets you query post-shader compile which names was actually declared in the shader.
This commit is contained in:
parent
a02b008ce0
commit
2c90ea3acc
@ -19,19 +19,19 @@ struct alias_2
|
||||
alias_1 alias_1;
|
||||
};
|
||||
|
||||
layout(binding = 0, std430) buffer _10_11
|
||||
{
|
||||
alias_2 alias;
|
||||
} alias_3;
|
||||
|
||||
layout(binding = 1, std140) buffer _15_16
|
||||
layout(binding = 0, std430) buffer alias_3
|
||||
{
|
||||
alias_2 alias;
|
||||
} alias_4;
|
||||
|
||||
layout(binding = 1, std140) buffer alias_5
|
||||
{
|
||||
alias_2 alias;
|
||||
} alias_6;
|
||||
|
||||
void main()
|
||||
{
|
||||
alias_2 alias_5 = alias_3.alias;
|
||||
alias_4.alias = alias_5;
|
||||
alias_2 alias_7 = alias_4.alias;
|
||||
alias_6.alias = alias_7;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0, std430) buffer Foobar
|
||||
{
|
||||
vec4 _data[];
|
||||
} Foobar_1;
|
||||
|
||||
layout(binding = 1, std430) buffer Foobaz
|
||||
{
|
||||
vec4 _data[];
|
||||
} Foobaz_1;
|
||||
|
||||
layout(location = 0) out vec4 _entryPointOutput;
|
||||
|
||||
void main()
|
||||
{
|
||||
_entryPointOutput = Foobar_1._data[0] + Foobaz_1._data[0];
|
||||
}
|
||||
|
@ -19,19 +19,19 @@ struct alias_2
|
||||
alias_1 alias_1;
|
||||
};
|
||||
|
||||
layout(binding = 0, std430) buffer _10_11
|
||||
{
|
||||
alias_2 alias;
|
||||
} alias_3;
|
||||
|
||||
layout(binding = 1, std140) buffer _15_16
|
||||
layout(binding = 0, std430) buffer alias_3
|
||||
{
|
||||
alias_2 alias;
|
||||
} alias_4;
|
||||
|
||||
layout(binding = 1, std140) buffer alias_5
|
||||
{
|
||||
alias_2 alias;
|
||||
} alias_6;
|
||||
|
||||
void main()
|
||||
{
|
||||
alias_2 alias_5 = alias_3.alias;
|
||||
alias_4.alias = alias_5;
|
||||
alias_2 alias_7 = alias_4.alias;
|
||||
alias_6.alias = alias_7;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0, std430) buffer Foobar
|
||||
{
|
||||
vec4 _data[];
|
||||
} Foobar_1;
|
||||
|
||||
layout(binding = 1, std430) buffer Foobaz
|
||||
{
|
||||
vec4 _data[];
|
||||
} Foobaz_1;
|
||||
|
||||
layout(location = 0) out vec4 _entryPointOutput;
|
||||
|
||||
vec4 _main()
|
||||
{
|
||||
return Foobar_1._data[0] + Foobaz_1._data[0];
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
_entryPointOutput = _main();
|
||||
}
|
||||
|
56
shaders/desktop-only/frag/hlsl-uav-block-alias.asm.frag
Normal file
56
shaders/desktop-only/frag/hlsl-uav-block-alias.asm.frag
Normal file
@ -0,0 +1,56 @@
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 2
|
||||
; Bound: 29
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %_entryPointOutput
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %main "main"
|
||||
OpName %_main_ "@main("
|
||||
OpName %Foobar "Foobar"
|
||||
OpMemberName %Foobar 0 "@data"
|
||||
OpName %Foobar_0 "Foobar"
|
||||
OpName %Foobaz "Foobaz"
|
||||
OpName %_entryPointOutput "@entryPointOutput"
|
||||
OpDecorate %_runtimearr_v4float ArrayStride 16
|
||||
OpMemberDecorate %Foobar 0 Offset 0
|
||||
OpDecorate %Foobar BufferBlock
|
||||
OpDecorate %Foobar_0 DescriptorSet 0
|
||||
OpDecorate %Foobar_0 Binding 0
|
||||
OpDecorate %Foobaz DescriptorSet 0
|
||||
OpDecorate %Foobaz Binding 1
|
||||
OpDecorate %_entryPointOutput Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%8 = OpTypeFunction %v4float
|
||||
%_runtimearr_v4float = OpTypeRuntimeArray %v4float
|
||||
%Foobar = OpTypeStruct %_runtimearr_v4float
|
||||
%_ptr_Uniform_Foobar = OpTypePointer Uniform %Foobar
|
||||
%Foobar_0 = OpVariable %_ptr_Uniform_Foobar Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
|
||||
%Foobaz = OpVariable %_ptr_Uniform_Foobar Uniform
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%28 = OpFunctionCall %v4float %_main_
|
||||
OpStore %_entryPointOutput %28
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%_main_ = OpFunction %v4float None %8
|
||||
%10 = OpLabel
|
||||
%18 = OpAccessChain %_ptr_Uniform_v4float %Foobar_0 %int_0 %int_0
|
||||
%19 = OpLoad %v4float %18
|
||||
%21 = OpAccessChain %_ptr_Uniform_v4float %Foobaz %int_0 %int_0
|
||||
%22 = OpLoad %v4float %21
|
||||
%23 = OpFAdd %v4float %19 %22
|
||||
OpReturnValue %23
|
||||
OpFunctionEnd
|
@ -679,7 +679,7 @@ ShaderResources Compiler::get_shader_resources(const unordered_set<uint32_t> *ac
|
||||
if (var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
if (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock))
|
||||
res.stage_inputs.push_back({ var.self, var.basetype, type.self, meta[type.self].decoration.alias });
|
||||
res.stage_inputs.push_back({ var.self, var.basetype, type.self, get_remapped_declared_block_name(var.self) });
|
||||
else
|
||||
res.stage_inputs.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
@ -692,7 +692,7 @@ ShaderResources Compiler::get_shader_resources(const unordered_set<uint32_t> *ac
|
||||
else if (var.storage == StorageClassOutput && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
if (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock))
|
||||
res.stage_outputs.push_back({ var.self, var.basetype, type.self, meta[type.self].decoration.alias });
|
||||
res.stage_outputs.push_back({ var.self, var.basetype, type.self, get_remapped_declared_block_name(var.self) });
|
||||
else
|
||||
res.stage_outputs.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
@ -700,24 +700,21 @@ ShaderResources Compiler::get_shader_resources(const unordered_set<uint32_t> *ac
|
||||
else if (type.storage == StorageClassUniform &&
|
||||
(meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)))
|
||||
{
|
||||
auto &block_name = meta[type.self].decoration.alias;
|
||||
res.uniform_buffers.push_back({ var.self, var.basetype, type.self,
|
||||
block_name.empty() ? get_block_fallback_name(var.self) : block_name });
|
||||
get_remapped_declared_block_name(var.self) });
|
||||
}
|
||||
// Old way to declare SSBOs.
|
||||
else if (type.storage == StorageClassUniform &&
|
||||
(meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)))
|
||||
{
|
||||
auto &block_name = meta[type.self].decoration.alias;
|
||||
res.storage_buffers.push_back({ var.self, var.basetype, type.self,
|
||||
block_name.empty() ? get_block_fallback_name(var.self) : block_name });
|
||||
get_remapped_declared_block_name(var.self) });
|
||||
}
|
||||
// Modern way to declare SSBOs.
|
||||
else if (type.storage == StorageClassStorageBuffer)
|
||||
{
|
||||
auto &block_name = meta[type.self].decoration.alias;
|
||||
res.storage_buffers.push_back({ var.self, var.basetype, type.self,
|
||||
block_name.empty() ? get_block_fallback_name(var.self) : block_name });
|
||||
get_remapped_declared_block_name(var.self) });
|
||||
}
|
||||
// Push constant blocks
|
||||
else if (type.storage == StorageClassPushConstant)
|
||||
@ -1180,7 +1177,10 @@ const std::string Compiler::get_fallback_name(uint32_t id) const
|
||||
const std::string Compiler::get_block_fallback_name(uint32_t id) const
|
||||
{
|
||||
auto &var = get<SPIRVariable>(id);
|
||||
if (get_name(id).empty())
|
||||
return join("_", get<SPIRType>(var.basetype).self, "_", id);
|
||||
else
|
||||
return get_name(id);
|
||||
}
|
||||
|
||||
uint64_t Compiler::get_decoration_mask(uint32_t id) const
|
||||
@ -3802,3 +3802,17 @@ const std::vector<std::string> &Compiler::get_declared_extensions() const
|
||||
{
|
||||
return declared_extensions;
|
||||
}
|
||||
|
||||
std::string Compiler::get_remapped_declared_block_name(uint32_t id) const
|
||||
{
|
||||
auto itr = declared_block_names.find(id);
|
||||
if (itr != end(declared_block_names))
|
||||
return itr->second;
|
||||
else
|
||||
{
|
||||
auto &var = get<SPIRVariable>(id);
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
auto &block_name = meta[type.self].decoration.alias;
|
||||
return block_name.empty() ? get_block_fallback_name(id) : block_name;
|
||||
}
|
||||
}
|
||||
|
@ -410,6 +410,19 @@ public:
|
||||
// Gets the list of all SPIR-V extensions which were declared in the SPIR-V module.
|
||||
const std::vector<std::string> &get_declared_extensions() const;
|
||||
|
||||
// When declaring buffer blocks in GLSL, the name declared in the GLSL source
|
||||
// might not be the same as the name declared in the SPIR-V module due to naming conflicts.
|
||||
// In this case, SPIRV-Cross needs to find a fallback-name, and it might only
|
||||
// be possible to know this name after compiling to GLSL.
|
||||
// This is particularly important for HLSL input and UAVs which tends to reuse the same block type
|
||||
// for multiple distinct blocks. For these cases it is not possible to modify the name of the type itself
|
||||
// because it might be unique. Instead, you can use this interface to check after compilation which
|
||||
// name was actually used if your input SPIR-V tends to have this problem.
|
||||
// For other names like remapped names for variables, etc, it's generally enough to query the name of the variables
|
||||
// after compiling, block names are an exception to this rule.
|
||||
// ID is the name of a variable as returned by Resource::id, and must be a variable with a Block-like type.
|
||||
std::string get_remapped_declared_block_name(uint32_t id) const;
|
||||
|
||||
protected:
|
||||
const uint32_t *stream(const Instruction &instr) const
|
||||
{
|
||||
@ -729,6 +742,7 @@ protected:
|
||||
|
||||
std::vector<spv::Capability> declared_capabilities;
|
||||
std::vector<std::string> declared_extensions;
|
||||
std::unordered_map<uint32_t, std::string> declared_block_names;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1374,17 +1374,24 @@ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
|
||||
bool is_readonly = ssbo && (flags & (1ull << DecorationNonWritable)) != 0;
|
||||
bool is_coherent = ssbo && (flags & (1ull << DecorationCoherent)) != 0;
|
||||
|
||||
add_resource_name(var.self);
|
||||
|
||||
// Block names should never alias.
|
||||
// Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
|
||||
auto buffer_name = to_name(type.self, false);
|
||||
|
||||
// Shaders never use the block by interface name, so we don't
|
||||
// have to track this other than updating name caches.
|
||||
if (meta[type.self].decoration.alias.empty() || resource_names.find(buffer_name) != end(resource_names))
|
||||
buffer_name = get_block_fallback_name(var.self);
|
||||
else
|
||||
resource_names.insert(buffer_name);
|
||||
|
||||
// Make sure we get something unique.
|
||||
add_variable(resource_names, buffer_name);
|
||||
|
||||
// If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
|
||||
// This cannot conflict with anything else, so we're safe now.
|
||||
if (buffer_name.empty())
|
||||
buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
|
||||
|
||||
// Save for post-reflection later.
|
||||
declared_block_names[var.self] = buffer_name;
|
||||
|
||||
statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
|
||||
is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
|
||||
@ -1402,6 +1409,7 @@ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
|
||||
i++;
|
||||
}
|
||||
|
||||
add_resource_name(var.self);
|
||||
end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
|
||||
statement("");
|
||||
}
|
||||
@ -1521,8 +1529,6 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
|
||||
require_extension("GL_EXT_shader_io_blocks");
|
||||
}
|
||||
|
||||
add_resource_name(var.self);
|
||||
|
||||
// Block names should never alias.
|
||||
auto block_name = to_name(type.self, false);
|
||||
|
||||
@ -1546,6 +1552,7 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
|
||||
i++;
|
||||
}
|
||||
|
||||
add_resource_name(var.self);
|
||||
end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
|
||||
statement("");
|
||||
}
|
||||
@ -7249,9 +7256,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
|
||||
void CompilerGLSL::add_variable(unordered_set<string> &variables, string &name)
|
||||
{
|
||||
auto &name = meta[id].decoration.alias;
|
||||
if (name.empty())
|
||||
return;
|
||||
|
||||
@ -7265,6 +7271,12 @@ void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
|
||||
update_name_cache(variables, name);
|
||||
}
|
||||
|
||||
void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
|
||||
{
|
||||
auto &name = meta[id].decoration.alias;
|
||||
add_variable(variables, name);
|
||||
}
|
||||
|
||||
void CompilerGLSL::add_local_variable_name(uint32_t id)
|
||||
{
|
||||
add_variable(local_variable_names, id);
|
||||
|
@ -488,6 +488,7 @@ protected:
|
||||
void remap_pls_variables();
|
||||
|
||||
void add_variable(std::unordered_set<std::string> &variables, uint32_t id);
|
||||
void add_variable(std::unordered_set<std::string> &variables, std::string &name);
|
||||
void check_function_call_constraints(const uint32_t *args, uint32_t length);
|
||||
void handle_invalid_expression(uint32_t id);
|
||||
void find_static_extensions();
|
||||
|
Loading…
Reference in New Issue
Block a user