hlsl: Support custom root constant layout
This commit is contained in:
parent
4b58f65af7
commit
d096f5cafe
@ -1040,7 +1040,8 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, uint64_t flags,
|
||||
return size;
|
||||
}
|
||||
|
||||
bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing)
|
||||
bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
|
||||
uint32_t start_offset, uint32_t end_offset)
|
||||
{
|
||||
// This is very tricky and error prone, but try to be exhaustive and correct here.
|
||||
// SPIR-V doesn't directly say if we're using std430 or std140.
|
||||
@ -1079,6 +1080,10 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
|
||||
uint32_t alignment = max(packed_alignment, pad_alignment);
|
||||
offset = (offset + alignment - 1) & ~(alignment - 1);
|
||||
|
||||
// Field is not in the specified range anymore and we can ignore any further fields.
|
||||
if (offset >= end_offset)
|
||||
break;
|
||||
|
||||
// The next member following a struct member is aligned to the base alignment of the struct that came before.
|
||||
// GL 4.5 spec, 7.6.2.2.
|
||||
if (memb_type.basetype == SPIRType::Struct)
|
||||
@ -1086,6 +1091,9 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
|
||||
else
|
||||
pad_alignment = 1;
|
||||
|
||||
// Only care about packing if we are in the given range
|
||||
if (offset >= start_offset)
|
||||
{
|
||||
// We only care about offsets in std140, std430, etc ...
|
||||
// For EnhancedLayout variants, we have the flexibility to choose our own offsets.
|
||||
if (!packing_has_flexible_offset(packing))
|
||||
@ -1096,8 +1104,8 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
|
||||
}
|
||||
|
||||
// Verify array stride rules.
|
||||
if (!memb_type.array.empty() &&
|
||||
type_to_packed_array_stride(memb_type, member_flags, packing) != type_struct_member_array_stride(type, i))
|
||||
if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
|
||||
type_struct_member_array_stride(type, i))
|
||||
return false;
|
||||
|
||||
// Verify that sub-structs also follow packing rules.
|
||||
@ -1106,6 +1114,7 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
|
||||
|
||||
if (!memb_type.member_types.empty() && !buffer_is_packing_standard(memb_type, substruct_packing))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bump size.
|
||||
offset += packed_size;
|
||||
@ -7066,7 +7075,7 @@ string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uin
|
||||
// Emit a structure member. Subclasses may override to modify output,
|
||||
// or to dynamically add a padding member if needed.
|
||||
void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const string &qualifier)
|
||||
const string &qualifier, uint32_t)
|
||||
{
|
||||
auto &membertype = get<SPIRType>(member_type_id);
|
||||
|
||||
|
@ -202,7 +202,7 @@ protected:
|
||||
virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0);
|
||||
virtual std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage);
|
||||
virtual void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const std::string &qualifier = "");
|
||||
const std::string &qualifier = "", uint32_t base_offset = 0);
|
||||
virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0);
|
||||
virtual std::string constant_expression(const SPIRConstant &c);
|
||||
std::string constant_op_expression(const SPIRConstantOp &cop);
|
||||
@ -424,7 +424,8 @@ protected:
|
||||
std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id);
|
||||
virtual bool skip_argument(uint32_t id) const;
|
||||
|
||||
bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing);
|
||||
bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, uint32_t start_offset = 0,
|
||||
uint32_t end_offset = std::numeric_limits<uint32_t>::max());
|
||||
uint32_t type_to_packed_base_size(const SPIRType &type, BufferPackingStandard packing);
|
||||
uint32_t type_to_packed_alignment(const SPIRType &type, uint64_t flags, BufferPackingStandard packing);
|
||||
uint32_t type_to_packed_array_stride(const SPIRType &type, uint64_t flags, BufferPackingStandard packing);
|
||||
|
102
spirv_hlsl.cpp
102
spirv_hlsl.cpp
@ -779,7 +779,8 @@ std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClas
|
||||
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.");
|
||||
SPIRV_CROSS_THROW("NumWorkgroups builtin is used, but remap_num_workgroups_builtin() was not called. "
|
||||
"Cannot emit code for this builtin.");
|
||||
|
||||
auto &var = get<SPIRVariable>(num_workgroups_builtin);
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
@ -1459,7 +1460,7 @@ string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index)
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const string &qualifier)
|
||||
const string &qualifier, uint32_t base_offset)
|
||||
{
|
||||
auto &membertype = get<SPIRType>(member_type_id);
|
||||
|
||||
@ -1475,9 +1476,12 @@ void CompilerHLSL::emit_struct_member(const SPIRType &type, uint32_t member_type
|
||||
qualifiers = to_interpolation_qualifiers(memberflags);
|
||||
|
||||
string packing_offset;
|
||||
if (has_decoration(type.self, DecorationCPacked) && has_member_decoration(type.self, index, DecorationOffset))
|
||||
bool is_push_constant = type.storage == StorageClassPushConstant;
|
||||
|
||||
if ((has_decoration(type.self, DecorationCPacked) || is_push_constant) &&
|
||||
has_member_decoration(type.self, index, DecorationOffset))
|
||||
{
|
||||
uint32_t offset = memb[index].offset;
|
||||
uint32_t offset = memb[index].offset - base_offset;
|
||||
if (offset & 3)
|
||||
SPIRV_CROSS_THROW("Cannot pack on tighter bounds than 4 bytes in HLSL.");
|
||||
|
||||
@ -1556,9 +1560,60 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_push_constant_block(const SPIRVariable &var)
|
||||
{
|
||||
if (root_constants_layout.empty())
|
||||
{
|
||||
emit_buffer_block(var);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &layout : root_constants_layout)
|
||||
{
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset, layout.start, layout.end))
|
||||
set_decoration(type.self, DecorationCPacked);
|
||||
else
|
||||
SPIRV_CROSS_THROW(
|
||||
"root constant cbuffer cannot be expressed with either HLSL packing layout or packoffset.");
|
||||
|
||||
flattened_structs.insert(var.self);
|
||||
type.member_name_cache.clear();
|
||||
add_resource_name(var.self);
|
||||
auto &memb = meta[type.self].members;
|
||||
|
||||
statement("cbuffer SPIRV_CROSS_RootConstant_", to_name(var.self),
|
||||
to_resource_register('b', layout.binding, layout.space));
|
||||
begin_scope();
|
||||
|
||||
// Index of the next field in the generated root constant constant buffer
|
||||
auto constant_index = 0u;
|
||||
|
||||
// Iterate over all member of the push constant and check which of the fields
|
||||
// fit into the given root constant layout.
|
||||
for (auto i = 0u; i < memb.size(); i++)
|
||||
{
|
||||
const auto offset = memb[i].offset;
|
||||
if (layout.start <= offset && offset < layout.end)
|
||||
{
|
||||
const auto &member = type.member_types[i];
|
||||
|
||||
add_member_name(type, constant_index);
|
||||
auto backup_name = get_member_name(type.self, i);
|
||||
auto member_name = to_member_name(type, i);
|
||||
set_member_name(type.self, constant_index,
|
||||
sanitize_underscores(join(to_name(type.self), "_", member_name)));
|
||||
emit_struct_member(type, member, i, "", layout.start);
|
||||
set_member_name(type.self, constant_index, backup_name);
|
||||
|
||||
constant_index++;
|
||||
}
|
||||
}
|
||||
|
||||
end_scope_decl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_sampler_expression(uint32_t id)
|
||||
{
|
||||
@ -2316,24 +2371,24 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||
if (!has_decoration(var.self, DecorationBinding))
|
||||
return "";
|
||||
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
const char *space = nullptr;
|
||||
const auto &type = get<SPIRType>(var.basetype);
|
||||
char space = '\0';
|
||||
|
||||
switch (type.basetype)
|
||||
{
|
||||
case SPIRType::SampledImage:
|
||||
space = "t"; // SRV
|
||||
space = 't'; // SRV
|
||||
break;
|
||||
|
||||
case SPIRType::Image:
|
||||
if (type.image.sampled == 2)
|
||||
space = "u"; // UAV
|
||||
space = 'u'; // UAV
|
||||
else
|
||||
space = "t"; // SRV
|
||||
space = 't'; // SRV
|
||||
break;
|
||||
|
||||
case SPIRType::Sampler:
|
||||
space = "s";
|
||||
space = 's';
|
||||
break;
|
||||
|
||||
case SPIRType::Struct:
|
||||
@ -2345,15 +2400,15 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||
{
|
||||
uint64_t flags = get_buffer_block_flags(var);
|
||||
bool is_readonly = (flags & (1ull << DecorationNonWritable)) != 0;
|
||||
space = is_readonly ? "t" : "u"; // UAV
|
||||
space = is_readonly ? 't' : 'u'; // UAV
|
||||
}
|
||||
else if (has_decoration(type.self, DecorationBlock))
|
||||
space = "b"; // Constant buffers
|
||||
space = 'b'; // Constant buffers
|
||||
}
|
||||
else if (storage == StorageClassPushConstant)
|
||||
space = "b"; // Constant buffers
|
||||
space = 'b'; // Constant buffers
|
||||
else if (storage == StorageClassStorageBuffer)
|
||||
space = "u"; // UAV
|
||||
space = 'u'; // UAV
|
||||
|
||||
break;
|
||||
}
|
||||
@ -2364,12 +2419,8 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||
if (!space)
|
||||
return "";
|
||||
|
||||
// shader model 5.1 supports space
|
||||
if (options.shader_model >= 51)
|
||||
return join(" : register(", space, get_decoration(var.self, DecorationBinding), ", space",
|
||||
get_decoration(var.self, DecorationDescriptorSet), ")");
|
||||
else
|
||||
return join(" : register(", space, get_decoration(var.self, DecorationBinding), ")");
|
||||
return to_resource_register(space, get_decoration(var.self, DecorationBinding),
|
||||
get_decoration(var.self, DecorationDescriptorSet));
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
|
||||
@ -2378,11 +2429,16 @@ string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
|
||||
if (!has_decoration(var.self, DecorationBinding))
|
||||
return "";
|
||||
|
||||
return to_resource_register('s', get_decoration(var.self, DecorationBinding),
|
||||
get_decoration(var.self, DecorationDescriptorSet));
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_resource_register(char space, uint32_t binding, uint32_t space_set)
|
||||
{
|
||||
if (options.shader_model >= 51)
|
||||
return join(" : register(s", get_decoration(var.self, DecorationBinding), ", space",
|
||||
get_decoration(var.self, DecorationDescriptorSet), ")");
|
||||
return join(" : register(", space, binding, ", space", space_set, ")");
|
||||
else
|
||||
return join(" : register(s", get_decoration(var.self, DecorationBinding), ")");
|
||||
return join(" : register(", space, binding, ")");
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var)
|
||||
|
@ -29,6 +29,18 @@ struct HLSLVertexAttributeRemap
|
||||
uint32_t location;
|
||||
std::string semantic;
|
||||
};
|
||||
// Specifying a root constant (d3d12) or push constant range (vulkan).
|
||||
//
|
||||
// `start` and `end` denotes the range of the root constant in bytes.
|
||||
// Both values need to be multiple of 4.
|
||||
struct RootConstants
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
|
||||
uint32_t binding;
|
||||
uint32_t space;
|
||||
};
|
||||
|
||||
class CompilerHLSL : public CompilerGLSL
|
||||
{
|
||||
@ -61,6 +73,15 @@ public:
|
||||
options = opts;
|
||||
}
|
||||
|
||||
// Optionally specify a custom root constant layout.
|
||||
//
|
||||
// Push constants ranges will be split up according to the
|
||||
// layout specified.
|
||||
void set_root_constant_layouts(std::vector<RootConstants> layout)
|
||||
{
|
||||
root_constants_layout = std::move(layout);
|
||||
}
|
||||
|
||||
// Compiles and remaps vertex attributes at specific locations to a fixed semantic.
|
||||
// The default is TEXCOORD# where # denotes location.
|
||||
// Matrices are unrolled to vectors with notation ${SEMANTIC}_#, where # denotes row.
|
||||
@ -113,6 +134,7 @@ private:
|
||||
std::string to_sampler_expression(uint32_t id);
|
||||
std::string to_resource_binding(const SPIRVariable &var);
|
||||
std::string to_resource_binding_sampler(const SPIRVariable &var);
|
||||
std::string to_resource_register(char space, uint32_t binding, uint32_t set);
|
||||
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
|
||||
void emit_access_chain(const Instruction &instruction);
|
||||
void emit_load(const Instruction &instruction);
|
||||
@ -121,8 +143,8 @@ private:
|
||||
void emit_store(const Instruction &instruction);
|
||||
void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op);
|
||||
|
||||
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const std::string &qualifier) override;
|
||||
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier,
|
||||
uint32_t base_offset = 0) override;
|
||||
|
||||
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
||||
|
||||
@ -173,6 +195,10 @@ private:
|
||||
std::string to_semantic(uint32_t vertex_location);
|
||||
|
||||
uint32_t num_workgroups_builtin = 0;
|
||||
|
||||
// Custom root constant layout, which should be emitted
|
||||
// when translating push constant ranges.
|
||||
std::vector<RootConstants> root_constants_layout;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2394,7 +2394,7 @@ void CompilerMSL::emit_fixup()
|
||||
|
||||
// Emit a structure member, padding and packing to maintain the correct memeber alignments.
|
||||
void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const string &qualifier)
|
||||
const string &qualifier, uint32_t)
|
||||
{
|
||||
auto &membertype = get<SPIRType>(member_type_id);
|
||||
|
||||
|
@ -187,7 +187,7 @@ protected:
|
||||
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
|
||||
void emit_fixup() override;
|
||||
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
|
||||
const std::string &qualifier = "") override;
|
||||
const std::string &qualifier = "", uint32_t base_offset = 0) override;
|
||||
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||
std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||
std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override;
|
||||
|
Loading…
Reference in New Issue
Block a user