mirror of https://github.com/bkaradzic/bgfx
Updated spirv-cross.
This commit is contained in:
parent
11137890f7
commit
4a27145184
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -521,6 +521,7 @@ struct CLIArguments
|
||||||
bool msl_view_index_from_device_index = false;
|
bool msl_view_index_from_device_index = false;
|
||||||
bool msl_dispatch_base = false;
|
bool msl_dispatch_base = false;
|
||||||
bool msl_decoration_binding = false;
|
bool msl_decoration_binding = false;
|
||||||
|
bool msl_force_active_argument_buffer_resources = false;
|
||||||
bool glsl_emit_push_constant_as_ubo = false;
|
bool glsl_emit_push_constant_as_ubo = false;
|
||||||
bool glsl_emit_ubo_as_plain_uniforms = false;
|
bool glsl_emit_ubo_as_plain_uniforms = false;
|
||||||
bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
|
bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
|
||||||
|
@ -528,6 +529,7 @@ struct CLIArguments
|
||||||
SmallVector<uint32_t> msl_discrete_descriptor_sets;
|
SmallVector<uint32_t> msl_discrete_descriptor_sets;
|
||||||
SmallVector<uint32_t> msl_device_argument_buffers;
|
SmallVector<uint32_t> msl_device_argument_buffers;
|
||||||
SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
|
SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
|
||||||
|
SmallVector<pair<uint32_t, uint32_t>> msl_inline_uniform_blocks;
|
||||||
SmallVector<PLSArg> pls_in;
|
SmallVector<PLSArg> pls_in;
|
||||||
SmallVector<PLSArg> pls_out;
|
SmallVector<PLSArg> pls_out;
|
||||||
SmallVector<Remap> remaps;
|
SmallVector<Remap> remaps;
|
||||||
|
@ -611,7 +613,9 @@ static void print_help()
|
||||||
"\t[--msl-view-index-from-device-index]\n"
|
"\t[--msl-view-index-from-device-index]\n"
|
||||||
"\t[--msl-dispatch-base]\n"
|
"\t[--msl-dispatch-base]\n"
|
||||||
"\t[--msl-dynamic-buffer <set index> <binding>]\n"
|
"\t[--msl-dynamic-buffer <set index> <binding>]\n"
|
||||||
|
"\t[--msl-inline-uniform-block <set index> <binding>]\n"
|
||||||
"\t[--msl-decoration-binding]\n"
|
"\t[--msl-decoration-binding]\n"
|
||||||
|
"\t[--msl-force-active-argument-buffer-resources]\n"
|
||||||
"\t[--hlsl]\n"
|
"\t[--hlsl]\n"
|
||||||
"\t[--reflect]\n"
|
"\t[--reflect]\n"
|
||||||
"\t[--shader-model]\n"
|
"\t[--shader-model]\n"
|
||||||
|
@ -801,6 +805,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
|
||||||
msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
|
msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
|
||||||
msl_opts.dispatch_base = args.msl_dispatch_base;
|
msl_opts.dispatch_base = args.msl_dispatch_base;
|
||||||
msl_opts.enable_decoration_binding = args.msl_decoration_binding;
|
msl_opts.enable_decoration_binding = args.msl_decoration_binding;
|
||||||
|
msl_opts.force_active_argument_buffer_resources = args.msl_force_active_argument_buffer_resources;
|
||||||
msl_comp->set_msl_options(msl_opts);
|
msl_comp->set_msl_options(msl_opts);
|
||||||
for (auto &v : args.msl_discrete_descriptor_sets)
|
for (auto &v : args.msl_discrete_descriptor_sets)
|
||||||
msl_comp->add_discrete_descriptor_set(v);
|
msl_comp->add_discrete_descriptor_set(v);
|
||||||
|
@ -809,6 +814,8 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
for (auto &v : args.msl_dynamic_buffers)
|
for (auto &v : args.msl_dynamic_buffers)
|
||||||
msl_comp->add_dynamic_buffer(v.first, v.second, i++);
|
msl_comp->add_dynamic_buffer(v.first, v.second, i++);
|
||||||
|
for (auto &v : args.msl_inline_uniform_blocks)
|
||||||
|
msl_comp->add_inline_uniform_block(v.first, v.second);
|
||||||
}
|
}
|
||||||
else if (args.hlsl)
|
else if (args.hlsl)
|
||||||
compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir())));
|
compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir())));
|
||||||
|
@ -1148,6 +1155,15 @@ static int main_inner(int argc, char *argv[])
|
||||||
args.msl_dynamic_buffers.push_back(make_pair(desc_set, binding));
|
args.msl_dynamic_buffers.push_back(make_pair(desc_set, binding));
|
||||||
});
|
});
|
||||||
cbs.add("--msl-decoration-binding", [&args](CLIParser &) { args.msl_decoration_binding = true; });
|
cbs.add("--msl-decoration-binding", [&args](CLIParser &) { args.msl_decoration_binding = true; });
|
||||||
|
cbs.add("--msl-force-active-argument-buffer-resources",
|
||||||
|
[&args](CLIParser &) { args.msl_force_active_argument_buffer_resources = true; });
|
||||||
|
cbs.add("--msl-inline-uniform-block", [&args](CLIParser &parser) {
|
||||||
|
args.msl_argument_buffers = true;
|
||||||
|
// Make sure next_uint() is called in-order.
|
||||||
|
uint32_t desc_set = parser.next_uint();
|
||||||
|
uint32_t binding = parser.next_uint();
|
||||||
|
args.msl_inline_uniform_blocks.push_back(make_pair(desc_set, binding));
|
||||||
|
});
|
||||||
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
||||||
cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
|
cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
|
||||||
auto old_name = parser.next_string();
|
auto old_name = parser.next_string();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2019 Arm Limited
|
* Copyright 2016-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2019 Arm Limited
|
* Copyright 2016-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -638,6 +638,7 @@ struct SPIREntryPoint
|
||||||
uint32_t invocations = 0;
|
uint32_t invocations = 0;
|
||||||
uint32_t output_vertices = 0;
|
uint32_t output_vertices = 0;
|
||||||
spv::ExecutionModel model = spv::ExecutionModelMax;
|
spv::ExecutionModel model = spv::ExecutionModelMax;
|
||||||
|
bool geometry_passthrough = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SPIRExpression : IVariant
|
struct SPIRExpression : IVariant
|
||||||
|
@ -975,6 +976,7 @@ struct SPIRAccessChain : IVariant
|
||||||
|
|
||||||
VariableID loaded_from = 0;
|
VariableID loaded_from = 0;
|
||||||
uint32_t matrix_stride = 0;
|
uint32_t matrix_stride = 0;
|
||||||
|
uint32_t array_stride = 0;
|
||||||
bool row_major_matrix = false;
|
bool row_major_matrix = false;
|
||||||
bool immutable = false;
|
bool immutable = false;
|
||||||
|
|
||||||
|
@ -1051,8 +1053,7 @@ struct SPIRConstant : IVariant
|
||||||
type = TypeConstant
|
type = TypeConstant
|
||||||
};
|
};
|
||||||
|
|
||||||
union Constant
|
union Constant {
|
||||||
{
|
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
int32_t i32;
|
int32_t i32;
|
||||||
float f32;
|
float f32;
|
||||||
|
@ -1090,8 +1091,7 @@ struct SPIRConstant : IVariant
|
||||||
int e = (u16_value >> 10) & 0x1f;
|
int e = (u16_value >> 10) & 0x1f;
|
||||||
int m = (u16_value >> 0) & 0x3ff;
|
int m = (u16_value >> 0) & 0x3ff;
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
float f32;
|
float f32;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
} u;
|
} u;
|
||||||
|
@ -1571,6 +1571,8 @@ struct Meta
|
||||||
uint32_t set = 0;
|
uint32_t set = 0;
|
||||||
uint32_t binding = 0;
|
uint32_t binding = 0;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
uint32_t xfb_buffer = 0;
|
||||||
|
uint32_t xfb_stride = 0;
|
||||||
uint32_t array_stride = 0;
|
uint32_t array_stride = 0;
|
||||||
uint32_t matrix_stride = 0;
|
uint32_t matrix_stride = 0;
|
||||||
uint32_t input_attachment = 0;
|
uint32_t input_attachment = 0;
|
||||||
|
@ -1695,6 +1697,62 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode)
|
||||||
return false;
|
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 SPIRV_CROSS_NAMESPACE
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -317,6 +317,8 @@ void Compiler::register_write(uint32_t chain)
|
||||||
var = maybe_get<SPIRVariable>(access_chain->loaded_from);
|
var = maybe_get<SPIRVariable>(access_chain->loaded_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &chain_type = expression_type(chain);
|
||||||
|
|
||||||
if (var)
|
if (var)
|
||||||
{
|
{
|
||||||
bool check_argument_storage_qualifier = true;
|
bool check_argument_storage_qualifier = true;
|
||||||
|
@ -359,7 +361,7 @@ void Compiler::register_write(uint32_t chain)
|
||||||
force_recompile();
|
force_recompile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (chain_type.pointer)
|
||||||
{
|
{
|
||||||
// If we stored through a variable pointer, then we don't know which
|
// If we stored through a variable pointer, then we don't know which
|
||||||
// variable we stored to. So *all* expressions after this point need to
|
// variable we stored to. So *all* expressions after this point need to
|
||||||
|
@ -368,6 +370,9 @@ void Compiler::register_write(uint32_t chain)
|
||||||
// only certain variables, we can invalidate only those.
|
// only certain variables, we can invalidate only those.
|
||||||
flush_all_active_variables();
|
flush_all_active_variables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If chain_type.pointer is false, we're not writing to memory backed variables, but temporaries instead.
|
||||||
|
// This can happen in copy_logical_type where we unroll complex reads and writes to temporaries.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::flush_dependees(SPIRVariable &var)
|
void Compiler::flush_dependees(SPIRVariable &var)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019 Hans-Kristian Arntzen
|
* Copyright 2019-2020 Hans-Kristian Arntzen
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -593,6 +593,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
|
||||||
case SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING:
|
case SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING:
|
||||||
options->msl.enable_decoration_binding = value != 0;
|
options->msl.enable_decoration_binding = value != 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES:
|
||||||
|
options->msl.force_active_argument_buffer_resources = value != 0;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -789,6 +793,60 @@ spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler
|
||||||
#endif
|
#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)
|
spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler)
|
||||||
{
|
{
|
||||||
#if SPIRV_CROSS_C_API_MSL
|
#if SPIRV_CROSS_C_API_MSL
|
||||||
|
@ -971,6 +1029,26 @@ spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigne
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding)
|
||||||
|
{
|
||||||
|
#if SPIRV_CROSS_C_API_MSL
|
||||||
|
if (compiler->backend != SPVC_BACKEND_MSL)
|
||||||
|
{
|
||||||
|
compiler->context->report_error("MSL function used on a non-MSL backend.");
|
||||||
|
return SPVC_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
|
||||||
|
msl.add_inline_uniform_block(desc_set, binding);
|
||||||
|
return SPVC_SUCCESS;
|
||||||
|
#else
|
||||||
|
(void)binding;
|
||||||
|
(void)desc_set;
|
||||||
|
compiler->context->report_error("MSL function used on a non-MSL backend.");
|
||||||
|
return SPVC_ERROR_INVALID_ARGUMENT;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set)
|
spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set)
|
||||||
{
|
{
|
||||||
#if SPIRV_CROSS_C_API_MSL
|
#if SPIRV_CROSS_C_API_MSL
|
||||||
|
@ -2157,6 +2235,26 @@ void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding)
|
||||||
#endif
|
#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)
|
void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler)
|
||||||
{
|
{
|
||||||
#if SPIRV_CROSS_C_API_MSL
|
#if SPIRV_CROSS_C_API_MSL
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019 Hans-Kristian Arntzen
|
* Copyright 2019-2020 Hans-Kristian Arntzen
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -33,7 +33,7 @@ extern "C" {
|
||||||
/* Bumped if ABI or API breaks backwards compatibility. */
|
/* Bumped if ABI or API breaks backwards compatibility. */
|
||||||
#define SPVC_C_API_VERSION_MAJOR 0
|
#define SPVC_C_API_VERSION_MAJOR 0
|
||||||
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
|
/* 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 24
|
||||||
/* Bumped if internal implementation details change. */
|
/* Bumped if internal implementation details change. */
|
||||||
#define SPVC_C_API_VERSION_PATCH 0
|
#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. */
|
/* Maps to C++ API. */
|
||||||
typedef enum spvc_hlsl_binding_flag_bits
|
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_PUSH_CONSTANT_BIT = 1 << 0,
|
||||||
SPVC_HLSL_BINDING_AUTO_CBV_BIT = 1 << 1,
|
SPVC_HLSL_BINDING_AUTO_CBV_BIT = 1 << 1,
|
||||||
SPVC_HLSL_BINDING_AUTO_SRV_BIT = 1 << 2,
|
SPVC_HLSL_BINDING_AUTO_SRV_BIT = 1 << 2,
|
||||||
|
@ -478,6 +479,31 @@ typedef enum spvc_hlsl_binding_flag_bits
|
||||||
} spvc_hlsl_binding_flag_bits;
|
} spvc_hlsl_binding_flag_bits;
|
||||||
typedef unsigned spvc_hlsl_binding_flags;
|
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. */
|
/* Maps to the various spirv_cross::Compiler*::Option structures. See C++ API for defaults and details. */
|
||||||
typedef enum spvc_compiler_option
|
typedef enum spvc_compiler_option
|
||||||
{
|
{
|
||||||
|
@ -545,6 +571,7 @@ typedef enum spvc_compiler_option
|
||||||
SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT,
|
SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||||
SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
|
SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||||
SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
|
SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||||
|
SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES = 50 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||||
|
|
||||||
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
|
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
|
||||||
} spvc_compiler_option;
|
} spvc_compiler_option;
|
||||||
|
@ -621,6 +648,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_PUBLIC_API spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler,
|
||||||
spvc_hlsl_binding_flags flags);
|
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.
|
* MSL specifics.
|
||||||
* Maps to C++ API.
|
* Maps to C++ API.
|
||||||
|
@ -657,6 +691,8 @@ SPVC_PUBLIC_API unsigned spvc_compiler_msl_get_automatic_resource_binding_second
|
||||||
|
|
||||||
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index);
|
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index);
|
||||||
|
|
||||||
|
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reflect resources.
|
* Reflect resources.
|
||||||
* Maps almost 1:1 to C++ API.
|
* Maps almost 1:1 to C++ API.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019 Hans-Kristian Arntzen
|
* Copyright 2019-2020 Hans-Kristian Arntzen
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -61,8 +61,7 @@ public:
|
||||||
private:
|
private:
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
// MSVC 2013 workarounds, sigh ...
|
// MSVC 2013 workarounds, sigh ...
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
char aligned_char[sizeof(T) * N];
|
char aligned_char[sizeof(T) * N];
|
||||||
double dummy_aligner;
|
double dummy_aligner;
|
||||||
} u;
|
} u;
|
||||||
|
@ -86,72 +85,72 @@ template <typename T>
|
||||||
class VectorView
|
class VectorView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
T &operator[](size_t i)
|
T &operator[](size_t i) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr[i];
|
return ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T &operator[](size_t i) const
|
const T &operator[](size_t i) const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr[i];
|
return ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const
|
bool empty() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return buffer_size == 0;
|
return buffer_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const
|
size_t size() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return buffer_size;
|
return buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
T *data()
|
T *data() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T *data() const
|
const T *data() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
T *begin()
|
T *begin() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
T *end()
|
T *end() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr + buffer_size;
|
return ptr + buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T *begin() const
|
const T *begin() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T *end() const
|
const T *end() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr + buffer_size;
|
return ptr + buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
T &front()
|
T &front() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr[0];
|
return ptr[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T &front() const
|
const T &front() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr[0];
|
return ptr[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
T &back()
|
T &back() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr[buffer_size - 1];
|
return ptr[buffer_size - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T &back() const
|
const T &back() const SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
return ptr[buffer_size - 1];
|
return ptr[buffer_size - 1];
|
||||||
}
|
}
|
||||||
|
@ -195,13 +194,13 @@ template <typename T, size_t N = 8>
|
||||||
class SmallVector : public VectorView<T>
|
class SmallVector : public VectorView<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SmallVector()
|
SmallVector() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
this->ptr = stack_storage.data();
|
this->ptr = stack_storage.data();
|
||||||
buffer_capacity = N;
|
buffer_capacity = N;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector(const T *arg_list_begin, const T *arg_list_end)
|
SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT
|
||||||
: SmallVector()
|
: SmallVector()
|
||||||
{
|
{
|
||||||
auto count = size_t(arg_list_end - arg_list_begin);
|
auto count = size_t(arg_list_end - arg_list_begin);
|
||||||
|
@ -246,14 +245,17 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector(const SmallVector &other)
|
SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT
|
||||||
: SmallVector()
|
: SmallVector()
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector &operator=(const SmallVector &other)
|
SmallVector &operator=(const SmallVector &other) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
reserve(other.buffer_size);
|
reserve(other.buffer_size);
|
||||||
for (size_t i = 0; i < other.buffer_size; i++)
|
for (size_t i = 0; i < other.buffer_size; i++)
|
||||||
|
@ -262,7 +264,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit SmallVector(size_t count)
|
explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT
|
||||||
: SmallVector()
|
: SmallVector()
|
||||||
{
|
{
|
||||||
resize(count);
|
resize(count);
|
||||||
|
@ -275,28 +277,28 @@ public:
|
||||||
free(this->ptr);
|
free(this->ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < this->buffer_size; i++)
|
for (size_t i = 0; i < this->buffer_size; i++)
|
||||||
this->ptr[i].~T();
|
this->ptr[i].~T();
|
||||||
this->buffer_size = 0;
|
this->buffer_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const T &t)
|
void push_back(const T &t) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
reserve(this->buffer_size + 1);
|
reserve(this->buffer_size + 1);
|
||||||
new (&this->ptr[this->buffer_size]) T(t);
|
new (&this->ptr[this->buffer_size]) T(t);
|
||||||
this->buffer_size++;
|
this->buffer_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(T &&t)
|
void push_back(T &&t) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
reserve(this->buffer_size + 1);
|
reserve(this->buffer_size + 1);
|
||||||
new (&this->ptr[this->buffer_size]) T(std::move(t));
|
new (&this->ptr[this->buffer_size]) T(std::move(t));
|
||||||
this->buffer_size++;
|
this->buffer_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_back()
|
void pop_back() SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
// Work around false positive warning on GCC 8.3.
|
// Work around false positive warning on GCC 8.3.
|
||||||
// Calling pop_back on empty vector is undefined.
|
// Calling pop_back on empty vector is undefined.
|
||||||
|
@ -305,14 +307,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
void emplace_back(Ts &&... ts)
|
void emplace_back(Ts &&... ts) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
reserve(this->buffer_size + 1);
|
reserve(this->buffer_size + 1);
|
||||||
new (&this->ptr[this->buffer_size]) T(std::forward<Ts>(ts)...);
|
new (&this->ptr[this->buffer_size]) T(std::forward<Ts>(ts)...);
|
||||||
this->buffer_size++;
|
this->buffer_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(size_t count)
|
void reserve(size_t count) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
if (count > buffer_capacity)
|
if (count > buffer_capacity)
|
||||||
{
|
{
|
||||||
|
@ -328,8 +330,9 @@ public:
|
||||||
T *new_buffer =
|
T *new_buffer =
|
||||||
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
|
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
|
||||||
|
|
||||||
|
// If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery.
|
||||||
if (!new_buffer)
|
if (!new_buffer)
|
||||||
SPIRV_CROSS_THROW("Out of memory.");
|
std::terminate();
|
||||||
|
|
||||||
// In case for some reason two allocations both come from same stack.
|
// In case for some reason two allocations both come from same stack.
|
||||||
if (new_buffer != this->ptr)
|
if (new_buffer != this->ptr)
|
||||||
|
@ -349,7 +352,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(T *itr, const T *insert_begin, const T *insert_end)
|
void insert(T *itr, const T *insert_begin, const T *insert_end) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
auto count = size_t(insert_end - insert_begin);
|
auto count = size_t(insert_end - insert_begin);
|
||||||
if (itr == this->end())
|
if (itr == this->end())
|
||||||
|
@ -375,8 +378,10 @@ public:
|
||||||
// Need to allocate new buffer. Move everything to a new buffer.
|
// Need to allocate new buffer. Move everything to a new buffer.
|
||||||
T *new_buffer =
|
T *new_buffer =
|
||||||
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
|
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
|
||||||
|
|
||||||
|
// If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery.
|
||||||
if (!new_buffer)
|
if (!new_buffer)
|
||||||
SPIRV_CROSS_THROW("Out of memory.");
|
std::terminate();
|
||||||
|
|
||||||
// First, move elements from source buffer to new buffer.
|
// First, move elements from source buffer to new buffer.
|
||||||
// We don't deal with types which can throw in move constructor.
|
// We don't deal with types which can throw in move constructor.
|
||||||
|
@ -448,19 +453,19 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(T *itr, const T &value)
|
void insert(T *itr, const T &value) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
insert(itr, &value, &value + 1);
|
insert(itr, &value, &value + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
T *erase(T *itr)
|
T *erase(T *itr) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
std::move(itr + 1, this->end(), itr);
|
std::move(itr + 1, this->end(), itr);
|
||||||
this->ptr[--this->buffer_size].~T();
|
this->ptr[--this->buffer_size].~T();
|
||||||
return itr;
|
return itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(T *start_erase, T *end_erase)
|
void erase(T *start_erase, T *end_erase) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
if (end_erase == this->end())
|
if (end_erase == this->end())
|
||||||
{
|
{
|
||||||
|
@ -474,7 +479,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(size_t new_size)
|
void resize(size_t new_size) SPIRV_CROSS_NOEXCEPT
|
||||||
{
|
{
|
||||||
if (new_size < this->buffer_size)
|
if (new_size < this->buffer_size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2019 Arm Limited
|
* Copyright 2018-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -128,6 +128,17 @@ void ParsedIR::set_id_bounds(uint32_t bounds)
|
||||||
block_meta.resize(bounds);
|
block_meta.resize(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Roll our own versions of these functions to avoid potential locale shenanigans.
|
||||||
|
static bool is_alpha(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_alphanumeric(char c)
|
||||||
|
{
|
||||||
|
return is_alpha(c) || (c >= '0' && c <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
static string ensure_valid_identifier(const string &name, bool member)
|
static string ensure_valid_identifier(const string &name, bool member)
|
||||||
{
|
{
|
||||||
// Functions in glslangValidator are mangled with name(<mangled> stuff.
|
// Functions in glslangValidator are mangled with name(<mangled> stuff.
|
||||||
|
@ -143,20 +154,20 @@ static string ensure_valid_identifier(const string &name, bool member)
|
||||||
// _m<num> variables are reserved by the internal implementation,
|
// _m<num> variables are reserved by the internal implementation,
|
||||||
// otherwise, make sure the name is a valid identifier.
|
// otherwise, make sure the name is a valid identifier.
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
c = isalpha(c) ? c : '_';
|
c = is_alpha(c) ? c : '_';
|
||||||
else if (i == 2 && str[0] == '_' && str[1] == 'm')
|
else if (i == 2 && str[0] == '_' && str[1] == 'm')
|
||||||
c = isalpha(c) ? c : '_';
|
c = is_alpha(c) ? c : '_';
|
||||||
else
|
else
|
||||||
c = isalnum(c) ? c : '_';
|
c = is_alphanumeric(c) ? c : '_';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// _<num> variables are reserved by the internal implementation,
|
// _<num> variables are reserved by the internal implementation,
|
||||||
// otherwise, make sure the name is a valid identifier.
|
// otherwise, make sure the name is a valid identifier.
|
||||||
if (i == 0 || (str[0] == '_' && i == 1))
|
if (i == 0 || (str[0] == '_' && i == 1))
|
||||||
c = isalpha(c) ? c : '_';
|
c = is_alpha(c) ? c : '_';
|
||||||
else
|
else
|
||||||
c = isalnum(c) ? c : '_';
|
c = is_alphanumeric(c) ? c : '_';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
|
@ -255,6 +266,14 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
|
||||||
dec.offset = argument;
|
dec.offset = argument;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbBuffer:
|
||||||
|
dec.xfb_buffer = argument;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbStride:
|
||||||
|
dec.xfb_stride = argument;
|
||||||
|
break;
|
||||||
|
|
||||||
case DecorationArrayStride:
|
case DecorationArrayStride:
|
||||||
dec.array_stride = argument;
|
dec.array_stride = argument;
|
||||||
break;
|
break;
|
||||||
|
@ -326,6 +345,14 @@ void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decor
|
||||||
dec.offset = argument;
|
dec.offset = argument;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbBuffer:
|
||||||
|
dec.xfb_buffer = argument;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbStride:
|
||||||
|
dec.xfb_stride = argument;
|
||||||
|
break;
|
||||||
|
|
||||||
case DecorationSpecId:
|
case DecorationSpecId:
|
||||||
dec.spec_id = argument;
|
dec.spec_id = argument;
|
||||||
break;
|
break;
|
||||||
|
@ -439,6 +466,10 @@ uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
|
||||||
return dec.component;
|
return dec.component;
|
||||||
case DecorationOffset:
|
case DecorationOffset:
|
||||||
return dec.offset;
|
return dec.offset;
|
||||||
|
case DecorationXfbBuffer:
|
||||||
|
return dec.xfb_buffer;
|
||||||
|
case DecorationXfbStride:
|
||||||
|
return dec.xfb_stride;
|
||||||
case DecorationBinding:
|
case DecorationBinding:
|
||||||
return dec.binding;
|
return dec.binding;
|
||||||
case DecorationDescriptorSet:
|
case DecorationDescriptorSet:
|
||||||
|
@ -503,6 +534,14 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration)
|
||||||
dec.offset = 0;
|
dec.offset = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbBuffer:
|
||||||
|
dec.xfb_buffer = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbStride:
|
||||||
|
dec.xfb_stride = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case DecorationBinding:
|
case DecorationBinding:
|
||||||
dec.binding = 0;
|
dec.binding = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -573,6 +612,10 @@ uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration d
|
||||||
return dec.binding;
|
return dec.binding;
|
||||||
case DecorationOffset:
|
case DecorationOffset:
|
||||||
return dec.offset;
|
return dec.offset;
|
||||||
|
case DecorationXfbBuffer:
|
||||||
|
return dec.xfb_buffer;
|
||||||
|
case DecorationXfbStride:
|
||||||
|
return dec.xfb_stride;
|
||||||
case DecorationSpecId:
|
case DecorationSpecId:
|
||||||
return dec.spec_id;
|
return dec.spec_id;
|
||||||
case DecorationIndex:
|
case DecorationIndex:
|
||||||
|
@ -661,6 +704,14 @@ void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration dec
|
||||||
dec.offset = 0;
|
dec.offset = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbBuffer:
|
||||||
|
dec.xfb_buffer = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationXfbStride:
|
||||||
|
dec.xfb_stride = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case DecorationSpecId:
|
case DecorationSpecId:
|
||||||
dec.spec_id = 0;
|
dec.spec_id = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2019 Arm Limited
|
* Copyright 2018-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2015-2019 Arm Limited
|
* Copyright 2015-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -56,7 +56,8 @@ enum AccessChainFlagBits
|
||||||
ACCESS_CHAIN_INDEX_IS_LITERAL_BIT = 1 << 0,
|
ACCESS_CHAIN_INDEX_IS_LITERAL_BIT = 1 << 0,
|
||||||
ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1,
|
ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1,
|
||||||
ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2,
|
ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2,
|
||||||
ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3
|
ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3,
|
||||||
|
ACCESS_CHAIN_LITERAL_MSB_FORCE_ID = 1 << 4
|
||||||
};
|
};
|
||||||
typedef uint32_t AccessChainFlags;
|
typedef uint32_t AccessChainFlags;
|
||||||
|
|
||||||
|
@ -275,6 +276,9 @@ protected:
|
||||||
|
|
||||||
virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const;
|
virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) 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);
|
||||||
|
|
||||||
StringStream<> buffer;
|
StringStream<> buffer;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -427,6 +431,7 @@ protected:
|
||||||
void emit_buffer_block_legacy(const SPIRVariable &var);
|
void emit_buffer_block_legacy(const SPIRVariable &var);
|
||||||
void emit_buffer_block_flattened(const SPIRVariable &type);
|
void emit_buffer_block_flattened(const SPIRVariable &type);
|
||||||
void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
|
void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
|
||||||
|
bool should_force_emit_builtin_block(spv::StorageClass storage);
|
||||||
void emit_push_constant_block_vulkan(const SPIRVariable &var);
|
void emit_push_constant_block_vulkan(const SPIRVariable &var);
|
||||||
void emit_push_constant_block_glsl(const SPIRVariable &var);
|
void emit_push_constant_block_glsl(const SPIRVariable &var);
|
||||||
void emit_interface_block(const SPIRVariable &type);
|
void emit_interface_block(const SPIRVariable &type);
|
||||||
|
@ -463,6 +468,8 @@ protected:
|
||||||
SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type);
|
SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type);
|
||||||
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
|
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
|
||||||
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
|
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
|
||||||
|
void emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
||||||
|
const char *op, SPIRType::BaseType input_type);
|
||||||
void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
||||||
const char *op, SPIRType::BaseType input_type);
|
const char *op, SPIRType::BaseType input_type);
|
||||||
void emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
void emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
||||||
|
@ -503,7 +510,7 @@ protected:
|
||||||
|
|
||||||
std::string flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
|
std::string flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||||
const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
|
const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
|
||||||
bool need_transpose);
|
uint32_t array_stride, bool need_transpose);
|
||||||
std::string flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
|
std::string flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||||
const SPIRType &target_type, uint32_t offset);
|
const SPIRType &target_type, uint32_t offset);
|
||||||
std::string flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
|
std::string flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
|
||||||
|
@ -516,6 +523,7 @@ protected:
|
||||||
uint32_t count, uint32_t offset,
|
uint32_t count, uint32_t offset,
|
||||||
uint32_t word_stride, bool *need_transpose = nullptr,
|
uint32_t word_stride, bool *need_transpose = nullptr,
|
||||||
uint32_t *matrix_stride = nullptr,
|
uint32_t *matrix_stride = nullptr,
|
||||||
|
uint32_t *array_stride = nullptr,
|
||||||
bool ptr_chain = false);
|
bool ptr_chain = false);
|
||||||
|
|
||||||
const char *index_to_swizzle(uint32_t index);
|
const char *index_to_swizzle(uint32_t index);
|
||||||
|
@ -583,6 +591,7 @@ protected:
|
||||||
bool check_atomic_image(uint32_t id);
|
bool check_atomic_image(uint32_t id);
|
||||||
|
|
||||||
virtual void replace_illegal_names();
|
virtual void replace_illegal_names();
|
||||||
|
void replace_illegal_names(const std::unordered_set<std::string> &keywords);
|
||||||
virtual void emit_entry_point_declarations();
|
virtual void emit_entry_point_declarations();
|
||||||
|
|
||||||
void replace_fragment_output(SPIRVariable &var);
|
void replace_fragment_output(SPIRVariable &var);
|
||||||
|
@ -705,6 +714,8 @@ protected:
|
||||||
|
|
||||||
void propagate_nonuniform_qualifier(uint32_t id);
|
void propagate_nonuniform_qualifier(uint32_t id);
|
||||||
|
|
||||||
|
static const char *vector_swizzle(int vecsize, int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2019 Robert Konrad
|
* Copyright 2016-2020 Robert Konrad
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1113,15 +1113,7 @@ void CompilerHLSL::replace_illegal_names()
|
||||||
"line", "linear", "matrix", "point", "row_major", "sampler",
|
"line", "linear", "matrix", "point", "row_major", "sampler",
|
||||||
};
|
};
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
CompilerGLSL::replace_illegal_names(keywords);
|
||||||
if (!is_hidden_variable(var))
|
|
||||||
{
|
|
||||||
auto &m = ir.meta[var.self].decoration;
|
|
||||||
if (keywords.find(m.alias) != end(keywords))
|
|
||||||
m.alias = join("_", m.alias);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
CompilerGLSL::replace_illegal_names();
|
CompilerGLSL::replace_illegal_names();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2934,16 +2926,15 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||||
|
|
||||||
string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||||
{
|
{
|
||||||
// TODO: Basic implementation, might need special consideration for RW/RO structured buffers,
|
const auto &type = get<SPIRType>(var.basetype);
|
||||||
// RW/RO images, and so on.
|
|
||||||
|
|
||||||
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 "";
|
return "";
|
||||||
|
|
||||||
const auto &type = get<SPIRType>(var.basetype);
|
|
||||||
char space = '\0';
|
char space = '\0';
|
||||||
|
|
||||||
HLSLBindingFlags resource_flags = 0;
|
HLSLBindingFlagBits resource_flags = HLSL_BINDING_AUTO_NONE_BIT;
|
||||||
|
|
||||||
switch (type.basetype)
|
switch (type.basetype)
|
||||||
{
|
{
|
||||||
|
@ -3011,8 +3002,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||||
if (!space)
|
if (!space)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return to_resource_register(resource_flags, space, get_decoration(var.self, DecorationBinding),
|
uint32_t desc_set =
|
||||||
get_decoration(var.self, DecorationDescriptorSet));
|
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)
|
string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
|
||||||
|
@ -3025,10 +3024,54 @@ string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
|
||||||
get_decoration(var.self, DecorationDescriptorSet));
|
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)
|
if (hlsl_options.shader_model >= 51)
|
||||||
return join(" : register(", space, binding, ", space", space_set, ")");
|
return join(" : register(", space, binding, ", space", space_set, ")");
|
||||||
else
|
else
|
||||||
|
@ -3401,7 +3444,57 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string CompilerHLSL::read_access_chain(const SPIRAccessChain &chain)
|
void CompilerHLSL::read_access_chain_array(const string &lhs, const SPIRAccessChain &chain)
|
||||||
|
{
|
||||||
|
auto &type = get<SPIRType>(chain.basetype);
|
||||||
|
|
||||||
|
// Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops.
|
||||||
|
auto ident = get_unique_identifier();
|
||||||
|
|
||||||
|
statement("[unroll]");
|
||||||
|
statement("for (int ", ident, " = 0; ", ident, " < ", to_array_size(type, uint32_t(type.array.size() - 1)), "; ",
|
||||||
|
ident, "++)");
|
||||||
|
begin_scope();
|
||||||
|
auto subchain = chain;
|
||||||
|
subchain.dynamic_index = join(ident, " * ", chain.array_stride, " + ", chain.dynamic_index);
|
||||||
|
subchain.basetype = type.parent_type;
|
||||||
|
if (!get<SPIRType>(subchain.basetype).array.empty())
|
||||||
|
subchain.array_stride = get_decoration(subchain.basetype, DecorationArrayStride);
|
||||||
|
read_access_chain(nullptr, join(lhs, "[", ident, "]"), subchain);
|
||||||
|
end_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::read_access_chain_struct(const string &lhs, const SPIRAccessChain &chain)
|
||||||
|
{
|
||||||
|
auto &type = get<SPIRType>(chain.basetype);
|
||||||
|
auto subchain = chain;
|
||||||
|
uint32_t member_count = uint32_t(type.member_types.size());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < member_count; i++)
|
||||||
|
{
|
||||||
|
uint32_t offset = type_struct_member_offset(type, i);
|
||||||
|
subchain.static_index = chain.static_index + offset;
|
||||||
|
subchain.basetype = type.member_types[i];
|
||||||
|
|
||||||
|
subchain.matrix_stride = 0;
|
||||||
|
subchain.array_stride = 0;
|
||||||
|
subchain.row_major_matrix = false;
|
||||||
|
|
||||||
|
auto &member_type = get<SPIRType>(subchain.basetype);
|
||||||
|
if (member_type.columns > 1)
|
||||||
|
{
|
||||||
|
subchain.matrix_stride = type_struct_member_matrix_stride(type, i);
|
||||||
|
subchain.row_major_matrix = has_member_decoration(type.self, i, DecorationRowMajor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!member_type.array.empty())
|
||||||
|
subchain.array_stride = type_struct_member_array_stride(type, i);
|
||||||
|
|
||||||
|
read_access_chain(nullptr, join(lhs, ".", to_member_name(type, i)), subchain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIRAccessChain &chain)
|
||||||
{
|
{
|
||||||
auto &type = get<SPIRType>(chain.basetype);
|
auto &type = get<SPIRType>(chain.basetype);
|
||||||
|
|
||||||
|
@ -3410,14 +3503,18 @@ string CompilerHLSL::read_access_chain(const SPIRAccessChain &chain)
|
||||||
target_type.vecsize = type.vecsize;
|
target_type.vecsize = type.vecsize;
|
||||||
target_type.columns = type.columns;
|
target_type.columns = type.columns;
|
||||||
|
|
||||||
if (type.basetype == SPIRType::Struct)
|
|
||||||
SPIRV_CROSS_THROW("Reading structs from ByteAddressBuffer not yet supported.");
|
|
||||||
|
|
||||||
if (type.width != 32)
|
|
||||||
SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported.");
|
|
||||||
|
|
||||||
if (!type.array.empty())
|
if (!type.array.empty())
|
||||||
SPIRV_CROSS_THROW("Reading arrays from ByteAddressBuffer not yet supported.");
|
{
|
||||||
|
read_access_chain_array(lhs, chain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type.basetype == SPIRType::Struct)
|
||||||
|
{
|
||||||
|
read_access_chain_struct(lhs, chain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type.width != 32)
|
||||||
|
SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported.");
|
||||||
|
|
||||||
string load_expr;
|
string load_expr;
|
||||||
|
|
||||||
|
@ -3525,7 +3622,13 @@ string CompilerHLSL::read_access_chain(const SPIRAccessChain &chain)
|
||||||
if (!bitcast_op.empty())
|
if (!bitcast_op.empty())
|
||||||
load_expr = join(bitcast_op, "(", load_expr, ")");
|
load_expr = join(bitcast_op, "(", load_expr, ")");
|
||||||
|
|
||||||
return load_expr;
|
if (lhs.empty())
|
||||||
|
{
|
||||||
|
assert(expr);
|
||||||
|
*expr = move(load_expr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
statement(lhs, " = ", load_expr, ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerHLSL::emit_load(const Instruction &instruction)
|
void CompilerHLSL::emit_load(const Instruction &instruction)
|
||||||
|
@ -3542,33 +3645,138 @@ void CompilerHLSL::emit_load(const Instruction &instruction)
|
||||||
if (has_decoration(ptr, DecorationNonUniformEXT))
|
if (has_decoration(ptr, DecorationNonUniformEXT))
|
||||||
propagate_nonuniform_qualifier(ptr);
|
propagate_nonuniform_qualifier(ptr);
|
||||||
|
|
||||||
auto load_expr = read_access_chain(*chain);
|
|
||||||
|
|
||||||
bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
|
|
||||||
|
|
||||||
// If we are forwarding this load,
|
|
||||||
// don't register the read to access chain here, defer that to when we actually use the expression,
|
|
||||||
// using the add_implied_read_expression mechanism.
|
|
||||||
if (!forward)
|
|
||||||
track_expression_read(chain->self);
|
|
||||||
|
|
||||||
// Do not forward complex load sequences like matrices, structs and arrays.
|
|
||||||
auto &type = get<SPIRType>(result_type);
|
auto &type = get<SPIRType>(result_type);
|
||||||
if (type.columns > 1 || !type.array.empty() || type.basetype == SPIRType::Struct)
|
bool composite_load = !type.array.empty() || type.basetype == SPIRType::Struct;
|
||||||
forward = false;
|
|
||||||
|
|
||||||
auto &e = emit_op(result_type, id, load_expr, forward, true);
|
if (composite_load)
|
||||||
e.need_transpose = false;
|
{
|
||||||
register_read(id, ptr, forward);
|
// We cannot make this work in one single expression as we might have nested structures and arrays,
|
||||||
inherit_expression_dependencies(id, ptr);
|
// so unroll the load to an uninitialized temporary.
|
||||||
if (forward)
|
emit_uninitialized_temporary_expression(result_type, id);
|
||||||
add_implied_read_expression(e, chain->self);
|
read_access_chain(nullptr, to_expression(id), *chain);
|
||||||
|
track_expression_read(chain->self);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string load_expr;
|
||||||
|
read_access_chain(&load_expr, "", *chain);
|
||||||
|
|
||||||
|
bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
|
||||||
|
|
||||||
|
// If we are forwarding this load,
|
||||||
|
// don't register the read to access chain here, defer that to when we actually use the expression,
|
||||||
|
// using the add_implied_read_expression mechanism.
|
||||||
|
if (!forward)
|
||||||
|
track_expression_read(chain->self);
|
||||||
|
|
||||||
|
// Do not forward complex load sequences like matrices, structs and arrays.
|
||||||
|
if (type.columns > 1)
|
||||||
|
forward = false;
|
||||||
|
|
||||||
|
auto &e = emit_op(result_type, id, load_expr, forward, true);
|
||||||
|
e.need_transpose = false;
|
||||||
|
register_read(id, ptr, forward);
|
||||||
|
inherit_expression_dependencies(id, ptr);
|
||||||
|
if (forward)
|
||||||
|
add_implied_read_expression(e, chain->self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CompilerGLSL::emit_instruction(instruction);
|
CompilerGLSL::emit_instruction(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t value)
|
void CompilerHLSL::write_access_chain_array(const SPIRAccessChain &chain, uint32_t value,
|
||||||
|
const SmallVector<uint32_t> &composite_chain)
|
||||||
|
{
|
||||||
|
auto &type = get<SPIRType>(chain.basetype);
|
||||||
|
|
||||||
|
// Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops.
|
||||||
|
auto ident = get_unique_identifier();
|
||||||
|
|
||||||
|
uint32_t id = ir.increase_bound_by(2);
|
||||||
|
uint32_t int_type_id = id + 1;
|
||||||
|
SPIRType int_type;
|
||||||
|
int_type.basetype = SPIRType::Int;
|
||||||
|
int_type.width = 32;
|
||||||
|
set<SPIRType>(int_type_id, int_type);
|
||||||
|
set<SPIRExpression>(id, ident, int_type_id, true);
|
||||||
|
set_name(id, ident);
|
||||||
|
suppressed_usage_tracking.insert(id);
|
||||||
|
|
||||||
|
statement("[unroll]");
|
||||||
|
statement("for (int ", ident, " = 0; ", ident, " < ", to_array_size(type, uint32_t(type.array.size() - 1)), "; ",
|
||||||
|
ident, "++)");
|
||||||
|
begin_scope();
|
||||||
|
auto subchain = chain;
|
||||||
|
subchain.dynamic_index = join(ident, " * ", chain.array_stride, " + ", chain.dynamic_index);
|
||||||
|
subchain.basetype = type.parent_type;
|
||||||
|
|
||||||
|
// Forcefully allow us to use an ID here by setting MSB.
|
||||||
|
auto subcomposite_chain = composite_chain;
|
||||||
|
subcomposite_chain.push_back(0x80000000u | id);
|
||||||
|
|
||||||
|
if (!get<SPIRType>(subchain.basetype).array.empty())
|
||||||
|
subchain.array_stride = get_decoration(subchain.basetype, DecorationArrayStride);
|
||||||
|
|
||||||
|
write_access_chain(subchain, value, subcomposite_chain);
|
||||||
|
end_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value,
|
||||||
|
const SmallVector<uint32_t> &composite_chain)
|
||||||
|
{
|
||||||
|
auto &type = get<SPIRType>(chain.basetype);
|
||||||
|
uint32_t member_count = uint32_t(type.member_types.size());
|
||||||
|
auto subchain = chain;
|
||||||
|
|
||||||
|
auto subcomposite_chain = composite_chain;
|
||||||
|
subcomposite_chain.push_back(0);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < member_count; i++)
|
||||||
|
{
|
||||||
|
uint32_t offset = type_struct_member_offset(type, i);
|
||||||
|
subchain.static_index = chain.static_index + offset;
|
||||||
|
subchain.basetype = type.member_types[i];
|
||||||
|
|
||||||
|
subchain.matrix_stride = 0;
|
||||||
|
subchain.array_stride = 0;
|
||||||
|
subchain.row_major_matrix = false;
|
||||||
|
|
||||||
|
auto &member_type = get<SPIRType>(subchain.basetype);
|
||||||
|
if (member_type.columns > 1)
|
||||||
|
{
|
||||||
|
subchain.matrix_stride = type_struct_member_matrix_stride(type, i);
|
||||||
|
subchain.row_major_matrix = has_member_decoration(type.self, i, DecorationRowMajor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!member_type.array.empty())
|
||||||
|
subchain.array_stride = type_struct_member_array_stride(type, i);
|
||||||
|
|
||||||
|
subcomposite_chain.back() = i;
|
||||||
|
write_access_chain(subchain, value, subcomposite_chain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string CompilerHLSL::write_access_chain_value(uint32_t value, const SmallVector<uint32_t> &composite_chain,
|
||||||
|
bool enclose)
|
||||||
|
{
|
||||||
|
string ret;
|
||||||
|
if (composite_chain.empty())
|
||||||
|
ret = to_expression(value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AccessChainMeta meta;
|
||||||
|
ret = access_chain_internal(value, composite_chain.data(), uint32_t(composite_chain.size()),
|
||||||
|
ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_LITERAL_MSB_FORCE_ID, &meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enclose)
|
||||||
|
ret = enclose_expression(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t value,
|
||||||
|
const SmallVector<uint32_t> &composite_chain)
|
||||||
{
|
{
|
||||||
auto &type = get<SPIRType>(chain.basetype);
|
auto &type = get<SPIRType>(chain.basetype);
|
||||||
|
|
||||||
|
@ -3583,12 +3791,20 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
||||||
target_type.vecsize = type.vecsize;
|
target_type.vecsize = type.vecsize;
|
||||||
target_type.columns = type.columns;
|
target_type.columns = type.columns;
|
||||||
|
|
||||||
if (type.basetype == SPIRType::Struct)
|
|
||||||
SPIRV_CROSS_THROW("Writing structs to RWByteAddressBuffer not yet supported.");
|
|
||||||
if (type.width != 32)
|
|
||||||
SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported.");
|
|
||||||
if (!type.array.empty())
|
if (!type.array.empty())
|
||||||
SPIRV_CROSS_THROW("Reading arrays from ByteAddressBuffer not yet supported.");
|
{
|
||||||
|
write_access_chain_array(chain, value, composite_chain);
|
||||||
|
register_write(chain.self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type.basetype == SPIRType::Struct)
|
||||||
|
{
|
||||||
|
write_access_chain_struct(chain, value, composite_chain);
|
||||||
|
register_write(chain.self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type.width != 32)
|
||||||
|
SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported.");
|
||||||
|
|
||||||
if (type.columns == 1 && !chain.row_major_matrix)
|
if (type.columns == 1 && !chain.row_major_matrix)
|
||||||
{
|
{
|
||||||
|
@ -3611,7 +3827,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
||||||
SPIRV_CROSS_THROW("Unknown vector size.");
|
SPIRV_CROSS_THROW("Unknown vector size.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto store_expr = to_expression(value);
|
auto store_expr = write_access_chain_value(value, composite_chain, false);
|
||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
if (!bitcast_op.empty())
|
if (!bitcast_op.empty())
|
||||||
store_expr = join(bitcast_op, "(", store_expr, ")");
|
store_expr = join(bitcast_op, "(", store_expr, ")");
|
||||||
|
@ -3622,7 +3838,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
||||||
// Strided store.
|
// Strided store.
|
||||||
for (uint32_t r = 0; r < type.vecsize; r++)
|
for (uint32_t r = 0; r < type.vecsize; r++)
|
||||||
{
|
{
|
||||||
auto store_expr = to_enclosed_expression(value);
|
auto store_expr = write_access_chain_value(value, composite_chain, true);
|
||||||
if (type.vecsize > 1)
|
if (type.vecsize > 1)
|
||||||
{
|
{
|
||||||
store_expr += ".";
|
store_expr += ".";
|
||||||
|
@ -3660,7 +3876,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
||||||
|
|
||||||
for (uint32_t c = 0; c < type.columns; c++)
|
for (uint32_t c = 0; c < type.columns; c++)
|
||||||
{
|
{
|
||||||
auto store_expr = join(to_enclosed_expression(value), "[", c, "]");
|
auto store_expr = join(write_access_chain_value(value, composite_chain, true), "[", c, "]");
|
||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
if (!bitcast_op.empty())
|
if (!bitcast_op.empty())
|
||||||
store_expr = join(bitcast_op, "(", store_expr, ")");
|
store_expr = join(bitcast_op, "(", store_expr, ")");
|
||||||
|
@ -3674,7 +3890,8 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
||||||
{
|
{
|
||||||
for (uint32_t c = 0; c < type.columns; c++)
|
for (uint32_t c = 0; c < type.columns; c++)
|
||||||
{
|
{
|
||||||
auto store_expr = join(to_enclosed_expression(value), "[", c, "].", index_to_swizzle(r));
|
auto store_expr =
|
||||||
|
join(write_access_chain_value(value, composite_chain, true), "[", c, "].", index_to_swizzle(r));
|
||||||
remove_duplicate_swizzle(store_expr);
|
remove_duplicate_swizzle(store_expr);
|
||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
if (!bitcast_op.empty())
|
if (!bitcast_op.empty())
|
||||||
|
@ -3693,7 +3910,7 @@ void CompilerHLSL::emit_store(const Instruction &instruction)
|
||||||
auto ops = stream(instruction);
|
auto ops = stream(instruction);
|
||||||
auto *chain = maybe_get<SPIRAccessChain>(ops[0]);
|
auto *chain = maybe_get<SPIRAccessChain>(ops[0]);
|
||||||
if (chain)
|
if (chain)
|
||||||
write_access_chain(*chain, ops[1]);
|
write_access_chain(*chain, ops[1], {});
|
||||||
else
|
else
|
||||||
CompilerGLSL::emit_instruction(instruction);
|
CompilerGLSL::emit_instruction(instruction);
|
||||||
}
|
}
|
||||||
|
@ -3723,7 +3940,10 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
|
||||||
|
|
||||||
if (need_byte_access_chain)
|
if (need_byte_access_chain)
|
||||||
{
|
{
|
||||||
uint32_t to_plain_buffer_length = static_cast<uint32_t>(type.array.size());
|
// If we have a chain variable, we are already inside the SSBO, and any array type will refer to arrays within a block,
|
||||||
|
// and not array of SSBO.
|
||||||
|
uint32_t to_plain_buffer_length = chain ? 0u : static_cast<uint32_t>(type.array.size());
|
||||||
|
|
||||||
auto *backing_variable = maybe_get_backing_variable(ops[2]);
|
auto *backing_variable = maybe_get_backing_variable(ops[2]);
|
||||||
|
|
||||||
string base;
|
string base;
|
||||||
|
@ -3745,6 +3965,7 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t matrix_stride = 0;
|
uint32_t matrix_stride = 0;
|
||||||
|
uint32_t array_stride = 0;
|
||||||
bool row_major_matrix = false;
|
bool row_major_matrix = false;
|
||||||
|
|
||||||
// Inherit matrix information.
|
// Inherit matrix information.
|
||||||
|
@ -3752,15 +3973,17 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
|
||||||
{
|
{
|
||||||
matrix_stride = chain->matrix_stride;
|
matrix_stride = chain->matrix_stride;
|
||||||
row_major_matrix = chain->row_major_matrix;
|
row_major_matrix = chain->row_major_matrix;
|
||||||
|
array_stride = chain->array_stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offsets =
|
auto offsets = flattened_access_chain_offset(*basetype, &ops[3 + to_plain_buffer_length],
|
||||||
flattened_access_chain_offset(*basetype, &ops[3 + to_plain_buffer_length],
|
length - 3 - to_plain_buffer_length, 0, 1, &row_major_matrix,
|
||||||
length - 3 - to_plain_buffer_length, 0, 1, &row_major_matrix, &matrix_stride);
|
&matrix_stride, &array_stride);
|
||||||
|
|
||||||
auto &e = set<SPIRAccessChain>(ops[1], ops[0], type.storage, base, offsets.first, offsets.second);
|
auto &e = set<SPIRAccessChain>(ops[1], ops[0], type.storage, base, offsets.first, offsets.second);
|
||||||
e.row_major_matrix = row_major_matrix;
|
e.row_major_matrix = row_major_matrix;
|
||||||
e.matrix_stride = matrix_stride;
|
e.matrix_stride = matrix_stride;
|
||||||
|
e.array_stride = array_stride;
|
||||||
e.immutable = should_forward(ops[2]);
|
e.immutable = should_forward(ops[2]);
|
||||||
e.loaded_from = backing_variable ? backing_variable->self : ID(0);
|
e.loaded_from = backing_variable ? backing_variable->self : ID(0);
|
||||||
|
|
||||||
|
@ -3899,6 +4122,11 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i)
|
||||||
return join(expr, " * ", to_expression(ops[4]));
|
return join(expr, " * ", to_expression(ops[4]));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If we need to do implicit bitcasts, make sure we do it with the correct type.
|
||||||
|
uint32_t integer_width = get_integer_width_for_instruction(i);
|
||||||
|
auto int_type = to_signed_basetype(integer_width);
|
||||||
|
auto uint_type = to_unsigned_basetype(integer_width);
|
||||||
|
|
||||||
#define make_inclusive_BitAnd(expr) ""
|
#define make_inclusive_BitAnd(expr) ""
|
||||||
#define make_inclusive_BitOr(expr) ""
|
#define make_inclusive_BitOr(expr) ""
|
||||||
#define make_inclusive_BitXor(expr) ""
|
#define make_inclusive_BitXor(expr) ""
|
||||||
|
@ -4007,20 +4235,34 @@ case OpGroupNonUniform##op: \
|
||||||
SPIRV_CROSS_THROW("Invalid group operation."); \
|
SPIRV_CROSS_THROW("Invalid group operation."); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HLSL_GROUP_OP_CAST(op, hlsl_op, type) \
|
||||||
|
case OpGroupNonUniform##op: \
|
||||||
|
{ \
|
||||||
|
auto operation = static_cast<GroupOperation>(ops[3]); \
|
||||||
|
if (operation == GroupOperationReduce) \
|
||||||
|
emit_unary_func_op_cast(result_type, id, ops[4], "WaveActive" #hlsl_op, type, type); \
|
||||||
|
else \
|
||||||
|
SPIRV_CROSS_THROW("Invalid group operation."); \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
HLSL_GROUP_OP(FAdd, Sum, true)
|
HLSL_GROUP_OP(FAdd, Sum, true)
|
||||||
HLSL_GROUP_OP(FMul, Product, true)
|
HLSL_GROUP_OP(FMul, Product, true)
|
||||||
HLSL_GROUP_OP(FMin, Min, false)
|
HLSL_GROUP_OP(FMin, Min, false)
|
||||||
HLSL_GROUP_OP(FMax, Max, false)
|
HLSL_GROUP_OP(FMax, Max, false)
|
||||||
HLSL_GROUP_OP(IAdd, Sum, true)
|
HLSL_GROUP_OP(IAdd, Sum, true)
|
||||||
HLSL_GROUP_OP(IMul, Product, true)
|
HLSL_GROUP_OP(IMul, Product, true)
|
||||||
HLSL_GROUP_OP(SMin, Min, false)
|
HLSL_GROUP_OP_CAST(SMin, Min, int_type)
|
||||||
HLSL_GROUP_OP(SMax, Max, false)
|
HLSL_GROUP_OP_CAST(SMax, Max, int_type)
|
||||||
HLSL_GROUP_OP(UMin, Min, false)
|
HLSL_GROUP_OP_CAST(UMin, Min, uint_type)
|
||||||
HLSL_GROUP_OP(UMax, Max, false)
|
HLSL_GROUP_OP_CAST(UMax, Max, uint_type)
|
||||||
HLSL_GROUP_OP(BitwiseAnd, BitAnd, false)
|
HLSL_GROUP_OP(BitwiseAnd, BitAnd, false)
|
||||||
HLSL_GROUP_OP(BitwiseOr, BitOr, false)
|
HLSL_GROUP_OP(BitwiseOr, BitOr, false)
|
||||||
HLSL_GROUP_OP(BitwiseXor, BitXor, false)
|
HLSL_GROUP_OP(BitwiseXor, BitXor, false)
|
||||||
|
|
||||||
#undef HLSL_GROUP_OP
|
#undef HLSL_GROUP_OP
|
||||||
|
#undef HLSL_GROUP_OP_CAST
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
case OpGroupNonUniformQuadSwap:
|
case OpGroupNonUniformQuadSwap:
|
||||||
|
@ -5030,3 +5272,21 @@ void CompilerHLSL::emit_block_hints(const SPIRBlock &block)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2019 Robert Konrad
|
* Copyright 2016-2020 Robert Konrad
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -44,6 +44,8 @@ struct RootConstants
|
||||||
// For finer control, decorations may be removed from specific resources instead with unset_decoration().
|
// For finer control, decorations may be removed from specific resources instead with unset_decoration().
|
||||||
enum HLSLBindingFlagBits
|
enum HLSLBindingFlagBits
|
||||||
{
|
{
|
||||||
|
HLSL_BINDING_AUTO_NONE_BIT = 0,
|
||||||
|
|
||||||
// Push constant (root constant) resources will be declared as CBVs (b-space) without a register() declaration.
|
// 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.
|
// 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.
|
// 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;
|
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
|
class CompilerHLSL : public CompilerGLSL
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -145,6 +169,14 @@ public:
|
||||||
// Controls how resource bindings are declared in the output HLSL.
|
// Controls how resource bindings are declared in the output HLSL.
|
||||||
void set_resource_binding_flags(HLSLBindingFlags flags);
|
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:
|
private:
|
||||||
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||||
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
|
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
|
||||||
|
@ -178,12 +210,19 @@ private:
|
||||||
std::string to_sampler_expression(uint32_t id);
|
std::string to_sampler_expression(uint32_t id);
|
||||||
std::string to_resource_binding(const SPIRVariable &var);
|
std::string to_resource_binding(const SPIRVariable &var);
|
||||||
std::string to_resource_binding_sampler(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_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_access_chain(const Instruction &instruction);
|
||||||
void emit_load(const Instruction &instruction);
|
void emit_load(const Instruction &instruction);
|
||||||
std::string read_access_chain(const SPIRAccessChain &chain);
|
void read_access_chain(std::string *expr, const std::string &lhs, const SPIRAccessChain &chain);
|
||||||
void write_access_chain(const SPIRAccessChain &chain, uint32_t value);
|
void read_access_chain_struct(const std::string &lhs, const SPIRAccessChain &chain);
|
||||||
|
void read_access_chain_array(const std::string &lhs, const SPIRAccessChain &chain);
|
||||||
|
void write_access_chain(const SPIRAccessChain &chain, uint32_t value, const SmallVector<uint32_t> &composite_chain);
|
||||||
|
void write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value,
|
||||||
|
const SmallVector<uint32_t> &composite_chain);
|
||||||
|
void write_access_chain_array(const SPIRAccessChain &chain, uint32_t value,
|
||||||
|
const SmallVector<uint32_t> &composite_chain);
|
||||||
|
std::string write_access_chain_value(uint32_t value, const SmallVector<uint32_t> &composite_chain, bool enclose);
|
||||||
void emit_store(const Instruction &instruction);
|
void emit_store(const Instruction &instruction);
|
||||||
void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op);
|
void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op);
|
||||||
void emit_subgroup_op(const Instruction &i) override;
|
void emit_subgroup_op(const Instruction &i) override;
|
||||||
|
@ -257,6 +296,12 @@ private:
|
||||||
std::vector<RootConstants> root_constants_layout;
|
std::vector<RootConstants> root_constants_layout;
|
||||||
|
|
||||||
void validate_shader_model();
|
void validate_shader_model();
|
||||||
|
|
||||||
|
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
|
} // namespace SPIRV_CROSS_NAMESPACE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2019 The Brenwill Workshop Ltd.
|
* Copyright 2016-2020 The Brenwill Workshop Ltd.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -68,6 +68,12 @@ void CompilerMSL::add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32
|
||||||
buffers_requiring_dynamic_offset[pair] = { index, 0 };
|
buffers_requiring_dynamic_offset[pair] = { index, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerMSL::add_inline_uniform_block(uint32_t desc_set, uint32_t binding)
|
||||||
|
{
|
||||||
|
SetBindingPair pair = { desc_set, binding };
|
||||||
|
inline_uniform_blocks.insert(pair);
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerMSL::add_discrete_descriptor_set(uint32_t desc_set)
|
void CompilerMSL::add_discrete_descriptor_set(uint32_t desc_set)
|
||||||
{
|
{
|
||||||
if (desc_set < kMaxArgumentBuffers)
|
if (desc_set < kMaxArgumentBuffers)
|
||||||
|
@ -90,7 +96,7 @@ bool CompilerMSL::is_msl_vertex_attribute_used(uint32_t location)
|
||||||
return vtx_attrs_in_use.count(location) != 0;
|
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 };
|
StageSetBinding tuple = { model, desc_set, binding };
|
||||||
auto itr = resource_bindings.find(tuple);
|
auto itr = resource_bindings.find(tuple);
|
||||||
|
@ -1003,6 +1009,9 @@ string CompilerMSL::compile()
|
||||||
fixup_image_load_store_access();
|
fixup_image_load_store_access();
|
||||||
|
|
||||||
set_enabled_interface_variables(get_active_interface_variables());
|
set_enabled_interface_variables(get_active_interface_variables());
|
||||||
|
if (msl_options.force_active_argument_buffer_resources)
|
||||||
|
activate_argument_buffer_resources();
|
||||||
|
|
||||||
if (swizzle_buffer_id)
|
if (swizzle_buffer_id)
|
||||||
active_interface_variables.insert(swizzle_buffer_id);
|
active_interface_variables.insert(swizzle_buffer_id);
|
||||||
if (buffer_size_buffer_id)
|
if (buffer_size_buffer_id)
|
||||||
|
@ -1451,7 +1460,7 @@ uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t comp
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, bool strip_array)
|
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta)
|
||||||
{
|
{
|
||||||
bool is_builtin = is_builtin_variable(var);
|
bool is_builtin = is_builtin_variable(var);
|
||||||
BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
|
BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
|
||||||
|
@ -1466,16 +1475,77 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||||
var.basetype = type_id;
|
var.basetype = type_id;
|
||||||
|
|
||||||
type_id = get_pointee_type_id(var.basetype);
|
type_id = get_pointee_type_id(var.basetype);
|
||||||
if (strip_array && is_array(get<SPIRType>(type_id)))
|
if (meta.strip_array && is_array(get<SPIRType>(type_id)))
|
||||||
type_id = get<SPIRType>(type_id).parent_type;
|
type_id = get<SPIRType>(type_id).parent_type;
|
||||||
auto &type = get<SPIRType>(type_id);
|
auto &type = get<SPIRType>(type_id);
|
||||||
uint32_t target_components = 0;
|
uint32_t target_components = 0;
|
||||||
uint32_t type_components = type.vecsize;
|
uint32_t type_components = type.vecsize;
|
||||||
|
|
||||||
bool padded_output = false;
|
bool padded_output = false;
|
||||||
|
bool padded_input = false;
|
||||||
|
uint32_t start_component = 0;
|
||||||
|
|
||||||
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
||||||
|
|
||||||
|
// Deal with Component decorations.
|
||||||
|
InterfaceBlockMeta::LocationMeta *location_meta = nullptr;
|
||||||
|
if (has_decoration(var.self, DecorationLocation))
|
||||||
|
{
|
||||||
|
auto location_meta_itr = meta.location_meta.find(get_decoration(var.self, DecorationLocation));
|
||||||
|
if (location_meta_itr != end(meta.location_meta))
|
||||||
|
location_meta = &location_meta_itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pad_fragment_output = has_decoration(var.self, DecorationLocation) &&
|
||||||
|
msl_options.pad_fragment_output_components &&
|
||||||
|
get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput;
|
||||||
|
|
||||||
// Check if we need to pad fragment output to match a certain number of components.
|
// Check if we need to pad fragment output to match a certain number of components.
|
||||||
if (get_decoration_bitset(var.self).get(DecorationLocation) && msl_options.pad_fragment_output_components &&
|
if (location_meta)
|
||||||
get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput)
|
{
|
||||||
|
start_component = get_decoration(var.self, DecorationComponent);
|
||||||
|
uint32_t num_components = location_meta->num_components;
|
||||||
|
if (pad_fragment_output)
|
||||||
|
{
|
||||||
|
uint32_t locn = get_decoration(var.self, DecorationLocation);
|
||||||
|
num_components = std::max(num_components, get_target_components_for_fragment_location(locn));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location_meta->ib_index != ~0u)
|
||||||
|
{
|
||||||
|
// We have already declared the variable. Just emit an early-declared variable and fixup as needed.
|
||||||
|
entry_func.add_local_variable(var.self);
|
||||||
|
vars_needing_early_declaration.push_back(var.self);
|
||||||
|
|
||||||
|
if (var.storage == StorageClassInput)
|
||||||
|
{
|
||||||
|
uint32_t ib_index = location_meta->ib_index;
|
||||||
|
entry_func.fixup_hooks_in.push_back([=, &var]() {
|
||||||
|
statement(to_name(var.self), " = ", ib_var_ref, ".", to_member_name(ib_type, ib_index),
|
||||||
|
vector_swizzle(type_components, start_component), ";");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t ib_index = location_meta->ib_index;
|
||||||
|
entry_func.fixup_hooks_out.push_back([=, &var]() {
|
||||||
|
statement(ib_var_ref, ".", to_member_name(ib_type, ib_index),
|
||||||
|
vector_swizzle(type_components, start_component), " = ", to_name(var.self), ";");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
location_meta->ib_index = uint32_t(ib_type.member_types.size());
|
||||||
|
type_id = build_extended_vector_type(type_id, num_components);
|
||||||
|
if (var.storage == StorageClassInput)
|
||||||
|
padded_input = true;
|
||||||
|
else
|
||||||
|
padded_output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pad_fragment_output)
|
||||||
{
|
{
|
||||||
uint32_t locn = get_decoration(var.self, DecorationLocation);
|
uint32_t locn = get_decoration(var.self, DecorationLocation);
|
||||||
target_components = get_target_components_for_fragment_location(locn);
|
target_components = get_target_components_for_fragment_location(locn);
|
||||||
|
@ -1495,25 +1565,42 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||||
|
|
||||||
// Update the original variable reference to include the structure reference
|
// Update the original variable reference to include the structure reference
|
||||||
string qual_var_name = ib_var_ref + "." + mbr_name;
|
string qual_var_name = ib_var_ref + "." + mbr_name;
|
||||||
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
|
||||||
|
|
||||||
if (padded_output)
|
if (padded_output || padded_input)
|
||||||
{
|
{
|
||||||
entry_func.add_local_variable(var.self);
|
entry_func.add_local_variable(var.self);
|
||||||
vars_needing_early_declaration.push_back(var.self);
|
vars_needing_early_declaration.push_back(var.self);
|
||||||
|
|
||||||
entry_func.fixup_hooks_out.push_back([=, &var]() {
|
if (padded_output)
|
||||||
SPIRType &padded_type = this->get<SPIRType>(type_id);
|
{
|
||||||
statement(qual_var_name, " = ", remap_swizzle(padded_type, type_components, to_name(var.self)), ";");
|
entry_func.fixup_hooks_out.push_back([=, &var]() {
|
||||||
});
|
statement(qual_var_name, vector_swizzle(type_components, start_component), " = ", to_name(var.self),
|
||||||
|
";");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry_func.fixup_hooks_in.push_back([=, &var]() {
|
||||||
|
statement(to_name(var.self), " = ", qual_var_name, vector_swizzle(type_components, start_component),
|
||||||
|
";");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!strip_array)
|
else if (!meta.strip_array)
|
||||||
ir.meta[var.self].decoration.qualified_alias = qual_var_name;
|
ir.meta[var.self].decoration.qualified_alias = qual_var_name;
|
||||||
|
|
||||||
if (var.storage == StorageClassOutput && var.initializer != ID(0))
|
if (var.storage == StorageClassOutput && var.initializer != ID(0))
|
||||||
{
|
{
|
||||||
entry_func.fixup_hooks_in.push_back(
|
if (padded_output || padded_input)
|
||||||
[=, &var]() { statement(qual_var_name, " = ", to_expression(var.initializer), ";"); });
|
{
|
||||||
|
entry_func.fixup_hooks_in.push_back(
|
||||||
|
[=, &var]() { statement(to_name(var.self), " = ", to_expression(var.initializer), ";"); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry_func.fixup_hooks_in.push_back(
|
||||||
|
[=, &var]() { statement(qual_var_name, " = ", to_expression(var.initializer), ";"); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the variable location from the original variable to the member
|
// Copy the variable location from the original variable to the member
|
||||||
|
@ -1522,10 +1609,14 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||||
uint32_t locn = get_decoration(var.self, DecorationLocation);
|
uint32_t locn = get_decoration(var.self, DecorationLocation);
|
||||||
if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader()))
|
if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader()))
|
||||||
{
|
{
|
||||||
type_id = ensure_correct_attribute_type(var.basetype, locn);
|
type_id = ensure_correct_attribute_type(var.basetype, locn,
|
||||||
var.basetype = type_id;
|
location_meta ? location_meta->num_components : type.vecsize);
|
||||||
|
|
||||||
|
if (!location_meta)
|
||||||
|
var.basetype = type_id;
|
||||||
|
|
||||||
type_id = get_pointee_type_id(type_id);
|
type_id = get_pointee_type_id(type_id);
|
||||||
if (strip_array && is_array(get<SPIRType>(type_id)))
|
if (meta.strip_array && is_array(get<SPIRType>(type_id)))
|
||||||
type_id = get<SPIRType>(type_id).parent_type;
|
type_id = get<SPIRType>(type_id).parent_type;
|
||||||
ib_type.member_types[ib_mbr_idx] = type_id;
|
ib_type.member_types[ib_mbr_idx] = type_id;
|
||||||
}
|
}
|
||||||
|
@ -1539,10 +1630,13 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||||
mark_location_as_used_by_shader(locn, storage);
|
mark_location_as_used_by_shader(locn, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_decoration_bitset(var.self).get(DecorationComponent))
|
if (!location_meta)
|
||||||
{
|
{
|
||||||
uint32_t comp = get_decoration(var.self, DecorationComponent);
|
if (get_decoration_bitset(var.self).get(DecorationComponent))
|
||||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp);
|
{
|
||||||
|
uint32_t component = get_decoration(var.self, DecorationComponent);
|
||||||
|
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_decoration_bitset(var.self).get(DecorationIndex))
|
if (get_decoration_bitset(var.self).get(DecorationIndex))
|
||||||
|
@ -1569,14 +1663,18 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||||
if (is_sample)
|
if (is_sample)
|
||||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||||
|
|
||||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
// If we have location meta, there is no unique OrigID. We won't need it, since we flatten/unflatten
|
||||||
|
// the variable to stack anyways here.
|
||||||
|
if (!location_meta)
|
||||||
|
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, bool strip_array)
|
SPIRType &ib_type, SPIRVariable &var,
|
||||||
|
InterfaceBlockMeta &meta)
|
||||||
{
|
{
|
||||||
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
||||||
auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
||||||
uint32_t elem_cnt = 0;
|
uint32_t elem_cnt = 0;
|
||||||
|
|
||||||
if (is_matrix(var_type))
|
if (is_matrix(var_type))
|
||||||
|
@ -1612,6 +1710,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||||
set_name(var.self, builtin_to_glsl(builtin, StorageClassFunction));
|
set_name(var.self, builtin_to_glsl(builtin, StorageClassFunction));
|
||||||
|
|
||||||
bool flatten_from_ib_var = false;
|
bool flatten_from_ib_var = false;
|
||||||
|
string flatten_from_ib_mbr_name;
|
||||||
|
|
||||||
if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance)
|
if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance)
|
||||||
{
|
{
|
||||||
|
@ -1619,13 +1718,15 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||||
uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size());
|
uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size());
|
||||||
ib_type.member_types.push_back(get_variable_data_type_id(var));
|
ib_type.member_types.push_back(get_variable_data_type_id(var));
|
||||||
set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance);
|
set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance);
|
||||||
set_member_name(ib_type.self, clip_array_mbr_idx, builtin_to_glsl(BuiltInClipDistance, StorageClassOutput));
|
|
||||||
|
flatten_from_ib_mbr_name = builtin_to_glsl(BuiltInClipDistance, StorageClassOutput);
|
||||||
|
set_member_name(ib_type.self, clip_array_mbr_idx, flatten_from_ib_mbr_name);
|
||||||
|
|
||||||
// When we flatten, we flatten directly from the "out" struct,
|
// When we flatten, we flatten directly from the "out" struct,
|
||||||
// not from a function variable.
|
// not from a function variable.
|
||||||
flatten_from_ib_var = true;
|
flatten_from_ib_var = true;
|
||||||
}
|
}
|
||||||
else if (!strip_array)
|
else if (!meta.strip_array)
|
||||||
{
|
{
|
||||||
// Only flatten/unflatten IO composites for non-tessellation cases where arrays are not stripped.
|
// Only flatten/unflatten IO composites for non-tessellation cases where arrays are not stripped.
|
||||||
entry_func.add_local_variable(var.self);
|
entry_func.add_local_variable(var.self);
|
||||||
|
@ -1708,7 +1809,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
||||||
|
|
||||||
// Only flatten/unflatten IO composites for non-tessellation cases where arrays are not stripped.
|
// Only flatten/unflatten IO composites for non-tessellation cases where arrays are not stripped.
|
||||||
if (!strip_array)
|
if (!meta.strip_array)
|
||||||
{
|
{
|
||||||
switch (storage)
|
switch (storage)
|
||||||
{
|
{
|
||||||
|
@ -1728,7 +1829,8 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||||
";");
|
";");
|
||||||
}
|
}
|
||||||
else if (flatten_from_ib_var)
|
else if (flatten_from_ib_var)
|
||||||
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", to_name(var.self), "[", i, "];");
|
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i,
|
||||||
|
"];");
|
||||||
else
|
else
|
||||||
statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), "[", i, "];");
|
statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), "[", i, "];");
|
||||||
});
|
});
|
||||||
|
@ -1771,10 +1873,10 @@ uint32_t CompilerMSL::get_accumulated_member_location(const SPIRVariable &var, u
|
||||||
|
|
||||||
void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var,
|
SPIRType &ib_type, SPIRVariable &var,
|
||||||
uint32_t mbr_idx, bool strip_array)
|
uint32_t mbr_idx, InterfaceBlockMeta &meta)
|
||||||
{
|
{
|
||||||
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
||||||
auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
||||||
|
|
||||||
BuiltIn builtin = BuiltInMax;
|
BuiltIn builtin = BuiltInMax;
|
||||||
bool is_builtin = is_member_builtin(var_type, mbr_idx, &builtin);
|
bool is_builtin = is_member_builtin(var_type, mbr_idx, &builtin);
|
||||||
|
@ -1813,6 +1915,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||||
usable_type = &get<SPIRType>(usable_type->parent_type);
|
usable_type = &get<SPIRType>(usable_type->parent_type);
|
||||||
|
|
||||||
bool flatten_from_ib_var = false;
|
bool flatten_from_ib_var = false;
|
||||||
|
string flatten_from_ib_mbr_name;
|
||||||
|
|
||||||
if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance)
|
if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance)
|
||||||
{
|
{
|
||||||
|
@ -1820,7 +1923,9 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||||
uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size());
|
uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size());
|
||||||
ib_type.member_types.push_back(mbr_type_id);
|
ib_type.member_types.push_back(mbr_type_id);
|
||||||
set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance);
|
set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance);
|
||||||
set_member_name(ib_type.self, clip_array_mbr_idx, builtin_to_glsl(BuiltInClipDistance, StorageClassOutput));
|
|
||||||
|
flatten_from_ib_mbr_name = builtin_to_glsl(BuiltInClipDistance, StorageClassOutput);
|
||||||
|
set_member_name(ib_type.self, clip_array_mbr_idx, flatten_from_ib_mbr_name);
|
||||||
|
|
||||||
// When we flatten, we flatten directly from the "out" struct,
|
// When we flatten, we flatten directly from the "out" struct,
|
||||||
// not from a function variable.
|
// not from a function variable.
|
||||||
|
@ -1845,7 +1950,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||||
}
|
}
|
||||||
else if (has_decoration(var.self, DecorationLocation))
|
else if (has_decoration(var.self, DecorationLocation))
|
||||||
{
|
{
|
||||||
uint32_t locn = get_accumulated_member_location(var, mbr_idx, strip_array) + i;
|
uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array) + i;
|
||||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||||
mark_location_as_used_by_shader(locn, storage);
|
mark_location_as_used_by_shader(locn, storage);
|
||||||
}
|
}
|
||||||
|
@ -1879,7 +1984,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx);
|
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx);
|
||||||
|
|
||||||
// Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate.
|
// Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate.
|
||||||
if (!strip_array)
|
if (!meta.strip_array)
|
||||||
{
|
{
|
||||||
switch (storage)
|
switch (storage)
|
||||||
{
|
{
|
||||||
|
@ -1894,8 +1999,8 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||||
entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() {
|
entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() {
|
||||||
if (flatten_from_ib_var)
|
if (flatten_from_ib_var)
|
||||||
{
|
{
|
||||||
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".",
|
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i,
|
||||||
to_member_name(var_type, mbr_idx), "[", i, "];");
|
"];");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1914,9 +2019,9 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||||
|
|
||||||
void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, uint32_t mbr_idx,
|
SPIRType &ib_type, SPIRVariable &var, uint32_t mbr_idx,
|
||||||
bool strip_array)
|
InterfaceBlockMeta &meta)
|
||||||
{
|
{
|
||||||
auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
||||||
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
||||||
|
|
||||||
BuiltIn builtin = BuiltInMax;
|
BuiltIn builtin = BuiltInMax;
|
||||||
|
@ -1944,13 +2049,13 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||||
// Update the original variable reference to include the structure reference
|
// Update the original variable reference to include the structure reference
|
||||||
string qual_var_name = ib_var_ref + "." + mbr_name;
|
string qual_var_name = ib_var_ref + "." + mbr_name;
|
||||||
|
|
||||||
if (is_builtin && !strip_array)
|
if (is_builtin && !meta.strip_array)
|
||||||
{
|
{
|
||||||
// For the builtin gl_PerVertex, we cannot treat it as a block anyways,
|
// For the builtin gl_PerVertex, we cannot treat it as a block anyways,
|
||||||
// so redirect to qualified name.
|
// so redirect to qualified name.
|
||||||
set_member_qualified_name(var_type.self, mbr_idx, qual_var_name);
|
set_member_qualified_name(var_type.self, mbr_idx, qual_var_name);
|
||||||
}
|
}
|
||||||
else if (!strip_array)
|
else if (!meta.strip_array)
|
||||||
{
|
{
|
||||||
// Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate.
|
// Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate.
|
||||||
switch (storage)
|
switch (storage)
|
||||||
|
@ -1989,7 +2094,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||||
{
|
{
|
||||||
// The block itself might have a location and in this case, all members of the block
|
// The block itself might have a location and in this case, all members of the block
|
||||||
// receive incrementing locations.
|
// receive incrementing locations.
|
||||||
uint32_t locn = get_accumulated_member_location(var, mbr_idx, strip_array);
|
uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array);
|
||||||
if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader()))
|
if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader()))
|
||||||
{
|
{
|
||||||
mbr_type_id = ensure_correct_attribute_type(mbr_type_id, locn);
|
mbr_type_id = ensure_correct_attribute_type(mbr_type_id, locn);
|
||||||
|
@ -2155,19 +2260,20 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, SPIRType &ib_type,
|
void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, SPIRType &ib_type,
|
||||||
SPIRVariable &var, bool strip_array)
|
SPIRVariable &var, InterfaceBlockMeta &meta)
|
||||||
{
|
{
|
||||||
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
||||||
// Tessellation control I/O variables and tessellation evaluation per-point inputs are
|
// Tessellation control I/O variables and tessellation evaluation per-point inputs are
|
||||||
// usually declared as arrays. In these cases, we want to add the element type to the
|
// usually declared as arrays. In these cases, we want to add the element type to the
|
||||||
// interface block, since in Metal it's the interface block itself which is arrayed.
|
// interface block, since in Metal it's the interface block itself which is arrayed.
|
||||||
auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
||||||
bool is_builtin = is_builtin_variable(var);
|
bool is_builtin = is_builtin_variable(var);
|
||||||
auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
|
auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
|
||||||
|
|
||||||
if (var_type.basetype == SPIRType::Struct)
|
if (var_type.basetype == SPIRType::Struct)
|
||||||
{
|
{
|
||||||
if (!is_builtin_type(var_type) && (!capture_output_to_buffer || storage == StorageClassInput) && !strip_array)
|
if (!is_builtin_type(var_type) && (!capture_output_to_buffer || storage == StorageClassInput) &&
|
||||||
|
!meta.strip_array)
|
||||||
{
|
{
|
||||||
// For I/O blocks or structs, we will need to pass the block itself around
|
// For I/O blocks or structs, we will need to pass the block itself around
|
||||||
// to functions if they are used globally in leaf functions.
|
// to functions if they are used globally in leaf functions.
|
||||||
|
@ -2186,7 +2292,7 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
||||||
// Luckily, for stage-out when capturing output, we can avoid this and just add
|
// Luckily, for stage-out when capturing output, we can avoid this and just add
|
||||||
// composite members directly, because the stage-out structure is stored to a buffer,
|
// composite members directly, because the stage-out structure is stored to a buffer,
|
||||||
// not returned.
|
// not returned.
|
||||||
add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, strip_array);
|
add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, meta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2200,7 +2306,8 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
||||||
if (!is_builtin || has_active_builtin(builtin, storage))
|
if (!is_builtin || has_active_builtin(builtin, storage))
|
||||||
{
|
{
|
||||||
bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type);
|
bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type);
|
||||||
bool attribute_load_store = storage == StorageClassInput && get_execution_model() != ExecutionModelFragment;
|
bool attribute_load_store =
|
||||||
|
storage == StorageClassInput && get_execution_model() != ExecutionModelFragment;
|
||||||
bool storage_is_stage_io = storage == StorageClassInput || storage == StorageClassOutput;
|
bool storage_is_stage_io = storage == StorageClassInput || storage == StorageClassOutput;
|
||||||
|
|
||||||
// ClipDistance always needs to be declared as user attributes.
|
// ClipDistance always needs to be declared as user attributes.
|
||||||
|
@ -2210,19 +2317,18 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
||||||
if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type)
|
if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type)
|
||||||
{
|
{
|
||||||
add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx,
|
add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx,
|
||||||
strip_array);
|
meta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx,
|
add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, meta);
|
||||||
strip_array);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput &&
|
else if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput &&
|
||||||
!strip_array && is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner))
|
!meta.strip_array && is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner))
|
||||||
{
|
{
|
||||||
add_tess_level_input_to_interface_block(ib_var_ref, ib_type, var);
|
add_tess_level_input_to_interface_block(ib_var_ref, ib_type, var);
|
||||||
}
|
}
|
||||||
|
@ -2233,7 +2339,7 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
||||||
{
|
{
|
||||||
bool is_composite_type = is_matrix(var_type) || is_array(var_type);
|
bool is_composite_type = is_matrix(var_type) || is_array(var_type);
|
||||||
bool storage_is_stage_io =
|
bool storage_is_stage_io =
|
||||||
storage == StorageClassInput || (storage == StorageClassOutput && !capture_output_to_buffer);
|
storage == StorageClassInput || (storage == StorageClassOutput && !capture_output_to_buffer);
|
||||||
bool attribute_load_store = storage == StorageClassInput && get_execution_model() != ExecutionModelFragment;
|
bool attribute_load_store = storage == StorageClassInput && get_execution_model() != ExecutionModelFragment;
|
||||||
|
|
||||||
// ClipDistance always needs to be declared as user attributes.
|
// ClipDistance always needs to be declared as user attributes.
|
||||||
|
@ -2243,11 +2349,11 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
||||||
// MSL does not allow matrices or arrays in input or output variables, so need to handle it specially.
|
// MSL does not allow matrices or arrays in input or output variables, so need to handle it specially.
|
||||||
if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type)
|
if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type)
|
||||||
{
|
{
|
||||||
add_composite_variable_to_interface_block(storage, ib_var_ref, ib_type, var, strip_array);
|
add_composite_variable_to_interface_block(storage, ib_var_ref, ib_type, var, meta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, strip_array);
|
add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2301,6 +2407,16 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
||||||
bool incl_builtins = storage == StorageClassOutput || is_tessellation_shader();
|
bool incl_builtins = storage == StorageClassOutput || is_tessellation_shader();
|
||||||
bool has_seen_barycentric = false;
|
bool has_seen_barycentric = false;
|
||||||
|
|
||||||
|
InterfaceBlockMeta meta;
|
||||||
|
|
||||||
|
// Varying interfaces between stages which use "user()" attribute can be dealt with
|
||||||
|
// without explicit packing and unpacking of components. For any variables which link against the runtime
|
||||||
|
// in some way (vertex attributes, fragment output, etc), we'll need to deal with it somehow.
|
||||||
|
bool pack_components =
|
||||||
|
(storage == StorageClassInput && get_execution_model() == ExecutionModelVertex) ||
|
||||||
|
(storage == StorageClassOutput && get_execution_model() == ExecutionModelFragment) ||
|
||||||
|
(storage == StorageClassOutput && get_execution_model() == ExecutionModelVertex && capture_output_to_buffer);
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
|
||||||
if (var.storage != storage)
|
if (var.storage != storage)
|
||||||
return;
|
return;
|
||||||
|
@ -2347,6 +2463,28 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
||||||
(!is_builtin || is_interface_block_builtin))
|
(!is_builtin || is_interface_block_builtin))
|
||||||
{
|
{
|
||||||
vars.push_back(&var);
|
vars.push_back(&var);
|
||||||
|
|
||||||
|
if (!is_builtin)
|
||||||
|
{
|
||||||
|
// Need to deal specially with DecorationComponent.
|
||||||
|
// Multiple variables can alias the same Location, and try to make sure each location is declared only once.
|
||||||
|
// We will swizzle data in and out to make this work.
|
||||||
|
// We only need to consider plain variables here, not composites.
|
||||||
|
// This is only relevant for vertex inputs and fragment outputs.
|
||||||
|
// Technically tessellation as well, but it is too complicated to support.
|
||||||
|
uint32_t component = get_decoration(var_id, DecorationComponent);
|
||||||
|
if (component != 0)
|
||||||
|
{
|
||||||
|
if (is_tessellation_shader())
|
||||||
|
SPIRV_CROSS_THROW("Component decoration is not supported in tessellation shaders.");
|
||||||
|
else if (pack_components)
|
||||||
|
{
|
||||||
|
uint32_t location = get_decoration(var_id, DecorationLocation);
|
||||||
|
auto &location_meta = meta.location_meta[location];
|
||||||
|
location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2480,7 +2618,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
||||||
(get_execution_model() == ExecutionModelTessellationControl ||
|
(get_execution_model() == ExecutionModelTessellationControl ||
|
||||||
(get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput)) &&
|
(get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput)) &&
|
||||||
!patch;
|
!patch;
|
||||||
add_variable_to_interface_block(storage, ib_var_ref, ib_type, *p_var, strip_array);
|
|
||||||
|
meta.strip_array = strip_array;
|
||||||
|
add_variable_to_interface_block(storage, ib_var_ref, ib_type, *p_var, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the members of the structure by their locations.
|
// Sort the members of the structure by their locations.
|
||||||
|
@ -2599,13 +2739,18 @@ uint32_t CompilerMSL::ensure_correct_builtin_type(uint32_t type_id, BuiltIn buil
|
||||||
// Ensure that the type is compatible with the vertex attribute.
|
// Ensure that the type is compatible with the vertex attribute.
|
||||||
// If it is, simply return the given type ID.
|
// If it is, simply return the given type ID.
|
||||||
// Otherwise, create a new type, and return its ID.
|
// Otherwise, create a new type, and return its ID.
|
||||||
uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t location)
|
uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t location, uint32_t num_components)
|
||||||
{
|
{
|
||||||
auto &type = get<SPIRType>(type_id);
|
auto &type = get<SPIRType>(type_id);
|
||||||
|
|
||||||
auto p_va = vtx_attrs_by_location.find(location);
|
auto p_va = vtx_attrs_by_location.find(location);
|
||||||
if (p_va == end(vtx_attrs_by_location))
|
if (p_va == end(vtx_attrs_by_location))
|
||||||
return type_id;
|
{
|
||||||
|
if (num_components != 0 && type.vecsize != num_components)
|
||||||
|
return build_extended_vector_type(type_id, num_components);
|
||||||
|
else
|
||||||
|
return type_id;
|
||||||
|
}
|
||||||
|
|
||||||
switch (p_va->second.format)
|
switch (p_va->second.format)
|
||||||
{
|
{
|
||||||
|
@ -2616,19 +2761,27 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
|
||||||
case SPIRType::UByte:
|
case SPIRType::UByte:
|
||||||
case SPIRType::UShort:
|
case SPIRType::UShort:
|
||||||
case SPIRType::UInt:
|
case SPIRType::UInt:
|
||||||
return type_id;
|
if (num_components != 0 && type.vecsize != num_components)
|
||||||
|
return build_extended_vector_type(type_id, num_components);
|
||||||
|
else
|
||||||
|
return type_id;
|
||||||
|
|
||||||
case SPIRType::Short:
|
case SPIRType::Short:
|
||||||
case SPIRType::Int:
|
case SPIRType::Int:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
SPIRV_CROSS_THROW("Vertex attribute type mismatch between host and shader");
|
SPIRV_CROSS_THROW("Vertex attribute type mismatch between host and shader");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1);
|
uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1);
|
||||||
uint32_t base_type_id = next_id++;
|
uint32_t base_type_id = next_id++;
|
||||||
auto &base_type = set<SPIRType>(base_type_id);
|
auto &base_type = set<SPIRType>(base_type_id);
|
||||||
base_type = type;
|
base_type = type;
|
||||||
base_type.basetype = type.basetype == SPIRType::Short ? SPIRType::UShort : SPIRType::UInt;
|
base_type.basetype = type.basetype == SPIRType::Short ? SPIRType::UShort : SPIRType::UInt;
|
||||||
base_type.pointer = false;
|
base_type.pointer = false;
|
||||||
|
if (num_components != 0)
|
||||||
|
base_type.vecsize = num_components;
|
||||||
|
|
||||||
if (!type.pointer)
|
if (!type.pointer)
|
||||||
return base_type_id;
|
return base_type_id;
|
||||||
|
@ -2648,18 +2801,26 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
|
||||||
{
|
{
|
||||||
case SPIRType::UShort:
|
case SPIRType::UShort:
|
||||||
case SPIRType::UInt:
|
case SPIRType::UInt:
|
||||||
return type_id;
|
if (num_components != 0 && type.vecsize != num_components)
|
||||||
|
return build_extended_vector_type(type_id, num_components);
|
||||||
|
else
|
||||||
|
return type_id;
|
||||||
|
|
||||||
case SPIRType::Int:
|
case SPIRType::Int:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
SPIRV_CROSS_THROW("Vertex attribute type mismatch between host and shader");
|
SPIRV_CROSS_THROW("Vertex attribute type mismatch between host and shader");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1);
|
uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1);
|
||||||
uint32_t base_type_id = next_id++;
|
uint32_t base_type_id = next_id++;
|
||||||
auto &base_type = set<SPIRType>(base_type_id);
|
auto &base_type = set<SPIRType>(base_type_id);
|
||||||
base_type = type;
|
base_type = type;
|
||||||
base_type.basetype = SPIRType::UInt;
|
base_type.basetype = SPIRType::UInt;
|
||||||
base_type.pointer = false;
|
base_type.pointer = false;
|
||||||
|
if (num_components != 0)
|
||||||
|
base_type.vecsize = num_components;
|
||||||
|
|
||||||
if (!type.pointer)
|
if (!type.pointer)
|
||||||
return base_type_id;
|
return base_type_id;
|
||||||
|
@ -2674,7 +2835,8 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case MSL_VERTEX_FORMAT_OTHER:
|
if (num_components != 0 && type.vecsize != num_components)
|
||||||
|
type_id = build_extended_vector_type(type_id, num_components);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3268,8 +3430,7 @@ string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type
|
||||||
assert(type.vecsize >= 1 && type.vecsize <= 3);
|
assert(type.vecsize >= 1 && type.vecsize <= 3);
|
||||||
return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1];
|
return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1];
|
||||||
}
|
}
|
||||||
else if (physical_type && is_matrix(*physical_type) && is_vector(type) &&
|
else if (physical_type && is_matrix(*physical_type) && is_vector(type) && physical_type->vecsize > type.vecsize)
|
||||||
physical_type->vecsize > type.vecsize)
|
|
||||||
{
|
{
|
||||||
// Extract column from padded matrix.
|
// Extract column from padded matrix.
|
||||||
assert(type.vecsize >= 1 && type.vecsize <= 3);
|
assert(type.vecsize >= 1 && type.vecsize <= 3);
|
||||||
|
@ -8604,7 +8765,14 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
|
||||||
uint32_t locn = get_ordered_member_location(type.self, index, &comp);
|
uint32_t locn = get_ordered_member_location(type.self, index, &comp);
|
||||||
if (locn != k_unknown_location)
|
if (locn != k_unknown_location)
|
||||||
{
|
{
|
||||||
if (comp != k_unknown_component)
|
// For user-defined attributes, this is fine. From Vulkan spec:
|
||||||
|
// A user-defined output variable is considered to match an input variable in the subsequent stage if
|
||||||
|
// the two variables are declared with the same Location and Component decoration and match in type
|
||||||
|
// and decoration, except that interpolation decorations are not required to match. For the purposes
|
||||||
|
// of interface matching, variables declared without a Component decoration are considered to have a
|
||||||
|
// Component decoration of zero.
|
||||||
|
|
||||||
|
if (comp != k_unknown_component && comp != 0)
|
||||||
quals = string("user(locn") + convert_to_string(locn) + "_" + convert_to_string(comp) + ")";
|
quals = string("user(locn") + convert_to_string(locn) + "_" + convert_to_string(comp) + ")";
|
||||||
else
|
else
|
||||||
quals = string("user(locn") + convert_to_string(locn) + ")";
|
quals = string("user(locn") + convert_to_string(locn) + ")";
|
||||||
|
@ -9704,9 +9872,8 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
|
||||||
bool use_secondary_binding = (var_type.basetype == SPIRType::SampledImage && basetype == SPIRType::Sampler) ||
|
bool use_secondary_binding = (var_type.basetype == SPIRType::SampledImage && basetype == SPIRType::Sampler) ||
|
||||||
basetype == SPIRType::AtomicCounter;
|
basetype == SPIRType::AtomicCounter;
|
||||||
|
|
||||||
auto resource_decoration = use_secondary_binding ?
|
auto resource_decoration =
|
||||||
SPIRVCrossDecorationResourceIndexSecondary :
|
use_secondary_binding ? SPIRVCrossDecorationResourceIndexSecondary : SPIRVCrossDecorationResourceIndexPrimary;
|
||||||
SPIRVCrossDecorationResourceIndexPrimary;
|
|
||||||
|
|
||||||
if (plane == 1)
|
if (plane == 1)
|
||||||
resource_decoration = SPIRVCrossDecorationResourceIndexTertiary;
|
resource_decoration = SPIRVCrossDecorationResourceIndexTertiary;
|
||||||
|
@ -9751,6 +9918,11 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
|
||||||
// If we did not explicitly remap, allocate bindings on demand.
|
// If we did not explicitly remap, allocate bindings on demand.
|
||||||
// We cannot reliably use Binding decorations since SPIR-V and MSL's binding models are very different.
|
// We cannot reliably use Binding decorations since SPIR-V and MSL's binding models are very different.
|
||||||
|
|
||||||
|
bool allocate_argument_buffer_ids = false;
|
||||||
|
|
||||||
|
if (var.storage != StorageClassPushConstant)
|
||||||
|
allocate_argument_buffer_ids = descriptor_set_is_argument_buffer(var_desc_set);
|
||||||
|
|
||||||
uint32_t binding_stride = 1;
|
uint32_t binding_stride = 1;
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
for (uint32_t i = 0; i < uint32_t(type.array.size()); i++)
|
for (uint32_t i = 0; i < uint32_t(type.array.size()); i++)
|
||||||
|
@ -9761,20 +9933,11 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
|
||||||
// If a binding has not been specified, revert to incrementing resource indices.
|
// If a binding has not been specified, revert to incrementing resource indices.
|
||||||
uint32_t resource_index;
|
uint32_t resource_index;
|
||||||
|
|
||||||
bool allocate_argument_buffer_ids = false;
|
|
||||||
uint32_t desc_set = 0;
|
|
||||||
|
|
||||||
if (var.storage != StorageClassPushConstant)
|
|
||||||
{
|
|
||||||
desc_set = get_decoration(var.self, DecorationDescriptorSet);
|
|
||||||
allocate_argument_buffer_ids = descriptor_set_is_argument_buffer(desc_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allocate_argument_buffer_ids)
|
if (allocate_argument_buffer_ids)
|
||||||
{
|
{
|
||||||
// Allocate from a flat ID binding space.
|
// Allocate from a flat ID binding space.
|
||||||
resource_index = next_metal_resource_ids[desc_set];
|
resource_index = next_metal_resource_ids[var_desc_set];
|
||||||
next_metal_resource_ids[desc_set] += binding_stride;
|
next_metal_resource_ids[var_desc_set] += binding_stride;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -10244,19 +10407,31 @@ void CompilerMSL::replace_illegal_names()
|
||||||
};
|
};
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, SPIRVariable &) {
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, SPIRVariable &) {
|
||||||
auto &dec = ir.meta[self].decoration;
|
auto *meta = ir.find_meta(self);
|
||||||
|
if (!meta)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto &dec = meta->decoration;
|
||||||
if (keywords.find(dec.alias) != end(keywords))
|
if (keywords.find(dec.alias) != end(keywords))
|
||||||
dec.alias += "0";
|
dec.alias += "0";
|
||||||
});
|
});
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRFunction>([&](uint32_t self, SPIRFunction &) {
|
ir.for_each_typed_id<SPIRFunction>([&](uint32_t self, SPIRFunction &) {
|
||||||
auto &dec = ir.meta[self].decoration;
|
auto *meta = ir.find_meta(self);
|
||||||
|
if (!meta)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto &dec = meta->decoration;
|
||||||
if (illegal_func_names.find(dec.alias) != end(illegal_func_names))
|
if (illegal_func_names.find(dec.alias) != end(illegal_func_names))
|
||||||
dec.alias += "0";
|
dec.alias += "0";
|
||||||
});
|
});
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &) {
|
ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &) {
|
||||||
for (auto &mbr_dec : ir.meta[self].members)
|
auto *meta = ir.find_meta(self);
|
||||||
|
if (!meta)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto &mbr_dec : meta->members)
|
||||||
if (keywords.find(mbr_dec.alias) != end(keywords))
|
if (keywords.find(mbr_dec.alias) != end(keywords))
|
||||||
mbr_dec.alias += "0";
|
mbr_dec.alias += "0";
|
||||||
});
|
});
|
||||||
|
@ -10709,6 +10884,11 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
|
||||||
if (!msl_options.supports_msl_version(2))
|
if (!msl_options.supports_msl_version(2))
|
||||||
SPIRV_CROSS_THROW("Subgroups are only supported in Metal 2.0 and up.");
|
SPIRV_CROSS_THROW("Subgroups are only supported in Metal 2.0 and up.");
|
||||||
|
|
||||||
|
// If we need to do implicit bitcasts, make sure we do it with the correct type.
|
||||||
|
uint32_t integer_width = get_integer_width_for_instruction(i);
|
||||||
|
auto int_type = to_signed_basetype(integer_width);
|
||||||
|
auto uint_type = to_unsigned_basetype(integer_width);
|
||||||
|
|
||||||
if (msl_options.is_ios())
|
if (msl_options.is_ios())
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
@ -10731,7 +10911,7 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
SPIRV_CROSS_THROW("Subgroup ops beyond broadcast and shuffle on macOS require Metal 2.0 and up.");
|
SPIRV_CROSS_THROW("Subgroup ops beyond broadcast and shuffle on macOS require Metal 2.1 and up.");
|
||||||
case OpGroupNonUniformBroadcast:
|
case OpGroupNonUniformBroadcast:
|
||||||
case OpGroupNonUniformShuffle:
|
case OpGroupNonUniformShuffle:
|
||||||
case OpGroupNonUniformShuffleXor:
|
case OpGroupNonUniformShuffleXor:
|
||||||
|
@ -10859,6 +11039,7 @@ case OpGroupNonUniform##op: \
|
||||||
MSL_GROUP_OP(IMul, product)
|
MSL_GROUP_OP(IMul, product)
|
||||||
#undef MSL_GROUP_OP
|
#undef MSL_GROUP_OP
|
||||||
// The others, unfortunately, don't support InclusiveScan or ExclusiveScan.
|
// The others, unfortunately, don't support InclusiveScan or ExclusiveScan.
|
||||||
|
|
||||||
#define MSL_GROUP_OP(op, msl_op) \
|
#define MSL_GROUP_OP(op, msl_op) \
|
||||||
case OpGroupNonUniform##op: \
|
case OpGroupNonUniform##op: \
|
||||||
{ \
|
{ \
|
||||||
|
@ -10881,12 +11062,36 @@ case OpGroupNonUniform##op: \
|
||||||
SPIRV_CROSS_THROW("Invalid group operation."); \
|
SPIRV_CROSS_THROW("Invalid group operation."); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MSL_GROUP_OP_CAST(op, msl_op, type) \
|
||||||
|
case OpGroupNonUniform##op: \
|
||||||
|
{ \
|
||||||
|
auto operation = static_cast<GroupOperation>(ops[3]); \
|
||||||
|
if (operation == GroupOperationReduce) \
|
||||||
|
emit_unary_func_op_cast(result_type, id, ops[4], "simd_" #msl_op, type, type); \
|
||||||
|
else if (operation == GroupOperationInclusiveScan) \
|
||||||
|
SPIRV_CROSS_THROW("Metal doesn't support InclusiveScan for OpGroupNonUniform" #op "."); \
|
||||||
|
else if (operation == GroupOperationExclusiveScan) \
|
||||||
|
SPIRV_CROSS_THROW("Metal doesn't support ExclusiveScan for OpGroupNonUniform" #op "."); \
|
||||||
|
else if (operation == GroupOperationClusteredReduce) \
|
||||||
|
{ \
|
||||||
|
/* Only cluster sizes of 4 are supported. */ \
|
||||||
|
uint32_t cluster_size = get<SPIRConstant>(ops[5]).scalar(); \
|
||||||
|
if (cluster_size != 4) \
|
||||||
|
SPIRV_CROSS_THROW("Metal only supports quad ClusteredReduce."); \
|
||||||
|
emit_unary_func_op_cast(result_type, id, ops[4], "quad_" #msl_op, type, type); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
SPIRV_CROSS_THROW("Invalid group operation."); \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
MSL_GROUP_OP(FMin, min)
|
MSL_GROUP_OP(FMin, min)
|
||||||
MSL_GROUP_OP(FMax, max)
|
MSL_GROUP_OP(FMax, max)
|
||||||
MSL_GROUP_OP(SMin, min)
|
MSL_GROUP_OP_CAST(SMin, min, int_type)
|
||||||
MSL_GROUP_OP(SMax, max)
|
MSL_GROUP_OP_CAST(SMax, max, int_type)
|
||||||
MSL_GROUP_OP(UMin, min)
|
MSL_GROUP_OP_CAST(UMin, min, uint_type)
|
||||||
MSL_GROUP_OP(UMax, max)
|
MSL_GROUP_OP_CAST(UMax, max, uint_type)
|
||||||
MSL_GROUP_OP(BitwiseAnd, and)
|
MSL_GROUP_OP(BitwiseAnd, and)
|
||||||
MSL_GROUP_OP(BitwiseOr, or)
|
MSL_GROUP_OP(BitwiseOr, or)
|
||||||
MSL_GROUP_OP(BitwiseXor, xor)
|
MSL_GROUP_OP(BitwiseXor, xor)
|
||||||
|
@ -10894,6 +11099,8 @@ case OpGroupNonUniform##op: \
|
||||||
MSL_GROUP_OP(LogicalOr, or)
|
MSL_GROUP_OP(LogicalOr, or)
|
||||||
MSL_GROUP_OP(LogicalXor, xor)
|
MSL_GROUP_OP(LogicalXor, xor)
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
#undef MSL_GROUP_OP
|
||||||
|
#undef MSL_GROUP_OP_CAST
|
||||||
|
|
||||||
case OpGroupNonUniformQuadSwap:
|
case OpGroupNonUniformQuadSwap:
|
||||||
{
|
{
|
||||||
|
@ -12243,6 +12450,7 @@ void CompilerMSL::analyze_argument_buffers()
|
||||||
uint32_t plane;
|
uint32_t plane;
|
||||||
};
|
};
|
||||||
SmallVector<Resource> resources_in_set[kMaxArgumentBuffers];
|
SmallVector<Resource> resources_in_set[kMaxArgumentBuffers];
|
||||||
|
SmallVector<uint32_t> inline_block_vars;
|
||||||
|
|
||||||
bool set_needs_swizzle_buffer[kMaxArgumentBuffers] = {};
|
bool set_needs_swizzle_buffer[kMaxArgumentBuffers] = {};
|
||||||
bool set_needs_buffer_sizes[kMaxArgumentBuffers] = {};
|
bool set_needs_buffer_sizes[kMaxArgumentBuffers] = {};
|
||||||
|
@ -12275,6 +12483,7 @@ void CompilerMSL::analyze_argument_buffers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t binding = get_decoration(var_id, DecorationBinding);
|
||||||
if (type.basetype == SPIRType::SampledImage)
|
if (type.basetype == SPIRType::SampledImage)
|
||||||
{
|
{
|
||||||
add_resource_name(var_id);
|
add_resource_name(var_id);
|
||||||
|
@ -12297,9 +12506,14 @@ void CompilerMSL::analyze_argument_buffers()
|
||||||
{ &var, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index, 0 });
|
{ &var, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index, 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (inline_uniform_blocks.count(SetBindingPair{ desc_set, binding }))
|
||||||
|
{
|
||||||
|
inline_block_vars.push_back(var_id);
|
||||||
|
}
|
||||||
else if (!constexpr_sampler)
|
else if (!constexpr_sampler)
|
||||||
{
|
{
|
||||||
// constexpr samplers are not declared as resources.
|
// constexpr samplers are not declared as resources.
|
||||||
|
// Inline uniform blocks are always emitted at the end.
|
||||||
if (!msl_options.is_ios() || type.basetype != SPIRType::Image || type.image.sampled != 2)
|
if (!msl_options.is_ios() || type.basetype != SPIRType::Image || type.image.sampled != 2)
|
||||||
{
|
{
|
||||||
add_resource_name(var_id);
|
add_resource_name(var_id);
|
||||||
|
@ -12374,6 +12588,16 @@ void CompilerMSL::analyze_argument_buffers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now add inline uniform blocks.
|
||||||
|
for (uint32_t var_id : inline_block_vars)
|
||||||
|
{
|
||||||
|
auto &var = get<SPIRVariable>(var_id);
|
||||||
|
uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet);
|
||||||
|
add_resource_name(var_id);
|
||||||
|
resources_in_set[desc_set].push_back(
|
||||||
|
{ &var, to_name(var_id), SPIRType::Struct, get_metal_resource_index(var, SPIRType::Struct), 0 });
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++)
|
for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++)
|
||||||
{
|
{
|
||||||
auto &resources = resources_in_set[desc_set];
|
auto &resources = resources_in_set[desc_set];
|
||||||
|
@ -12471,6 +12695,12 @@ void CompilerMSL::analyze_argument_buffers()
|
||||||
buffer_type.member_types.push_back(var.basetype);
|
buffer_type.member_types.push_back(var.basetype);
|
||||||
buffers_requiring_dynamic_offset[pair].second = var.self;
|
buffers_requiring_dynamic_offset[pair].second = var.self;
|
||||||
}
|
}
|
||||||
|
else if (inline_uniform_blocks.count(pair))
|
||||||
|
{
|
||||||
|
// Put the buffer block itself into the argument buffer.
|
||||||
|
buffer_type.member_types.push_back(get_variable_data_type_id(var));
|
||||||
|
set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Resources will be declared as pointers not references, so automatically dereference as appropriate.
|
// Resources will be declared as pointers not references, so automatically dereference as appropriate.
|
||||||
|
@ -12491,34 +12721,15 @@ void CompilerMSL::analyze_argument_buffers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompilerMSL::SetBindingPair::operator==(const SetBindingPair &other) const
|
void CompilerMSL::activate_argument_buffer_resources()
|
||||||
{
|
{
|
||||||
return desc_set == other.desc_set && binding == other.binding;
|
// For ABI compatibility, force-enable all resources which are part of argument buffers.
|
||||||
}
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, const SPIRVariable &) {
|
||||||
|
if (!has_decoration(self, DecorationDescriptorSet))
|
||||||
|
return;
|
||||||
|
|
||||||
bool CompilerMSL::SetBindingPair::operator<(const SetBindingPair &other) const
|
uint32_t desc_set = get_decoration(self, DecorationDescriptorSet);
|
||||||
{
|
if (descriptor_set_is_argument_buffer(desc_set))
|
||||||
return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding);
|
active_interface_variables.insert(self);
|
||||||
}
|
});
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2019 The Brenwill Workshop Ltd.
|
* Copyright 2016-2020 The Brenwill Workshop Ltd.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -218,11 +218,13 @@ struct MSLConstexprSampler
|
||||||
|
|
||||||
// Special constant used in a MSLResourceBinding desc_set
|
// Special constant used in a MSLResourceBinding desc_set
|
||||||
// element to indicate the bindings for the push constants.
|
// 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
|
// Special constant used in a MSLResourceBinding binding
|
||||||
// element to indicate the bindings for the push constants.
|
// 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
|
// Special constant used in a MSLResourceBinding binding
|
||||||
// element to indicate the buffer binding for swizzle buffers.
|
// element to indicate the buffer binding for swizzle buffers.
|
||||||
|
@ -305,6 +307,11 @@ public:
|
||||||
// Requires MSL 2.1, use the native support for texel buffers.
|
// Requires MSL 2.1, use the native support for texel buffers.
|
||||||
bool texture_buffer_native = false;
|
bool texture_buffer_native = false;
|
||||||
|
|
||||||
|
// Forces all resources which are part of an argument buffer to be considered active.
|
||||||
|
// This ensures ABI compatibility between shaders where some resources might be unused,
|
||||||
|
// and would otherwise declare a different IAB.
|
||||||
|
bool force_active_argument_buffer_resources = false;
|
||||||
|
|
||||||
bool is_ios()
|
bool is_ios()
|
||||||
{
|
{
|
||||||
return platform == iOS;
|
return platform == iOS;
|
||||||
|
@ -425,6 +432,13 @@ public:
|
||||||
// an offset taken from the dynamic offset buffer.
|
// an offset taken from the dynamic offset buffer.
|
||||||
void add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32_t index);
|
void add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32_t index);
|
||||||
|
|
||||||
|
// desc_set and binding are the SPIR-V descriptor set and binding of a buffer resource
|
||||||
|
// in this shader. This function marks that resource as an inline uniform block
|
||||||
|
// (VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT). This function only has any effect if argument buffers
|
||||||
|
// are enabled. If so, the buffer block will be directly embedded into the argument
|
||||||
|
// buffer, instead of being referenced indirectly via pointer.
|
||||||
|
void add_inline_uniform_block(uint32_t desc_set, uint32_t binding);
|
||||||
|
|
||||||
// When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets.
|
// When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets.
|
||||||
// This corresponds to VK_KHR_push_descriptor in Vulkan.
|
// This corresponds to VK_KHR_push_descriptor in Vulkan.
|
||||||
void add_discrete_descriptor_set(uint32_t desc_set);
|
void add_discrete_descriptor_set(uint32_t desc_set);
|
||||||
|
@ -440,7 +454,7 @@ public:
|
||||||
// Constexpr samplers are always assumed to be emitted.
|
// Constexpr samplers are always assumed to be emitted.
|
||||||
// No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped
|
// No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped
|
||||||
// by remap_constexpr_sampler(_by_binding).
|
// 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().
|
// 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.
|
// For a variable resource ID obtained through reflection API, report the automatically assigned resource index.
|
||||||
|
@ -637,18 +651,29 @@ protected:
|
||||||
uint32_t add_interface_block(spv::StorageClass storage, bool patch = false);
|
uint32_t add_interface_block(spv::StorageClass storage, bool patch = false);
|
||||||
uint32_t add_interface_block_pointer(uint32_t ib_var_id, spv::StorageClass storage);
|
uint32_t add_interface_block_pointer(uint32_t ib_var_id, spv::StorageClass storage);
|
||||||
|
|
||||||
|
struct InterfaceBlockMeta
|
||||||
|
{
|
||||||
|
struct LocationMeta
|
||||||
|
{
|
||||||
|
uint32_t num_components = 0;
|
||||||
|
uint32_t ib_index = ~0u;
|
||||||
|
};
|
||||||
|
std::unordered_map<uint32_t, LocationMeta> location_meta;
|
||||||
|
bool strip_array = false;
|
||||||
|
};
|
||||||
|
|
||||||
void add_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type,
|
void add_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type,
|
||||||
SPIRVariable &var, bool strip_array);
|
SPIRVariable &var, InterfaceBlockMeta &meta);
|
||||||
void add_composite_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
void add_composite_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, bool strip_array);
|
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta);
|
||||||
void add_plain_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
void add_plain_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, bool strip_array);
|
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta);
|
||||||
void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, uint32_t index,
|
SPIRType &ib_type, SPIRVariable &var, uint32_t index,
|
||||||
bool strip_array);
|
InterfaceBlockMeta &meta);
|
||||||
void add_composite_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
void add_composite_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
|
||||||
SPIRType &ib_type, SPIRVariable &var, uint32_t index,
|
SPIRType &ib_type, SPIRVariable &var, uint32_t index,
|
||||||
bool strip_array);
|
InterfaceBlockMeta &meta);
|
||||||
uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array);
|
uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array);
|
||||||
void add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var);
|
void add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var);
|
||||||
|
|
||||||
|
@ -656,7 +681,7 @@ protected:
|
||||||
|
|
||||||
void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);
|
void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);
|
||||||
uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin);
|
uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin);
|
||||||
uint32_t ensure_correct_attribute_type(uint32_t type_id, uint32_t location);
|
uint32_t ensure_correct_attribute_type(uint32_t type_id, uint32_t location, uint32_t num_components = 0);
|
||||||
|
|
||||||
void emit_custom_templates();
|
void emit_custom_templates();
|
||||||
void emit_custom_functions();
|
void emit_custom_functions();
|
||||||
|
@ -775,28 +800,6 @@ protected:
|
||||||
std::set<std::string> typedef_lines;
|
std::set<std::string> typedef_lines;
|
||||||
SmallVector<uint32_t> vars_needing_early_declaration;
|
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;
|
std::unordered_map<StageSetBinding, std::pair<MSLResourceBinding, bool>, InternalHasher> resource_bindings;
|
||||||
|
|
||||||
uint32_t next_metal_resource_index_buffer = 0;
|
uint32_t next_metal_resource_index_buffer = 0;
|
||||||
|
@ -858,6 +861,8 @@ protected:
|
||||||
// Must be ordered since array is in a specific order.
|
// Must be ordered since array is in a specific order.
|
||||||
std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset;
|
std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset;
|
||||||
|
|
||||||
|
std::unordered_set<SetBindingPair, InternalHasher> inline_uniform_blocks;
|
||||||
|
|
||||||
uint32_t argument_buffer_ids[kMaxArgumentBuffers];
|
uint32_t argument_buffer_ids[kMaxArgumentBuffers];
|
||||||
uint32_t argument_buffer_discrete_mask = 0;
|
uint32_t argument_buffer_discrete_mask = 0;
|
||||||
uint32_t argument_buffer_device_storage_mask = 0;
|
uint32_t argument_buffer_device_storage_mask = 0;
|
||||||
|
@ -872,6 +877,8 @@ protected:
|
||||||
|
|
||||||
void add_spv_func_and_recompile(SPVFuncImpl spv_func);
|
void add_spv_func_and_recompile(SPVFuncImpl spv_func);
|
||||||
|
|
||||||
|
void activate_argument_buffer_resources();
|
||||||
|
|
||||||
// OpcodeHandler that handles several MSL preprocessing operations.
|
// OpcodeHandler that handles several MSL preprocessing operations.
|
||||||
struct OpCodePreprocessor : OpcodeHandler
|
struct OpCodePreprocessor : OpcodeHandler
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2019 Arm Limited
|
* Copyright 2018-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2019 Arm Limited
|
* Copyright 2018-2020 Arm Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2019 Bradley Austin Davis
|
* Copyright 2018-2020 Bradley Austin Davis
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -358,15 +358,16 @@ void CompilerReflection::emit_type_array(const SPIRType &type)
|
||||||
for (const auto &value : type.array)
|
for (const auto &value : type.array)
|
||||||
json_stream->emit_json_array_value(value);
|
json_stream->emit_json_array_value(value);
|
||||||
json_stream->end_json_array();
|
json_stream->end_json_array();
|
||||||
|
|
||||||
|
json_stream->emit_json_key_array("array_size_is_literal");
|
||||||
|
for (const auto &value : type.array_size_literal)
|
||||||
|
json_stream->emit_json_array_value(value);
|
||||||
|
json_stream->end_json_array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index)
|
void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index)
|
||||||
{
|
{
|
||||||
auto flags = combined_decoration_for_member(type, index);
|
|
||||||
if (flags.get(DecorationRowMajor))
|
|
||||||
json_stream->emit_json_key_value("row_major", true);
|
|
||||||
|
|
||||||
auto &membertype = get<SPIRType>(type.member_types[index]);
|
auto &membertype = get<SPIRType>(type.member_types[index]);
|
||||||
emit_type_array(membertype);
|
emit_type_array(membertype);
|
||||||
auto &memb = ir.meta[type.self].members;
|
auto &memb = ir.meta[type.self].members;
|
||||||
|
@ -377,6 +378,16 @@ void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint3
|
||||||
json_stream->emit_json_key_value("location", dec.location);
|
json_stream->emit_json_key_value("location", dec.location);
|
||||||
if (dec.decoration_flags.get(DecorationOffset))
|
if (dec.decoration_flags.get(DecorationOffset))
|
||||||
json_stream->emit_json_key_value("offset", dec.offset);
|
json_stream->emit_json_key_value("offset", dec.offset);
|
||||||
|
|
||||||
|
// Array stride is a property of the array type, not the struct.
|
||||||
|
if (has_decoration(type.member_types[index], DecorationArrayStride))
|
||||||
|
json_stream->emit_json_key_value("array_stride",
|
||||||
|
get_decoration(type.member_types[index], DecorationArrayStride));
|
||||||
|
|
||||||
|
if (dec.decoration_flags.get(DecorationMatrixStride))
|
||||||
|
json_stream->emit_json_key_value("matrix_stride", dec.matrix_stride);
|
||||||
|
if (dec.decoration_flags.get(DecorationRowMajor))
|
||||||
|
json_stream->emit_json_key_value("row_major", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,6 +603,7 @@ void CompilerReflection::emit_specialization_constants()
|
||||||
json_stream->begin_json_object();
|
json_stream->begin_json_object();
|
||||||
json_stream->emit_json_key_value("id", spec_const.constant_id);
|
json_stream->emit_json_key_value("id", spec_const.constant_id);
|
||||||
json_stream->emit_json_key_value("type", type_to_glsl(type));
|
json_stream->emit_json_key_value("type", type_to_glsl(type));
|
||||||
|
json_stream->emit_json_key_value("variable_id", spec_const.id);
|
||||||
switch (type.basetype)
|
switch (type.basetype)
|
||||||
{
|
{
|
||||||
case SPIRType::UInt:
|
case SPIRType::UInt:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2019 Bradley Austin Davis
|
* Copyright 2018-2020 Bradley Austin Davis
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
Loading…
Reference in New Issue