Merge pull request #1256 from KhronosGroup/fix-1252
HLSL: Add a resource remapping API similar to MSL.
This commit is contained in:
commit
74107a04d1
@ -312,7 +312,7 @@ if (SPIRV_CROSS_STATIC)
|
||||
endif()
|
||||
|
||||
set(spirv-cross-abi-major 0)
|
||||
set(spirv-cross-abi-minor 21)
|
||||
set(spirv-cross-abi-minor 22)
|
||||
set(spirv-cross-abi-patch 0)
|
||||
|
||||
if (SPIRV_CROSS_SHARED)
|
||||
@ -491,6 +491,10 @@ if (SPIRV_CROSS_CLI)
|
||||
target_link_libraries(spirv-cross-msl-resource-binding-test spirv-cross-c)
|
||||
set_target_properties(spirv-cross-msl-resource-binding-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}")
|
||||
|
||||
add_executable(spirv-cross-hlsl-resource-binding-test tests-other/hlsl_resource_bindings.cpp)
|
||||
target_link_libraries(spirv-cross-hlsl-resource-binding-test spirv-cross-c)
|
||||
set_target_properties(spirv-cross-hlsl-resource-binding-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}")
|
||||
|
||||
add_executable(spirv-cross-msl-ycbcr-conversion-test tests-other/msl_ycbcr_conversion_test.cpp)
|
||||
target_link_libraries(spirv-cross-msl-ycbcr-conversion-test spirv-cross-c)
|
||||
set_target_properties(spirv-cross-msl-ycbcr-conversion-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}")
|
||||
@ -513,6 +517,8 @@ if (SPIRV_CROSS_CLI)
|
||||
COMMAND $<TARGET_FILE:spirv-cross-msl-constexpr-test> ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_constexpr_test.spv)
|
||||
add_test(NAME spirv-cross-msl-resource-binding-test
|
||||
COMMAND $<TARGET_FILE:spirv-cross-msl-resource-binding-test> ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_resource_binding.spv)
|
||||
add_test(NAME spirv-cross-hlsl-resource-binding-test
|
||||
COMMAND $<TARGET_FILE:spirv-cross-hlsl-resource-binding-test> ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/hlsl_resource_binding.spv)
|
||||
add_test(NAME spirv-cross-msl-ycbcr-conversion-test
|
||||
COMMAND $<TARGET_FILE:spirv-cross-msl-ycbcr-conversion-test> ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_ycbcr_conversion_test.spv)
|
||||
add_test(NAME spirv-cross-msl-ycbcr-conversion-test-2
|
||||
|
@ -1694,6 +1694,62 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct SetBindingPair
|
||||
{
|
||||
uint32_t desc_set;
|
||||
uint32_t binding;
|
||||
|
||||
inline bool operator==(const SetBindingPair &other) const
|
||||
{
|
||||
return desc_set == other.desc_set && binding == other.binding;
|
||||
}
|
||||
|
||||
inline bool operator<(const SetBindingPair &other) const
|
||||
{
|
||||
return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding);
|
||||
}
|
||||
};
|
||||
|
||||
struct StageSetBinding
|
||||
{
|
||||
spv::ExecutionModel model;
|
||||
uint32_t desc_set;
|
||||
uint32_t binding;
|
||||
|
||||
inline bool operator==(const StageSetBinding &other) const
|
||||
{
|
||||
return model == other.model && desc_set == other.desc_set && binding == other.binding;
|
||||
}
|
||||
};
|
||||
|
||||
struct InternalHasher
|
||||
{
|
||||
inline size_t operator()(const SetBindingPair &value) const
|
||||
{
|
||||
// Quality of hash doesn't really matter here.
|
||||
auto hash_set = std::hash<uint32_t>()(value.desc_set);
|
||||
auto hash_binding = std::hash<uint32_t>()(value.binding);
|
||||
return (hash_set * 0x10001b31) ^ hash_binding;
|
||||
}
|
||||
|
||||
inline size_t operator()(const StageSetBinding &value) const
|
||||
{
|
||||
// Quality of hash doesn't really matter here.
|
||||
auto hash_model = std::hash<uint32_t>()(value.model);
|
||||
auto hash_set = std::hash<uint32_t>()(value.desc_set);
|
||||
auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set;
|
||||
return (tmp_hash * 0x10001b31) ^ value.binding;
|
||||
}
|
||||
};
|
||||
|
||||
// Special constant used in a {MSL,HLSL}ResourceBinding desc_set
|
||||
// element to indicate the bindings for the push constants.
|
||||
static const uint32_t ResourceBindingPushConstantDescriptorSet = ~(0u);
|
||||
|
||||
// Special constant used in a {MSL,HLSL}ResourceBinding binding
|
||||
// element to indicate the bindings for the push constants.
|
||||
static const uint32_t ResourceBindingPushConstantBinding = 0;
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
namespace std
|
||||
|
@ -789,6 +789,60 @@ spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler
|
||||
#endif
|
||||
}
|
||||
|
||||
spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler,
|
||||
const spvc_hlsl_resource_binding *binding)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_HLSL
|
||||
if (compiler->backend != SPVC_BACKEND_HLSL)
|
||||
{
|
||||
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
|
||||
return SPVC_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
auto &hlsl = *static_cast<CompilerHLSL *>(compiler->compiler.get());
|
||||
HLSLResourceBinding bind;
|
||||
bind.binding = binding->binding;
|
||||
bind.desc_set = binding->desc_set;
|
||||
bind.stage = static_cast<spv::ExecutionModel>(binding->stage);
|
||||
bind.cbv.register_binding = binding->cbv.register_binding;
|
||||
bind.cbv.register_space = binding->cbv.register_space;
|
||||
bind.uav.register_binding = binding->uav.register_binding;
|
||||
bind.uav.register_space = binding->uav.register_space;
|
||||
bind.srv.register_binding = binding->srv.register_binding;
|
||||
bind.srv.register_space = binding->srv.register_space;
|
||||
bind.sampler.register_binding = binding->sampler.register_binding;
|
||||
bind.sampler.register_space = binding->sampler.register_space;
|
||||
hlsl.add_hlsl_resource_binding(bind);
|
||||
return SPVC_SUCCESS;
|
||||
#else
|
||||
(void)binding;
|
||||
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
|
||||
return SPVC_ERROR_INVALID_ARGUMENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set,
|
||||
unsigned binding)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_HLSL
|
||||
if (compiler->backend != SPVC_BACKEND_HLSL)
|
||||
{
|
||||
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
|
||||
return SPVC_FALSE;
|
||||
}
|
||||
|
||||
auto &hlsl = *static_cast<CompilerHLSL *>(compiler->compiler.get());
|
||||
return hlsl.is_hlsl_resource_binding_used(static_cast<spv::ExecutionModel>(model), set, binding) ? SPVC_TRUE :
|
||||
SPVC_FALSE;
|
||||
#else
|
||||
(void)model;
|
||||
(void)set;
|
||||
(void)binding;
|
||||
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
|
||||
return SPVC_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_MSL
|
||||
@ -2157,6 +2211,26 @@ void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding)
|
||||
#endif
|
||||
}
|
||||
|
||||
void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_HLSL
|
||||
HLSLResourceBinding binding_default;
|
||||
binding->desc_set = binding_default.desc_set;
|
||||
binding->binding = binding_default.binding;
|
||||
binding->cbv.register_binding = binding_default.cbv.register_binding;
|
||||
binding->cbv.register_space = binding_default.cbv.register_space;
|
||||
binding->srv.register_binding = binding_default.srv.register_binding;
|
||||
binding->srv.register_space = binding_default.srv.register_space;
|
||||
binding->uav.register_binding = binding_default.uav.register_binding;
|
||||
binding->uav.register_space = binding_default.uav.register_space;
|
||||
binding->sampler.register_binding = binding_default.sampler.register_binding;
|
||||
binding->sampler.register_space = binding_default.sampler.register_space;
|
||||
binding->stage = static_cast<SpvExecutionModel>(binding_default.stage);
|
||||
#else
|
||||
memset(binding, 0, sizeof(*binding));
|
||||
#endif
|
||||
}
|
||||
|
||||
void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_MSL
|
||||
|
@ -33,7 +33,7 @@ extern "C" {
|
||||
/* Bumped if ABI or API breaks backwards compatibility. */
|
||||
#define SPVC_C_API_VERSION_MAJOR 0
|
||||
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
|
||||
#define SPVC_C_API_VERSION_MINOR 21
|
||||
#define SPVC_C_API_VERSION_MINOR 22
|
||||
/* Bumped if internal implementation details change. */
|
||||
#define SPVC_C_API_VERSION_PATCH 0
|
||||
|
||||
@ -469,6 +469,7 @@ SPVC_PUBLIC_API void spvc_msl_sampler_ycbcr_conversion_init(spvc_msl_sampler_ycb
|
||||
/* Maps to C++ API. */
|
||||
typedef enum spvc_hlsl_binding_flag_bits
|
||||
{
|
||||
SPVC_HLSL_BINDING_AUTO_NONE_BIT = 0,
|
||||
SPVC_HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0,
|
||||
SPVC_HLSL_BINDING_AUTO_CBV_BIT = 1 << 1,
|
||||
SPVC_HLSL_BINDING_AUTO_SRV_BIT = 1 << 2,
|
||||
@ -478,6 +479,31 @@ typedef enum spvc_hlsl_binding_flag_bits
|
||||
} spvc_hlsl_binding_flag_bits;
|
||||
typedef unsigned spvc_hlsl_binding_flags;
|
||||
|
||||
#define SPVC_HLSL_PUSH_CONSTANT_DESC_SET (~(0u))
|
||||
#define SPVC_HLSL_PUSH_CONSTANT_BINDING (0)
|
||||
|
||||
/* Maps to C++ API. */
|
||||
typedef struct spvc_hlsl_resource_binding_mapping
|
||||
{
|
||||
unsigned register_space;
|
||||
unsigned register_binding;
|
||||
} spvc_hlsl_resource_binding_mapping;
|
||||
|
||||
typedef struct spvc_hlsl_resource_binding
|
||||
{
|
||||
SpvExecutionModel stage;
|
||||
unsigned desc_set;
|
||||
unsigned binding;
|
||||
|
||||
spvc_hlsl_resource_binding_mapping cbv, uav, srv, sampler;
|
||||
} spvc_hlsl_resource_binding;
|
||||
|
||||
/*
|
||||
* Initializes the resource binding struct.
|
||||
* The defaults are non-zero.
|
||||
*/
|
||||
SPVC_PUBLIC_API void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding);
|
||||
|
||||
/* Maps to the various spirv_cross::Compiler*::Option structures. See C++ API for defaults and details. */
|
||||
typedef enum spvc_compiler_option
|
||||
{
|
||||
@ -621,6 +647,13 @@ SPVC_PUBLIC_API spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin
|
||||
SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler,
|
||||
spvc_hlsl_binding_flags flags);
|
||||
|
||||
SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler,
|
||||
const spvc_hlsl_resource_binding *binding);
|
||||
SPVC_PUBLIC_API spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler,
|
||||
SpvExecutionModel model,
|
||||
unsigned set,
|
||||
unsigned binding);
|
||||
|
||||
/*
|
||||
* MSL specifics.
|
||||
* Maps to C++ API.
|
||||
|
@ -2934,16 +2934,15 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
|
||||
string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||
{
|
||||
// TODO: Basic implementation, might need special consideration for RW/RO structured buffers,
|
||||
// RW/RO images, and so on.
|
||||
const auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (!has_decoration(var.self, DecorationBinding))
|
||||
// We can remap push constant blocks, even if they don't have any binding decoration.
|
||||
if (type.storage != StorageClassPushConstant && !has_decoration(var.self, DecorationBinding))
|
||||
return "";
|
||||
|
||||
const auto &type = get<SPIRType>(var.basetype);
|
||||
char space = '\0';
|
||||
|
||||
HLSLBindingFlags resource_flags = 0;
|
||||
HLSLBindingFlagBits resource_flags = HLSL_BINDING_AUTO_NONE_BIT;
|
||||
|
||||
switch (type.basetype)
|
||||
{
|
||||
@ -3011,8 +3010,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||
if (!space)
|
||||
return "";
|
||||
|
||||
return to_resource_register(resource_flags, space, get_decoration(var.self, DecorationBinding),
|
||||
get_decoration(var.self, DecorationDescriptorSet));
|
||||
uint32_t desc_set =
|
||||
resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantDescriptorSet : 0u;
|
||||
uint32_t binding = resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantBinding : 0u;
|
||||
|
||||
if (has_decoration(var.self, DecorationBinding))
|
||||
binding = get_decoration(var.self, DecorationBinding);
|
||||
if (has_decoration(var.self, DecorationDescriptorSet))
|
||||
desc_set = get_decoration(var.self, DecorationDescriptorSet);
|
||||
|
||||
return to_resource_register(resource_flags, space, binding, desc_set);
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
|
||||
@ -3025,10 +3032,54 @@ string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
|
||||
get_decoration(var.self, DecorationDescriptorSet));
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_resource_register(uint32_t flags, char space, uint32_t binding, uint32_t space_set)
|
||||
void CompilerHLSL::remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding)
|
||||
{
|
||||
if ((flags & resource_binding_flags) == 0)
|
||||
auto itr = resource_bindings.find({ get_execution_model(), desc_set, binding });
|
||||
if (itr != end(resource_bindings))
|
||||
{
|
||||
auto &remap = itr->second;
|
||||
remap.second = true;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT:
|
||||
case HLSL_BINDING_AUTO_CBV_BIT:
|
||||
desc_set = remap.first.cbv.register_space;
|
||||
binding = remap.first.cbv.register_binding;
|
||||
break;
|
||||
|
||||
case HLSL_BINDING_AUTO_SRV_BIT:
|
||||
desc_set = remap.first.srv.register_space;
|
||||
binding = remap.first.srv.register_binding;
|
||||
break;
|
||||
|
||||
case HLSL_BINDING_AUTO_SAMPLER_BIT:
|
||||
desc_set = remap.first.sampler.register_space;
|
||||
binding = remap.first.sampler.register_binding;
|
||||
break;
|
||||
|
||||
case HLSL_BINDING_AUTO_UAV_BIT:
|
||||
desc_set = remap.first.uav.register_space;
|
||||
binding = remap.first.uav.register_binding;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t space_set)
|
||||
{
|
||||
if ((flag & resource_binding_flags) == 0)
|
||||
{
|
||||
remap_hlsl_resource_binding(flag, space_set, binding);
|
||||
|
||||
// The push constant block did not have a binding, and there were no remap for it,
|
||||
// so, declare without register binding.
|
||||
if (flag == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT && space_set == ResourceBindingPushConstantDescriptorSet)
|
||||
return "";
|
||||
|
||||
if (hlsl_options.shader_model >= 51)
|
||||
return join(" : register(", space, binding, ", space", space_set, ")");
|
||||
else
|
||||
@ -5215,3 +5266,16 @@ string CompilerHLSL::get_unique_identifier()
|
||||
{
|
||||
return join("_", unique_identifier_count++, "ident");
|
||||
}
|
||||
|
||||
void CompilerHLSL::add_hlsl_resource_binding(const HLSLResourceBinding &binding)
|
||||
{
|
||||
StageSetBinding tuple = { binding.stage, binding.desc_set, binding.binding };
|
||||
resource_bindings[tuple] = { binding, false };
|
||||
}
|
||||
|
||||
bool CompilerHLSL::is_hlsl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const
|
||||
{
|
||||
StageSetBinding tuple = { model, desc_set, binding };
|
||||
auto itr = resource_bindings.find(tuple);
|
||||
return itr != end(resource_bindings) && itr->second.second;
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ struct RootConstants
|
||||
// For finer control, decorations may be removed from specific resources instead with unset_decoration().
|
||||
enum HLSLBindingFlagBits
|
||||
{
|
||||
HLSL_BINDING_AUTO_NONE_BIT = 0,
|
||||
|
||||
// Push constant (root constant) resources will be declared as CBVs (b-space) without a register() declaration.
|
||||
// A register will be automatically assigned by the D3D compiler, but must therefore be reflected in D3D-land.
|
||||
// Push constants do not normally have a DecorationBinding set, but if they do, this can be used to ignore it.
|
||||
@ -67,6 +69,28 @@ enum HLSLBindingFlagBits
|
||||
};
|
||||
using HLSLBindingFlags = uint32_t;
|
||||
|
||||
// By matching stage, desc_set and binding for a SPIR-V resource,
|
||||
// register bindings are set based on whether the HLSL resource is a
|
||||
// CBV, UAV, SRV or Sampler. A single binding in SPIR-V might contain multiple
|
||||
// resource types, e.g. COMBINED_IMAGE_SAMPLER, and SRV/Sampler bindings will be used respectively.
|
||||
// On SM 5.0 and lower, register_space is ignored.
|
||||
//
|
||||
// To remap a push constant block which does not have any desc_set/binding associated with it,
|
||||
// use ResourceBindingPushConstant{DescriptorSet,Binding} as values for desc_set/binding.
|
||||
// For deeper control of push constants, set_root_constant_layouts() can be used instead.
|
||||
struct HLSLResourceBinding
|
||||
{
|
||||
spv::ExecutionModel stage = spv::ExecutionModelMax;
|
||||
uint32_t desc_set = 0;
|
||||
uint32_t binding = 0;
|
||||
|
||||
struct Binding
|
||||
{
|
||||
uint32_t register_space = 0;
|
||||
uint32_t register_binding = 0;
|
||||
} cbv, uav, srv, sampler;
|
||||
};
|
||||
|
||||
class CompilerHLSL : public CompilerGLSL
|
||||
{
|
||||
public:
|
||||
@ -145,6 +169,14 @@ public:
|
||||
// Controls how resource bindings are declared in the output HLSL.
|
||||
void set_resource_binding_flags(HLSLBindingFlags flags);
|
||||
|
||||
// resource is a resource binding to indicate the HLSL CBV, SRV, UAV or sampler binding
|
||||
// to use for a particular SPIR-V description set
|
||||
// and binding. If resource bindings are provided,
|
||||
// is_hlsl_resource_binding_used() will return true after calling ::compile() if
|
||||
// the set/binding combination was used by the HLSL code.
|
||||
void add_hlsl_resource_binding(const HLSLResourceBinding &resource);
|
||||
bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
|
||||
|
||||
private:
|
||||
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
|
||||
@ -178,7 +210,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(HLSLBindingFlags flags, char space, uint32_t binding, uint32_t set);
|
||||
std::string to_resource_register(HLSLBindingFlagBits flag, 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);
|
||||
@ -267,6 +299,9 @@ private:
|
||||
|
||||
std::string get_unique_identifier();
|
||||
uint32_t unique_identifier_count = 0;
|
||||
|
||||
std::unordered_map<StageSetBinding, std::pair<HLSLResourceBinding, bool>, InternalHasher> resource_bindings;
|
||||
void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding);
|
||||
};
|
||||
} // namespace SPIRV_CROSS_NAMESPACE
|
||||
|
||||
|
@ -90,7 +90,7 @@ bool CompilerMSL::is_msl_vertex_attribute_used(uint32_t location)
|
||||
return vtx_attrs_in_use.count(location) != 0;
|
||||
}
|
||||
|
||||
bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding)
|
||||
bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const
|
||||
{
|
||||
StageSetBinding tuple = { model, desc_set, binding };
|
||||
auto itr = resource_bindings.find(tuple);
|
||||
@ -12641,35 +12641,3 @@ void CompilerMSL::analyze_argument_buffers()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CompilerMSL::SetBindingPair::operator==(const SetBindingPair &other) const
|
||||
{
|
||||
return desc_set == other.desc_set && binding == other.binding;
|
||||
}
|
||||
|
||||
bool CompilerMSL::SetBindingPair::operator<(const SetBindingPair &other) const
|
||||
{
|
||||
return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding);
|
||||
}
|
||||
|
||||
bool CompilerMSL::StageSetBinding::operator==(const StageSetBinding &other) const
|
||||
{
|
||||
return model == other.model && desc_set == other.desc_set && binding == other.binding;
|
||||
}
|
||||
|
||||
size_t CompilerMSL::InternalHasher::operator()(const SetBindingPair &value) const
|
||||
{
|
||||
// Quality of hash doesn't really matter here.
|
||||
auto hash_set = std::hash<uint32_t>()(value.desc_set);
|
||||
auto hash_binding = std::hash<uint32_t>()(value.binding);
|
||||
return (hash_set * 0x10001b31) ^ hash_binding;
|
||||
}
|
||||
|
||||
size_t CompilerMSL::InternalHasher::operator()(const StageSetBinding &value) const
|
||||
{
|
||||
// Quality of hash doesn't really matter here.
|
||||
auto hash_model = std::hash<uint32_t>()(value.model);
|
||||
auto hash_set = std::hash<uint32_t>()(value.desc_set);
|
||||
auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set;
|
||||
return (tmp_hash * 0x10001b31) ^ value.binding;
|
||||
}
|
||||
|
@ -218,11 +218,13 @@ struct MSLConstexprSampler
|
||||
|
||||
// Special constant used in a MSLResourceBinding desc_set
|
||||
// element to indicate the bindings for the push constants.
|
||||
static const uint32_t kPushConstDescSet = ~(0u);
|
||||
// Kinda deprecated. Just use ResourceBindingPushConstant{DescriptorSet,Binding} directly.
|
||||
static const uint32_t kPushConstDescSet = ResourceBindingPushConstantDescriptorSet;
|
||||
|
||||
// Special constant used in a MSLResourceBinding binding
|
||||
// element to indicate the bindings for the push constants.
|
||||
static const uint32_t kPushConstBinding = 0;
|
||||
// Kinda deprecated. Just use ResourceBindingPushConstant{DescriptorSet,Binding} directly.
|
||||
static const uint32_t kPushConstBinding = ResourceBindingPushConstantBinding;
|
||||
|
||||
// Special constant used in a MSLResourceBinding binding
|
||||
// element to indicate the buffer binding for swizzle buffers.
|
||||
@ -440,7 +442,7 @@ public:
|
||||
// Constexpr samplers are always assumed to be emitted.
|
||||
// No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped
|
||||
// by remap_constexpr_sampler(_by_binding).
|
||||
bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding);
|
||||
bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
|
||||
|
||||
// This must only be called after a successful call to CompilerMSL::compile().
|
||||
// For a variable resource ID obtained through reflection API, report the automatically assigned resource index.
|
||||
@ -786,28 +788,6 @@ protected:
|
||||
std::set<std::string> typedef_lines;
|
||||
SmallVector<uint32_t> vars_needing_early_declaration;
|
||||
|
||||
struct SetBindingPair
|
||||
{
|
||||
uint32_t desc_set;
|
||||
uint32_t binding;
|
||||
bool operator==(const SetBindingPair &other) const;
|
||||
bool operator<(const SetBindingPair &other) const;
|
||||
};
|
||||
|
||||
struct StageSetBinding
|
||||
{
|
||||
spv::ExecutionModel model;
|
||||
uint32_t desc_set;
|
||||
uint32_t binding;
|
||||
bool operator==(const StageSetBinding &other) const;
|
||||
};
|
||||
|
||||
struct InternalHasher
|
||||
{
|
||||
size_t operator()(const SetBindingPair &value) const;
|
||||
size_t operator()(const StageSetBinding &value) const;
|
||||
};
|
||||
|
||||
std::unordered_map<StageSetBinding, std::pair<MSLResourceBinding, bool>, InternalHasher> resource_bindings;
|
||||
|
||||
uint32_t next_metal_resource_index_buffer = 0;
|
||||
|
BIN
tests-other/hlsl_resource_binding.spv
Normal file
BIN
tests-other/hlsl_resource_binding.spv
Normal file
Binary file not shown.
89
tests-other/hlsl_resource_bindings.cpp
Normal file
89
tests-other/hlsl_resource_bindings.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
// Testbench for HLSL resource binding APIs.
|
||||
// It does not validate output at the moment, but it's useful for ad-hoc testing.
|
||||
|
||||
#include <spirv_cross_c.h>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SPVC_CHECKED_CALL(x) do { \
|
||||
if ((x) != SPVC_SUCCESS) { \
|
||||
fprintf(stderr, "Failed at line %d.\n", __LINE__); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static std::vector<SpvId> read_file(const char *path)
|
||||
{
|
||||
long len;
|
||||
FILE *file = fopen(path, "rb");
|
||||
|
||||
if (!file)
|
||||
return {};
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
len = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
std::vector<SpvId> buffer(len / sizeof(SpvId));
|
||||
if (fread(buffer.data(), 1, len, file) != (size_t)len)
|
||||
{
|
||||
fclose(file);
|
||||
return {};
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
auto buffer = read_file(argv[1]);
|
||||
if (buffer.empty())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
spvc_context ctx;
|
||||
spvc_parsed_ir parsed_ir;
|
||||
spvc_compiler compiler;
|
||||
|
||||
SPVC_CHECKED_CALL(spvc_context_create(&ctx));
|
||||
SPVC_CHECKED_CALL(spvc_context_parse_spirv(ctx, buffer.data(), buffer.size(), &parsed_ir));
|
||||
SPVC_CHECKED_CALL(spvc_context_create_compiler(ctx, SPVC_BACKEND_HLSL, parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler));
|
||||
|
||||
spvc_compiler_options opts;
|
||||
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler, &opts));
|
||||
SPVC_CHECKED_CALL(spvc_compiler_options_set_uint(opts, SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, 51));
|
||||
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler, opts));
|
||||
|
||||
spvc_hlsl_resource_binding binding;
|
||||
spvc_hlsl_resource_binding_init(&binding);
|
||||
binding.stage = SpvExecutionModelFragment;
|
||||
binding.desc_set = 1;
|
||||
binding.binding = 4;
|
||||
binding.srv.register_space = 2;
|
||||
binding.srv.register_binding = 3;
|
||||
binding.sampler.register_space = 4;
|
||||
binding.sampler.register_binding = 5;
|
||||
SPVC_CHECKED_CALL(spvc_compiler_hlsl_add_resource_binding(compiler, &binding));
|
||||
|
||||
binding.desc_set = SPVC_HLSL_PUSH_CONSTANT_DESC_SET;
|
||||
binding.binding = SPVC_HLSL_PUSH_CONSTANT_BINDING;
|
||||
binding.cbv.register_space = 0;
|
||||
binding.cbv.register_binding = 4;
|
||||
SPVC_CHECKED_CALL(spvc_compiler_hlsl_add_resource_binding(compiler, &binding));
|
||||
|
||||
const char *str;
|
||||
SPVC_CHECKED_CALL(spvc_compiler_compile(compiler, &str));
|
||||
|
||||
fprintf(stderr, "Output:\n%s\n", str);
|
||||
|
||||
if (!spvc_compiler_hlsl_is_resource_used(compiler, SpvExecutionModelFragment, 1, 4))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!spvc_compiler_hlsl_is_resource_used(compiler, SpvExecutionModelFragment, SPVC_HLSL_PUSH_CONSTANT_DESC_SET, SPVC_HLSL_PUSH_CONSTANT_BINDING))
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user