Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Cross.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChip Davis <chip@holochip.com>2022-10-11 02:20:08 +0300
committerChip Davis <chip@holochip.com>2022-10-19 01:04:42 +0300
commit0b679334e4cbc3e42e4ed9d3fb1df6b94c018628 (patch)
tree78926f3b90f6f10f2a5032a6cb817d7fa731db6f
parenta17108718015a58cb9e3e9c792ff49202498f6ce (diff)
MSL: Don't flatten arrayed per-patch output blocks in tessellation shaders.
Flattening doesn't play well with dynamic indices. In this case, it's better to leave it as an array of structs. (I wanted to do this for named blocks generally. Trouble is, the builtin `gl_out` block is *also* a named block...) Fixes six more CTS tests, under `dEQP-VK.tessellation.user_defined_io.per_patch_block_array.*`.
-rw-r--r--main.cpp68
-rw-r--r--reference/opt/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc123
-rw-r--r--reference/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc111
-rw-r--r--shaders-msl/tesc/arrayed-block-io.multi-patch.tesc64
-rw-r--r--spirv_cross_c.cpp64
-rw-r--r--spirv_cross_c.h36
-rw-r--r--spirv_msl.cpp20
-rw-r--r--spirv_msl.hpp12
8 files changed, 483 insertions, 15 deletions
diff --git a/main.cpp b/main.cpp
index 0c84ac2a..aa6fa512 100644
--- a/main.cpp
+++ b/main.cpp
@@ -879,14 +879,24 @@ 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 <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 <index> <format> <size>]:\n\t\tSpecify the format of the shader input at <index>.\n"
+ "\t[--msl-add-shader-input <index> <format> <size> <rate>]:\n\t\tSpecify the format of the shader input at <index>.\n"
"\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
- "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader.\n"
+ "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader. <rate> can be 'vertex', "
+ "'primitive', or 'patch' to indicate a per-vertex, per-primitive, or per-patch variable.\n"
"\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\n"
- "\t[--msl-shader-output <index> <format> <size>]:\n\t\tSpecify the format of the shader output at <index>.\n"
+ "\t[--msl-add-shader-output <index> <format> <size> <rate>]:\n\t\tSpecify the format of the shader output at <index>.\n"
"\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
- "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader.\n"
+ "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader. <rate> can be 'vertex', "
+ "'primitive', or 'patch' to indicate a per-vertex, per-primitive, or per-patch variable.\n"
"\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\n"
+ "\t[--msl-shader-input <index> <format> <size>]:\n\t\tSpecify the format of the shader input at <index>.\n"
+ "\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
+ "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader."
+ "\t\tEquivalent to --msl-add-shader-input with a rate of 'vertex'.\n"
+ "\t[--msl-shader-output <index> <format> <size>]:\n\t\tSpecify the format of the shader output at <index>.\n"
+ "\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
+ "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader."
+ "\t\tEquivalent to --msl-add-shader-output with a rate of 'vertex'.\n"
"\t[--msl-raw-buffer-tese-input]:\n\t\tUse raw buffers for tessellation evaluation input.\n"
"\t\tThis allows the use of nested structures and arrays.\n"
"\t\tIn a future version of SPIRV-Cross, this will become the default.\n"
@@ -1614,6 +1624,56 @@ 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-add-shader-input", [&args](CLIParser &parser) {
+ MSLShaderInterfaceVariable 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, "any32") == 0)
+ input.format = MSL_SHADER_VARIABLE_FORMAT_ANY32;
+ else if (strcmp(format, "any16") == 0)
+ input.format = MSL_SHADER_VARIABLE_FORMAT_ANY16;
+ else if (strcmp(format, "u16") == 0)
+ input.format = MSL_SHADER_VARIABLE_FORMAT_UINT16;
+ else if (strcmp(format, "u8") == 0)
+ input.format = MSL_SHADER_VARIABLE_FORMAT_UINT8;
+ else
+ input.format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
+ input.vecsize = parser.next_uint();
+ const char *rate = parser.next_value_string("vertex");
+ if (strcmp(rate, "primitive") == 0)
+ input.rate = MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE;
+ else if (strcmp(rate, "patch") == 0)
+ input.rate = MSL_SHADER_VARIABLE_RATE_PER_PATCH;
+ else
+ input.rate = MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
+ args.msl_shader_inputs.push_back(input);
+ });
+ cbs.add("--msl-add-shader-output", [&args](CLIParser &parser) {
+ MSLShaderInterfaceVariable output;
+ // Make sure next_uint() is called in-order.
+ output.location = parser.next_uint();
+ const char *format = parser.next_value_string("other");
+ if (strcmp(format, "any32") == 0)
+ output.format = MSL_SHADER_VARIABLE_FORMAT_ANY32;
+ else if (strcmp(format, "any16") == 0)
+ output.format = MSL_SHADER_VARIABLE_FORMAT_ANY16;
+ else if (strcmp(format, "u16") == 0)
+ output.format = MSL_SHADER_VARIABLE_FORMAT_UINT16;
+ else if (strcmp(format, "u8") == 0)
+ output.format = MSL_SHADER_VARIABLE_FORMAT_UINT8;
+ else
+ output.format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
+ output.vecsize = parser.next_uint();
+ const char *rate = parser.next_value_string("vertex");
+ if (strcmp(rate, "primitive") == 0)
+ output.rate = MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE;
+ else if (strcmp(rate, "patch") == 0)
+ output.rate = MSL_SHADER_VARIABLE_RATE_PER_PATCH;
+ else
+ output.rate = MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
+ args.msl_shader_outputs.push_back(output);
+ });
cbs.add("--msl-shader-input", [&args](CLIParser &parser) {
MSLShaderInterfaceVariable input;
// Make sure next_uint() is called in-order.
diff --git a/reference/opt/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc b/reference/opt/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc
new file mode 100644
index 00000000..1618eaa6
--- /dev/null
+++ b/reference/opt/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc
@@ -0,0 +1,123 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+#pragma clang diagnostic ignored "-Wmissing-braces"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+template<typename T, size_t Num>
+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 S
+{
+ int x;
+ float4 y;
+ spvUnsafeArray<float, 2> z;
+};
+
+struct TheBlock
+{
+ spvUnsafeArray<float, 3> blockFa;
+ spvUnsafeArray<S, 2> blockSa;
+ float blockF;
+};
+
+struct main0_patchOut
+{
+ float2 in_te_positionScale;
+ float2 in_te_positionOffset;
+ spvUnsafeArray<TheBlock, 2> tcBlock;
+};
+
+struct main0_in
+{
+ float3 in_tc_attr;
+ ushort2 m_196;
+};
+
+kernel void main0(uint3 gl_GlobalInvocationID [[thread_position_in_grid]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], device main0_in* spvIn [[buffer(22)]])
+{
+ device main0_patchOut& patchOut = spvPatchOut[gl_GlobalInvocationID.x / 5];
+ device main0_in* gl_in = &spvIn[min(gl_GlobalInvocationID.x / 5, spvIndirectParams[1] - 1) * spvIndirectParams[0]];
+ uint gl_PrimitiveID = min(gl_GlobalInvocationID.x / 5, spvIndirectParams[1] - 1);
+ int _163;
+ _163 = 0;
+ float _111;
+ for (float _170 = 1.2999999523162841796875; _163 < 2; _170 = _111, _163++)
+ {
+ float _169;
+ _169 = _170;
+ for (int _164 = 0; _164 < 3; )
+ {
+ patchOut.tcBlock[_163].blockFa[_164] = _169;
+ _169 += 0.4000000059604644775390625;
+ _164++;
+ continue;
+ }
+ int _165;
+ float _168;
+ _168 = _169;
+ _165 = 0;
+ float _174;
+ for (; _165 < 2; _168 = _174, _165++)
+ {
+ patchOut.tcBlock[_163].blockSa[_165].x = int(_168);
+ patchOut.tcBlock[_163].blockSa[_165].y = float4(_168 + 0.4000000059604644775390625, _168 + 1.2000000476837158203125, _168 + 2.0, _168 + 2.80000019073486328125);
+ _174 = _168 + 0.800000011920928955078125;
+ for (int _171 = 0; _171 < 2; )
+ {
+ patchOut.tcBlock[_163].blockSa[_165].z[_171] = _174;
+ _174 += 0.4000000059604644775390625;
+ _171++;
+ continue;
+ }
+ }
+ patchOut.tcBlock[_163].blockF = _168;
+ _111 = _168 + 0.4000000059604644775390625;
+ }
+ spvTessLevel[gl_PrimitiveID].insideTessellationFactor[0] = half(gl_in[0].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].insideTessellationFactor[1] = half(gl_in[1].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0] = half(gl_in[2].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1] = half(gl_in[3].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2] = half(gl_in[4].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[3] = half(gl_in[5].in_tc_attr.x);
+ patchOut.in_te_positionScale = float2(gl_in[6].in_tc_attr.x, gl_in[7].in_tc_attr.x);
+ patchOut.in_te_positionOffset = float2(gl_in[8].in_tc_attr.x, gl_in[9].in_tc_attr.x);
+}
+
diff --git a/reference/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc b/reference/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc
new file mode 100644
index 00000000..c11c7410
--- /dev/null
+++ b/reference/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc
@@ -0,0 +1,111 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+#pragma clang diagnostic ignored "-Wmissing-braces"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+template<typename T, size_t Num>
+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 S
+{
+ int x;
+ float4 y;
+ spvUnsafeArray<float, 2> z;
+};
+
+struct TheBlock
+{
+ spvUnsafeArray<float, 3> blockFa;
+ spvUnsafeArray<S, 2> blockSa;
+ float blockF;
+};
+
+struct main0_patchOut
+{
+ float2 in_te_positionScale;
+ float2 in_te_positionOffset;
+ spvUnsafeArray<TheBlock, 2> tcBlock;
+};
+
+struct main0_in
+{
+ float3 in_tc_attr;
+ ushort2 m_179;
+};
+
+kernel void main0(uint3 gl_GlobalInvocationID [[thread_position_in_grid]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], device main0_in* spvIn [[buffer(22)]])
+{
+ device main0_patchOut& patchOut = spvPatchOut[gl_GlobalInvocationID.x / 5];
+ device main0_in* gl_in = &spvIn[min(gl_GlobalInvocationID.x / 5, spvIndirectParams[1] - 1) * spvIndirectParams[0]];
+ uint gl_PrimitiveID = min(gl_GlobalInvocationID.x / 5, spvIndirectParams[1] - 1);
+ float v = 1.2999999523162841796875;
+ for (int i0 = 0; i0 < 2; i0++)
+ {
+ for (int i1 = 0; i1 < 3; i1++)
+ {
+ patchOut.tcBlock[i0].blockFa[i1] = v;
+ v += 0.4000000059604644775390625;
+ }
+ for (int i1_1 = 0; i1_1 < 2; i1_1++)
+ {
+ patchOut.tcBlock[i0].blockSa[i1_1].x = int(v);
+ v += 0.4000000059604644775390625;
+ patchOut.tcBlock[i0].blockSa[i1_1].y = float4(v, v + 0.800000011920928955078125, v + 1.60000002384185791015625, v + 2.400000095367431640625);
+ v += 0.4000000059604644775390625;
+ for (int i2 = 0; i2 < 2; i2++)
+ {
+ patchOut.tcBlock[i0].blockSa[i1_1].z[i2] = v;
+ v += 0.4000000059604644775390625;
+ }
+ }
+ patchOut.tcBlock[i0].blockF = v;
+ v += 0.4000000059604644775390625;
+ }
+ spvTessLevel[gl_PrimitiveID].insideTessellationFactor[0] = half(gl_in[0].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].insideTessellationFactor[1] = half(gl_in[1].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0] = half(gl_in[2].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1] = half(gl_in[3].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2] = half(gl_in[4].in_tc_attr.x);
+ spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[3] = half(gl_in[5].in_tc_attr.x);
+ patchOut.in_te_positionScale = float2(gl_in[6].in_tc_attr.x, gl_in[7].in_tc_attr.x);
+ patchOut.in_te_positionOffset = float2(gl_in[8].in_tc_attr.x, gl_in[9].in_tc_attr.x);
+}
+
diff --git a/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc b/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc
new file mode 100644
index 00000000..0fc300d6
--- /dev/null
+++ b/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc
@@ -0,0 +1,64 @@
+#version 310 es
+#extension GL_EXT_tessellation_shader : require
+
+layout(vertices = 5) out;
+
+layout(location = 0) patch out highp vec2 in_te_positionScale;
+layout(location = 1) patch out highp vec2 in_te_positionOffset;
+
+struct S
+{
+ highp int x;
+ highp vec4 y;
+ highp float z[2];
+};
+layout(location = 2) patch out TheBlock
+{
+ highp float blockFa[3];
+ S blockSa[2];
+ highp float blockF;
+} tcBlock[2];
+
+layout(location = 0) in highp float in_tc_attr[];
+
+void main (void)
+{
+ {
+ highp float v = 1.3;
+
+ // Assign values to output tcBlock
+ for (int i0 = 0; i0 < 2; ++i0)
+ {
+ for (int i1 = 0; i1 < 3; ++i1)
+ {
+ tcBlock[i0].blockFa[i1] = v;
+ v += 0.4;
+ }
+ for (int i1 = 0; i1 < 2; ++i1)
+ {
+ tcBlock[i0].blockSa[i1].x = int(v);
+ v += 0.4;
+ tcBlock[i0].blockSa[i1].y = vec4(v, v+0.8, v+1.6, v+2.4);
+ v += 0.4;
+ for (int i2 = 0; i2 < 2; ++i2)
+ {
+ tcBlock[i0].blockSa[i1].z[i2] = v;
+ v += 0.4;
+ }
+ }
+ tcBlock[i0].blockF = v;
+ v += 0.4;
+ }
+ }
+
+ gl_TessLevelInner[0] = in_tc_attr[0];
+ gl_TessLevelInner[1] = in_tc_attr[1];
+
+ gl_TessLevelOuter[0] = in_tc_attr[2];
+ gl_TessLevelOuter[1] = in_tc_attr[3];
+ gl_TessLevelOuter[2] = in_tc_attr[4];
+ gl_TessLevelOuter[3] = in_tc_attr[5];
+
+ in_te_positionScale = vec2(in_tc_attr[6], in_tc_attr[7]);
+ in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);
+}
diff --git a/spirv_cross_c.cpp b/spirv_cross_c.cpp
index d227f342..4e4a0189 100644
--- a/spirv_cross_c.cpp
+++ b/spirv_cross_c.cpp
@@ -1182,6 +1182,31 @@ spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler, const spv
#endif
}
+spvc_result spvc_compiler_msl_add_shader_input_2(spvc_compiler compiler, const spvc_msl_shader_interface_var_2 *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<CompilerMSL *>(compiler->compiler.get());
+ MSLShaderInterfaceVariable input;
+ input.location = si->location;
+ input.format = static_cast<MSLShaderVariableFormat>(si->format);
+ input.builtin = static_cast<spv::BuiltIn>(si->builtin);
+ input.vecsize = si->vecsize;
+ input.rate = static_cast<MSLShaderVariableRate>(si->rate);
+ 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_shader_output(spvc_compiler compiler, const spvc_msl_shader_interface_var *so)
{
#if SPIRV_CROSS_C_API_MSL
@@ -1206,6 +1231,31 @@ spvc_result spvc_compiler_msl_add_shader_output(spvc_compiler compiler, const sp
#endif
}
+spvc_result spvc_compiler_msl_add_shader_output_2(spvc_compiler compiler, const spvc_msl_shader_interface_var_2 *so)
+{
+#if SPIRV_CROSS_C_API_MSL
+ if (compiler->backend != SPVC_BACKEND_MSL)
+ {
+ compiler->context->report_error("MSL function used on a non-MSL backend.");
+ return SPVC_ERROR_INVALID_ARGUMENT;
+ }
+
+ auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
+ MSLShaderInterfaceVariable output;
+ output.location = so->location;
+ output.format = static_cast<MSLShaderVariableFormat>(so->format);
+ output.builtin = static_cast<spv::BuiltIn>(so->builtin);
+ output.vecsize = so->vecsize;
+ output.rate = static_cast<MSLShaderVariableRate>(so->rate);
+ msl.add_msl_shader_output(output);
+ return SPVC_SUCCESS;
+#else
+ (void)so;
+ 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)
{
@@ -2595,6 +2645,20 @@ void spvc_msl_shader_input_init(spvc_msl_shader_input *input)
spvc_msl_shader_interface_var_init(input);
}
+void spvc_msl_shader_interface_var_init_2(spvc_msl_shader_interface_var_2 *var)
+{
+#if SPIRV_CROSS_C_API_MSL
+ MSLShaderInterfaceVariable var_default;
+ var->location = var_default.location;
+ var->format = static_cast<spvc_msl_shader_variable_format>(var_default.format);
+ var->builtin = static_cast<SpvBuiltIn>(var_default.builtin);
+ var->vecsize = var_default.vecsize;
+ var->rate = static_cast<spvc_msl_shader_variable_rate>(var_default.rate);
+#else
+ memset(var, 0, sizeof(*var));
+#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 a8a64d4d..7cb3ba05 100644
--- a/spirv_cross_c.h
+++ b/spirv_cross_c.h
@@ -336,7 +336,7 @@ typedef struct spvc_msl_vertex_attribute
*/
SPVC_PUBLIC_API void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr);
-/* Maps to C++ API. */
+/* Maps to C++ API. Deprecated; use spvc_msl_shader_interface_var_2. */
typedef struct spvc_msl_shader_interface_var
{
unsigned location;
@@ -347,14 +347,40 @@ typedef struct spvc_msl_shader_interface_var
/*
* Initializes the shader input struct.
+ * Deprecated. Use spvc_msl_shader_interface_var_init_2().
*/
SPVC_PUBLIC_API void spvc_msl_shader_interface_var_init(spvc_msl_shader_interface_var *var);
/*
- * Deprecated. Use spvc_msl_shader_interface_var_init().
+ * Deprecated. Use spvc_msl_shader_interface_var_init_2().
*/
SPVC_PUBLIC_API void spvc_msl_shader_input_init(spvc_msl_shader_input *input);
/* Maps to C++ API. */
+typedef enum spvc_msl_shader_variable_rate
+{
+ SPVC_MSL_SHADER_VARIABLE_RATE_PER_VERTEX = 0,
+ SPVC_MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE = 1,
+ SPVC_MSL_SHADER_VARIABLE_RATE_PER_PATCH = 2,
+
+ SPVC_MSL_SHADER_VARIABLE_RATE_INT_MAX = 0x7fffffff,
+} spvc_msl_shader_variable_rate;
+
+/* Maps to C++ API. */
+typedef struct spvc_msl_shader_interface_var_2
+{
+ unsigned location;
+ spvc_msl_shader_variable_format format;
+ SpvBuiltIn builtin;
+ unsigned vecsize;
+ spvc_msl_shader_variable_rate rate;
+} spvc_msl_shader_interface_var_2;
+
+/*
+ * Initializes the shader interface variable struct.
+ */
+SPVC_PUBLIC_API void spvc_msl_shader_interface_var_init_2(spvc_msl_shader_interface_var_2 *var);
+
+/* Maps to C++ API. */
typedef struct spvc_msl_resource_binding
{
SpvExecutionModel stage;
@@ -799,10 +825,16 @@ 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);
+/* Deprecated; use spvc_compiler_msl_add_shader_input_2(). */
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler,
const spvc_msl_shader_interface_var *input);
+SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_input_2(spvc_compiler compiler,
+ const spvc_msl_shader_interface_var_2 *input);
+/* Deprecated; use spvc_compiler_msl_add_shader_output_2(). */
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_output(spvc_compiler compiler,
const spvc_msl_shader_interface_var *output);
+SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_output_2(spvc_compiler compiler,
+ const spvc_msl_shader_interface_var_2 *output);
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);
diff --git a/spirv_msl.cpp b/spirv_msl.cpp
index b56edf74..07d23262 100644
--- a/spirv_msl.cpp
+++ b/spirv_msl.cpp
@@ -3359,7 +3359,8 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
if (var_type.basetype == SPIRType::Struct)
{
- bool block_requires_flattening = variable_storage_requires_stage_io(storage) || is_block;
+ bool block_requires_flattening =
+ variable_storage_requires_stage_io(storage) || (is_block && var_type.array.empty());
bool needs_local_declaration = !is_builtin && block_requires_flattening && meta.allow_local_declaration;
if (needs_local_declaration)
@@ -3978,7 +3979,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
if (location_inputs_in_use.count(input.first.location) != 0)
continue;
- if (input.second.patch != patch)
+ if (patch != (input.second.rate == MSL_SHADER_VARIABLE_RATE_PER_PATCH))
continue;
// Tessellation levels have their own struct, so there's no need to add them here.
@@ -7719,20 +7720,22 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
bool flatten_composites = false;
bool is_block = false;
-
- if (var)
- is_block = has_decoration(get_variable_data_type(*var).self, DecorationBlock);
+ bool is_arrayed = false;
if (var)
{
+ auto &type = get_variable_data_type(*var);
+ is_block = has_decoration(type.self, DecorationBlock);
+ is_arrayed = !type.array.empty();
+
flatten_composites = variable_storage_requires_stage_io(var->storage);
- patch = has_decoration(ops[2], DecorationPatch) || is_patch_block(get_variable_data_type(*var));
+ patch = has_decoration(ops[2], DecorationPatch) || is_patch_block(type);
// Should match strip_array in add_interface_block.
flat_data = var->storage == StorageClassInput || (var->storage == StorageClassOutput && is_tesc_shader());
// Patch inputs are treated as normal block IO variables, so they don't deal with this path at all.
- if (patch && (!is_block || var->storage == StorageClassInput))
+ if (patch && (!is_block || is_arrayed || var->storage == StorageClassInput))
flat_data = false;
// We might have a chained access chain, where
@@ -12053,8 +12056,7 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo
if (is_tese_shader() && msl_options.raw_buffer_tese_input && var)
{
bool is_stage_in = var->basevariable == stage_in_ptr_var_id;
- bool is_patch_stage_in = has_decoration(var->self, DecorationPatch) ||
- is_patch_block(get_variable_data_type(get<SPIRVariable>(var->basevariable)));
+ bool is_patch_stage_in = has_decoration(var->self, DecorationPatch);
bool is_builtin = has_decoration(var->self, DecorationBuiltIn);
BuiltIn builtin = (BuiltIn)get_decoration(var->self, DecorationBuiltIn);
bool is_tess_level = is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner);
diff --git a/spirv_msl.hpp b/spirv_msl.hpp
index 9bf7672b..bd4ecc34 100644
--- a/spirv_msl.hpp
+++ b/spirv_msl.hpp
@@ -58,6 +58,17 @@ enum MSLShaderVariableFormat
MSL_SHADER_VARIABLE_FORMAT_INT_MAX = 0x7fffffff
};
+// Indicates the rate at which a variable changes value, one of: per-vertex,
+// per-primitive, or per-patch.
+enum MSLShaderVariableRate
+{
+ MSL_SHADER_VARIABLE_RATE_PER_VERTEX = 0,
+ MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE = 1,
+ MSL_SHADER_VARIABLE_RATE_PER_PATCH = 2,
+
+ MSL_SHADER_VARIABLE_RATE_INT_MAX = 0x7fffffff,
+};
+
// Defines MSL characteristics of a shader interface 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,
@@ -69,6 +80,7 @@ struct MSLShaderInterfaceVariable
MSLShaderVariableFormat format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
spv::BuiltIn builtin = spv::BuiltInMax;
uint32_t vecsize = 0;
+ MSLShaderVariableRate rate = MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
};
// Matches the binding index of a MSL resource for a binding within a descriptor set.