mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-17 20:52:36 +01:00
Updated spirv-cross.
This commit is contained in:
4
3rdparty/spirv-cross/main.cpp
vendored
4
3rdparty/spirv-cross/main.cpp
vendored
@@ -607,6 +607,7 @@ struct CLIArguments
|
||||
bool hlsl_force_storage_buffer_as_uav = false;
|
||||
bool hlsl_nonwritable_uav_texture_as_srv = false;
|
||||
bool hlsl_enable_16bit_types = false;
|
||||
bool hlsl_flatten_matrix_vertex_input_semantics = false;
|
||||
HLSLBindingFlags hlsl_binding_flags = 0;
|
||||
bool vulkan_semantics = false;
|
||||
bool flatten_multidimensional_arrays = false;
|
||||
@@ -705,6 +706,7 @@ static void print_help_hlsl()
|
||||
"\t[--set-hlsl-vertex-input-semantic <location> <semantic>]:\n\t\tEmits a specific vertex input semantic for a given location.\n"
|
||||
"\t\tOtherwise, TEXCOORD# is used as semantics, where # is location.\n"
|
||||
"\t[--hlsl-enable-16bit-types]:\n\t\tEnables native use of half/int16_t/uint16_t and ByteAddressBuffer interaction with these types. Requires SM 6.2.\n"
|
||||
"\t[--hlsl-flatten-matrix-vertex-input-semantics]:\n\t\tEmits matrix vertex inputs with input semantics as if they were independent vectors, e.g. TEXCOORD{2,3,4} rather than matrix form TEXCOORD2_{0,1,2}.\n"
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
@@ -1195,6 +1197,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
|
||||
hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav;
|
||||
hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv;
|
||||
hlsl_opts.enable_16bit_types = args.hlsl_enable_16bit_types;
|
||||
hlsl_opts.flatten_matrix_vertex_input_semantics = args.hlsl_flatten_matrix_vertex_input_semantics;
|
||||
hlsl->set_hlsl_options(hlsl_opts);
|
||||
hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
|
||||
}
|
||||
@@ -1367,6 +1370,7 @@ static int main_inner(int argc, char *argv[])
|
||||
cbs.add("--hlsl-nonwritable-uav-texture-as-srv",
|
||||
[&args](CLIParser &) { args.hlsl_nonwritable_uav_texture_as_srv = true; });
|
||||
cbs.add("--hlsl-enable-16bit-types", [&args](CLIParser &) { args.hlsl_enable_16bit_types = true; });
|
||||
cbs.add("--hlsl-flatten-matrix-vertex-input-semantics", [&args](CLIParser &) { args.hlsl_flatten_matrix_vertex_input_semantics = true; });
|
||||
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
|
||||
cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; });
|
||||
cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
|
||||
|
||||
8
3rdparty/spirv-cross/spirv_common.hpp
vendored
8
3rdparty/spirv-cross/spirv_common.hpp
vendored
@@ -516,6 +516,7 @@ struct SPIRType : IVariant
|
||||
|
||||
// Keep internal types at the end.
|
||||
ControlPointArray,
|
||||
Interpolant,
|
||||
Char
|
||||
};
|
||||
|
||||
@@ -1573,6 +1574,13 @@ enum ExtendedDecorations
|
||||
// addition of swizzles to keep the generated code compiling.
|
||||
SPIRVCrossDecorationTessIOOriginalInputTypeID,
|
||||
|
||||
// Apply to any access chain of an interface variable used with pull-model interpolation, where the variable is a
|
||||
// vector but the resulting pointer is a scalar; stores the component index that is to be accessed by the chain.
|
||||
// This is used when emitting calls to interpolation functions on the chain in MSL: in this case, the component
|
||||
// must be applied to the result, since pull-model interpolants in MSL cannot be swizzled directly, but the
|
||||
// results of interpolation can.
|
||||
SPIRVCrossDecorationInterpolantComponentExpr,
|
||||
|
||||
SPIRVCrossDecorationCount
|
||||
};
|
||||
|
||||
|
||||
31
3rdparty/spirv-cross/spirv_cross.cpp
vendored
31
3rdparty/spirv-cross/spirv_cross.cpp
vendored
@@ -699,8 +699,31 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
|
||||
{
|
||||
if (length < 5)
|
||||
return false;
|
||||
uint32_t extension_set = args[2];
|
||||
if (compiler.get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
|
||||
auto &extension_set = compiler.get<SPIRExtension>(args[2]);
|
||||
switch (extension_set.ext)
|
||||
{
|
||||
case SPIRExtension::GLSL:
|
||||
{
|
||||
auto op = static_cast<GLSLstd450>(args[3]);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GLSLstd450InterpolateAtCentroid:
|
||||
case GLSLstd450InterpolateAtSample:
|
||||
case GLSLstd450InterpolateAtOffset:
|
||||
{
|
||||
auto *var = compiler.maybe_get<SPIRVariable>(args[4]);
|
||||
if (var && storage_class_is_interface(var->storage))
|
||||
variables.insert(args[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter:
|
||||
{
|
||||
enum AMDShaderExplicitVertexParameter
|
||||
{
|
||||
@@ -722,6 +745,10 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
4
3rdparty/spirv-cross/spirv_cross_c.cpp
vendored
4
3rdparty/spirv-cross/spirv_cross_c.cpp
vendored
@@ -492,6 +492,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
|
||||
case SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES:
|
||||
options->hlsl.enable_16bit_types = value != 0;
|
||||
break;
|
||||
|
||||
case SPVC_COMPILER_OPTION_HLSL_FLATTEN_MATRIX_VERTEX_INPUT_SEMANTICS:
|
||||
options->hlsl.flatten_matrix_vertex_input_semantics = value != 0;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if SPIRV_CROSS_C_API_MSL
|
||||
|
||||
4
3rdparty/spirv-cross/spirv_cross_c.h
vendored
4
3rdparty/spirv-cross/spirv_cross_c.h
vendored
@@ -33,7 +33,7 @@ extern "C" {
|
||||
/* Bumped if ABI or API breaks backwards compatibility. */
|
||||
#define SPVC_C_API_VERSION_MAJOR 0
|
||||
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
|
||||
#define SPVC_C_API_VERSION_MINOR 41
|
||||
#define SPVC_C_API_VERSION_MINOR 42
|
||||
/* Bumped if internal implementation details change. */
|
||||
#define SPVC_C_API_VERSION_PATCH 0
|
||||
|
||||
@@ -645,6 +645,8 @@ typedef enum spvc_compiler_option
|
||||
SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT = 69 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||
SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID = 70 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||
|
||||
SPVC_COMPILER_OPTION_HLSL_FLATTEN_MATRIX_VERTEX_INPUT_SEMANTICS = 71 | SPVC_COMPILER_OPTION_HLSL_BIT,
|
||||
|
||||
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
|
||||
} spvc_compiler_option;
|
||||
|
||||
|
||||
221
3rdparty/spirv-cross/spirv_glsl.cpp
vendored
221
3rdparty/spirv-cross/spirv_glsl.cpp
vendored
@@ -3706,8 +3706,12 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
|
||||
{
|
||||
// Extensions we're using in place of GL_KHR_shader_subgroup_basic state
|
||||
// that subgroup execute in lockstep so this barrier is implicit.
|
||||
// However the GL 4.6 spec also states that `barrier` implies a shared memory barrier,
|
||||
// and a specific test of optimizing scans by leveraging lock-step invocation execution,
|
||||
// has shown that a `memoryBarrierShared` is needed in place of a `subgroupBarrier`.
|
||||
// https://github.com/buildaworldnet/IrrlichtBAW/commit/d8536857991b89a30a6b65d29441e51b64c2c7ad#diff-9f898d27be1ea6fc79b03d9b361e299334c1a347b6e4dc344ee66110c6aa596aR19
|
||||
statement("#ifndef GL_KHR_shader_subgroup_basic");
|
||||
statement("void subgroupBarrier() { /*NOOP*/ }");
|
||||
statement("void subgroupBarrier() { memoryBarrierShared(); }");
|
||||
statement("#endif");
|
||||
statement("");
|
||||
}
|
||||
@@ -3719,7 +3723,7 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
|
||||
statement("#ifndef GL_KHR_shader_subgroup_basic");
|
||||
statement("void subgroupMemoryBarrier() { groupMemoryBarrier(); }");
|
||||
statement("void subgroupMemoryBarrierBuffer() { groupMemoryBarrier(); }");
|
||||
statement("void subgroupMemoryBarrierShared() { groupMemoryBarrier(); }");
|
||||
statement("void subgroupMemoryBarrierShared() { memoryBarrierShared(); }");
|
||||
statement("void subgroupMemoryBarrierImage() { groupMemoryBarrier(); }");
|
||||
statement("#endif");
|
||||
}
|
||||
@@ -3810,6 +3814,33 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
|
||||
}
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (requires_transpose_2x2)
|
||||
{
|
||||
statement("mat2 SPIRV_Cross_Transpose(mat2 m)");
|
||||
begin_scope();
|
||||
statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (requires_transpose_3x3)
|
||||
{
|
||||
statement("mat3 SPIRV_Cross_Transpose(mat3 m)");
|
||||
begin_scope();
|
||||
statement("return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]);");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (requires_transpose_4x4)
|
||||
{
|
||||
statement("mat4 SPIRV_Cross_Transpose(mat4 m)");
|
||||
begin_scope();
|
||||
statement("return mat4(m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3]);");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a string representation of the ID, usable as a function arg.
|
||||
@@ -5637,26 +5668,7 @@ void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result
|
||||
inherit_expression_dependencies(result_id, op3);
|
||||
}
|
||||
|
||||
// EXT_shader_texture_lod only concerns fragment shaders so lod tex functions
|
||||
// are not allowed in ES 2 vertex shaders. But SPIR-V only supports lod tex
|
||||
// functions in vertex shaders so we revert those back to plain calls when
|
||||
// the lod is a constant value of zero.
|
||||
bool CompilerGLSL::check_explicit_lod_allowed(uint32_t lod)
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
bool allowed = !is_legacy_es() || execution.model == ExecutionModelFragment;
|
||||
if (!allowed && lod != 0)
|
||||
{
|
||||
auto *lod_constant = maybe_get<SPIRConstant>(lod);
|
||||
if (!lod_constant || lod_constant->scalar_f32() != 0.0f)
|
||||
{
|
||||
SPIRV_CROSS_THROW("Explicit lod not allowed in legacy ES non-fragment shaders.");
|
||||
}
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t tex)
|
||||
string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t tex)
|
||||
{
|
||||
const char *type;
|
||||
switch (imgtype.image.dim)
|
||||
@@ -5687,16 +5699,19 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
|
||||
break;
|
||||
}
|
||||
|
||||
bool use_explicit_lod = check_explicit_lod_allowed(lod);
|
||||
|
||||
if (op == "textureLod" || op == "textureProjLod" || op == "textureGrad" || op == "textureProjGrad")
|
||||
// In legacy GLSL, an extension is required for textureLod in the fragment
|
||||
// shader or textureGrad anywhere.
|
||||
bool legacy_lod_ext = false;
|
||||
auto &execution = get_entry_point();
|
||||
if (op == "textureGrad" || op == "textureProjGrad" ||
|
||||
((op == "textureLod" || op == "textureProjLod") && execution.model != ExecutionModelVertex))
|
||||
{
|
||||
if (is_legacy_es())
|
||||
{
|
||||
if (use_explicit_lod)
|
||||
require_extension_internal("GL_EXT_shader_texture_lod");
|
||||
legacy_lod_ext = true;
|
||||
require_extension_internal("GL_EXT_shader_texture_lod");
|
||||
}
|
||||
else if (is_legacy())
|
||||
else if (is_legacy_desktop())
|
||||
require_extension_internal("GL_ARB_shader_texture_lod");
|
||||
}
|
||||
|
||||
@@ -5725,40 +5740,20 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
|
||||
if (op == "texture")
|
||||
return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
|
||||
else if (op == "textureLod")
|
||||
{
|
||||
if (use_explicit_lod)
|
||||
return join(type_prefix, type, is_legacy_es() ? "LodEXT" : "Lod");
|
||||
else
|
||||
return join(type_prefix, type);
|
||||
}
|
||||
return join(type_prefix, type, legacy_lod_ext ? "LodEXT" : "Lod");
|
||||
else if (op == "textureProj")
|
||||
return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
|
||||
else if (op == "textureGrad")
|
||||
return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
|
||||
else if (op == "textureProjLod")
|
||||
{
|
||||
if (use_explicit_lod)
|
||||
return join(type_prefix, type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
|
||||
else
|
||||
return join(type_prefix, type, "Proj");
|
||||
}
|
||||
return join(type_prefix, type, legacy_lod_ext ? "ProjLodEXT" : "ProjLod");
|
||||
else if (op == "textureLodOffset")
|
||||
{
|
||||
if (use_explicit_lod)
|
||||
return join(type_prefix, type, "LodOffset");
|
||||
else
|
||||
return join(type_prefix, type);
|
||||
}
|
||||
return join(type_prefix, type, "LodOffset");
|
||||
else if (op == "textureProjGrad")
|
||||
return join(type_prefix, type,
|
||||
is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
|
||||
else if (op == "textureProjLodOffset")
|
||||
{
|
||||
if (use_explicit_lod)
|
||||
return join(type_prefix, type, "ProjLodOffset");
|
||||
else
|
||||
return join(type_prefix, type, "ProjOffset");
|
||||
}
|
||||
return join(type_prefix, type, "ProjLodOffset");
|
||||
else
|
||||
{
|
||||
SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
|
||||
@@ -6443,7 +6438,7 @@ string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args)
|
||||
if (args.is_sparse_feedback || args.has_min_lod)
|
||||
fname += "ARB";
|
||||
|
||||
return is_legacy() ? legacy_tex_op(fname, imgtype, args.lod, tex) : fname;
|
||||
return is_legacy() ? legacy_tex_op(fname, imgtype, tex) : fname;
|
||||
}
|
||||
|
||||
std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
|
||||
@@ -6628,23 +6623,20 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
if (check_explicit_lod_allowed(args.lod))
|
||||
forward = forward && should_forward(args.lod);
|
||||
farg_str += ", ";
|
||||
|
||||
auto &lod_expr_type = expression_type(args.lod);
|
||||
|
||||
// Lod expression for TexelFetch in GLSL must be int, and only int.
|
||||
if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
|
||||
lod_expr_type.basetype != SPIRType::Int)
|
||||
{
|
||||
forward = forward && should_forward(args.lod);
|
||||
farg_str += ", ";
|
||||
|
||||
auto &lod_expr_type = expression_type(args.lod);
|
||||
|
||||
// Lod expression for TexelFetch in GLSL must be int, and only int.
|
||||
if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
|
||||
lod_expr_type.basetype != SPIRType::Int)
|
||||
{
|
||||
farg_str += join("int(", to_expression(args.lod), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
farg_str += to_expression(args.lod);
|
||||
}
|
||||
farg_str += join("int(", to_expression(args.lod), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
farg_str += to_expression(args.lod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6721,14 +6713,30 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
{
|
||||
// FP fiddling
|
||||
case GLSLstd450Round:
|
||||
emit_unary_func_op(result_type, id, args[0], "round");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "round");
|
||||
else
|
||||
{
|
||||
auto op0 = to_enclosed_expression(args[0]);
|
||||
auto &op0_type = expression_type(args[0]);
|
||||
auto expr = join("floor(", op0, " + ", type_to_glsl_constructor(op0_type), "(0.5))");
|
||||
bool forward = should_forward(args[0]);
|
||||
emit_op(result_type, id, expr, forward);
|
||||
inherit_expression_dependencies(id, args[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case GLSLstd450RoundEven:
|
||||
if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "roundEven");
|
||||
else if (!options.es)
|
||||
{
|
||||
// This extension provides round() with round-to-even semantics.
|
||||
require_extension_internal("GL_EXT_gpu_shader4");
|
||||
emit_unary_func_op(result_type, id, args[0], "round");
|
||||
}
|
||||
else
|
||||
SPIRV_CROSS_THROW("roundEven supported only in ESSL 300 and GLSL 130 and up.");
|
||||
SPIRV_CROSS_THROW("roundEven supported only in ESSL 300.");
|
||||
break;
|
||||
|
||||
case GLSLstd450Trunc:
|
||||
@@ -10020,12 +10028,22 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
bool pointer = get<SPIRType>(result_type).pointer;
|
||||
|
||||
auto *chain = maybe_get<SPIRAccessChain>(rhs);
|
||||
auto *imgsamp = maybe_get<SPIRCombinedImageSampler>(rhs);
|
||||
if (chain)
|
||||
{
|
||||
// Cannot lower to a SPIRExpression, just copy the object.
|
||||
auto &e = set<SPIRAccessChain>(id, *chain);
|
||||
e.self = id;
|
||||
}
|
||||
else if (imgsamp)
|
||||
{
|
||||
// Cannot lower to a SPIRExpression, just copy the object.
|
||||
// GLSL does not currently use this type and will never get here, but MSL does.
|
||||
// Handled here instead of CompilerMSL for better integration and general handling,
|
||||
// and in case GLSL or other subclasses require it in the future.
|
||||
auto &e = set<SPIRCombinedImageSampler>(id, *imgsamp);
|
||||
e.self = id;
|
||||
}
|
||||
else if (expression_is_lvalue(rhs) && !pointer)
|
||||
{
|
||||
// Need a copy.
|
||||
@@ -10251,7 +10269,32 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
break;
|
||||
|
||||
case OpTranspose:
|
||||
GLSL_UFOP(transpose);
|
||||
if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00
|
||||
{
|
||||
// transpose() is not available, so instead, flip need_transpose,
|
||||
// which can later be turned into an emulated transpose op by
|
||||
// convert_row_major_matrix(), if necessary.
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t result_id = ops[1];
|
||||
uint32_t input = ops[2];
|
||||
|
||||
// Force need_transpose to false temporarily to prevent
|
||||
// to_expression() from doing the transpose.
|
||||
bool need_transpose = false;
|
||||
auto *input_e = maybe_get<SPIRExpression>(input);
|
||||
if (input_e)
|
||||
swap(need_transpose, input_e->need_transpose);
|
||||
|
||||
bool forward = should_forward(input);
|
||||
auto &e = emit_op(result_type, result_id, to_expression(input), forward);
|
||||
e.need_transpose = !need_transpose;
|
||||
|
||||
// Restore the old need_transpose flag.
|
||||
if (input_e)
|
||||
input_e->need_transpose = need_transpose;
|
||||
}
|
||||
else
|
||||
GLSL_UFOP(transpose);
|
||||
break;
|
||||
|
||||
case OpSRem:
|
||||
@@ -12126,6 +12169,38 @@ string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &ex
|
||||
transposed_expr += ")";
|
||||
return transposed_expr;
|
||||
}
|
||||
else if (options.version < 120)
|
||||
{
|
||||
// GLSL 110, ES 100 do not have transpose(), so emulate it. Note that
|
||||
// these GLSL versions do not support non-square matrices.
|
||||
if (exp_type.vecsize == 2 && exp_type.columns == 2)
|
||||
{
|
||||
if (!requires_transpose_2x2)
|
||||
{
|
||||
requires_transpose_2x2 = true;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
else if (exp_type.vecsize == 3 && exp_type.columns == 3)
|
||||
{
|
||||
if (!requires_transpose_3x3)
|
||||
{
|
||||
requires_transpose_3x3 = true;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
else if (exp_type.vecsize == 4 && exp_type.columns == 4)
|
||||
{
|
||||
if (!requires_transpose_4x4)
|
||||
{
|
||||
requires_transpose_4x4 = true;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
else
|
||||
SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose.");
|
||||
return join("SPIRV_Cross_Transpose(", exp_str, ")");
|
||||
}
|
||||
else
|
||||
return join("transpose(", exp_str, ")");
|
||||
}
|
||||
|
||||
7
3rdparty/spirv-cross/spirv_glsl.hpp
vendored
7
3rdparty/spirv-cross/spirv_glsl.hpp
vendored
@@ -750,8 +750,7 @@ protected:
|
||||
|
||||
void replace_fragment_output(SPIRVariable &var);
|
||||
void replace_fragment_outputs();
|
||||
bool check_explicit_lod_allowed(uint32_t lod);
|
||||
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t id);
|
||||
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t id);
|
||||
|
||||
uint32_t indent = 0;
|
||||
|
||||
@@ -806,6 +805,10 @@ protected:
|
||||
return !options.es && options.version < 130;
|
||||
}
|
||||
|
||||
bool requires_transpose_2x2 = false;
|
||||
bool requires_transpose_3x3 = false;
|
||||
bool requires_transpose_4x4 = false;
|
||||
|
||||
bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure);
|
||||
void register_call_out_argument(uint32_t id);
|
||||
void register_impure_function_call();
|
||||
|
||||
85
3rdparty/spirv-cross/spirv_hlsl.cpp
vendored
85
3rdparty/spirv-cross/spirv_hlsl.cpp
vendored
@@ -310,7 +310,7 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
|
||||
">");
|
||||
}
|
||||
|
||||
string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type, uint32_t id)
|
||||
string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type, uint32_t /*id*/)
|
||||
{
|
||||
auto &imagetype = get<SPIRType>(type.image.type);
|
||||
string res;
|
||||
@@ -373,8 +373,6 @@ string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type, uint32_t id)
|
||||
res += "MS";
|
||||
if (type.image.arrayed)
|
||||
res += "Array";
|
||||
if (image_is_comparison(type, id))
|
||||
res += "Shadow";
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -935,8 +933,15 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
|
||||
{
|
||||
SPIRType newtype = type;
|
||||
newtype.columns = 1;
|
||||
|
||||
string effective_semantic;
|
||||
if (hlsl_options.flatten_matrix_vertex_input_semantics)
|
||||
effective_semantic = to_semantic(location_number, execution.model, var.storage);
|
||||
else
|
||||
effective_semantic = join(semantic, "_", i);
|
||||
|
||||
statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)),
|
||||
variable_decl(newtype, join(name, "_", i)), " : ", semantic, "_", i, ";");
|
||||
variable_decl(newtype, join(name, "_", i)), " : ", effective_semantic, ";");
|
||||
active_locations.insert(location_number++);
|
||||
}
|
||||
}
|
||||
@@ -2926,14 +2931,15 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse)
|
||||
SPIRV_CROSS_THROW("textureGather is not supported in HLSL shader model 2/3.");
|
||||
if (offset || coffset)
|
||||
SPIRV_CROSS_THROW("textureOffset is not supported in HLSL shader model 2/3.");
|
||||
if (proj)
|
||||
texop += "proj";
|
||||
|
||||
if (grad_x || grad_y)
|
||||
texop += "grad";
|
||||
if (lod)
|
||||
else if (lod)
|
||||
texop += "lod";
|
||||
if (bias)
|
||||
else if (bias)
|
||||
texop += "bias";
|
||||
else if (proj || dref)
|
||||
texop += "proj";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2987,35 +2993,47 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse)
|
||||
|
||||
if (hlsl_options.shader_model < 40)
|
||||
{
|
||||
string coord_filler;
|
||||
uint32_t modifier_count = 0;
|
||||
if (dref)
|
||||
{
|
||||
if (imgtype.image.dim != spv::Dim1D && imgtype.image.dim != spv::Dim2D)
|
||||
SPIRV_CROSS_THROW("Depth comparison is only supported for 1D and 2D textures in HLSL shader model 2/3.");
|
||||
|
||||
if (grad_x || grad_y)
|
||||
SPIRV_CROSS_THROW("Depth comparison is not supported for grad sampling in HLSL shader model 2/3.");
|
||||
|
||||
for (uint32_t size = coord_components; size < 2; ++size)
|
||||
coord_expr += ", 0.0";
|
||||
|
||||
forward = forward && should_forward(dref);
|
||||
coord_expr += ", " + to_expression(dref);
|
||||
}
|
||||
else if (lod || bias || proj)
|
||||
{
|
||||
for (uint32_t size = coord_components; size < 3; ++size)
|
||||
coord_expr += ", 0.0";
|
||||
}
|
||||
|
||||
if (lod)
|
||||
{
|
||||
for (uint32_t size = coord_components; size < 3; ++size)
|
||||
coord_filler += ", 0.0";
|
||||
coord_expr = "float4(" + coord_expr + coord_filler + ", " + to_expression(lod) + ")";
|
||||
modifier_count++;
|
||||
coord_expr = "float4(" + coord_expr + ", " + to_expression(lod) + ")";
|
||||
}
|
||||
|
||||
if (bias)
|
||||
else if (bias)
|
||||
{
|
||||
for (uint32_t size = coord_components; size < 3; ++size)
|
||||
coord_filler += ", 0.0";
|
||||
coord_expr = "float4(" + coord_expr + coord_filler + ", " + to_expression(bias) + ")";
|
||||
modifier_count++;
|
||||
coord_expr = "float4(" + coord_expr + ", " + to_expression(bias) + ")";
|
||||
}
|
||||
|
||||
if (proj)
|
||||
else if (proj)
|
||||
{
|
||||
for (uint32_t size = coord_components; size < 3; ++size)
|
||||
coord_filler += ", 0.0";
|
||||
coord_expr = "float4(" + coord_expr + coord_filler + ", " +
|
||||
coord_expr = "float4(" + coord_expr + ", " +
|
||||
to_extract_component_expression(coord, coord_components) + ")";
|
||||
modifier_count++;
|
||||
}
|
||||
else if (dref)
|
||||
{
|
||||
// A "normal" sample gets fed into tex2Dproj as well, because the
|
||||
// regular tex2D accepts only two coordinates.
|
||||
coord_expr = "float4(" + coord_expr + ", 1.0)";
|
||||
}
|
||||
|
||||
if (modifier_count > 1)
|
||||
if (!!lod + !!bias + !!proj > 1)
|
||||
SPIRV_CROSS_THROW("Legacy HLSL can only use one of lod/bias/proj modifiers.");
|
||||
}
|
||||
|
||||
@@ -3029,11 +3047,8 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse)
|
||||
expr += ", ";
|
||||
expr += coord_expr;
|
||||
|
||||
if (dref)
|
||||
if (dref && hlsl_options.shader_model >= 40)
|
||||
{
|
||||
if (hlsl_options.shader_model < 40)
|
||||
SPIRV_CROSS_THROW("Legacy HLSL does not support comparison sampling.");
|
||||
|
||||
forward = forward && should_forward(dref);
|
||||
expr += ", ";
|
||||
|
||||
@@ -3088,6 +3103,9 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse)
|
||||
|
||||
expr += ")";
|
||||
|
||||
if (dref && hlsl_options.shader_model < 40)
|
||||
expr += ".x";
|
||||
|
||||
if (op == OpImageQueryLod)
|
||||
{
|
||||
// This is rather awkward.
|
||||
@@ -3426,7 +3444,10 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
break;
|
||||
|
||||
case GLSLstd450RoundEven:
|
||||
SPIRV_CROSS_THROW("roundEven is not supported on HLSL.");
|
||||
if (hlsl_options.shader_model < 40)
|
||||
SPIRV_CROSS_THROW("roundEven is not supported in HLSL shader model 2/3.");
|
||||
emit_unary_func_op(result_type, id, args[0], "round");
|
||||
break;
|
||||
|
||||
case GLSLstd450Acosh:
|
||||
case GLSLstd450Asinh:
|
||||
|
||||
6
3rdparty/spirv-cross/spirv_hlsl.hpp
vendored
6
3rdparty/spirv-cross/spirv_hlsl.hpp
vendored
@@ -124,6 +124,12 @@ public:
|
||||
// Uses half/int16_t/uint16_t instead of min16* types.
|
||||
// Also adds support for 16-bit load-store from (RW)ByteAddressBuffer.
|
||||
bool enable_16bit_types = false;
|
||||
|
||||
// If matrices are used as IO variables, flatten the attribute declaration to use
|
||||
// TEXCOORD{N,N+1,N+2,...} rather than TEXCOORDN_{0,1,2,3}.
|
||||
// If add_vertex_attribute_remap is used and this feature is used,
|
||||
// the semantic name will be queried once per active location.
|
||||
bool flatten_matrix_vertex_input_semantics = false;
|
||||
};
|
||||
|
||||
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
|
||||
|
||||
472
3rdparty/spirv-cross/spirv_msl.cpp
vendored
472
3rdparty/spirv-cross/spirv_msl.cpp
vendored
@@ -103,6 +103,16 @@ bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t de
|
||||
return itr != end(resource_bindings) && itr->second.second;
|
||||
}
|
||||
|
||||
// Returns the size of the array of resources used by the variable with the specified id.
|
||||
// The returned value is retrieved from the resource binding added using add_msl_resource_binding().
|
||||
uint32_t CompilerMSL::get_resource_array_size(uint32_t id) const
|
||||
{
|
||||
StageSetBinding tuple = { get_entry_point().model, get_decoration(id, DecorationDescriptorSet),
|
||||
get_decoration(id, DecorationBinding) };
|
||||
auto itr = resource_bindings.find(tuple);
|
||||
return itr != end(resource_bindings) ? itr->second.first.count : 0;
|
||||
}
|
||||
|
||||
uint32_t CompilerMSL::get_automatic_msl_resource_binding(uint32_t id) const
|
||||
{
|
||||
return get_extended_decoration(id, SPIRVCrossDecorationResourceIndexPrimary);
|
||||
@@ -159,7 +169,7 @@ void CompilerMSL::build_implicit_builtins()
|
||||
active_input_builtins.get(BuiltInInstanceIndex) || active_input_builtins.get(BuiltInBaseInstance));
|
||||
bool need_sample_mask = msl_options.additional_fixed_sample_mask != 0xffffffff;
|
||||
if (need_subpass_input || need_sample_pos || need_subgroup_mask || need_vertex_params || need_tesc_params ||
|
||||
need_multiview || need_dispatch_base || need_vertex_base_params || need_grid_params ||
|
||||
need_multiview || need_dispatch_base || need_vertex_base_params || need_grid_params || needs_sample_id ||
|
||||
needs_subgroup_invocation_id || needs_subgroup_size || need_sample_mask)
|
||||
{
|
||||
bool has_frag_coord = false;
|
||||
@@ -225,7 +235,7 @@ void CompilerMSL::build_implicit_builtins()
|
||||
}
|
||||
}
|
||||
|
||||
if (need_sample_pos && builtin == BuiltInSampleId)
|
||||
if ((need_sample_pos || needs_sample_id) && builtin == BuiltInSampleId)
|
||||
{
|
||||
builtin_sample_id_id = var.self;
|
||||
mark_implicit_builtin(StorageClassInput, BuiltInSampleId, var.self);
|
||||
@@ -404,7 +414,7 @@ void CompilerMSL::build_implicit_builtins()
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_sample_id && need_sample_pos)
|
||||
if (!has_sample_id && (need_sample_pos || needs_sample_id))
|
||||
{
|
||||
uint32_t offset = ir.increase_bound_by(2);
|
||||
uint32_t type_ptr_id = offset;
|
||||
@@ -1283,6 +1293,8 @@ void CompilerMSL::preprocess_op_codes()
|
||||
needs_subgroup_invocation_id = true;
|
||||
if (preproc.needs_subgroup_size)
|
||||
needs_subgroup_size = true;
|
||||
if (preproc.needs_sample_id)
|
||||
needs_sample_id = true;
|
||||
}
|
||||
|
||||
// Move the Private and Workgroup global variables to the entry function.
|
||||
@@ -1454,6 +1466,31 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
|
||||
break;
|
||||
}
|
||||
|
||||
case OpExtInst:
|
||||
{
|
||||
uint32_t extension_set = ops[2];
|
||||
if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
|
||||
{
|
||||
auto op_450 = static_cast<GLSLstd450>(ops[3]);
|
||||
switch (op_450)
|
||||
{
|
||||
case GLSLstd450InterpolateAtCentroid:
|
||||
case GLSLstd450InterpolateAtSample:
|
||||
case GLSLstd450InterpolateAtOffset:
|
||||
{
|
||||
// For these, we really need the stage-in block. It is theoretically possible to pass the
|
||||
// interpolant object, but a) doing so would require us to create an entirely new variable
|
||||
// with Interpolant type, and b) if we have a struct or array, handling all the members and
|
||||
// elements could get unwieldy fast.
|
||||
added_arg_ids.insert(stage_in_var_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1685,6 +1722,19 @@ uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t comp
|
||||
return new_type_id;
|
||||
}
|
||||
|
||||
uint32_t CompilerMSL::build_msl_interpolant_type(uint32_t type_id, bool is_noperspective)
|
||||
{
|
||||
uint32_t new_type_id = ir.increase_bound_by(1);
|
||||
SPIRType &type = set<SPIRType>(new_type_id, get<SPIRType>(type_id));
|
||||
type.basetype = SPIRType::Interpolant;
|
||||
type.parent_type = type_id;
|
||||
// In Metal, the pull-model interpolant type encodes perspective-vs-no-perspective in the type itself.
|
||||
// Add this decoration so we know which argument to pass to the template.
|
||||
if (is_noperspective)
|
||||
set_decoration(new_type_id, DecorationNoPerspective);
|
||||
return new_type_id;
|
||||
}
|
||||
|
||||
void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
||||
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta)
|
||||
{
|
||||
@@ -1783,7 +1833,10 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||
}
|
||||
}
|
||||
|
||||
ib_type.member_types.push_back(type_id);
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types.push_back(build_msl_interpolant_type(type_id, is_noperspective));
|
||||
else
|
||||
ib_type.member_types.push_back(type_id);
|
||||
|
||||
// Give the member a name
|
||||
string mbr_name = ensure_valid_name(to_expression(var.self), "m");
|
||||
@@ -1791,6 +1844,16 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||
|
||||
// Update the original variable reference to include the structure reference
|
||||
string qual_var_name = ib_var_ref + "." + mbr_name;
|
||||
// If using pull-model interpolation, need to add a call to the correct interpolation method.
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
{
|
||||
if (is_centroid)
|
||||
qual_var_name += ".interpolate_at_centroid()";
|
||||
else if (is_sample)
|
||||
qual_var_name += join(".interpolate_at_sample(", to_expression(builtin_sample_id_id), ")");
|
||||
else
|
||||
qual_var_name += ".interpolate_at_center()";
|
||||
}
|
||||
|
||||
if (padded_output || padded_input)
|
||||
{
|
||||
@@ -1842,7 +1905,10 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||
type_id = get_pointee_type_id(type_id);
|
||||
if (meta.strip_array && is_array(get<SPIRType>(type_id)))
|
||||
type_id = get<SPIRType>(type_id).parent_type;
|
||||
ib_type.member_types[ib_mbr_idx] = type_id;
|
||||
if (pull_model_inputs.count(var.self))
|
||||
ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(type_id, is_noperspective);
|
||||
else
|
||||
ib_type.member_types[ib_mbr_idx] = type_id;
|
||||
}
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
mark_location_as_used_by_shader(locn, get<SPIRType>(type_id), storage);
|
||||
@@ -1878,14 +1944,17 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
|
||||
}
|
||||
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
if (storage != StorageClassInput || !pull_model_inputs.count(var.self))
|
||||
{
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -1984,7 +2053,10 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||
}
|
||||
}
|
||||
|
||||
ib_type.member_types.push_back(get_pointee_type_id(type_id));
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types.push_back(build_msl_interpolant_type(get_pointee_type_id(type_id), is_noperspective));
|
||||
else
|
||||
ib_type.member_types.push_back(get_pointee_type_id(type_id));
|
||||
|
||||
// Give the member a name
|
||||
string mbr_name = ensure_valid_name(join(to_expression(var.self), "_", i), "m");
|
||||
@@ -1998,7 +2070,10 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||
{
|
||||
var.basetype = ensure_correct_input_type(var.basetype, locn);
|
||||
uint32_t mbr_type_id = ensure_correct_input_type(usable_type->self, locn);
|
||||
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective);
|
||||
else
|
||||
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
||||
}
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
mark_location_as_used_by_shader(locn, *usable_type, storage);
|
||||
@@ -2022,15 +2097,18 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationIndex, index);
|
||||
}
|
||||
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
if (storage != StorageClassInput || !pull_model_inputs.count(var.self))
|
||||
{
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
}
|
||||
|
||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
||||
|
||||
@@ -2040,8 +2118,23 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
||||
switch (storage)
|
||||
{
|
||||
case StorageClassInput:
|
||||
entry_func.fixup_hooks_in.push_back(
|
||||
[=, &var]() { statement(to_name(var.self), "[", i, "] = ", ib_var_ref, ".", mbr_name, ";"); });
|
||||
entry_func.fixup_hooks_in.push_back([=, &var]() {
|
||||
if (pull_model_inputs.count(var.self))
|
||||
{
|
||||
string lerp_call;
|
||||
if (is_centroid)
|
||||
lerp_call = ".interpolate_at_centroid()";
|
||||
else if (is_sample)
|
||||
lerp_call = join(".interpolate_at_sample(", to_expression(builtin_sample_id_id), ")");
|
||||
else
|
||||
lerp_call = ".interpolate_at_center()";
|
||||
statement(to_name(var.self), "[", i, "] = ", ib_var_ref, ".", mbr_name, lerp_call, ";");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement(to_name(var.self), "[", i, "] = ", ib_var_ref, ".", mbr_name, ";");
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case StorageClassOutput:
|
||||
@@ -2165,7 +2258,10 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||
{
|
||||
// Add a reference to the variable type to the interface struct.
|
||||
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
|
||||
ib_type.member_types.push_back(usable_type->self);
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types.push_back(build_msl_interpolant_type(usable_type->self, is_noperspective));
|
||||
else
|
||||
ib_type.member_types.push_back(usable_type->self);
|
||||
|
||||
// Give the member a name
|
||||
string mbr_name = ensure_valid_name(join(to_qualified_member_name(var_type, mbr_idx), "_", i), "m");
|
||||
@@ -2199,15 +2295,18 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||
if (has_member_decoration(var_type.self, mbr_idx, DecorationComponent))
|
||||
SPIRV_CROSS_THROW("DecorationComponent on matrices and arrays make little sense.");
|
||||
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
if (storage != StorageClassInput || !pull_model_inputs.count(var.self))
|
||||
{
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
}
|
||||
|
||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx);
|
||||
@@ -2219,8 +2318,23 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
||||
{
|
||||
case StorageClassInput:
|
||||
entry_func.fixup_hooks_in.push_back([=, &var, &var_type]() {
|
||||
statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref,
|
||||
".", mbr_name, ";");
|
||||
if (pull_model_inputs.count(var.self))
|
||||
{
|
||||
string lerp_call;
|
||||
if (is_centroid)
|
||||
lerp_call = ".interpolate_at_centroid()";
|
||||
else if (is_sample)
|
||||
lerp_call = join(".interpolate_at_sample(", to_expression(builtin_sample_id_id), ")");
|
||||
else
|
||||
lerp_call = ".interpolate_at_center()";
|
||||
statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref,
|
||||
".", mbr_name, lerp_call, ";");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref,
|
||||
".", mbr_name, ";");
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -2269,7 +2383,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
|
||||
mbr_type_id = ensure_correct_builtin_type(mbr_type_id, builtin);
|
||||
var_type.member_types[mbr_idx] = mbr_type_id;
|
||||
ib_type.member_types.push_back(mbr_type_id);
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types.push_back(build_msl_interpolant_type(mbr_type_id, is_noperspective));
|
||||
else
|
||||
ib_type.member_types.push_back(mbr_type_id);
|
||||
|
||||
// Give the member a name
|
||||
string mbr_name = ensure_valid_name(to_qualified_member_name(var_type, mbr_idx), "m");
|
||||
@@ -2277,6 +2394,16 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||
|
||||
// Update the original variable reference to include the structure reference
|
||||
string qual_var_name = ib_var_ref + "." + mbr_name;
|
||||
// If using pull-model interpolation, need to add a call to the correct interpolation method.
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
{
|
||||
if (is_centroid)
|
||||
qual_var_name += ".interpolate_at_centroid()";
|
||||
else if (is_sample)
|
||||
qual_var_name += join(".interpolate_at_sample(", to_expression(builtin_sample_id_id), ")");
|
||||
else
|
||||
qual_var_name += ".interpolate_at_center()";
|
||||
}
|
||||
|
||||
if (is_builtin && !meta.strip_array)
|
||||
{
|
||||
@@ -2314,7 +2441,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||
{
|
||||
mbr_type_id = ensure_correct_input_type(mbr_type_id, locn);
|
||||
var_type.member_types[mbr_idx] = mbr_type_id;
|
||||
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective);
|
||||
else
|
||||
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
||||
}
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
mark_location_as_used_by_shader(locn, get<SPIRType>(mbr_type_id), storage);
|
||||
@@ -2328,7 +2458,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||
{
|
||||
mbr_type_id = ensure_correct_input_type(mbr_type_id, locn);
|
||||
var_type.member_types[mbr_idx] = mbr_type_id;
|
||||
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
||||
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
||||
ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective);
|
||||
else
|
||||
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
||||
}
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
||||
mark_location_as_used_by_shader(locn, get<SPIRType>(mbr_type_id), storage);
|
||||
@@ -2358,15 +2491,18 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
||||
qual_pos_var_name = qual_var_name;
|
||||
}
|
||||
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
if (storage != StorageClassInput || !pull_model_inputs.count(var.self))
|
||||
{
|
||||
// Copy interpolation decorations if needed
|
||||
if (is_flat)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
|
||||
if (is_noperspective)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
|
||||
if (is_centroid)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
|
||||
if (is_sample)
|
||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
|
||||
}
|
||||
|
||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
||||
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx);
|
||||
@@ -2597,11 +2733,13 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
||||
// for per-vertex variables in a tessellation control shader.
|
||||
void CompilerMSL::fix_up_interface_member_indices(StorageClass storage, uint32_t ib_type_id)
|
||||
{
|
||||
// Only needed for tessellation shaders.
|
||||
// Only needed for tessellation shaders and pull-model interpolants.
|
||||
// Need to redirect interface indices back to variables themselves.
|
||||
// For structs, each member of the struct need a separate instance.
|
||||
if (get_execution_model() != ExecutionModelTessellationControl &&
|
||||
!(get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput))
|
||||
!(get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput) &&
|
||||
!(get_execution_model() == ExecutionModelFragment && storage == StorageClassInput &&
|
||||
!pull_model_inputs.empty()))
|
||||
return;
|
||||
|
||||
auto mbr_cnt = uint32_t(ir.meta[ib_type_id].members.size());
|
||||
@@ -6539,6 +6677,61 @@ void CompilerMSL::prepare_access_chain_for_scalar_access(std::string &expr, cons
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the interface member index for an access chain to a pull-model interpolant.
|
||||
void CompilerMSL::fix_up_interpolant_access_chain(const uint32_t *ops, uint32_t length)
|
||||
{
|
||||
auto *var = maybe_get_backing_variable(ops[2]);
|
||||
if (!var || !pull_model_inputs.count(var->self))
|
||||
return;
|
||||
// Get the base index.
|
||||
uint32_t interface_index;
|
||||
auto &var_type = get_variable_data_type(*var);
|
||||
auto &result_type = get<SPIRType>(ops[0]);
|
||||
auto *type = &var_type;
|
||||
if (has_extended_decoration(ops[2], SPIRVCrossDecorationInterfaceMemberIndex))
|
||||
{
|
||||
interface_index = get_extended_decoration(ops[2], SPIRVCrossDecorationInterfaceMemberIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume an access chain into a struct variable.
|
||||
assert(var_type.basetype == SPIRType::Struct);
|
||||
auto &c = get<SPIRConstant>(ops[3 + var_type.array.size()]);
|
||||
interface_index = get_extended_member_decoration(var->self, c.scalar(),
|
||||
SPIRVCrossDecorationInterfaceMemberIndex);
|
||||
}
|
||||
// Accumulate indices. We'll have to skip over the one for the struct, if present, because we already accounted
|
||||
// for that getting the base index.
|
||||
for (uint32_t i = 3; i < length; ++i)
|
||||
{
|
||||
if (is_vector(*type) && is_scalar(result_type))
|
||||
{
|
||||
// We don't want to combine the next index. Actually, we need to save it
|
||||
// so we know to apply a swizzle to the result of the interpolation.
|
||||
set_extended_decoration(ops[1], SPIRVCrossDecorationInterpolantComponentExpr, ops[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
auto *c = maybe_get<SPIRConstant>(ops[i]);
|
||||
if (!c || c->specialization)
|
||||
SPIRV_CROSS_THROW("Trying to dynamically index into an array interface variable using pull-model "
|
||||
"interpolation. This is currently unsupported.");
|
||||
|
||||
if (type->parent_type)
|
||||
type = &get<SPIRType>(type->parent_type);
|
||||
else if (type->basetype == SPIRType::Struct)
|
||||
type = &get<SPIRType>(type->member_types[c->scalar()]);
|
||||
|
||||
if (!has_extended_decoration(ops[2], SPIRVCrossDecorationInterfaceMemberIndex) &&
|
||||
i - 3 == var_type.array.size())
|
||||
continue;
|
||||
|
||||
interface_index += c->scalar();
|
||||
}
|
||||
// Save this to the access chain itself so we can recover it later when calling an interpolation function.
|
||||
set_extended_decoration(ops[1], SPIRVCrossDecorationInterfaceMemberIndex, interface_index);
|
||||
}
|
||||
|
||||
// Override for MSL-specific syntax instructions
|
||||
void CompilerMSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
@@ -7134,6 +7327,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
|
||||
}
|
||||
else
|
||||
CompilerGLSL::emit_instruction(instruction);
|
||||
fix_up_interpolant_access_chain(ops, instruction.length);
|
||||
break;
|
||||
|
||||
case OpStore:
|
||||
@@ -7893,10 +8087,70 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "precise::clamp");
|
||||
break;
|
||||
|
||||
// TODO:
|
||||
// GLSLstd450InterpolateAtCentroid (centroid_no_perspective qualifier)
|
||||
// GLSLstd450InterpolateAtSample (sample_no_perspective qualifier)
|
||||
// GLSLstd450InterpolateAtOffset
|
||||
case GLSLstd450InterpolateAtCentroid:
|
||||
{
|
||||
// We can't just emit the expression normally, because the qualified name contains a call to the default
|
||||
// interpolate method, or refers to a local variable. We saved the interface index we need; use it to construct
|
||||
// the base for the method call.
|
||||
uint32_t interface_index = get_extended_decoration(args[0], SPIRVCrossDecorationInterfaceMemberIndex);
|
||||
string component;
|
||||
if (has_extended_decoration(args[0], SPIRVCrossDecorationInterpolantComponentExpr))
|
||||
{
|
||||
uint32_t index_expr = get_extended_decoration(args[0], SPIRVCrossDecorationInterpolantComponentExpr);
|
||||
auto *c = maybe_get<SPIRConstant>(index_expr);
|
||||
if (!c || c->specialization)
|
||||
component = join("[", to_expression(index_expr), "]");
|
||||
else
|
||||
component = join(".", index_to_swizzle(c->scalar()));
|
||||
}
|
||||
emit_op(result_type, id,
|
||||
join(to_name(stage_in_var_id), ".", to_member_name(get_stage_in_struct_type(), interface_index),
|
||||
".interpolate_at_centroid()", component), should_forward(args[0]));
|
||||
break;
|
||||
}
|
||||
|
||||
case GLSLstd450InterpolateAtSample:
|
||||
{
|
||||
uint32_t interface_index = get_extended_decoration(args[0], SPIRVCrossDecorationInterfaceMemberIndex);
|
||||
string component;
|
||||
if (has_extended_decoration(args[0], SPIRVCrossDecorationInterpolantComponentExpr))
|
||||
{
|
||||
uint32_t index_expr = get_extended_decoration(args[0], SPIRVCrossDecorationInterpolantComponentExpr);
|
||||
auto *c = maybe_get<SPIRConstant>(index_expr);
|
||||
if (!c || c->specialization)
|
||||
component = join("[", to_expression(index_expr), "]");
|
||||
else
|
||||
component = join(".", index_to_swizzle(c->scalar()));
|
||||
}
|
||||
emit_op(result_type, id,
|
||||
join(to_name(stage_in_var_id), ".", to_member_name(get_stage_in_struct_type(), interface_index),
|
||||
".interpolate_at_sample(", to_expression(args[1]), ")", component),
|
||||
should_forward(args[0]) && should_forward(args[1]));
|
||||
break;
|
||||
}
|
||||
|
||||
case GLSLstd450InterpolateAtOffset:
|
||||
{
|
||||
uint32_t interface_index = get_extended_decoration(args[0], SPIRVCrossDecorationInterfaceMemberIndex);
|
||||
string component;
|
||||
if (has_extended_decoration(args[0], SPIRVCrossDecorationInterpolantComponentExpr))
|
||||
{
|
||||
uint32_t index_expr = get_extended_decoration(args[0], SPIRVCrossDecorationInterpolantComponentExpr);
|
||||
auto *c = maybe_get<SPIRConstant>(index_expr);
|
||||
if (!c || c->specialization)
|
||||
component = join("[", to_expression(index_expr), "]");
|
||||
else
|
||||
component = join(".", index_to_swizzle(c->scalar()));
|
||||
}
|
||||
// Like Direct3D, Metal puts the (0, 0) at the upper-left corner, not the center as SPIR-V and GLSL do.
|
||||
// Offset the offset by (1/2 - 1/16), or 0.4375, to compensate for this.
|
||||
// It has to be (1/2 - 1/16) and not 1/2, or several CTS tests subtly break on Intel.
|
||||
emit_op(result_type, id,
|
||||
join(to_name(stage_in_var_id), ".", to_member_name(get_stage_in_struct_type(), interface_index),
|
||||
".interpolate_at_offset(", to_expression(args[1]), " + 0.4375)", component),
|
||||
should_forward(args[0]) && should_forward(args[1]));
|
||||
break;
|
||||
}
|
||||
|
||||
case GLSLstd450Distance:
|
||||
// MSL does not support scalar versions here.
|
||||
@@ -8136,7 +8390,7 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
|
||||
|
||||
// Manufacture automatic sampler arg for SampledImage texture
|
||||
if (arg_type.image.dim != DimBuffer)
|
||||
decl += join(", thread const ", sampler_type(arg_type), " ", to_sampler_expression(arg.id));
|
||||
decl += join(", thread const ", sampler_type(arg_type, arg.id), " ", to_sampler_expression(arg.id));
|
||||
}
|
||||
|
||||
// Manufacture automatic swizzle arg.
|
||||
@@ -8642,10 +8896,10 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool
|
||||
grad_y = 0;
|
||||
farg_str += ", level(0)";
|
||||
}
|
||||
else
|
||||
else if (!msl_options.supports_msl_version(2, 3))
|
||||
{
|
||||
SPIRV_CROSS_THROW("Using non-constant 0.0 gradient() qualifier for sample_compare. This is not "
|
||||
"supported in MSL macOS.");
|
||||
"supported on macOS prior to MSL 2.3.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8657,10 +8911,10 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool
|
||||
{
|
||||
bias = 0;
|
||||
}
|
||||
else
|
||||
else if (!msl_options.supports_msl_version(2, 3))
|
||||
{
|
||||
SPIRV_CROSS_THROW(
|
||||
"Using non-constant 0.0 bias() qualifier for sample_compare. This is not supported in MSL macOS.");
|
||||
"Using non-constant 0.0 bias() qualifier for sample_compare. This is not supported on macOS prior to MSL 2.3.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8794,9 +9048,19 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool
|
||||
{
|
||||
forward = forward && should_forward(args.component);
|
||||
|
||||
if (const auto *var = maybe_get_backing_variable(img))
|
||||
if (!image_is_comparison(get<SPIRType>(var->basetype), var->self))
|
||||
farg_str += ", " + to_component_argument(args.component);
|
||||
uint32_t image_var = 0;
|
||||
if (const auto *combined = maybe_get<SPIRCombinedImageSampler>(img))
|
||||
{
|
||||
if (const auto *img_var = maybe_get_backing_variable(combined->image))
|
||||
image_var = img_var->self;
|
||||
}
|
||||
else if (const auto *var = maybe_get_backing_variable(img))
|
||||
{
|
||||
image_var = var->self;
|
||||
}
|
||||
|
||||
if (image_var == 0 || !image_is_comparison(expression_type(image_var), image_var))
|
||||
farg_str += ", " + to_component_argument(args.component);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9941,6 +10205,8 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo
|
||||
if (get_execution_model() == ExecutionModelTessellationControl && var &&
|
||||
var->basevariable == stage_in_ptr_var_id)
|
||||
addr_space = msl_options.multi_patch_workgroup ? "constant" : "threadgroup";
|
||||
if (get_execution_model() == ExecutionModelFragment && var && var->basevariable == stage_in_var_id)
|
||||
addr_space = "thread";
|
||||
break;
|
||||
|
||||
case StorageClassOutput:
|
||||
@@ -10449,7 +10715,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
|
||||
case SPIRType::Sampler:
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += sampler_type(type) + " " + r.name;
|
||||
ep_args += sampler_type(type, var_id) + " " + r.name;
|
||||
ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]";
|
||||
break;
|
||||
case SPIRType::Image:
|
||||
@@ -11245,7 +11511,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||
decl += ")";
|
||||
decl += type_to_array_glsl(type);
|
||||
}
|
||||
else if (!opaque_handle)
|
||||
else if (!opaque_handle && (!pull_model_inputs.count(var.basevariable) || type.basetype == SPIRType::Struct))
|
||||
{
|
||||
// If this is going to be a reference to a variable pointer, the address space
|
||||
// for the reference has to go before the '&', but after the '*'.
|
||||
@@ -11709,7 +11975,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
||||
return image_type_glsl(type, id);
|
||||
|
||||
case SPIRType::Sampler:
|
||||
return sampler_type(type);
|
||||
return sampler_type(type, id);
|
||||
|
||||
case SPIRType::Void:
|
||||
return "void";
|
||||
@@ -11719,6 +11985,10 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
||||
|
||||
case SPIRType::ControlPointArray:
|
||||
return join("patch_control_point<", type_to_glsl(get<SPIRType>(type.parent_type), id), ">");
|
||||
|
||||
case SPIRType::Interpolant:
|
||||
return join("interpolant<", type_to_glsl(get<SPIRType>(type.parent_type), id), ", interpolation::",
|
||||
has_decoration(type.self, DecorationNoPerspective) ? "no_perspective" : "perspective", ">");
|
||||
|
||||
// Scalars
|
||||
case SPIRType::Boolean:
|
||||
@@ -11840,8 +12110,15 @@ std::string CompilerMSL::variable_decl(const SPIRType &type, const std::string &
|
||||
return CompilerGLSL::variable_decl(type, name, id);
|
||||
}
|
||||
|
||||
std::string CompilerMSL::sampler_type(const SPIRType &type)
|
||||
std::string CompilerMSL::sampler_type(const SPIRType &type, uint32_t id)
|
||||
{
|
||||
auto *var = maybe_get<SPIRVariable>(id);
|
||||
if (var && var->basevariable)
|
||||
{
|
||||
// Check against the base variable, and not a fake ID which might have been generated for this variable.
|
||||
id = var->basevariable;
|
||||
}
|
||||
|
||||
if (!type.array.empty())
|
||||
{
|
||||
if (!msl_options.supports_msl_version(2))
|
||||
@@ -11851,12 +12128,16 @@ std::string CompilerMSL::sampler_type(const SPIRType &type)
|
||||
SPIRV_CROSS_THROW("Arrays of arrays of samplers are not supported in MSL.");
|
||||
|
||||
// Arrays of samplers in MSL must be declared with a special array<T, N> syntax ala C++11 std::array.
|
||||
// If we have a runtime array, it could be a variable-count descriptor set binding.
|
||||
uint32_t array_size = to_array_size_literal(type);
|
||||
if (array_size == 0)
|
||||
array_size = get_resource_array_size(id);
|
||||
|
||||
if (array_size == 0)
|
||||
SPIRV_CROSS_THROW("Unsized array of samplers is not supported in MSL.");
|
||||
|
||||
auto &parent = get<SPIRType>(get_pointee_type(type).parent_type);
|
||||
return join("array<", sampler_type(parent), ", ", array_size, ">");
|
||||
return join("array<", sampler_type(parent, id), ", ", array_size, ">");
|
||||
}
|
||||
else
|
||||
return "sampler";
|
||||
@@ -11893,7 +12174,11 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
||||
SPIRV_CROSS_THROW("Arrays of arrays of textures are not supported in MSL.");
|
||||
|
||||
// Arrays of images in MSL must be declared with a special array<T, N> syntax ala C++11 std::array.
|
||||
// If we have a runtime array, it could be a variable-count descriptor set binding.
|
||||
uint32_t array_size = to_array_size_literal(type);
|
||||
if (array_size == 0)
|
||||
array_size = get_resource_array_size(id);
|
||||
|
||||
if (array_size == 0)
|
||||
SPIRV_CROSS_THROW("Unsized array of images is not supported in MSL.");
|
||||
|
||||
@@ -13285,6 +13570,55 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui
|
||||
break;
|
||||
}
|
||||
|
||||
case OpExtInst:
|
||||
{
|
||||
uint32_t extension_set = args[2];
|
||||
if (compiler.get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
|
||||
{
|
||||
auto op_450 = static_cast<GLSLstd450>(args[3]);
|
||||
switch (op_450)
|
||||
{
|
||||
case GLSLstd450InterpolateAtCentroid:
|
||||
case GLSLstd450InterpolateAtSample:
|
||||
case GLSLstd450InterpolateAtOffset:
|
||||
{
|
||||
if (!compiler.msl_options.supports_msl_version(2, 3))
|
||||
SPIRV_CROSS_THROW("Pull-model interpolation requires MSL 2.3.");
|
||||
// Fragment varyings used with pull-model interpolation need special handling,
|
||||
// due to the way pull-model interpolation works in Metal.
|
||||
auto *var = compiler.maybe_get_backing_variable(args[4]);
|
||||
if (var)
|
||||
{
|
||||
compiler.pull_model_inputs.insert(var->self);
|
||||
auto &var_type = compiler.get_variable_element_type(*var);
|
||||
// In addition, if this variable has a 'Sample' decoration, we need the sample ID
|
||||
// in order to do default interpolation.
|
||||
if (compiler.has_decoration(var->self, DecorationSample))
|
||||
{
|
||||
needs_sample_id = true;
|
||||
}
|
||||
else if (var_type.basetype == SPIRType::Struct)
|
||||
{
|
||||
// Now we need to check each member and see if it has this decoration.
|
||||
for (uint32_t i = 0; i < var_type.member_types.size(); ++i)
|
||||
{
|
||||
if (compiler.has_member_decoration(var_type.self, i, DecorationSample))
|
||||
{
|
||||
needs_sample_id = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
15
3rdparty/spirv-cross/spirv_msl.hpp
vendored
15
3rdparty/spirv-cross/spirv_msl.hpp
vendored
@@ -60,7 +60,11 @@ struct MSLShaderInput
|
||||
|
||||
// Matches the binding index of a MSL resource for a binding within a descriptor set.
|
||||
// Taken together, the stage, desc_set and binding combine to form a reference to a resource
|
||||
// descriptor used in a particular shading stage.
|
||||
// descriptor used in a particular shading stage. The count field indicates the number of
|
||||
// resources consumed by this binding, if the binding represents an array of resources.
|
||||
// If the resource array is a run-time-sized array, which are legal in GLSL or SPIR-V, this value
|
||||
// will be used to declare the array size in MSL, which does not support run-time-sized arrays.
|
||||
// For resources that are not held in a run-time-sized array, the count field does not need to be populated.
|
||||
// If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set,
|
||||
// and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we
|
||||
// remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure.
|
||||
@@ -71,6 +75,7 @@ struct MSLResourceBinding
|
||||
spv::ExecutionModel stage = spv::ExecutionModelMax;
|
||||
uint32_t desc_set = 0;
|
||||
uint32_t binding = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t msl_buffer = 0;
|
||||
uint32_t msl_texture = 0;
|
||||
uint32_t msl_sampler = 0;
|
||||
@@ -672,7 +677,7 @@ protected:
|
||||
std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override;
|
||||
|
||||
std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||
std::string sampler_type(const SPIRType &type);
|
||||
std::string sampler_type(const SPIRType &type, uint32_t id);
|
||||
std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override;
|
||||
std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override;
|
||||
std::string to_name(uint32_t id, bool allow_alias = true) const override;
|
||||
@@ -756,6 +761,7 @@ protected:
|
||||
void emit_specialization_constants_and_structs();
|
||||
void emit_interface_block(uint32_t ib_var_id);
|
||||
bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs);
|
||||
uint32_t get_resource_array_size(uint32_t id) const;
|
||||
|
||||
void fix_up_shader_inputs_outputs();
|
||||
|
||||
@@ -863,6 +869,7 @@ protected:
|
||||
|
||||
void prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, spv::StorageClass storage,
|
||||
bool &is_packed) override;
|
||||
void fix_up_interpolant_access_chain(const uint32_t *ops, uint32_t length);
|
||||
bool emit_tessellation_access_chain(const uint32_t *ops, uint32_t length);
|
||||
bool emit_tessellation_io_load(uint32_t result_type, uint32_t id, uint32_t ptr);
|
||||
bool is_out_of_bounds_tessellation_level(uint32_t id_lhs);
|
||||
@@ -922,6 +929,7 @@ protected:
|
||||
bool added_builtin_tess_level = false;
|
||||
bool needs_subgroup_invocation_id = false;
|
||||
bool needs_subgroup_size = false;
|
||||
bool needs_sample_id = false;
|
||||
std::string qual_pos_var_name;
|
||||
std::string stage_in_var_name = "in";
|
||||
std::string stage_out_var_name = "out";
|
||||
@@ -947,6 +955,7 @@ protected:
|
||||
std::unordered_set<uint32_t> buffers_requiring_array_length;
|
||||
SmallVector<uint32_t> buffer_arrays;
|
||||
std::unordered_set<uint32_t> atomic_image_vars; // Emulate texture2D atomic operations
|
||||
std::unordered_set<uint32_t> pull_model_inputs;
|
||||
|
||||
// Must be ordered since array is in a specific order.
|
||||
std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset;
|
||||
@@ -965,6 +974,7 @@ protected:
|
||||
uint32_t get_target_components_for_fragment_location(uint32_t location) const;
|
||||
uint32_t build_extended_vector_type(uint32_t type_id, uint32_t components,
|
||||
SPIRType::BaseType basetype = SPIRType::Unknown);
|
||||
uint32_t build_msl_interpolant_type(uint32_t type_id, bool is_noperspective);
|
||||
|
||||
bool suppress_missing_prototypes = false;
|
||||
|
||||
@@ -994,6 +1004,7 @@ protected:
|
||||
bool uses_resource_write = false;
|
||||
bool needs_subgroup_invocation_id = false;
|
||||
bool needs_subgroup_size = false;
|
||||
bool needs_sample_id = false;
|
||||
};
|
||||
|
||||
// OpcodeHandler that scans for uses of sampled images
|
||||
|
||||
11
3rdparty/spirv-cross/spirv_parser.cpp
vendored
11
3rdparty/spirv-cross/spirv_parser.cpp
vendored
@@ -623,10 +623,15 @@ void Parser::parse(const Instruction &instruction)
|
||||
{
|
||||
uint32_t id = ops[0];
|
||||
|
||||
auto &base = get<SPIRType>(ops[2]);
|
||||
// Very rarely, we might receive a FunctionPrototype here.
|
||||
// We won't be able to compile it, but we shouldn't crash when parsing.
|
||||
// We should be able to reflect.
|
||||
auto *base = maybe_get<SPIRType>(ops[2]);
|
||||
auto &ptrbase = set<SPIRType>(id);
|
||||
|
||||
ptrbase = base;
|
||||
if (base)
|
||||
ptrbase = *base;
|
||||
|
||||
ptrbase.pointer = true;
|
||||
ptrbase.pointer_depth++;
|
||||
ptrbase.storage = static_cast<StorageClass>(ops[1]);
|
||||
@@ -634,7 +639,7 @@ void Parser::parse(const Instruction &instruction)
|
||||
if (ptrbase.storage == StorageClassAtomicCounter)
|
||||
ptrbase.basetype = SPIRType::AtomicCounter;
|
||||
|
||||
if (base.forward_pointer)
|
||||
if (base && base->forward_pointer)
|
||||
forward_pointer_fixups.push_back({ id, ops[2] });
|
||||
|
||||
ptrbase.parent_type = ops[2];
|
||||
|
||||
Reference in New Issue
Block a user