diff --git a/CMakeLists.txt b/CMakeLists.txt index e9493e16..639cd68e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,7 @@ if (WIN32) endif() if (CMAKE_COMPILER_IS_GNUCXX OR ((${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") AND NOT MSVC)) - set(spirv-compiler-options ${spirv-compiler-options} -Wall -Wextra -Wshadow) + set(spirv-compiler-options ${spirv-compiler-options} -Wall -Wextra -Wshadow -Wno-deprecated-declarations) if (SPIRV_CROSS_MISC_WARNINGS) if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") set(spirv-compiler-options ${spirv-compiler-options} -Wshorten-64-to-32) @@ -323,7 +323,7 @@ if (SPIRV_CROSS_STATIC) endif() set(spirv-cross-abi-major 0) -set(spirv-cross-abi-minor 34) +set(spirv-cross-abi-minor 35) set(spirv-cross-abi-patch 0) if (SPIRV_CROSS_SHARED) diff --git a/main.cpp b/main.cpp index b2cda3a4..f057d994 100644 --- a/main.cpp +++ b/main.cpp @@ -569,6 +569,7 @@ struct CLIArguments SmallVector msl_device_argument_buffers; SmallVector> msl_dynamic_buffers; SmallVector> msl_inline_uniform_blocks; + SmallVector msl_shader_inputs; SmallVector pls_in; SmallVector pls_out; SmallVector remaps; @@ -738,7 +739,10 @@ static void print_help_msl() "\t[--msl-disable-frag-stencil-ref-builtin]:\n\t\tDisable FragStencilRef output. Useful if pipeline does not enable stencil output, as pipeline creation might otherwise fail.\n" "\t[--msl-enable-frag-output-mask ]:\n\t\tOnly selectively enable fragment outputs. Useful if pipeline does not enable fragment output for certain locations, as pipeline creation might otherwise fail.\n" "\t[--msl-no-clip-distance-user-varying]:\n\t\tDo not emit user varyings to emulate gl_ClipDistance in fragment shaders.\n" - ); + "\t[--msl-shader-input ]:\n\t\tSpecify the format of the shader input at .\n" + "\t\t can be 'u16', 'u8', or 'other', to indicate a 16-bit unsigned integer, 8-bit unsigned integer, " + "or other-typed variable. is the vector length of the variable, which must be greater than or equal to that declared in the shader.\n" + "\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\n"); } static void print_help_common() @@ -975,6 +979,8 @@ static string compile_iteration(const CLIArguments &args, std::vector 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); + for (auto &v : args.msl_shader_inputs) + msl_comp->add_msl_shader_input(v); } else if (args.hlsl) compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir()))); @@ -1356,6 +1362,20 @@ static int main_inner(int argc, char *argv[]) [&args](CLIParser &parser) { args.msl_enable_frag_output_mask = parser.next_hex_uint(); }); cbs.add("--msl-no-clip-distance-user-varying", [&args](CLIParser &) { args.msl_enable_clip_distance_user_varying = false; }); + cbs.add("--msl-shader-input", [&args](CLIParser &parser) { + MSLShaderInput input; + // Make sure next_uint() is called in-order. + input.location = parser.next_uint(); + const char *format = parser.next_value_string("other"); + if (strcmp(format, "u16") == 0) + input.format = MSL_VERTEX_FORMAT_UINT16; + else if (strcmp(format, "u8") == 0) + input.format = MSL_VERTEX_FORMAT_UINT8; + else + input.format = MSL_VERTEX_FORMAT_OTHER; + input.vecsize = parser.next_uint(); + args.msl_shader_inputs.push_back(input); + }); cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); cbs.add("--rename-entry-point", [&args](CLIParser &parser) { auto old_name = parser.next_string(); diff --git a/reference/opt/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag b/reference/opt/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag new file mode 100644 index 00000000..6116deab --- /dev/null +++ b/reference/opt/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag @@ -0,0 +1,75 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + ushort2 a [[user(locn0)]]; + uint3 b [[user(locn1)]]; + ushort c_0 [[user(locn2)]]; + ushort c_1 [[user(locn3)]]; + uint4 e_0 [[user(locn4)]]; + uint4 e_1 [[user(locn5)]]; + float4 d [[user(locn6)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray c = {}; + spvUnsafeArray e = {}; + c[0] = in.c_0; + c[1] = in.c_1; + e[0] = in.e_0; + e[1] = in.e_1; + out.FragColor = float4(float(int(in.a.x)), float(in.b.x), float2(float(uint(c[1])), float(e[0].w)) + in.d.xy); + return out; +} + diff --git a/reference/opt/shaders-msl/vert/signedness-mismatch.shader-inputs.vert b/reference/opt/shaders-msl/vert/signedness-mismatch.shader-inputs.vert new file mode 100644 index 00000000..d6e056be --- /dev/null +++ b/reference/opt/shaders-msl/vert/signedness-mismatch.shader-inputs.vert @@ -0,0 +1,74 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + ushort2 a [[attribute(0)]]; + uint3 b [[attribute(1)]]; + ushort c_0 [[attribute(2)]]; + ushort c_1 [[attribute(3)]]; + uint4 d_0 [[attribute(4)]]; + uint4 d_1 [[attribute(5)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray c = {}; + spvUnsafeArray d = {}; + c[0] = in.c_0; + c[1] = in.c_1; + d[0] = in.d_0; + d[1] = in.d_1; + out.gl_Position = float4(float(int(in.a.x)), float(in.b.x), float(uint(c[1])), float(d[0].w)); + return out; +} + diff --git a/reference/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag b/reference/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag new file mode 100644 index 00000000..6116deab --- /dev/null +++ b/reference/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag @@ -0,0 +1,75 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + ushort2 a [[user(locn0)]]; + uint3 b [[user(locn1)]]; + ushort c_0 [[user(locn2)]]; + ushort c_1 [[user(locn3)]]; + uint4 e_0 [[user(locn4)]]; + uint4 e_1 [[user(locn5)]]; + float4 d [[user(locn6)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray c = {}; + spvUnsafeArray e = {}; + c[0] = in.c_0; + c[1] = in.c_1; + e[0] = in.e_0; + e[1] = in.e_1; + out.FragColor = float4(float(int(in.a.x)), float(in.b.x), float2(float(uint(c[1])), float(e[0].w)) + in.d.xy); + return out; +} + diff --git a/reference/shaders-msl/vert/signedness-mismatch.shader-inputs.vert b/reference/shaders-msl/vert/signedness-mismatch.shader-inputs.vert new file mode 100644 index 00000000..d6e056be --- /dev/null +++ b/reference/shaders-msl/vert/signedness-mismatch.shader-inputs.vert @@ -0,0 +1,74 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + ushort2 a [[attribute(0)]]; + uint3 b [[attribute(1)]]; + ushort c_0 [[attribute(2)]]; + ushort c_1 [[attribute(3)]]; + uint4 d_0 [[attribute(4)]]; + uint4 d_1 [[attribute(5)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray c = {}; + spvUnsafeArray d = {}; + c[0] = in.c_0; + c[1] = in.c_1; + d[0] = in.d_0; + d[1] = in.d_1; + out.gl_Position = float4(float(int(in.a.x)), float(in.b.x), float(uint(c[1])), float(d[0].w)); + return out; +} + diff --git a/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag b/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag new file mode 100644 index 00000000..900c5b00 --- /dev/null +++ b/shaders-msl/frag/vecsize-mismatch.shader-inputs.frag @@ -0,0 +1,17 @@ +#version 450 + +#extension GL_AMD_gpu_shader_int16 : require + +layout(location = 0) flat in int16_t a; +layout(location = 1) flat in ivec2 b; +layout(location = 2) flat in uint16_t c[2]; +layout(location = 4) flat in uvec4 e[2]; +layout(location = 6) in vec2 d; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(float(int(a)), float(b.x), vec2(uint(c[1]), float(e[0].w)) + d); +} + diff --git a/shaders-msl/vert/signedness-mismatch.shader-inputs.vert b/shaders-msl/vert/signedness-mismatch.shader-inputs.vert new file mode 100644 index 00000000..dc0f7e6b --- /dev/null +++ b/shaders-msl/vert/signedness-mismatch.shader-inputs.vert @@ -0,0 +1,14 @@ +#version 450 + +#extension GL_AMD_gpu_shader_int16 : require + +layout(location = 0) in int16_t a; +layout(location = 1) in ivec2 b; +layout(location = 2) in uint16_t c[2]; +layout(location = 4) in uvec4 d[2]; + +void main() +{ + gl_Position = vec4(float(int(a)), float(b.x), float(uint(c[1])), float(d[0].w)); +} + diff --git a/spirv_cross_c.cpp b/spirv_cross_c.cpp index 8cc07426..1c42ad01 100644 --- a/spirv_cross_c.cpp +++ b/spirv_cross_c.cpp @@ -1032,6 +1032,30 @@ spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler, const #endif } +spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler, const spvc_msl_shader_input *si) +{ +#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(compiler->compiler.get()); + MSLShaderInput input; + input.location = si->location; + input.format = static_cast(si->format); + input.builtin = static_cast(si->builtin); + input.vecsize = si->vecsize; + msl.add_msl_shader_input(input); + return SPVC_SUCCESS; +#else + (void)si; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler, const spvc_msl_resource_binding *binding) { @@ -2267,6 +2291,19 @@ void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr) #endif } +void spvc_msl_shader_input_init(spvc_msl_shader_input *input) +{ +#if SPIRV_CROSS_C_API_MSL + MSLShaderInput input_default; + input->location = input_default.location; + input->format = static_cast(input_default.format); + input->builtin = static_cast(input_default.builtin); + input->vecsize = input_default.vecsize; +#else + memset(input, 0, sizeof(*input)); +#endif +} + void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding) { #if SPIRV_CROSS_C_API_MSL diff --git a/spirv_cross_c.h b/spirv_cross_c.h index 1ec154ba..5900f123 100644 --- a/spirv_cross_c.h +++ b/spirv_cross_c.h @@ -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 34 +#define SPVC_C_API_VERSION_MINOR 35 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -259,14 +259,19 @@ typedef enum spvc_msl_platform } spvc_msl_platform; /* Maps to C++ API. */ -typedef enum spvc_msl_vertex_format +typedef enum spvc_msl_shader_input_format { - SPVC_MSL_VERTEX_FORMAT_OTHER = 0, - SPVC_MSL_VERTEX_FORMAT_UINT8 = 1, - SPVC_MSL_VERTEX_FORMAT_UINT16 = 2 -} spvc_msl_vertex_format; + SPVC_MSL_SHADER_INPUT_FORMAT_OTHER = 0, + SPVC_MSL_SHADER_INPUT_FORMAT_UINT8 = 1, + SPVC_MSL_SHADER_INPUT_FORMAT_UINT16 = 2, -/* Maps to C++ API. */ + /* Deprecated names. */ + SPVC_MSL_VERTEX_FORMAT_OTHER = SPVC_MSL_SHADER_INPUT_FORMAT_OTHER, + SPVC_MSL_VERTEX_FORMAT_UINT8 = SPVC_MSL_SHADER_INPUT_FORMAT_UINT8, + SPVC_MSL_VERTEX_FORMAT_UINT16 = SPVC_MSL_SHADER_INPUT_FORMAT_UINT16 +} spvc_msl_shader_input_format, spvc_msl_vertex_format; + +/* Maps to C++ API. Deprecated; use spvc_msl_shader_input. */ typedef struct spvc_msl_vertex_attribute { unsigned location; @@ -289,6 +294,20 @@ typedef struct spvc_msl_vertex_attribute */ SPVC_PUBLIC_API void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr); +/* Maps to C++ API. */ +typedef struct spvc_msl_shader_input +{ + unsigned location; + spvc_msl_vertex_format format; + SpvBuiltIn builtin; + unsigned vecsize; +} spvc_msl_shader_input; + +/* + * Initializes the shader input struct. + */ +SPVC_PUBLIC_API void spvc_msl_shader_input_init(spvc_msl_shader_input *input); + /* Maps to C++ API. */ typedef struct spvc_msl_resource_binding { @@ -698,6 +717,8 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler const spvc_msl_vertex_attribute *attrs); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler, const spvc_msl_resource_binding *binding); +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler, + const spvc_msl_shader_input *input); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address); SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location); diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index d64d36f5..b417b0af 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -8697,15 +8697,23 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) expr = to_unpacked_expression(ptr); } + auto &type = get(result_type); + auto &expr_type = expression_type(ptr); + + // If the expression has more vector components than the result type, insert + // a swizzle. This shouldn't happen normally on valid SPIR-V, but it might + // happen with e.g. the MSL backend replacing the type of an input variable. + if (expr_type.vecsize > type.vecsize) + expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0)); + // We might need to bitcast in order to load from a builtin. - bitcast_from_builtin_load(ptr, expr, get(result_type)); + bitcast_from_builtin_load(ptr, expr, type); // We might be trying to load a gl_Position[N], where we should be // doing float4[](gl_in[i].gl_Position, ...) instead. // Similar workarounds are required for input arrays in tessellation. unroll_array_from_complex_load(id, ptr, expr); - auto &type = get(result_type); // Shouldn't need to check for ID, but current glslang codegen requires it in some cases // when loading Image/Sampler descriptors. It does not hurt to check ID as well. if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ptr, DecorationNonUniformEXT)) diff --git a/spirv_msl.cpp b/spirv_msl.cpp index bfe6a3d9..b1930f0a 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -49,11 +49,20 @@ CompilerMSL::CompilerMSL(ParsedIR &&ir_) { } +void CompilerMSL::add_msl_shader_input(const MSLShaderInput &si) +{ + inputs_by_location[si.location] = si; + if (si.builtin != BuiltInMax && !inputs_by_builtin.count(si.builtin)) + inputs_by_builtin[si.builtin] = si; +} + void CompilerMSL::add_msl_vertex_attribute(const MSLVertexAttr &va) { - vtx_attrs_by_location[va.location] = va; - if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin)) - vtx_attrs_by_builtin[va.builtin] = va; + MSLShaderInput si; + si.location = va.location; + si.format = va.format; + si.builtin = va.builtin; + add_msl_shader_input(si); } void CompilerMSL::add_msl_resource_binding(const MSLResourceBinding &binding) @@ -93,7 +102,12 @@ void CompilerMSL::set_argument_buffer_device_address_space(uint32_t desc_set, bo bool CompilerMSL::is_msl_vertex_attribute_used(uint32_t location) { - return vtx_attrs_in_use.count(location) != 0; + return is_msl_shader_input_used(location); +} + +bool CompilerMSL::is_msl_shader_input_used(uint32_t location) +{ + return inputs_in_use.count(location) != 0; } bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const @@ -1458,11 +1472,11 @@ void CompilerMSL::mark_as_packable(SPIRType &type) } } -// If a vertex attribute exists at the location, it is marked as being used by this shader +// If a shader input exists at the location, it is marked as being used by this shader void CompilerMSL::mark_location_as_used_by_shader(uint32_t location, StorageClass storage) { - if ((get_execution_model() == ExecutionModelVertex || is_tessellation_shader()) && (storage == StorageClassInput)) - vtx_attrs_in_use.insert(location); + if (storage == StorageClassInput) + inputs_in_use.insert(location); } uint32_t CompilerMSL::get_target_components_for_fragment_location(uint32_t location) const @@ -1474,11 +1488,13 @@ uint32_t CompilerMSL::get_target_components_for_fragment_location(uint32_t locat return itr->second; } -uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t components) +uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t components, SPIRType::BaseType basetype) { uint32_t new_type_id = ir.increase_bound_by(1); auto &type = set(new_type_id, get(type_id)); type.vecsize = components; + if (basetype != SPIRType::Unknown) + type.basetype = basetype; type.self = new_type_id; type.parent_type = type_id; type.pointer = false; @@ -1634,11 +1650,9 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co if (get_decoration_bitset(var.self).get(DecorationLocation)) { uint32_t locn = get_decoration(var.self, DecorationLocation); - if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader())) + if (storage == StorageClassInput) { - type_id = ensure_correct_attribute_type(var.basetype, locn, - location_meta ? location_meta->num_components : type.vecsize); - + type_id = ensure_correct_input_type(var.basetype, locn, location_meta ? location_meta->num_components : 0); if (!location_meta) var.basetype = type_id; @@ -1650,9 +1664,9 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } - else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) + else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin)) { - uint32_t locn = vtx_attrs_by_builtin[builtin].location; + uint32_t locn = inputs_by_builtin[builtin].location; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } @@ -1797,19 +1811,18 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage if (get_decoration_bitset(var.self).get(DecorationLocation)) { uint32_t locn = get_decoration(var.self, DecorationLocation) + i; - if (storage == StorageClassInput && - (get_execution_model() == ExecutionModelVertex || is_tessellation_shader())) + if (storage == StorageClassInput) { - var.basetype = ensure_correct_attribute_type(var.basetype, locn); - uint32_t mbr_type_id = ensure_correct_attribute_type(usable_type->self, locn); + 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; } set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } - else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) + else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin)) { - uint32_t locn = vtx_attrs_by_builtin[builtin].location + i; + uint32_t locn = inputs_by_builtin[builtin].location + i; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } @@ -1987,9 +2000,9 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } - else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) + else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin)) { - uint32_t locn = vtx_attrs_by_builtin[builtin].location + i; + uint32_t locn = inputs_by_builtin[builtin].location + i; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } @@ -2114,9 +2127,9 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation)) { uint32_t locn = get_member_decoration(var_type.self, mbr_idx, DecorationLocation); - if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader())) + if (storage == StorageClassInput) { - mbr_type_id = ensure_correct_attribute_type(mbr_type_id, locn); + 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; } @@ -2128,20 +2141,20 @@ 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 // receive incrementing locations. 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) { - mbr_type_id = ensure_correct_attribute_type(mbr_type_id, locn); + 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; } set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } - else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) + else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin)) { uint32_t locn = 0; - auto builtin_itr = vtx_attrs_by_builtin.find(builtin); - if (builtin_itr != end(vtx_attrs_by_builtin)) + auto builtin_itr = inputs_by_builtin.find(builtin); + if (builtin_itr != end(inputs_by_builtin)) locn = builtin_itr->second.location; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); @@ -2222,9 +2235,9 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, StorageClassInput); } - else if (vtx_attrs_by_builtin.count(builtin)) + else if (inputs_by_builtin.count(builtin)) { - uint32_t locn = vtx_attrs_by_builtin[builtin].location; + uint32_t locn = inputs_by_builtin[builtin].location; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, StorageClassInput); } @@ -2283,9 +2296,9 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, StorageClassInput); } - else if (vtx_attrs_by_builtin.count(builtin)) + else if (inputs_by_builtin.count(builtin)) { - uint32_t locn = vtx_attrs_by_builtin[builtin].location; + uint32_t locn = inputs_by_builtin[builtin].location; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, StorageClassInput); } @@ -2488,8 +2501,8 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) // accept them. We can't put them in the struct at all, or otherwise the compiler // complains that the outputs weren't explicitly marked. if (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput && !patch && - ((is_builtin && ((bi_type == BuiltInFragDepth && !msl_options.enable_frag_depth_builtin) || - (bi_type == BuiltInFragStencilRefEXT && !msl_options.enable_frag_stencil_ref_builtin))) || + ((is_builtin && ((bi_type == BuiltInFragDepth && !msl_options.enable_frag_depth_builtin) || + (bi_type == BuiltInFragStencilRefEXT && !msl_options.enable_frag_stencil_ref_builtin))) || (!is_builtin && !(msl_options.enable_frag_output_mask & (1 << location))))) { hidden = true; @@ -2784,63 +2797,49 @@ uint32_t CompilerMSL::ensure_correct_builtin_type(uint32_t type_id, BuiltIn buil return type_id; } -// Ensure that the type is compatible with the vertex attribute. +// Ensure that the type is compatible with the shader input. // If it is, simply return the given type 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 num_components) +uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t location, uint32_t num_components) { auto &type = get(type_id); - auto p_va = vtx_attrs_by_location.find(location); - if (p_va == end(vtx_attrs_by_location)) + auto p_va = inputs_by_location.find(location); + if (p_va == end(inputs_by_location)) { - if (num_components != 0 && type.vecsize != num_components) + if (num_components > type.vecsize) return build_extended_vector_type(type_id, num_components); else return type_id; } + if (num_components == 0) + num_components = p_va->second.vecsize; + switch (p_va->second.format) { - case MSL_VERTEX_FORMAT_UINT8: + case MSL_SHADER_INPUT_FORMAT_UINT8: { switch (type.basetype) { case SPIRType::UByte: case SPIRType::UShort: case SPIRType::UInt: - if (num_components != 0 && type.vecsize != num_components) + if (num_components > type.vecsize) return build_extended_vector_type(type_id, num_components); else return type_id; case SPIRType::Short: + return build_extended_vector_type(type_id, num_components > type.vecsize ? num_components : type.vecsize, + SPIRType::UShort); case SPIRType::Int: - break; + return build_extended_vector_type(type_id, num_components > type.vecsize ? num_components : type.vecsize, + SPIRType::UInt); default: 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 base_type_id = next_id++; - auto &base_type = set(base_type_id); - base_type = type; - base_type.basetype = type.basetype == SPIRType::Short ? SPIRType::UShort : SPIRType::UInt; - base_type.pointer = false; - if (num_components != 0) - base_type.vecsize = num_components; - - if (!type.pointer) - return base_type_id; - - uint32_t ptr_type_id = next_id++; - auto &ptr_type = set(ptr_type_id); - ptr_type = base_type; - ptr_type.pointer = true; - ptr_type.storage = type.storage; - ptr_type.parent_type = base_type_id; - return ptr_type_id; } case MSL_VERTEX_FORMAT_UINT16: @@ -2849,41 +2848,22 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l { case SPIRType::UShort: case SPIRType::UInt: - if (num_components != 0 && type.vecsize != num_components) + if (num_components > type.vecsize) return build_extended_vector_type(type_id, num_components); else return type_id; case SPIRType::Int: - break; + return build_extended_vector_type(type_id, num_components > type.vecsize ? num_components : type.vecsize, + SPIRType::UInt); default: 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 base_type_id = next_id++; - auto &base_type = set(base_type_id); - base_type = type; - base_type.basetype = SPIRType::UInt; - base_type.pointer = false; - if (num_components != 0) - base_type.vecsize = num_components; - - if (!type.pointer) - return base_type_id; - - uint32_t ptr_type_id = next_id++; - auto &ptr_type = set(ptr_type_id); - ptr_type = base_type; - ptr_type.pointer = true; - ptr_type.storage = type.storage; - ptr_type.parent_type = base_type_id; - return ptr_type_id; } default: - if (num_components != 0 && type.vecsize != num_components) + if (num_components > type.vecsize) type_id = build_extended_vector_type(type_id, num_components); break; } diff --git a/spirv_msl.hpp b/spirv_msl.hpp index 1ec68845..d400afe7 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -27,26 +27,46 @@ namespace SPIRV_CROSS_NAMESPACE { -// Indicates the format of the vertex attribute. Currently limited to specifying -// if the attribute is an 8-bit unsigned integer, 16-bit unsigned integer, or +// Indicates the format of a shader input. Currently limited to specifying +// if the input is an 8-bit unsigned integer, 16-bit unsigned integer, or // some other format. -enum MSLVertexFormat +enum MSLShaderInputFormat { - MSL_VERTEX_FORMAT_OTHER = 0, - MSL_VERTEX_FORMAT_UINT8 = 1, - MSL_VERTEX_FORMAT_UINT16 = 2, - MSL_VERTEX_FORMAT_INT_MAX = 0x7fffffff + MSL_SHADER_INPUT_FORMAT_OTHER = 0, + MSL_SHADER_INPUT_FORMAT_UINT8 = 1, + MSL_SHADER_INPUT_FORMAT_UINT16 = 2, + + // Deprecated aliases. + MSL_VERTEX_FORMAT_OTHER = MSL_SHADER_INPUT_FORMAT_OTHER, + MSL_VERTEX_FORMAT_UINT8 = MSL_SHADER_INPUT_FORMAT_UINT8, + MSL_VERTEX_FORMAT_UINT16 = MSL_SHADER_INPUT_FORMAT_UINT16, + + MSL_SHADER_INPUT_FORMAT_INT_MAX = 0x7fffffff }; +typedef SPIRV_CROSS_DEPRECATED("Use MSLShaderInputFormat.") MSLShaderInputFormat MSLVertexFormat; // Defines MSL characteristics of a vertex attribute at a particular location. // After compilation, it is possible to query whether or not this location was used. -struct MSLVertexAttr +struct SPIRV_CROSS_DEPRECATED("Use MSLShaderInput.") MSLVertexAttr { uint32_t location = 0; MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER; spv::BuiltIn builtin = spv::BuiltInMax; }; +// Defines MSL characteristics of an input variable at a particular location. +// After compilation, it is possible to query whether or not this location was used. +// If vecsize is nonzero, it must be greater than or equal to the vecsize declared in the shader, +// or behavior is undefined. +struct MSLShaderInput +{ + uint32_t location = 0; + bool per_instance = false; + MSLShaderInputFormat format = MSL_SHADER_INPUT_FORMAT_OTHER; + spv::BuiltIn builtin = spv::BuiltInMax; + uint32_t vecsize = 0; +}; + // 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. @@ -423,8 +443,14 @@ public: // vertex content locations to MSL attributes. If vertex attributes are provided, // is_msl_vertex_attribute_used() will return true after calling ::compile() if // the location was used by the MSL code. + SPIRV_CROSS_DEPRECATED("Use add_msl_shader_input().") void add_msl_vertex_attribute(const MSLVertexAttr &attr); + // input is a shader input description used to fix up shader input variables. + // If shader inputs are provided, is_msl_shader_input_used() will return true after + // calling ::compile() if the location was used by the MSL code. + void add_msl_shader_input(const MSLShaderInput &attr); + // resource is a resource binding to indicate the MSL buffer, // texture or sampler index to use for a particular SPIR-V description set // and binding. If resource bindings are provided, @@ -456,8 +482,12 @@ public: void set_argument_buffer_device_address_space(uint32_t desc_set, bool device_storage); // Query after compilation is done. This allows you to check if a location or set/binding combination was used by the shader. + SPIRV_CROSS_DEPRECATED("Use is_msl_shader_input_used().") bool is_msl_vertex_attribute_used(uint32_t location); + // Query after compilation is done. This allows you to check if an input location was used by the shader. + bool is_msl_shader_input_used(uint32_t location); + // NOTE: Only resources which are remapped using add_msl_resource_binding will be reported here. // Constexpr samplers are always assumed to be emitted. // No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped @@ -686,7 +716,7 @@ protected: 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_attribute_type(uint32_t type_id, uint32_t location, uint32_t num_components = 0); + uint32_t ensure_correct_input_type(uint32_t type_id, uint32_t location, uint32_t num_components = 0); void emit_custom_templates(); void emit_custom_functions(); @@ -797,9 +827,9 @@ protected: Options msl_options; std::set spv_function_implementations; - std::unordered_map vtx_attrs_by_location; - std::unordered_map vtx_attrs_by_builtin; - std::unordered_set vtx_attrs_in_use; + std::unordered_map inputs_by_location; + std::unordered_map inputs_by_builtin; + std::unordered_set inputs_in_use; std::unordered_map fragment_output_components; std::set pragma_lines; std::set typedef_lines; @@ -881,7 +911,7 @@ protected: bool descriptor_set_is_argument_buffer(uint32_t desc_set) const; 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); + uint32_t build_extended_vector_type(uint32_t type_id, uint32_t components, SPIRType::BaseType basetype = SPIRType::Unknown); bool suppress_missing_prototypes = false; diff --git a/test_shaders.py b/test_shaders.py index ae603477..c0130bf4 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -266,6 +266,20 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): msl_args.append('0x000000ca') if '.no-user-varying.' in shader: msl_args.append('--msl-no-clip-distance-user-varying') + if '.shader-inputs.' in shader: + # Arbitrary for testing purposes. + msl_args.append('--msl-shader-input') + msl_args.append('0') + msl_args.append('u8') + msl_args.append('2') + msl_args.append('--msl-shader-input') + msl_args.append('1') + msl_args.append('u16') + msl_args.append('3') + msl_args.append('--msl-shader-input') + msl_args.append('6') + msl_args.append('other') + msl_args.append('4') subprocess.check_call(msl_args)