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.*`.
This commit is contained in:
Chip Davis 2022-10-10 16:20:08 -07:00
parent a171087180
commit 0b679334e4
8 changed files with 483 additions and 15 deletions

View File

@ -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-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. <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-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. <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.\n"
"\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\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."
"\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.\n"
"\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\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."
"\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.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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]);
}

View File

@ -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

View File

@ -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,13 +347,39 @@ 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
{
@ -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);

View File

@ -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);

View File

@ -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.