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:
authorHans-Kristian Arntzen <post@arntzen-software.no>2022-10-19 12:00:40 +0300
committerGitHub <noreply@github.com>2022-10-19 12:00:40 +0300
commit57639196694a8b5c572c9358f5d9cb443dd341e5 (patch)
treee3a0524ab0beb76379ed7e5fd1e74b3d55c2bb73
parentf09ba2777714871bddb70d049878af34b94fa54d (diff)
parente698633e2295df658788b301782e6cddee53f6f2 (diff)
Merge pull request #2039 from cdavis5e/raw-buffer-tess-input
Raw buffer tess input
-rw-r--r--CMakeLists.txt2
-rw-r--r--main.cpp82
-rw-r--r--reference/opt/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese12
-rw-r--r--reference/opt/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc123
-rw-r--r--reference/opt/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese72
-rw-r--r--reference/opt/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese38
-rw-r--r--reference/opt/shaders-msl/tese/input-types.raw-tess-in.tese70
-rw-r--r--reference/opt/shaders-msl/tese/quad.domain.tese12
-rw-r--r--reference/opt/shaders-msl/tese/quad.tese12
-rw-r--r--reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese12
-rw-r--r--reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese66
-rw-r--r--reference/opt/shaders-msl/tese/read-tess-level-in-func.msl2.tese8
-rw-r--r--reference/opt/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese64
-rw-r--r--reference/opt/shaders-msl/tese/triangle-tess-level.tese8
-rw-r--r--reference/opt/shaders-msl/tese/water_tess.raw-tess-in.tese46
-rw-r--r--reference/shaders-msl-no-opt/asm/tese/copy-tess-level.asm.msl2.tese12
-rw-r--r--reference/shaders-msl-no-opt/tese/builtin-input-automatic-attribute-assignment.tese12
-rw-r--r--reference/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese12
-rw-r--r--reference/shaders-msl/tesc/arrayed-block-io.multi-patch.tesc111
-rw-r--r--reference/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese73
-rw-r--r--reference/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese39
-rw-r--r--reference/shaders-msl/tese/input-types.raw-tess-in.tese81
-rw-r--r--reference/shaders-msl/tese/quad.domain.tese12
-rw-r--r--reference/shaders-msl/tese/quad.tese12
-rw-r--r--reference/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese12
-rw-r--r--reference/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese72
-rw-r--r--reference/shaders-msl/tese/read-tess-level-in-func.msl2.tese8
-rw-r--r--reference/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese70
-rw-r--r--reference/shaders-msl/tese/triangle-tess-level.tese8
-rw-r--r--reference/shaders-msl/tese/water_tess.raw-tess-in.tese77
-rw-r--r--shaders-msl/tesc/arrayed-block-io.multi-patch.tesc64
-rw-r--r--shaders-msl/tese/in-array-of-struct.raw-tess-in.tese19
-rw-r--r--shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese31
-rw-r--r--shaders-msl/tese/input-types.raw-tess-in.tese75
-rw-r--r--shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese17
-rw-r--r--shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese17
-rw-r--r--shaders-msl/tese/water_tess.raw-tess-in.tese65
-rw-r--r--spirv_cross.cpp5
-rw-r--r--spirv_cross.hpp1
-rw-r--r--spirv_cross_c.cpp72
-rw-r--r--spirv_cross_c.h41
-rw-r--r--spirv_msl.cpp460
-rw-r--r--spirv_msl.hpp25
-rwxr-xr-xtest_shaders.py2
44 files changed, 1875 insertions, 257 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf14c8d5..b28fe0ae 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -332,7 +332,7 @@ if (SPIRV_CROSS_STATIC)
endif()
set(spirv-cross-abi-major 0)
-set(spirv-cross-abi-minor 50)
+set(spirv-cross-abi-minor 51)
set(spirv-cross-abi-patch 0)
if (SPIRV_CROSS_SHARED)
diff --git a/main.cpp b/main.cpp
index 7f7bda4b..aa6fa512 100644
--- a/main.cpp
+++ b/main.cpp
@@ -654,6 +654,7 @@ struct CLIArguments
bool msl_enable_frag_stencil_ref_builtin = true;
uint32_t msl_enable_frag_output_mask = 0xffffffff;
bool msl_enable_clip_distance_user_varying = true;
+ bool msl_raw_buffer_tese_input = false;
bool msl_multi_patch_workgroup = false;
bool msl_vertex_for_tessellation = false;
uint32_t msl_additional_fixed_sample_mask = 0xffffffff;
@@ -878,20 +879,33 @@ 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"
"\t[--msl-multi-patch-workgroup]:\n\t\tUse the new style of tessellation control processing, where multiple patches are processed per workgroup.\n"
- "\t\tThis should increase throughput by ensuring all the GPU's SIMD lanes are occupied, but it is not compatible with the old style.\n"
- "\t\tIn addition, this style also passes input variables in buffers directly instead of using vertex attribute processing.\n"
- "\t\tIn a future version of SPIRV-Cross, this will become the default.\n"
+ "\t\tThis should increase throughput by ensuring all the GPU's SIMD lanes are occupied, but it is not compatible with the old style.\n"
+ "\t\tIn addition, this style also passes input variables in buffers directly instead of using vertex attribute processing.\n"
+ "\t\tIn a future version of SPIRV-Cross, this will become the default.\n"
"\t[--msl-vertex-for-tessellation]:\n\t\tWhen handling a vertex shader, marks it as one that will be used with a new-style tessellation control shader.\n"
- "\t\tThe vertex shader is output to MSL as a compute kernel which outputs vertices to the buffer in the order they are received, rather than in index order as with --msl-capture-output normally.\n"
+ "\t\tThe vertex shader is output to MSL as a compute kernel which outputs vertices to the buffer in the order they are received, rather than in index order as with --msl-capture-output normally.\n"
"\t[--msl-additional-fixed-sample-mask <mask>]:\n"
"\t\tSet an additional fixed sample mask. If the shader outputs a sample mask, then the final sample mask will be a bitwise AND of the two.\n"
"\t[--msl-arrayed-subpass-input]:\n\t\tAssume that images of dimension SubpassData have multiple layers. Layered input attachments are accessed relative to BuiltInLayer.\n"
@@ -1170,6 +1184,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
msl_opts.enable_frag_stencil_ref_builtin = args.msl_enable_frag_stencil_ref_builtin;
msl_opts.enable_frag_output_mask = args.msl_enable_frag_output_mask;
msl_opts.enable_clip_distance_user_varying = args.msl_enable_clip_distance_user_varying;
+ msl_opts.raw_buffer_tese_input = args.msl_raw_buffer_tese_input;
msl_opts.multi_patch_workgroup = args.msl_multi_patch_workgroup;
msl_opts.vertex_for_tessellation = args.msl_vertex_for_tessellation;
msl_opts.additional_fixed_sample_mask = args.msl_additional_fixed_sample_mask;
@@ -1609,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.
@@ -1645,6 +1710,7 @@ static int main_inner(int argc, char *argv[])
output.vecsize = parser.next_uint();
args.msl_shader_outputs.push_back(output);
});
+ cbs.add("--msl-raw-buffer-tese-input", [&args](CLIParser &) { args.msl_raw_buffer_tese_input = true; });
cbs.add("--msl-multi-patch-workgroup", [&args](CLIParser &) { args.msl_multi_patch_workgroup = true; });
cbs.add("--msl-vertex-for-tessellation", [&args](CLIParser &) { args.msl_vertex_for_tessellation = true; });
cbs.add("--msl-additional-fixed-sample-mask",
diff --git a/reference/opt/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese b/reference/opt/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese
index 2245cb98..bfa96f9c 100644
--- a/reference/opt/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese
+++ b/reference/opt/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese
@@ -60,12 +60,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
out.gl_Position = float4(fma(gl_TessCoord.x * gl_TessLevelInner[0], gl_TessLevelOuter[0], ((1.0 - gl_TessCoord.x) * gl_TessLevelInner[0]) * gl_TessLevelOuter[2]), fma(gl_TessCoord.y * gl_TessLevelInner[1], gl_TessLevelOuter[1], ((1.0 - gl_TessCoord.y) * gl_TessLevelInner[1]) * gl_TessLevelOuter[3]), 0.0, 1.0);
return out;
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/opt/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese b/reference/opt/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese
new file mode 100644
index 00000000..e1f1f3c9
--- /dev/null
+++ b/reference/opt/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese
@@ -0,0 +1,72 @@
+#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 _35
+{
+ float dummy;
+ float4 variableInStruct;
+};
+
+struct main0_out
+{
+ float outResult [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ spvUnsafeArray<_35, 3> testStructArray;
+};
+
+[[ patch(triangle, 0) ]] vertex main0_out main0(float3 gl_TessCoord [[position_in_patch]], uint gl_PrimitiveID [[patch_id]], const device main0_in* spvIn [[buffer(22)]])
+{
+ main0_out out = {};
+ const device main0_in* gl_in = &spvIn[gl_PrimitiveID * 0];
+ out.gl_Position = float4((gl_TessCoord.xy * 2.0) - float2(1.0), 0.0, 1.0);
+ out.outResult = ((float(abs(gl_in[0].testStructArray[2].variableInStruct.x - (-4.0)) < 0.001000000047497451305389404296875) * float(abs(gl_in[0].testStructArray[2].variableInStruct.y - (-9.0)) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].testStructArray[2].variableInStruct.z - 3.0) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].testStructArray[2].variableInStruct.w - 7.0) < 0.001000000047497451305389404296875);
+ return out;
+}
+
diff --git a/reference/opt/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese b/reference/opt/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese
new file mode 100644
index 00000000..d81d44b0
--- /dev/null
+++ b/reference/opt/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese
@@ -0,0 +1,38 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct t35
+{
+ float2 m0;
+ float4 m1;
+};
+
+struct t36
+{
+ float2 m0;
+ t35 m1;
+};
+
+struct main0_out
+{
+ float v80 [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float2 v40_m0;
+ t35 v40_m1;
+};
+
+[[ patch(triangle, 0) ]] vertex main0_out main0(float3 gl_TessCoord [[position_in_patch]], uint gl_PrimitiveID [[patch_id]], const device main0_in* spvIn [[buffer(22)]])
+{
+ main0_out out = {};
+ const device main0_in* gl_in = &spvIn[gl_PrimitiveID * 0];
+ out.gl_Position = float4((gl_TessCoord.xy * 2.0) - float2(1.0), 0.0, 1.0);
+ out.v80 = ((float(abs(gl_in[0].v40_m1.m1.x - (-4.0)) < 0.001000000047497451305389404296875) * float(abs(gl_in[0].v40_m1.m1.y - (-9.0)) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].v40_m1.m1.z - 3.0) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].v40_m1.m1.w - 7.0) < 0.001000000047497451305389404296875);
+ return out;
+}
+
diff --git a/reference/opt/shaders-msl/tese/input-types.raw-tess-in.tese b/reference/opt/shaders-msl/tese/input-types.raw-tess-in.tese
new file mode 100644
index 00000000..e918f5b6
--- /dev/null
+++ b/reference/opt/shaders-msl/tese/input-types.raw-tess-in.tese
@@ -0,0 +1,70 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct Block
+{
+ float4 a;
+ float4 b;
+};
+
+struct PatchBlock
+{
+ float4 a;
+ float4 b;
+};
+
+struct Foo
+{
+ float4 a;
+ float4 b;
+};
+
+struct main0_out
+{
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float4 vColor;
+ float4 blocks_a;
+ float4 blocks_b;
+ Foo vFoos;
+};
+
+struct main0_patchIn
+{
+ float4 vColors;
+ float4 patch_block_a;
+ float4 patch_block_b;
+ Foo vFoo;
+};
+
+[[ patch(quad, 0) ]] vertex main0_out main0(uint gl_PrimitiveID [[patch_id]], const device main0_patchIn* spvPatchIn [[buffer(20)]], const device main0_in* spvIn [[buffer(22)]])
+{
+ main0_out out = {};
+ PatchBlock patch_block = {};
+ const device main0_in* gl_in = &spvIn[gl_PrimitiveID * 0];
+ const device main0_patchIn& patchIn = spvPatchIn[gl_PrimitiveID];
+ patch_block.a = patchIn.patch_block_a;
+ patch_block.b = patchIn.patch_block_b;
+ out.gl_Position = gl_in[0].blocks_a;
+ out.gl_Position += gl_in[0].blocks_b;
+ out.gl_Position += gl_in[1].blocks_a;
+ out.gl_Position += gl_in[1].blocks_b;
+ out.gl_Position += patch_block.a;
+ out.gl_Position += patch_block.b;
+ out.gl_Position += gl_in[0].vColor;
+ out.gl_Position += gl_in[1].vColor;
+ out.gl_Position += patchIn.vColors;
+ out.gl_Position += patchIn.vFoo.a;
+ out.gl_Position += patchIn.vFoo.b;
+ out.gl_Position += gl_in[0].vFoos.a;
+ out.gl_Position += gl_in[0].vFoos.b;
+ out.gl_Position += gl_in[1].vFoos.a;
+ out.gl_Position += gl_in[1].vFoos.b;
+ return out;
+}
+
diff --git a/reference/opt/shaders-msl/tese/quad.domain.tese b/reference/opt/shaders-msl/tese/quad.domain.tese
index 6d844054..81c4aa49 100644
--- a/reference/opt/shaders-msl/tese/quad.domain.tese
+++ b/reference/opt/shaders-msl/tese/quad.domain.tese
@@ -60,12 +60,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
gl_TessCoord.y = 1.0 - gl_TessCoord.y;
out.gl_Position = float4(fma(gl_TessCoord.x * gl_TessLevelInner[0], gl_TessLevelOuter[0], ((1.0 - gl_TessCoord.x) * gl_TessLevelInner[0]) * gl_TessLevelOuter[2]), fma(gl_TessCoord.y * gl_TessLevelInner[1], gl_TessLevelOuter[3], ((1.0 - gl_TessCoord.y) * gl_TessLevelInner[1]) * gl_TessLevelOuter[1]), 0.0, 1.0);
diff --git a/reference/opt/shaders-msl/tese/quad.tese b/reference/opt/shaders-msl/tese/quad.tese
index 2245cb98..bfa96f9c 100644
--- a/reference/opt/shaders-msl/tese/quad.tese
+++ b/reference/opt/shaders-msl/tese/quad.tese
@@ -60,12 +60,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
out.gl_Position = float4(fma(gl_TessCoord.x * gl_TessLevelInner[0], gl_TessLevelOuter[0], ((1.0 - gl_TessCoord.x) * gl_TessLevelInner[0]) * gl_TessLevelOuter[2]), fma(gl_TessCoord.y * gl_TessLevelInner[1], gl_TessLevelOuter[1], ((1.0 - gl_TessCoord.y) * gl_TessLevelInner[1]) * gl_TessLevelOuter[3]), 0.0, 1.0);
return out;
diff --git a/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese b/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese
index 251cb2fa..44bdd5ff 100644
--- a/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese
+++ b/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese
@@ -60,12 +60,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
out.gl_Position = float4(gl_TessLevelOuter[0], gl_TessLevelOuter[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]) + float2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
return out;
}
diff --git a/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese b/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese
new file mode 100644
index 00000000..65d2fd94
--- /dev/null
+++ b/reference/opt/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese
@@ -0,0 +1,66 @@
+#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 main0_out
+{
+ float4 gl_Position [[position]];
+};
+
+[[ patch(quad, 0) ]] vertex main0_out main0(uint gl_PrimitiveID [[patch_id]], const device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]])
+{
+ main0_out out = {};
+ spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
+ spvUnsafeArray<float, 2> gl_TessLevelInner = {};
+ gl_TessLevelOuter[0] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0];
+ gl_TessLevelOuter[1] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1];
+ gl_TessLevelOuter[2] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2];
+ gl_TessLevelOuter[3] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[3];
+ gl_TessLevelInner[0] = spvTessLevel[gl_PrimitiveID].insideTessellationFactor[0];
+ gl_TessLevelInner[1] = spvTessLevel[gl_PrimitiveID].insideTessellationFactor[1];
+ out.gl_Position = float4(gl_TessLevelOuter[0], gl_TessLevelOuter[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]) + float2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
+ return out;
+}
+
diff --git a/reference/opt/shaders-msl/tese/read-tess-level-in-func.msl2.tese b/reference/opt/shaders-msl/tese/read-tess-level-in-func.msl2.tese
index bb2e1e59..decaca3d 100644
--- a/reference/opt/shaders-msl/tese/read-tess-level-in-func.msl2.tese
+++ b/reference/opt/shaders-msl/tese/read-tess-level-in-func.msl2.tese
@@ -59,10 +59,10 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
- gl_TessLevelOuter[0] = patchIn.gl_TessLevel.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevel.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevel.z;
- gl_TessLevelInner[0] = patchIn.gl_TessLevel.w;
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevel[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevel[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevel[2];
+ gl_TessLevelInner[0] = patchIn.gl_TessLevel[3];
out.gl_Position = float4(gl_TessLevelOuter[0], gl_TessLevelOuter[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]) + float2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
return out;
}
diff --git a/reference/opt/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese b/reference/opt/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese
new file mode 100644
index 00000000..0b555ed0
--- /dev/null
+++ b/reference/opt/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese
@@ -0,0 +1,64 @@
+#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 main0_out
+{
+ float4 gl_Position [[position]];
+};
+
+[[ patch(triangle, 0) ]] vertex main0_out main0(uint gl_PrimitiveID [[patch_id]], const device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]])
+{
+ main0_out out = {};
+ spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
+ spvUnsafeArray<float, 2> gl_TessLevelInner = {};
+ gl_TessLevelOuter[0] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0];
+ gl_TessLevelOuter[1] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1];
+ gl_TessLevelOuter[2] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2];
+ gl_TessLevelInner[0] = spvTessLevel[gl_PrimitiveID].insideTessellationFactor;
+ out.gl_Position = float4(gl_TessLevelOuter[0], gl_TessLevelOuter[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]) + float2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
+ return out;
+}
+
diff --git a/reference/opt/shaders-msl/tese/triangle-tess-level.tese b/reference/opt/shaders-msl/tese/triangle-tess-level.tese
index 6930e147..86ccc4f0 100644
--- a/reference/opt/shaders-msl/tese/triangle-tess-level.tese
+++ b/reference/opt/shaders-msl/tese/triangle-tess-level.tese
@@ -59,10 +59,10 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevel.w;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevel.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevel.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevel.z;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevel[3];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevel[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevel[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevel[2];
out.gl_Position = float4((gl_TessCoord.x * gl_TessLevelInner[0]) * gl_TessLevelOuter[0], (gl_TessCoord.y * gl_TessLevelInner[0]) * gl_TessLevelOuter[1], (gl_TessCoord.z * gl_TessLevelInner[0]) * gl_TessLevelOuter[2], 1.0);
return out;
}
diff --git a/reference/opt/shaders-msl/tese/water_tess.raw-tess-in.tese b/reference/opt/shaders-msl/tese/water_tess.raw-tess-in.tese
new file mode 100644
index 00000000..d4441c2e
--- /dev/null
+++ b/reference/opt/shaders-msl/tese/water_tess.raw-tess-in.tese
@@ -0,0 +1,46 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct UBO
+{
+ float4x4 uMVP;
+ float4 uScale;
+ float2 uInvScale;
+ float3 uCamPos;
+ float2 uPatchSize;
+ float2 uInvHeightmapSize;
+};
+
+struct main0_out
+{
+ float3 vWorld [[user(locn0)]];
+ float4 vGradNormalTex [[user(locn1)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_patchIn
+{
+ float2 vOutPatchPosBase;
+ float4 vPatchLods;
+};
+
+[[ patch(quad, 0) ]] vertex main0_out main0(constant UBO& _31 [[buffer(0)]], texture2d<float> uHeightmapDisplacement [[texture(0)]], sampler uHeightmapDisplacementSmplr [[sampler(0)]], float2 gl_TessCoordIn [[position_in_patch]], uint gl_PrimitiveID [[patch_id]], const device main0_patchIn* spvPatchIn [[buffer(20)]])
+{
+ main0_out out = {};
+ const device main0_patchIn& patchIn = spvPatchIn[gl_PrimitiveID];
+ float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
+ float2 _202 = fma(gl_TessCoord.xy, _31.uPatchSize, patchIn.vOutPatchPosBase);
+ float2 _216 = mix(patchIn.vPatchLods.yx, patchIn.vPatchLods.zw, float2(gl_TessCoord.x));
+ float _223 = mix(_216.x, _216.y, gl_TessCoord.y);
+ float _225 = floor(_223);
+ float2 _141 = _31.uInvHeightmapSize * exp2(_225);
+ out.vGradNormalTex = float4(fma(_202, _31.uInvHeightmapSize, _31.uInvHeightmapSize * 0.5), (_202 * _31.uInvHeightmapSize) * _31.uScale.zw);
+ float3 _256 = mix(uHeightmapDisplacement.sample(uHeightmapDisplacementSmplr, fma(_202, _31.uInvHeightmapSize, _141 * 0.5), level(_225)).xyz, uHeightmapDisplacement.sample(uHeightmapDisplacementSmplr, fma(_202, _31.uInvHeightmapSize, _141 * 1.0), level(_225 + 1.0)).xyz, float3(_223 - _225));
+ float2 _171 = fma(_202, _31.uScale.xy, _256.yz);
+ out.vWorld = float3(_171.x, _256.x, _171.y);
+ out.gl_Position = _31.uMVP * float4(out.vWorld, 1.0);
+ return out;
+}
+
diff --git a/reference/shaders-msl-no-opt/asm/tese/copy-tess-level.asm.msl2.tese b/reference/shaders-msl-no-opt/asm/tese/copy-tess-level.asm.msl2.tese
index e34fd66e..7fa0f5a4 100644
--- a/reference/shaders-msl-no-opt/asm/tese/copy-tess-level.asm.msl2.tese
+++ b/reference/shaders-msl-no-opt/asm/tese/copy-tess-level.asm.msl2.tese
@@ -61,12 +61,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
out.out_var_CUSTOM_VALUE = float4(gl_TessLevelOuter[0] + gl_TessLevelInner[0], gl_TessLevelOuter[1] + gl_TessLevelInner[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]);
return out;
}
diff --git a/reference/shaders-msl-no-opt/tese/builtin-input-automatic-attribute-assignment.tese b/reference/shaders-msl-no-opt/tese/builtin-input-automatic-attribute-assignment.tese
index 02581a3e..15f04e73 100644
--- a/reference/shaders-msl-no-opt/tese/builtin-input-automatic-attribute-assignment.tese
+++ b/reference/shaders-msl-no-opt/tese/builtin-input-automatic-attribute-assignment.tese
@@ -68,12 +68,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
out.gl_Position = (((((float4(1.0) + patchIn.FragColor) + patchIn.gl_in[0].FragColors) + patchIn.gl_in[1].FragColors) + float4(gl_TessLevelInner[0])) + float4(gl_TessLevelOuter[int(gl_PrimitiveID) & 1])) + patchIn.gl_in[0].gl_Position;
return out;
}
diff --git a/reference/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese b/reference/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese
index b6bdf415..7fd48b4f 100644
--- a/reference/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese
+++ b/reference/shaders-msl/asm/tese/unnamed-builtin-array.asm.tese
@@ -60,12 +60,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
out.gl_Position = float4(((gl_TessCoord.x * gl_TessLevelInner[0]) * gl_TessLevelOuter[0]) + (((1.0 - gl_TessCoord.x) * gl_TessLevelInner[0]) * gl_TessLevelOuter[2]), ((gl_TessCoord.y * gl_TessLevelInner[1]) * gl_TessLevelOuter[1]) + (((1.0 - gl_TessCoord.y) * gl_TessLevelInner[1]) * gl_TessLevelOuter[3]), 0.0, 1.0);
return out;
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/reference/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese b/reference/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese
new file mode 100644
index 00000000..44e495fb
--- /dev/null
+++ b/reference/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese
@@ -0,0 +1,73 @@
+#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 _35
+{
+ float dummy;
+ float4 variableInStruct;
+};
+
+struct main0_out
+{
+ float outResult [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ spvUnsafeArray<_35, 3> testStructArray;
+};
+
+[[ patch(triangle, 0) ]] vertex main0_out main0(float3 gl_TessCoord [[position_in_patch]], uint gl_PrimitiveID [[patch_id]], const device main0_in* spvIn [[buffer(22)]])
+{
+ main0_out out = {};
+ const device main0_in* gl_in = &spvIn[gl_PrimitiveID * 0];
+ out.gl_Position = float4((gl_TessCoord.xy * 2.0) - float2(1.0), 0.0, 1.0);
+ float result = ((float(abs(gl_in[0].testStructArray[2].variableInStruct.x - (-4.0)) < 0.001000000047497451305389404296875) * float(abs(gl_in[0].testStructArray[2].variableInStruct.y - (-9.0)) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].testStructArray[2].variableInStruct.z - 3.0) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].testStructArray[2].variableInStruct.w - 7.0) < 0.001000000047497451305389404296875);
+ out.outResult = result;
+ return out;
+}
+
diff --git a/reference/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese b/reference/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese
new file mode 100644
index 00000000..23c2cc3e
--- /dev/null
+++ b/reference/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese
@@ -0,0 +1,39 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct t35
+{
+ float2 m0;
+ float4 m1;
+};
+
+struct t36
+{
+ float2 m0;
+ t35 m1;
+};
+
+struct main0_out
+{
+ float v80 [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float2 v40_m0;
+ t35 v40_m1;
+};
+
+[[ patch(triangle, 0) ]] vertex main0_out main0(float3 gl_TessCoord [[position_in_patch]], uint gl_PrimitiveID [[patch_id]], const device main0_in* spvIn [[buffer(22)]])
+{
+ main0_out out = {};
+ const device main0_in* gl_in = &spvIn[gl_PrimitiveID * 0];
+ out.gl_Position = float4((gl_TessCoord.xy * 2.0) - float2(1.0), 0.0, 1.0);
+ float v34 = ((float(abs(gl_in[0].v40_m1.m1.x - (-4.0)) < 0.001000000047497451305389404296875) * float(abs(gl_in[0].v40_m1.m1.y - (-9.0)) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].v40_m1.m1.z - 3.0) < 0.001000000047497451305389404296875)) * float(abs(gl_in[0].v40_m1.m1.w - 7.0) < 0.001000000047497451305389404296875);
+ out.v80 = v34;
+ return out;
+}
+
diff --git a/reference/shaders-msl/tese/input-types.raw-tess-in.tese b/reference/shaders-msl/tese/input-types.raw-tess-in.tese
new file mode 100644
index 00000000..52952220
--- /dev/null
+++ b/reference/shaders-msl/tese/input-types.raw-tess-in.tese
@@ -0,0 +1,81 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct Block
+{
+ float4 a;
+ float4 b;
+};
+
+struct PatchBlock
+{
+ float4 a;
+ float4 b;
+};
+
+struct Foo
+{
+ float4 a;
+ float4 b;
+};
+
+struct main0_out
+{
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float4 vColor;
+ float4 blocks_a;
+ float4 blocks_b;
+ Foo vFoos;
+};
+
+struct main0_patchIn
+{
+ float4 vColors;
+ float4 patch_block_a;
+ float4 patch_block_b;
+ Foo vFoo;
+};
+
+static inline __attribute__((always_inline))
+void set_from_function(thread float4& gl_Position, const device main0_in* thread & gl_in, thread PatchBlock& patch_block, const device float4& vColors, const device Foo& vFoo)
+{
+ gl_Position = gl_in[0].blocks_a;
+ gl_Position += gl_in[0].blocks_b;
+ gl_Position += gl_in[1].blocks_a;
+ gl_Position += gl_in[1].blocks_b;
+ gl_Position += patch_block.a;
+ gl_Position += patch_block.b;
+ gl_Position += gl_in[0].vColor;
+ gl_Position += gl_in[1].vColor;
+ gl_Position += vColors;
+ Foo foo = vFoo;
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+ foo = gl_in[0].vFoos;
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+ foo = gl_in[1].vFoos;
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+}
+
+[[ patch(quad, 0) ]] vertex main0_out main0(uint gl_PrimitiveID [[patch_id]], const device main0_patchIn* spvPatchIn [[buffer(20)]], const device main0_in* spvIn [[buffer(22)]])
+{
+ main0_out out = {};
+ PatchBlock patch_block = {};
+ const device main0_in* gl_in = &spvIn[gl_PrimitiveID * 0];
+ const device main0_patchIn& patchIn = spvPatchIn[gl_PrimitiveID];
+ patch_block.a = patchIn.patch_block_a;
+ patch_block.b = patchIn.patch_block_b;
+ set_from_function(out.gl_Position, gl_in, patch_block, patchIn.vColors, patchIn.vFoo);
+ return out;
+}
+
diff --git a/reference/shaders-msl/tese/quad.domain.tese b/reference/shaders-msl/tese/quad.domain.tese
index dc5c7e40..10cdf5f1 100644
--- a/reference/shaders-msl/tese/quad.domain.tese
+++ b/reference/shaders-msl/tese/quad.domain.tese
@@ -60,12 +60,12 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
gl_TessCoord.y = 1.0 - gl_TessCoord.y;
out.gl_Position = float4(((gl_TessCoord.x * gl_TessLevelInner[0]) * gl_TessLevelOuter[0]) + (((1.0 - gl_TessCoord.x) * gl_TessLevelInner[0]) * gl_TessLevelOuter[2]), ((gl_TessCoord.y * gl_TessLevelInner[1]) * gl_TessLevelOuter[3]) + (((1.0 - gl_TessCoord.y) * gl_TessLevelInner[1]) * gl_TessLevelOuter[1]), 0.0, 1.0);
diff --git a/reference/shaders-msl/tese/quad.tese b/reference/shaders-msl/tese/quad.tese
index 0b48661e..e0c79443 100644
--- a/reference/shaders-msl/tese/quad.tese
+++ b/reference/shaders-msl/tese/quad.tese
@@ -66,12 +66,12 @@ void set_position(thread float4& gl_Position, thread float3& gl_TessCoord, threa
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
set_position(out.gl_Position, gl_TessCoord, gl_TessLevelInner, gl_TessLevelOuter);
return out;
diff --git a/reference/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese b/reference/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese
index 14d2565e..7048546c 100644
--- a/reference/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese
+++ b/reference/shaders-msl/tese/read-tess-level-in-func-quad.msl2.tese
@@ -66,12 +66,12 @@ float4 read_tess_levels(thread spvUnsafeArray<float, 4>& gl_TessLevelOuter, thre
main0_out out = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
- gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter.z;
- gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter.w;
- gl_TessLevelInner[0] = patchIn.gl_TessLevelInner.x;
- gl_TessLevelInner[1] = patchIn.gl_TessLevelInner.y;
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevelOuter[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevelOuter[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevelOuter[2];
+ gl_TessLevelOuter[3] = patchIn.gl_TessLevelOuter[3];
+ gl_TessLevelInner[0] = patchIn.gl_TessLevelInner[0];
+ gl_TessLevelInner[1] = patchIn.gl_TessLevelInner[1];
out.gl_Position = read_tess_levels(gl_TessLevelOuter, gl_TessLevelInner);
return out;
}
diff --git a/reference/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese b/reference/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese
new file mode 100644
index 00000000..f8f81b75
--- /dev/null
+++ b/reference/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese
@@ -0,0 +1,72 @@
+#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 main0_out
+{
+ float4 gl_Position [[position]];
+};
+
+static inline __attribute__((always_inline))
+float4 read_tess_levels(thread spvUnsafeArray<float, 4>& gl_TessLevelOuter, thread spvUnsafeArray<float, 2>& gl_TessLevelInner)
+{
+ return float4(gl_TessLevelOuter[0], gl_TessLevelOuter[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]) + float2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
+}
+
+[[ patch(quad, 0) ]] vertex main0_out main0(uint gl_PrimitiveID [[patch_id]], const device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]])
+{
+ main0_out out = {};
+ spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
+ spvUnsafeArray<float, 2> gl_TessLevelInner = {};
+ gl_TessLevelOuter[0] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0];
+ gl_TessLevelOuter[1] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1];
+ gl_TessLevelOuter[2] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2];
+ gl_TessLevelOuter[3] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[3];
+ gl_TessLevelInner[0] = spvTessLevel[gl_PrimitiveID].insideTessellationFactor[0];
+ gl_TessLevelInner[1] = spvTessLevel[gl_PrimitiveID].insideTessellationFactor[1];
+ out.gl_Position = read_tess_levels(gl_TessLevelOuter, gl_TessLevelInner);
+ return out;
+}
+
diff --git a/reference/shaders-msl/tese/read-tess-level-in-func.msl2.tese b/reference/shaders-msl/tese/read-tess-level-in-func.msl2.tese
index f2fd49e9..432ad7cc 100644
--- a/reference/shaders-msl/tese/read-tess-level-in-func.msl2.tese
+++ b/reference/shaders-msl/tese/read-tess-level-in-func.msl2.tese
@@ -65,10 +65,10 @@ float4 read_tess_levels(thread spvUnsafeArray<float, 4>& gl_TessLevelOuter, thre
main0_out out = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
- gl_TessLevelOuter[0] = patchIn.gl_TessLevel.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevel.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevel.z;
- gl_TessLevelInner[0] = patchIn.gl_TessLevel.w;
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevel[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevel[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevel[2];
+ gl_TessLevelInner[0] = patchIn.gl_TessLevel[3];
out.gl_Position = read_tess_levels(gl_TessLevelOuter, gl_TessLevelInner);
return out;
}
diff --git a/reference/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese b/reference/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese
new file mode 100644
index 00000000..5be7c401
--- /dev/null
+++ b/reference/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese
@@ -0,0 +1,70 @@
+#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 main0_out
+{
+ float4 gl_Position [[position]];
+};
+
+static inline __attribute__((always_inline))
+float4 read_tess_levels(thread spvUnsafeArray<float, 4>& gl_TessLevelOuter, thread spvUnsafeArray<float, 2>& gl_TessLevelInner)
+{
+ return float4(gl_TessLevelOuter[0], gl_TessLevelOuter[1], gl_TessLevelOuter[2], gl_TessLevelOuter[3]) + float2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
+}
+
+[[ patch(triangle, 0) ]] vertex main0_out main0(uint gl_PrimitiveID [[patch_id]], const device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]])
+{
+ main0_out out = {};
+ spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
+ spvUnsafeArray<float, 2> gl_TessLevelInner = {};
+ gl_TessLevelOuter[0] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0];
+ gl_TessLevelOuter[1] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1];
+ gl_TessLevelOuter[2] = spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2];
+ gl_TessLevelInner[0] = spvTessLevel[gl_PrimitiveID].insideTessellationFactor;
+ out.gl_Position = read_tess_levels(gl_TessLevelOuter, gl_TessLevelInner);
+ return out;
+}
+
diff --git a/reference/shaders-msl/tese/triangle-tess-level.tese b/reference/shaders-msl/tese/triangle-tess-level.tese
index 6930e147..86ccc4f0 100644
--- a/reference/shaders-msl/tese/triangle-tess-level.tese
+++ b/reference/shaders-msl/tese/triangle-tess-level.tese
@@ -59,10 +59,10 @@ struct main0_patchIn
main0_out out = {};
spvUnsafeArray<float, 2> gl_TessLevelInner = {};
spvUnsafeArray<float, 4> gl_TessLevelOuter = {};
- gl_TessLevelInner[0] = patchIn.gl_TessLevel.w;
- gl_TessLevelOuter[0] = patchIn.gl_TessLevel.x;
- gl_TessLevelOuter[1] = patchIn.gl_TessLevel.y;
- gl_TessLevelOuter[2] = patchIn.gl_TessLevel.z;
+ gl_TessLevelInner[0] = patchIn.gl_TessLevel[3];
+ gl_TessLevelOuter[0] = patchIn.gl_TessLevel[0];
+ gl_TessLevelOuter[1] = patchIn.gl_TessLevel[1];
+ gl_TessLevelOuter[2] = patchIn.gl_TessLevel[2];
out.gl_Position = float4((gl_TessCoord.x * gl_TessLevelInner[0]) * gl_TessLevelOuter[0], (gl_TessCoord.y * gl_TessLevelInner[0]) * gl_TessLevelOuter[1], (gl_TessCoord.z * gl_TessLevelInner[0]) * gl_TessLevelOuter[2], 1.0);
return out;
}
diff --git a/reference/shaders-msl/tese/water_tess.raw-tess-in.tese b/reference/shaders-msl/tese/water_tess.raw-tess-in.tese
new file mode 100644
index 00000000..bf934564
--- /dev/null
+++ b/reference/shaders-msl/tese/water_tess.raw-tess-in.tese
@@ -0,0 +1,77 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct UBO
+{
+ float4x4 uMVP;
+ float4 uScale;
+ float2 uInvScale;
+ float3 uCamPos;
+ float2 uPatchSize;
+ float2 uInvHeightmapSize;
+};
+
+struct main0_out
+{
+ float3 vWorld [[user(locn0)]];
+ float4 vGradNormalTex [[user(locn1)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_patchIn
+{
+ float2 vOutPatchPosBase;
+ float4 vPatchLods;
+};
+
+static inline __attribute__((always_inline))
+float2 lerp_vertex(thread const float2& tess_coord, const device float2& vOutPatchPosBase, constant UBO& v_31)
+{
+ return vOutPatchPosBase + (tess_coord * v_31.uPatchSize);
+}
+
+static inline __attribute__((always_inline))
+float2 lod_factor(thread const float2& tess_coord, const device float4& vPatchLods)
+{
+ float2 x = mix(vPatchLods.yx, vPatchLods.zw, float2(tess_coord.x));
+ float level0 = mix(x.x, x.y, tess_coord.y);
+ float floor_level = floor(level0);
+ float fract_level = level0 - floor_level;
+ return float2(floor_level, fract_level);
+}
+
+static inline __attribute__((always_inline))
+float3 sample_height_displacement(thread const float2& uv, thread const float2& off, thread const float2& lod, texture2d<float> uHeightmapDisplacement, sampler uHeightmapDisplacementSmplr)
+{
+ return mix(uHeightmapDisplacement.sample(uHeightmapDisplacementSmplr, (uv + (off * 0.5)), level(lod.x)).xyz, uHeightmapDisplacement.sample(uHeightmapDisplacementSmplr, (uv + (off * 1.0)), level(lod.x + 1.0)).xyz, float3(lod.y));
+}
+
+[[ patch(quad, 0) ]] vertex main0_out main0(constant UBO& v_31 [[buffer(0)]], texture2d<float> uHeightmapDisplacement [[texture(0)]], sampler uHeightmapDisplacementSmplr [[sampler(0)]], float2 gl_TessCoordIn [[position_in_patch]], uint gl_PrimitiveID [[patch_id]], const device main0_patchIn* spvPatchIn [[buffer(20)]])
+{
+ main0_out out = {};
+ const device main0_patchIn& patchIn = spvPatchIn[gl_PrimitiveID];
+ float3 gl_TessCoord = float3(gl_TessCoordIn.x, gl_TessCoordIn.y, 0.0);
+ float2 tess_coord = gl_TessCoord.xy;
+ float2 param = tess_coord;
+ float2 pos = lerp_vertex(param, patchIn.vOutPatchPosBase, v_31);
+ float2 param_1 = tess_coord;
+ float2 lod = lod_factor(param_1, patchIn.vPatchLods);
+ float2 tex = pos * v_31.uInvHeightmapSize;
+ pos *= v_31.uScale.xy;
+ float delta_mod = exp2(lod.x);
+ float2 off = v_31.uInvHeightmapSize * delta_mod;
+ out.vGradNormalTex = float4(tex + (v_31.uInvHeightmapSize * 0.5), tex * v_31.uScale.zw);
+ float2 param_2 = tex;
+ float2 param_3 = off;
+ float2 param_4 = lod;
+ float3 height_displacement = sample_height_displacement(param_2, param_3, param_4, uHeightmapDisplacement, uHeightmapDisplacementSmplr);
+ pos += height_displacement.yz;
+ out.vWorld = float3(pos.x, height_displacement.x, pos.y);
+ out.gl_Position = v_31.uMVP * float4(out.vWorld, 1.0);
+ return out;
+}
+
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/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese b/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese
new file mode 100644
index 00000000..a32c1309
--- /dev/null
+++ b/shaders-msl/tese/in-array-of-struct.raw-tess-in.tese
@@ -0,0 +1,19 @@
+#version 450
+#extension GL_EXT_tessellation_shader : require
+
+layout(triangles) in;
+layout(location = 0) in struct {
+ float dummy;
+ vec4 variableInStruct;
+} testStructArray[][3];
+layout(location = 0) out float outResult;
+void main(void)
+{
+ gl_Position = vec4(gl_TessCoord.xy * 2.0 - 1.0, 0.0, 1.0);
+ float result;
+ result = float(abs(testStructArray[0][2].variableInStruct.x - -4.0) < 0.001) *
+ float(abs(testStructArray[0][2].variableInStruct.y - -9.0) < 0.001) *
+ float(abs(testStructArray[0][2].variableInStruct.z - 3.0) < 0.001) *
+ float(abs(testStructArray[0][2].variableInStruct.w - 7.0) < 0.001);
+ outResult = result;
+}
diff --git a/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese b/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese
new file mode 100644
index 00000000..629415a8
--- /dev/null
+++ b/shaders-msl/tese/in-block-with-nested-struct.raw-tess-in.tese
@@ -0,0 +1,31 @@
+#version 450
+layout(triangles, ccw, equal_spacing) in;
+
+out gl_PerVertex
+{
+ vec4 gl_Position;
+ float gl_PointSize;
+ float gl_ClipDistance[1];
+ float gl_CullDistance[1];
+};
+
+struct t35
+{
+ vec2 m0;
+ vec4 m1;
+};
+
+layout(location = 0) in t36
+{
+ vec2 m0;
+ t35 m1;
+} v40[32];
+
+layout(location = 0) out float v80;
+
+void main()
+{
+ gl_Position = vec4((gl_TessCoord.xy * 2.0) - vec2(1.0), 0.0, 1.0);
+ float v34 = ((float(abs(v40[0].m1.m1.x - (-4.0)) < 0.001000000047497451305389404296875) * float(abs(v40[0].m1.m1.y - (-9.0)) < 0.001000000047497451305389404296875)) * float(abs(v40[0].m1.m1.z - 3.0) < 0.001000000047497451305389404296875)) * float(abs(v40[0].m1.m1.w - 7.0) < 0.001000000047497451305389404296875);
+ v80 = v34;
+}
diff --git a/shaders-msl/tese/input-types.raw-tess-in.tese b/shaders-msl/tese/input-types.raw-tess-in.tese
new file mode 100644
index 00000000..3157953f
--- /dev/null
+++ b/shaders-msl/tese/input-types.raw-tess-in.tese
@@ -0,0 +1,75 @@
+#version 450
+
+layout(ccw, quads, fractional_even_spacing) in;
+
+// Try to use the whole taxonomy of input methods.
+
+// Per-vertex vector.
+layout(location = 0) in vec4 vColor[];
+// Per-patch vector.
+layout(location = 1) patch in vec4 vColors;
+// Per-patch vector array.
+layout(location = 2) patch in vec4 vColorsArray[2];
+
+// I/O blocks, per patch and per control point.
+layout(location = 4) in Block
+{
+ vec4 a;
+ vec4 b;
+} blocks[];
+
+layout(location = 6) patch in PatchBlock
+{
+ vec4 a;
+ vec4 b;
+} patch_block;
+
+// Composites.
+struct Foo
+{
+ vec4 a;
+ vec4 b;
+};
+layout(location = 8) patch in Foo vFoo;
+//layout(location = 10) patch in Foo vFooArray[2]; // FIXME: Handling of array-of-struct input is broken!
+
+// Per-control point struct.
+layout(location = 14) in Foo vFoos[];
+
+void set_from_function()
+{
+ gl_Position = blocks[0].a;
+ gl_Position += blocks[0].b;
+ gl_Position += blocks[1].a;
+ gl_Position += blocks[1].b;
+ gl_Position += patch_block.a;
+ gl_Position += patch_block.b;
+ gl_Position += vColor[0];
+ gl_Position += vColor[1];
+ gl_Position += vColors;
+
+ Foo foo = vFoo;
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+
+ /*foo = vFooArray[0];
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+
+ foo = vFooArray[1];
+ gl_Position += foo.a;
+ gl_Position += foo.b;*/
+
+ foo = vFoos[0];
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+
+ foo = vFoos[1];
+ gl_Position += foo.a;
+ gl_Position += foo.b;
+}
+
+void main()
+{
+ set_from_function();
+}
diff --git a/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese b/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese
new file mode 100644
index 00000000..0c289ac5
--- /dev/null
+++ b/shaders-msl/tese/read-tess-level-in-func-quad.raw-tess-in.msl2.tese
@@ -0,0 +1,17 @@
+#version 450
+layout(quads) in;
+
+vec4 read_tess_levels()
+{
+ return vec4(
+ gl_TessLevelOuter[0],
+ gl_TessLevelOuter[1],
+ gl_TessLevelOuter[2],
+ gl_TessLevelOuter[3]) +
+ vec2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
+}
+
+void main()
+{
+ gl_Position = read_tess_levels();
+}
diff --git a/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese b/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese
new file mode 100644
index 00000000..8cf1f1a8
--- /dev/null
+++ b/shaders-msl/tese/read-tess-level-in-func.raw-tess-in.msl2.tese
@@ -0,0 +1,17 @@
+#version 450
+layout(triangles) in;
+
+vec4 read_tess_levels()
+{
+ return vec4(
+ gl_TessLevelOuter[0],
+ gl_TessLevelOuter[1],
+ gl_TessLevelOuter[2],
+ gl_TessLevelOuter[3]) +
+ vec2(gl_TessLevelInner[0], gl_TessLevelInner[1]).xyxy;
+}
+
+void main()
+{
+ gl_Position = read_tess_levels();
+}
diff --git a/shaders-msl/tese/water_tess.raw-tess-in.tese b/shaders-msl/tese/water_tess.raw-tess-in.tese
new file mode 100644
index 00000000..32d6bc93
--- /dev/null
+++ b/shaders-msl/tese/water_tess.raw-tess-in.tese
@@ -0,0 +1,65 @@
+#version 310 es
+#extension GL_EXT_tessellation_shader : require
+precision highp int;
+
+layout(cw, quads, fractional_even_spacing) in;
+
+layout(location = 0) patch in vec2 vOutPatchPosBase;
+layout(location = 1) patch in vec4 vPatchLods;
+
+layout(binding = 1, std140) uniform UBO
+{
+ mat4 uMVP;
+ vec4 uScale;
+ vec2 uInvScale;
+ vec3 uCamPos;
+ vec2 uPatchSize;
+ vec2 uInvHeightmapSize;
+};
+layout(binding = 0) uniform mediump sampler2D uHeightmapDisplacement;
+
+layout(location = 0) highp out vec3 vWorld;
+layout(location = 1) highp out vec4 vGradNormalTex;
+
+vec2 lerp_vertex(vec2 tess_coord)
+{
+ return vOutPatchPosBase + tess_coord * uPatchSize;
+}
+
+mediump vec2 lod_factor(vec2 tess_coord)
+{
+ mediump vec2 x = mix(vPatchLods.yx, vPatchLods.zw, tess_coord.x);
+ mediump float level = mix(x.x, x.y, tess_coord.y);
+ mediump float floor_level = floor(level);
+ mediump float fract_level = level - floor_level;
+ return vec2(floor_level, fract_level);
+}
+
+mediump vec3 sample_height_displacement(vec2 uv, vec2 off, mediump vec2 lod)
+{
+ return mix(
+ textureLod(uHeightmapDisplacement, uv + 0.5 * off, lod.x).xyz,
+ textureLod(uHeightmapDisplacement, uv + 1.0 * off, lod.x + 1.0).xyz,
+ lod.y);
+}
+
+void main()
+{
+ vec2 tess_coord = gl_TessCoord.xy;
+ vec2 pos = lerp_vertex(tess_coord);
+ mediump vec2 lod = lod_factor(tess_coord);
+
+ vec2 tex = pos * uInvHeightmapSize.xy;
+ pos *= uScale.xy;
+
+ mediump float delta_mod = exp2(lod.x);
+ vec2 off = uInvHeightmapSize.xy * delta_mod;
+
+ vGradNormalTex = vec4(tex + 0.5 * uInvHeightmapSize.xy, tex * uScale.zw);
+ vec3 height_displacement = sample_height_displacement(tex, off, lod);
+
+ pos += height_displacement.yz;
+ vWorld = vec3(pos.x, height_displacement.x, pos.y);
+ gl_Position = uMVP * vec4(vWorld, 1.0);
+}
+
diff --git a/spirv_cross.cpp b/spirv_cross.cpp
index e8c57720..3b8bc87b 100644
--- a/spirv_cross.cpp
+++ b/spirv_cross.cpp
@@ -2345,6 +2345,11 @@ bool Compiler::is_tessellation_shader() const
return is_tessellation_shader(get_execution_model());
}
+bool Compiler::is_tessellating_triangles() const
+{
+ return get_execution_mode_bitset().get(ExecutionModeTriangles);
+}
+
void Compiler::set_remapped_variable_state(VariableID id, bool remap_enable)
{
get<SPIRVariable>(id).remapped_variable = remap_enable;
diff --git a/spirv_cross.hpp b/spirv_cross.hpp
index 53c8b653..789010fa 100644
--- a/spirv_cross.hpp
+++ b/spirv_cross.hpp
@@ -371,6 +371,7 @@ public:
spv::ExecutionModel get_execution_model() const;
bool is_tessellation_shader() const;
+ bool is_tessellating_triangles() const;
// In SPIR-V, the compute work group size can be represented by a constant vector, in which case
// the LocalSize execution mode is ignored.
diff --git a/spirv_cross_c.cpp b/spirv_cross_c.cpp
index 011d127a..4e4a0189 100644
--- a/spirv_cross_c.cpp
+++ b/spirv_cross_c.cpp
@@ -715,6 +715,14 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE:
options->msl.ios_support_base_vertex_instance = value != 0;
break;
+
+ case SPVC_COMPILER_OPTION_MSL_RAW_BUFFER_TESE_INPUT:
+ options->msl.raw_buffer_tese_input = value != 0;
+ break;
+
+ case SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_INPUT_BUFFER_INDEX:
+ options->msl.shader_patch_input_buffer_index = value;
+ break;
#endif
default:
@@ -1174,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
@@ -1198,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)
{
@@ -2587,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 89434878..7cb3ba05 100644
--- a/spirv_cross_c.h
+++ b/spirv_cross_c.h
@@ -40,7 +40,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 50
+#define SPVC_C_API_VERSION_MINOR 51
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
@@ -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;
@@ -690,6 +716,9 @@ typedef enum spvc_compiler_option
SPVC_COMPILER_OPTION_RELAX_NAN_CHECKS = 78 | SPVC_COMPILER_OPTION_COMMON_BIT,
+ SPVC_COMPILER_OPTION_MSL_RAW_BUFFER_TESE_INPUT = 79 | SPVC_COMPILER_OPTION_MSL_BIT,
+ SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_INPUT_BUFFER_INDEX = 80 | SPVC_COMPILER_OPTION_MSL_BIT,
+
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
} spvc_compiler_option;
@@ -796,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 b974b669..bc51447a 100644
--- a/spirv_msl.cpp
+++ b/spirv_msl.cpp
@@ -234,7 +234,8 @@ void CompilerMSL::build_implicit_builtins()
bool need_sample_pos = active_input_builtins.get(BuiltInSamplePosition);
bool need_vertex_params = capture_output_to_buffer && get_execution_model() == ExecutionModelVertex &&
!msl_options.vertex_for_tessellation;
- bool need_tesc_params = get_execution_model() == ExecutionModelTessellationControl;
+ bool need_tesc_params = is_tesc_shader();
+ bool need_tese_params = is_tese_shader() && msl_options.raw_buffer_tese_input;
bool need_subgroup_mask =
active_input_builtins.get(BuiltInSubgroupEqMask) || active_input_builtins.get(BuiltInSubgroupGeMask) ||
active_input_builtins.get(BuiltInSubgroupGtMask) || active_input_builtins.get(BuiltInSubgroupLeMask) ||
@@ -257,9 +258,9 @@ void CompilerMSL::build_implicit_builtins()
bool need_workgroup_size = msl_options.emulate_subgroups && active_input_builtins.get(BuiltInNumSubgroups);
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 || needs_sample_id ||
- needs_subgroup_invocation_id || needs_subgroup_size || has_additional_fixed_sample_mask() || need_local_invocation_index ||
- need_workgroup_size)
+ need_tese_params || need_multiview || need_dispatch_base || need_vertex_base_params || need_grid_params ||
+ needs_sample_id || needs_subgroup_invocation_id || needs_subgroup_size || has_additional_fixed_sample_mask() ||
+ need_local_invocation_index || need_workgroup_size)
{
bool has_frag_coord = false;
bool has_sample_id = false;
@@ -365,23 +366,28 @@ void CompilerMSL::build_implicit_builtins()
}
}
- if (need_tesc_params)
+ if (need_tesc_params && builtin == BuiltInInvocationId)
{
- switch (builtin)
- {
- case BuiltInInvocationId:
- builtin_invocation_id_id = var.self;
- mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var.self);
- has_invocation_id = true;
- break;
- case BuiltInPrimitiveId:
- builtin_primitive_id_id = var.self;
- mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var.self);
- has_primitive_id = true;
- break;
- default:
- break;
- }
+ builtin_invocation_id_id = var.self;
+ mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var.self);
+ has_invocation_id = true;
+ }
+
+ if ((need_tesc_params || need_tese_params) && builtin == BuiltInPrimitiveId)
+ {
+ builtin_primitive_id_id = var.self;
+ mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var.self);
+ has_primitive_id = true;
+ }
+
+ if (need_tese_params && builtin == BuiltInTessLevelOuter)
+ {
+ tess_level_outer_var_id = var.self;
+ }
+
+ if (need_tese_params && builtin == BuiltInTessLevelInner)
+ {
+ tess_level_inner_var_id = var.self;
}
if ((need_subgroup_mask || needs_subgroup_invocation_id) && builtin == BuiltInSubgroupLocalInvocationId)
@@ -640,7 +646,7 @@ void CompilerMSL::build_implicit_builtins()
}
if ((need_tesc_params && (msl_options.multi_patch_workgroup || !has_invocation_id || !has_primitive_id)) ||
- need_grid_params)
+ (need_tese_params && !has_primitive_id) || need_grid_params)
{
uint32_t type_ptr_id = ir.increase_bound_by(1);
@@ -653,7 +659,7 @@ void CompilerMSL::build_implicit_builtins()
auto &ptr_type = set<SPIRType>(type_ptr_id, uint_type_ptr);
ptr_type.self = get_uint_type_id();
- if (msl_options.multi_patch_workgroup || need_grid_params)
+ if ((need_tesc_params && msl_options.multi_patch_workgroup) || need_grid_params)
{
uint32_t var_id = ir.increase_bound_by(1);
@@ -674,7 +680,7 @@ void CompilerMSL::build_implicit_builtins()
mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var_id);
}
- if (need_tesc_params && !has_primitive_id)
+ if ((need_tesc_params || need_tese_params) && !has_primitive_id)
{
uint32_t var_id = ir.increase_bound_by(1);
@@ -891,11 +897,9 @@ void CompilerMSL::build_implicit_builtins()
}
// If we're returning a struct from a vertex-like entry point, we must return a position attribute.
- bool need_position =
- (get_execution_model() == ExecutionModelVertex ||
- get_execution_model() == ExecutionModelTessellationEvaluation) &&
- !capture_output_to_buffer && !get_is_rasterization_disabled() &&
- !active_output_builtins.get(BuiltInPosition);
+ bool need_position = (get_execution_model() == ExecutionModelVertex || is_tese_shader()) &&
+ !capture_output_to_buffer && !get_is_rasterization_disabled() &&
+ !active_output_builtins.get(BuiltInPosition);
if (need_position)
{
@@ -1085,7 +1089,7 @@ SPIRType &CompilerMSL::get_patch_stage_out_struct_type()
std::string CompilerMSL::get_tess_factor_struct_name()
{
- if (get_entry_point().flags.get(ExecutionModeTriangles))
+ if (is_tessellating_triangles())
return "MTLTriangleTessellationFactorsHalf";
return "MTLQuadTessellationFactorsHalf";
}
@@ -1483,10 +1487,10 @@ string CompilerMSL::compile()
stage_out_var_id = add_interface_block(StorageClassOutput);
patch_stage_out_var_id = add_interface_block(StorageClassOutput, true);
stage_in_var_id = add_interface_block(StorageClassInput);
- if (get_execution_model() == ExecutionModelTessellationEvaluation)
+ if (is_tese_shader())
patch_stage_in_var_id = add_interface_block(StorageClassInput, true);
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader())
stage_out_ptr_var_id = add_interface_block_pointer(stage_out_var_id, StorageClassOutput);
if (is_tessellation_shader())
stage_in_ptr_var_id = add_interface_block_pointer(stage_in_var_id, StorageClassInput);
@@ -1565,8 +1569,7 @@ void CompilerMSL::preprocess_op_codes()
// Tessellation control shaders are run as compute functions in Metal, and so
// must capture their output to a buffer.
- if (get_execution_model() == ExecutionModelTessellationControl ||
- (get_execution_model() == ExecutionModelVertex && msl_options.vertex_for_tessellation))
+ if (is_tesc_shader() || (get_execution_model() == ExecutionModelVertex && msl_options.vertex_for_tessellation))
{
is_rasterization_disabled = true;
capture_output_to_buffer = true;
@@ -1906,9 +1909,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
bool is_patch = has_decoration(arg_id, DecorationPatch) || is_patch_block(*p_type);
bool is_block = has_decoration(p_type->self, DecorationBlock);
bool is_control_point_storage =
- !is_patch &&
- ((is_tessellation_shader() && var.storage == StorageClassInput) ||
- (get_execution_model() == ExecutionModelTessellationControl && var.storage == StorageClassOutput));
+ !is_patch && ((is_tessellation_shader() && var.storage == StorageClassInput) ||
+ (is_tesc_shader() && var.storage == StorageClassOutput));
bool is_patch_block_storage = is_patch && is_block && var.storage == StorageClassOutput;
bool is_builtin = is_builtin_variable(var);
bool variable_is_stage_io =
@@ -1924,8 +1926,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
if (is_redirected_to_global_stage_io)
{
- // Tessellation control shaders see inputs and per-vertex outputs as arrays.
- // Similarly, tessellation evaluation shaders see per-vertex inputs as arrays.
+ // Tessellation control shaders see inputs and per-point outputs as arrays.
+ // Similarly, tessellation evaluation shaders see per-point inputs as arrays.
// We collected them into a structure; we must pass the array of this
// structure to the function.
std::string name;
@@ -1948,10 +1950,6 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
}
}
- // Tessellation control shaders see inputs and per-vertex outputs as arrays.
- // Similarly, tessellation evaluation shaders see per-vertex inputs as arrays.
- // We collected them into a structure; we must pass the array of this
- // structure to the function.
if (var.storage == StorageClassInput)
{
auto &added_in = is_patch ? patch_added_in : control_point_added_in;
@@ -1975,6 +1973,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
set<SPIRVariable>(next_id, type_id, StorageClassFunction, 0, arg_id);
set_name(next_id, name);
+ if (is_tese_shader() && msl_options.raw_buffer_tese_input && var.storage == StorageClassInput)
+ set_decoration(next_id, DecorationNonWritable);
}
else if (is_builtin && has_decoration(p_type->self, DecorationBlock))
{
@@ -2994,7 +2994,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
{
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
- location++;
+ location += type_to_location_count(get<SPIRType>(mbr_type_id));
}
else if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation))
{
@@ -3011,7 +3011,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
}
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
- location++;
+ location += type_to_location_count(get<SPIRType>(mbr_type_id));
}
else if (has_decoration(var.self, DecorationLocation))
{
@@ -3027,21 +3027,21 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
}
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
- location++;
+ location += type_to_location_count(get<SPIRType>(mbr_type_id));
}
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
{
location = inputs_by_builtin[builtin].location;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
- location++;
+ location += type_to_location_count(get<SPIRType>(mbr_type_id));
}
else if (is_builtin && capture_output_to_buffer && storage == StorageClassOutput && outputs_by_builtin.count(builtin))
{
location = outputs_by_builtin[builtin].location;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
- location++;
+ location += type_to_location_count(get<SPIRType>(mbr_type_id));
}
// Copy the component location, if present.
@@ -3111,19 +3111,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type,
SPIRVariable &var)
{
- auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
auto &var_type = get_variable_element_type(var);
BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
-
- // Force the variable to have the proper name.
- string var_name = builtin_to_glsl(builtin, StorageClassFunction);
- set_name(var.self, var_name);
-
- // We need to declare the variable early and at entry-point scope.
- entry_func.add_local_variable(var.self);
- vars_needing_early_declaration.push_back(var.self);
- bool triangles = get_execution_mode_bitset().get(ExecutionModeTriangles);
+ bool triangles = is_tessellating_triangles();
string mbr_name;
// Add a reference to the variable type to the interface struct.
@@ -3169,7 +3160,7 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_
}
else
{
- mbr_name = var_name;
+ mbr_name = builtin_to_glsl(builtin, StorageClassFunction);
uint32_t type_id = build_extended_vector_type(var_type.self, builtin == BuiltInTessLevelOuter ? 4 : 2);
@@ -3189,27 +3180,49 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_
mark_locations(new_var_type);
}
+ add_tess_level_input(ib_var_ref, mbr_name, var);
+}
+
+void CompilerMSL::add_tess_level_input(const std::string &base_ref, const std::string &mbr_name, SPIRVariable &var)
+{
+ auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
+ BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
+
+ // Force the variable to have the proper name.
+ string var_name = builtin_to_glsl(builtin, StorageClassFunction);
+ set_name(var.self, var_name);
+
+ // We need to declare the variable early and at entry-point scope.
+ entry_func.add_local_variable(var.self);
+ vars_needing_early_declaration.push_back(var.self);
+ bool triangles = is_tessellating_triangles();
+
if (builtin == BuiltInTessLevelOuter)
{
- entry_func.fixup_hooks_in.push_back([=]() {
- statement(var_name, "[0] = ", ib_var_ref, ".", mbr_name, ".x;");
- statement(var_name, "[1] = ", ib_var_ref, ".", mbr_name, ".y;");
- statement(var_name, "[2] = ", ib_var_ref, ".", mbr_name, ".z;");
- if (!triangles)
- statement(var_name, "[3] = ", ib_var_ref, ".", mbr_name, ".w;");
- });
+ entry_func.fixup_hooks_in.push_back(
+ [=]()
+ {
+ statement(var_name, "[0] = ", base_ref, ".", mbr_name, "[0];");
+ statement(var_name, "[1] = ", base_ref, ".", mbr_name, "[1];");
+ statement(var_name, "[2] = ", base_ref, ".", mbr_name, "[2];");
+ if (!triangles)
+ statement(var_name, "[3] = ", base_ref, ".", mbr_name, "[3];");
+ });
}
else
{
entry_func.fixup_hooks_in.push_back([=]() {
if (triangles)
{
- statement(var_name, "[0] = ", ib_var_ref, ".", mbr_name, ".w;");
+ if (msl_options.raw_buffer_tese_input)
+ statement(var_name, "[0] = ", base_ref, ".", mbr_name, ";");
+ else
+ statement(var_name, "[0] = ", base_ref, ".", mbr_name, "[3];");
}
else
{
- statement(var_name, "[0] = ", ib_var_ref, ".", mbr_name, ".x;");
- statement(var_name, "[1] = ", ib_var_ref, ".", mbr_name, ".y;");
+ statement(var_name, "[0] = ", base_ref, ".", mbr_name, "[0];");
+ statement(var_name, "[1] = ", base_ref, ".", mbr_name, "[1];");
}
});
}
@@ -3220,7 +3233,8 @@ bool CompilerMSL::variable_storage_requires_stage_io(spv::StorageClass storage)
if (storage == StorageClassOutput)
return !capture_output_to_buffer;
else if (storage == StorageClassInput)
- return !(get_execution_model() == ExecutionModelTessellationControl && msl_options.multi_patch_workgroup);
+ return !(is_tesc_shader() && msl_options.multi_patch_workgroup) &&
+ !(is_tese_shader() && msl_options.raw_buffer_tese_input);
else
return false;
}
@@ -3345,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)
@@ -3474,8 +3489,7 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
// If we're redirecting a block, we might still need to access the original block
// variable if we're masking some members.
- if (masked_block && !needs_local_declaration &&
- (!is_builtin_variable(var) || get_execution_model() == ExecutionModelTessellationControl))
+ if (masked_block && !needs_local_declaration && (!is_builtin_variable(var) || is_tesc_shader()))
{
if (is_builtin_variable(var))
{
@@ -3496,8 +3510,8 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
}
}
}
- else if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput &&
- !meta.strip_array && is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner))
+ else if (is_tese_shader() && storage == StorageClassInput && !meta.strip_array && is_builtin &&
+ (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner))
{
add_tess_level_input_to_interface_block(ib_var_ref, ib_type, var);
}
@@ -3534,8 +3548,7 @@ void CompilerMSL::fix_up_interface_member_indices(StorageClass storage, uint32_t
// 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) &&
+ if (!is_tesc_shader() && !(is_tese_shader() && storage == StorageClassInput) &&
!(get_execution_model() == ExecutionModelFragment && storage == StorageClassInput &&
!pull_model_inputs.empty()))
return;
@@ -3624,9 +3637,8 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
// These builtins are part of the stage in/out structs.
bool is_interface_block_builtin =
- builtin_is_stage_in_out ||
- (get_execution_model() == ExecutionModelTessellationEvaluation &&
- (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner));
+ builtin_is_stage_in_out || (is_tese_shader() && !msl_options.raw_buffer_tese_input &&
+ (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner));
bool is_active = interface_variable_exists_in_entry_point(var.self);
if (is_builtin && is_active)
@@ -3722,12 +3734,29 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
}
}
}
+
+ if (is_tese_shader() && msl_options.raw_buffer_tese_input && patch && storage == StorageClassInput &&
+ (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner))
+ {
+ // In this case, we won't add the builtin to the interface struct,
+ // but we still need the hook to run to populate the arrays.
+ string base_ref = join(tess_factor_buffer_var_name, "[", to_expression(builtin_primitive_id_id), "]");
+ const char *mbr_name =
+ bi_type == BuiltInTessLevelOuter ? "edgeTessellationFactor" : "insideTessellationFactor";
+ add_tess_level_input(base_ref, mbr_name, var);
+ if (inputs_by_builtin.count(bi_type))
+ {
+ uint32_t locn = inputs_by_builtin[bi_type].location;
+ mark_location_as_used_by_shader(locn, type, StorageClassInput);
+ }
+ }
});
// If no variables qualify, leave.
// For patch input in a tessellation evaluation shader, the per-vertex stage inputs
// are included in a special patch control point array.
- if (vars.empty() && !(storage == StorageClassInput && patch && stage_in_var_id))
+ if (vars.empty() &&
+ !(!msl_options.raw_buffer_tese_input && storage == StorageClassInput && patch && stage_in_var_id))
return 0;
// Add a new typed variable for this interface structure.
@@ -3750,8 +3779,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
{
case StorageClassInput:
ib_var_ref = patch ? patch_stage_in_var_name : stage_in_var_name;
- if (get_execution_model() == ExecutionModelTessellationControl)
+ switch (get_execution_model())
{
+ case ExecutionModelTessellationControl:
// Add a hook to populate the shared workgroup memory containing the gl_in array.
entry_func.fixup_hooks_in.push_back([=]() {
// Can't use PatchVertices, PrimitiveId, or InvocationId yet; the hooks for those may not have run yet.
@@ -3777,6 +3807,33 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
statement(" return;");
}
});
+ break;
+ case ExecutionModelTessellationEvaluation:
+ if (!msl_options.raw_buffer_tese_input)
+ break;
+ if (patch)
+ {
+ entry_func.fixup_hooks_in.push_back(
+ [=]()
+ {
+ statement("const device ", to_name(ir.default_entry_point), "_", ib_var_ref, "& ", ib_var_ref,
+ " = ", patch_input_buffer_var_name, "[", to_expression(builtin_primitive_id_id),
+ "];");
+ });
+ }
+ else
+ {
+ entry_func.fixup_hooks_in.push_back(
+ [=]()
+ {
+ statement("const device ", to_name(ir.default_entry_point), "_", ib_var_ref, "* gl_in = &",
+ input_buffer_var_name, "[", to_expression(builtin_primitive_id_id), " * ",
+ get_entry_point().output_vertices, "];");
+ });
+ }
+ break;
+ default:
+ break;
}
break;
@@ -3902,29 +3959,33 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
for (auto *p_var : vars)
{
- bool strip_array =
- (get_execution_model() == ExecutionModelTessellationControl ||
- (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput)) &&
- !patch;
+ bool strip_array = (is_tesc_shader() || (is_tese_shader() && storage == StorageClassInput)) && !patch;
// Fixing up flattened stores in TESC is impossible since the memory is group shared either via
// device (not masked) or threadgroup (masked) storage classes and it's race condition city.
meta.strip_array = strip_array;
- meta.allow_local_declaration = !strip_array && !(get_execution_model() == ExecutionModelTessellationControl &&
- storage == StorageClassOutput);
+ meta.allow_local_declaration = !strip_array && !(is_tesc_shader() && storage == StorageClassOutput);
add_variable_to_interface_block(storage, ib_var_ref, ib_type, *p_var, meta);
}
- if (get_execution_model() == ExecutionModelTessellationControl && msl_options.multi_patch_workgroup &&
+ if (((is_tesc_shader() && msl_options.multi_patch_workgroup) ||
+ (is_tese_shader() && msl_options.raw_buffer_tese_input)) &&
storage == StorageClassInput)
{
- // For tessellation control inputs, add all outputs from the vertex shader to ensure
+ // For tessellation inputs, add all outputs from the previous stage to ensure
// the struct containing them is the correct size and layout.
for (auto &input : inputs_by_location)
{
if (location_inputs_in_use.count(input.first.location) != 0)
continue;
+ 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.
+ if (input.second.builtin == BuiltInTessLevelOuter || input.second.builtin == BuiltInTessLevelInner)
+ continue;
+
// Create a fake variable to put at the location.
uint32_t offset = ir.increase_bound_by(4);
uint32_t type_id = offset;
@@ -4007,7 +4068,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
type.vecsize = output.second.vecsize;
set<SPIRType>(type_id, type);
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader())
{
type.array.push_back(0);
type.array_size_literal.push_back(true);
@@ -4017,7 +4078,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
type.pointer = true;
type.pointer_depth++;
- type.parent_type = get_execution_model() == ExecutionModelTessellationControl ? array_type_id : type_id;
+ type.parent_type = is_tesc_shader() ? array_type_id : type_id;
type.storage = storage;
auto &ptr_type = set<SPIRType>(ptr_type_id, type);
ptr_type.self = type.parent_type;
@@ -4067,7 +4128,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
fix_up_interface_member_indices(storage, ib_type_id);
// For patch inputs, add one more member, holding the array of control point data.
- if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput && patch &&
+ if (is_tese_shader() && !msl_options.raw_buffer_tese_input && storage == StorageClassInput && patch &&
stage_in_var_id)
{
uint32_t pcp_type_id = ir.increase_bound_by(1);
@@ -4081,6 +4142,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
set_member_name(ib_type.self, mbr_idx, "gl_in");
}
+ if (storage == StorageClassInput)
+ set_decoration(ib_var_id, DecorationNonWritable);
+
return ib_var_id;
}
@@ -4092,7 +4156,7 @@ uint32_t CompilerMSL::add_interface_block_pointer(uint32_t ib_var_id, StorageCla
uint32_t ib_ptr_var_id;
uint32_t next_id = ir.increase_bound_by(3);
auto &ib_type = expression_type(ib_var_id);
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader() || (is_tese_shader() && msl_options.raw_buffer_tese_input))
{
// Tessellation control per-vertex I/O is presented as an array, so we must
// do the same with our struct here.
@@ -4101,10 +4165,12 @@ uint32_t CompilerMSL::add_interface_block_pointer(uint32_t ib_var_id, StorageCla
ib_ptr_type.parent_type = ib_ptr_type.type_alias = ib_type.self;
ib_ptr_type.pointer = true;
ib_ptr_type.pointer_depth++;
- ib_ptr_type.storage =
- storage == StorageClassInput ?
- (msl_options.multi_patch_workgroup ? StorageClassStorageBuffer : StorageClassWorkgroup) :
- StorageClassStorageBuffer;
+ ib_ptr_type.storage = storage == StorageClassInput ?
+ ((is_tesc_shader() && msl_options.multi_patch_workgroup) ||
+ (is_tese_shader() && msl_options.raw_buffer_tese_input) ?
+ StorageClassStorageBuffer :
+ StorageClassWorkgroup) :
+ StorageClassStorageBuffer;
ir.meta[ib_ptr_type_id] = ir.meta[ib_type.self];
// To ensure that get_variable_data_type() doesn't strip off the pointer,
// which we need, use another pointer.
@@ -4118,6 +4184,8 @@ uint32_t CompilerMSL::add_interface_block_pointer(uint32_t ib_var_id, StorageCla
ib_ptr_var_id = next_id;
set<SPIRVariable>(ib_ptr_var_id, ib_ptr_ptr_type_id, StorageClassFunction, 0);
set_name(ib_ptr_var_id, storage == StorageClassInput ? "gl_in" : "gl_out");
+ if (storage == StorageClassInput)
+ set_decoration(ib_ptr_var_id, DecorationNonWritable);
}
else
{
@@ -7330,7 +7398,7 @@ bool CompilerMSL::emit_tessellation_io_load(uint32_t result_type_id, uint32_t id
auto &result_type = get<SPIRType>(result_type_id);
if (ptr_type.storage != StorageClassInput && ptr_type.storage != StorageClassOutput)
return false;
- if (ptr_type.storage == StorageClassOutput && get_execution_model() == ExecutionModelTessellationEvaluation)
+ if (ptr_type.storage == StorageClassOutput && is_tese_shader())
return false;
if (has_decoration(ptr, DecorationPatch))
@@ -7652,21 +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 && get_execution_model() == ExecutionModelTessellationControl);
+ 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
@@ -7947,8 +8016,8 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
// Don't do this if the index is a constant 1, though. We need to drop stores
// to that one.
auto *m = ir.find_meta(var ? var->self : ID(0));
- if (get_execution_model() == ExecutionModelTessellationControl && var && m &&
- m->decoration.builtin_type == BuiltInTessLevelInner && get_entry_point().flags.get(ExecutionModeTriangles))
+ if (is_tesc_shader() && var && m && m->decoration.builtin_type == BuiltInTessLevelInner &&
+ is_tessellating_triangles())
{
auto *c = maybe_get<SPIRConstant>(ops[3]);
if (c && c->scalar() == 1)
@@ -7965,7 +8034,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
bool CompilerMSL::is_out_of_bounds_tessellation_level(uint32_t id_lhs)
{
- if (!get_entry_point().flags.get(ExecutionModeTriangles))
+ if (!is_tessellating_triangles())
return false;
// In SPIR-V, TessLevelInner always has two elements and TessLevelOuter always has
@@ -7975,7 +8044,7 @@ bool CompilerMSL::is_out_of_bounds_tessellation_level(uint32_t id_lhs)
// In Metal, however, only the first element of TessLevelInner and the first three
// of TessLevelOuter are accessible. This stems from how in Metal, the tessellation
// levels must be stored to a dedicated buffer in a particular format that depends
- // on the patch type. Therefore, in Triangles mode, any access to the second
+ // on the patch type. Therefore, in Triangles mode, any store to the second
// inner level or the fourth outer level must be dropped.
const auto *e = maybe_get<SPIRExpression>(id_lhs);
if (!e || !e->access_chain)
@@ -8017,8 +8086,7 @@ bool CompilerMSL::access_chain_needs_stage_io_builtin_translation(uint32_t base)
// Avoid overriding it back to just gl_ClipDistance.
// This can only happen in scenarios where we cannot flatten/unflatten access chains, so, the only case
// where this triggers is evaluation shader inputs.
- bool redirect_builtin = get_execution_model() == ExecutionModelTessellationEvaluation ?
- var->storage == StorageClassOutput : false;
+ bool redirect_builtin = is_tese_shader() ? var->storage == StorageClassOutput : false;
return redirect_builtin;
}
@@ -9127,7 +9195,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i, bool sparse)
void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem)
{
- if (get_execution_model() != ExecutionModelGLCompute && get_execution_model() != ExecutionModelTessellationControl)
+ if (get_execution_model() != ExecutionModelGLCompute && !is_tesc_shader())
return;
uint32_t exe_scope = id_exe_scope ? evaluate_constant_u32(id_exe_scope) : uint32_t(ScopeInvocation);
@@ -9154,13 +9222,12 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin
string mem_flags = "";
// For tesc shaders, this also affects objects in the Output storage class.
// Since in Metal, these are placed in a device buffer, we have to sync device memory here.
- if (get_execution_model() == ExecutionModelTessellationControl ||
+ if (is_tesc_shader() ||
(mem_sem & (MemorySemanticsUniformMemoryMask | MemorySemanticsCrossWorkgroupMemoryMask)))
mem_flags += "mem_flags::mem_device";
// Fix tessellation patch function processing
- if (get_execution_model() == ExecutionModelTessellationControl ||
- (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask)))
+ if (is_tesc_shader() || (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask)))
{
if (!mem_flags.empty())
mem_flags += " | ";
@@ -9338,7 +9405,7 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r
uint32_t CompilerMSL::get_physical_tess_level_array_size(spv::BuiltIn builtin) const
{
- if (get_execution_mode_bitset().get(ExecutionModeTriangles))
+ if (is_tessellating_triangles())
return builtin == BuiltInTessLevelInner ? 1 : 3;
else
return builtin == BuiltInTessLevelInner ? 2 : 4;
@@ -9372,8 +9439,7 @@ bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs)
return true;
}
- if (get_execution_model() == ExecutionModelTessellationControl &&
- has_decoration(id_lhs, DecorationBuiltIn))
+ if (is_tesc_shader() && has_decoration(id_lhs, DecorationBuiltIn))
{
auto builtin = BuiltIn(get_decoration(id_lhs, DecorationBuiltIn));
// Need to manually unroll the array store.
@@ -11411,8 +11477,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
}
// Vertex and tessellation evaluation function outputs
- if (((execution.model == ExecutionModelVertex && !msl_options.vertex_for_tessellation) ||
- execution.model == ExecutionModelTessellationEvaluation) &&
+ if (((execution.model == ExecutionModelVertex && !msl_options.vertex_for_tessellation) || is_tese_shader()) &&
type.storage == StorageClassOutput)
{
if (is_builtin)
@@ -11466,7 +11531,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
}
// Tessellation control function inputs
- if (execution.model == ExecutionModelTessellationControl && type.storage == StorageClassInput)
+ if (is_tesc_shader() && type.storage == StorageClassInput)
{
if (is_builtin)
{
@@ -11503,7 +11568,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
}
// Tessellation control function outputs
- if (execution.model == ExecutionModelTessellationControl && type.storage == StorageClassOutput)
+ if (is_tesc_shader() && type.storage == StorageClassOutput)
{
// For this type of shader, we always arrange for it to capture its
// output to a buffer. For this reason, qualifiers are irrelevant here.
@@ -11514,7 +11579,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
}
// Tessellation evaluation function inputs
- if (execution.model == ExecutionModelTessellationEvaluation && type.storage == StorageClassInput)
+ if (is_tese_shader() && type.storage == StorageClassInput)
{
if (is_builtin)
{
@@ -11530,6 +11595,10 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
break;
}
}
+
+ if (msl_options.raw_buffer_tese_input)
+ return "";
+
// The special control point array must not be marked with an attribute.
if (get_type(type.member_types[index]).basetype == SPIRType::ControlPointArray)
return "";
@@ -11787,7 +11856,7 @@ uint32_t CompilerMSL::get_or_allocate_builtin_input_member_location(spv::BuiltIn
// Triangle tess level inputs are shared in one packed float4,
// mark both builtins as sharing one location.
- if (get_execution_mode_bitset().get(ExecutionModeTriangles) &&
+ if (!msl_options.raw_buffer_tese_input && is_tessellating_triangles() &&
(builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter))
{
builtin_to_automatic_input_location[BuiltInTessLevelInner] = loc;
@@ -11831,8 +11900,7 @@ uint32_t CompilerMSL::get_or_allocate_builtin_output_member_location(spv::BuiltI
// Triangle tess level inputs are shared in one packed float4;
// mark both builtins as sharing one location.
- if (get_execution_mode_bitset().get(ExecutionModeTriangles) &&
- (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter))
+ if (is_tessellating_triangles() && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter))
{
builtin_to_automatic_output_location[BuiltInTessLevelInner] = loc;
builtin_to_automatic_output_location[BuiltInTessLevelOuter] = loc;
@@ -11874,10 +11942,9 @@ string CompilerMSL::func_type_decl(SPIRType &type)
if (execution.flags.get(ExecutionModeIsolines))
SPIRV_CROSS_THROW("Metal does not support isoline tessellation.");
if (msl_options.is_ios())
- entry_type =
- join("[[ patch(", execution.flags.get(ExecutionModeTriangles) ? "triangle" : "quad", ") ]] vertex");
+ entry_type = join("[[ patch(", is_tessellating_triangles() ? "triangle" : "quad", ") ]] vertex");
else
- entry_type = join("[[ patch(", execution.flags.get(ExecutionModeTriangles) ? "triangle" : "quad", ", ",
+ entry_type = join("[[ patch(", is_tessellating_triangles() ? "triangle" : "quad", ", ",
execution.output_vertices, ") ]] vertex");
break;
case ExecutionModelFragment:
@@ -11901,6 +11968,16 @@ string CompilerMSL::func_type_decl(SPIRType &type)
return entry_type + " " + return_type;
}
+bool CompilerMSL::is_tesc_shader() const
+{
+ return get_execution_model() == ExecutionModelTessellationControl;
+}
+
+bool CompilerMSL::is_tese_shader() const
+{
+ return get_execution_model() == ExecutionModelTessellationEvaluation;
+}
+
bool CompilerMSL::uses_explicit_early_fragment_test()
{
auto &ep_flags = get_entry_point().flags;
@@ -11972,9 +12049,20 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo
break;
case StorageClassInput:
- if (get_execution_model() == ExecutionModelTessellationControl && var &&
- var->basevariable == stage_in_ptr_var_id)
- addr_space = msl_options.multi_patch_workgroup ? "constant" : "threadgroup";
+ if (is_tesc_shader() && var && var->basevariable == stage_in_ptr_var_id)
+ addr_space = msl_options.multi_patch_workgroup ? "const device" : "threadgroup";
+ // Don't pass tessellation levels in the device AS; we load and convert them
+ // to float manually.
+ 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);
+ 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);
+ if (is_stage_in || (is_patch_stage_in && !is_tess_level))
+ addr_space = "const device";
+ }
if (get_execution_model() == ExecutionModelFragment && var && var->basevariable == stage_in_var_id)
addr_space = "thread";
break;
@@ -12039,12 +12127,13 @@ string CompilerMSL::entry_point_arg_stage_in()
{
string decl;
- if (get_execution_model() == ExecutionModelTessellationControl && msl_options.multi_patch_workgroup)
+ if ((is_tesc_shader() && msl_options.multi_patch_workgroup) ||
+ (is_tese_shader() && msl_options.raw_buffer_tese_input))
return decl;
// Stage-in structure
uint32_t stage_in_id;
- if (get_execution_model() == ExecutionModelTessellationEvaluation)
+ if (is_tese_shader())
stage_in_id = patch_stage_in_var_id;
else
stage_in_id = stage_in_var_id;
@@ -12084,7 +12173,7 @@ bool CompilerMSL::is_direct_input_builtin(BuiltIn bi_type)
return false;
case BuiltInInvocationId:
case BuiltInPrimitiveId:
- return get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup;
+ return !is_tesc_shader() || !msl_options.multi_patch_workgroup;
// Tess. evaluation function in
case BuiltInTessLevelInner:
case BuiltInTessLevelOuter:
@@ -12239,7 +12328,7 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
" [[buffer(", msl_options.shader_output_buffer_index, ")]]");
}
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader())
{
if (!ep_args.empty())
ep_args += ", ";
@@ -12281,7 +12370,7 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
// a buffer to hold the per-patch data, a buffer to hold the per-patch
// tessellation levels, and a block of workgroup memory to hold the
// input control point data.
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader())
{
if (patch_stage_out_var_id)
{
@@ -12315,20 +12404,22 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
if (outer_factor_initializer_id && (c = maybe_get<SPIRConstant>(outer_factor_initializer_id)))
{
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
- entry_func.fixup_hooks_in.push_back([=]() {
- uint32_t components = get_execution_mode_bitset().get(ExecutionModeTriangles) ? 3 : 4;
- for (uint32_t i = 0; i < components; i++)
- {
- statement(builtin_to_glsl(BuiltInTessLevelOuter, StorageClassOutput), "[", i, "] = ",
- "half(", to_expression(c->subconstants[i]), ");");
- }
- });
+ entry_func.fixup_hooks_in.push_back(
+ [=]()
+ {
+ uint32_t components = is_tessellating_triangles() ? 3 : 4;
+ for (uint32_t i = 0; i < components; i++)
+ {
+ statement(builtin_to_glsl(BuiltInTessLevelOuter, StorageClassOutput), "[", i,
+ "] = ", "half(", to_expression(c->subconstants[i]), ");");
+ }
+ });
}
if (inner_factor_initializer_id && (c = maybe_get<SPIRConstant>(inner_factor_initializer_id)))
{
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
- if (get_execution_mode_bitset().get(ExecutionModeTriangles))
+ if (is_tessellating_triangles())
{
entry_func.fixup_hooks_in.push_back([=]() {
statement(builtin_to_glsl(BuiltInTessLevelInner, StorageClassOutput), " = ", "half(",
@@ -12364,6 +12455,36 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
}
}
}
+ // Tessellation evaluation shaders get three additional parameters:
+ // a buffer for the per-patch data, a buffer for the per-patch
+ // tessellation levels, and a buffer for the control point data.
+ if (is_tese_shader() && msl_options.raw_buffer_tese_input)
+ {
+ if (patch_stage_in_var_id)
+ {
+ if (!ep_args.empty())
+ ep_args += ", ";
+ ep_args +=
+ join("const device ", type_to_glsl(get_patch_stage_in_struct_type()), "* ", patch_input_buffer_var_name,
+ " [[buffer(", convert_to_string(msl_options.shader_patch_input_buffer_index), ")]]");
+ }
+
+ if (tess_level_inner_var_id || tess_level_outer_var_id)
+ {
+ if (!ep_args.empty())
+ ep_args += ", ";
+ ep_args += join("const device ", get_tess_factor_struct_name(), "* ", tess_factor_buffer_var_name,
+ " [[buffer(", convert_to_string(msl_options.shader_tess_factor_buffer_index), ")]]");
+ }
+
+ if (stage_in_var_id)
+ {
+ if (!ep_args.empty())
+ ep_args += ", ";
+ ep_args += join("const device ", type_to_glsl(get_stage_in_struct_type()), "* ", input_buffer_var_name,
+ " [[buffer(", convert_to_string(msl_options.shader_input_buffer_index), ")]]");
+ }
+ }
}
string CompilerMSL::entry_point_args_argument_buffer(bool append_comma)
@@ -12823,7 +12944,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
break;
case BuiltInInvocationId:
// This is direct-mapped without multi-patch workgroups.
- if (get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup)
+ if (!is_tesc_shader() || !msl_options.multi_patch_workgroup)
break;
entry_func.fixup_hooks_in.push_back([=]() {
@@ -12835,7 +12956,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
case BuiltInPrimitiveId:
// This is natively supported by fragment and tessellation evaluation shaders.
// In tessellation control shaders, this is direct-mapped without multi-patch workgroups.
- if (get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup)
+ if (!is_tesc_shader() || !msl_options.multi_patch_workgroup)
break;
entry_func.fixup_hooks_in.push_back([=]() {
@@ -12845,7 +12966,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
});
break;
case BuiltInPatchVertices:
- if (get_execution_model() == ExecutionModelTessellationEvaluation)
+ if (is_tese_shader())
entry_func.fixup_hooks_in.push_back([=]() {
statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ",
to_expression(patch_stage_in_var_id), ".gl_in.size();");
@@ -12868,7 +12989,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
// Emit a fixup to account for the shifted domain. Don't do this for triangles;
// MoltenVK will just reverse the winding order instead.
- if (msl_options.tess_domain_origin_lower_left && !get_entry_point().flags.get(ExecutionModeTriangles))
+ if (msl_options.tess_domain_origin_lower_left && !is_tessellating_triangles())
{
string tc = to_expression(var_id);
entry_func.fixup_hooks_in.push_back([=]() { statement(tc, ".y = 1.0 - ", tc, ".y;"); });
@@ -13598,7 +13719,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
}
// Special case, need to override the array size here if we're using tess level as an argument.
- if (get_execution_model() == ExecutionModelTessellationControl && builtin &&
+ if (is_tesc_shader() && builtin &&
(builtin_type == BuiltInTessLevelInner || builtin_type == BuiltInTessLevelOuter))
{
uint32_t array_size = get_physical_tess_level_array_size(builtin_type);
@@ -14355,23 +14476,25 @@ bool CompilerMSL::variable_decl_is_remapped_storage(const SPIRVariable &variable
if (storage == StorageClassWorkgroup)
{
- auto model = get_execution_model();
-
// Specially masked IO block variable.
// Normally, we will never access IO blocks directly here.
// The only scenario which that should occur is with a masked IO block.
- if (model == ExecutionModelTessellationControl && variable.storage == StorageClassOutput &&
+ if (is_tesc_shader() && variable.storage == StorageClassOutput &&
has_decoration(get<SPIRType>(variable.basetype).self, DecorationBlock))
{
return true;
}
- return variable.storage == StorageClassOutput &&
- model == ExecutionModelTessellationControl &&
- is_stage_output_variable_masked(variable);
+ return variable.storage == StorageClassOutput && is_tesc_shader() && is_stage_output_variable_masked(variable);
}
else if (storage == StorageClassStorageBuffer)
{
+ // These builtins are passed directly; we don't want to use remapping
+ // for them.
+ auto builtin = (BuiltIn)get_decoration(variable.self, DecorationBuiltIn);
+ if (is_tese_shader() && is_builtin_variable(variable) && (builtin == BuiltInTessCoord || builtin == BuiltInPrimitiveId))
+ return false;
+
// We won't be able to catch writes to control point outputs here since variable
// refers to a function local pointer.
// This is fine, as there cannot be concurrent writers to that memory anyways,
@@ -15091,7 +15214,7 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
case BuiltInClipDistance:
case BuiltInCullDistance:
case BuiltInLayer:
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader())
break;
if (storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point) &&
!is_stage_output_builtin_masked(builtin))
@@ -15123,8 +15246,8 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
break;
case BuiltInTessLevelOuter:
- if (get_execution_model() == ExecutionModelTessellationControl &&
- storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point))
+ if (is_tesc_shader() && storage != StorageClassInput && current_function &&
+ (current_function->self == ir.default_entry_point))
{
return join(tess_factor_buffer_var_name, "[", to_expression(builtin_primitive_id_id),
"].edgeTessellationFactor");
@@ -15132,8 +15255,8 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
break;
case BuiltInTessLevelInner:
- if (get_execution_model() == ExecutionModelTessellationControl &&
- storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point))
+ if (is_tesc_shader() && storage != StorageClassInput && current_function &&
+ (current_function->self == ir.default_entry_point))
{
return join(tess_factor_buffer_var_name, "[", to_expression(builtin_primitive_id_id),
"].insideTessellationFactor");
@@ -15376,7 +15499,6 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
// Returns an MSL string type declaration for a SPIR-V builtin
string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id)
{
- const SPIREntryPoint &execution = get_entry_point();
switch (builtin)
{
// Vertex function in
@@ -15420,12 +15542,12 @@ string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id)
// Tess. control function out
case BuiltInTessLevelInner:
- if (execution.model == ExecutionModelTessellationEvaluation)
- return !execution.flags.get(ExecutionModeTriangles) ? "float2" : "float";
+ if (is_tese_shader())
+ return (msl_options.raw_buffer_tese_input || is_tessellating_triangles()) ? "float" : "float2";
return "half";
case BuiltInTessLevelOuter:
- if (execution.model == ExecutionModelTessellationEvaluation)
- return !execution.flags.get(ExecutionModeTriangles) ? "float4" : "float";
+ if (is_tese_shader())
+ return (msl_options.raw_buffer_tese_input || is_tessellating_triangles()) ? "float" : "float4";
return "half";
// Tess. evaluation function in
@@ -16397,7 +16519,7 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr,
case BuiltInTessLevelInner:
case BuiltInTessLevelOuter:
- if (get_execution_model() == ExecutionModelTessellationControl)
+ if (is_tesc_shader())
{
expected_type = SPIRType::Half;
expected_width = 16;
@@ -16427,7 +16549,7 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr,
wrap_expr += ", ";
}
- if (get_execution_mode_bitset().get(ExecutionModeTriangles))
+ if (is_tessellating_triangles())
wrap_expr += ", 0.0";
wrap_expr += " })";
diff --git a/spirv_msl.hpp b/spirv_msl.hpp
index a848f9b5..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.
@@ -306,6 +318,7 @@ public:
uint32_t dynamic_offsets_buffer_index = 23;
uint32_t shader_input_buffer_index = 22;
uint32_t shader_index_buffer_index = 21;
+ uint32_t shader_patch_input_buffer_index = 20;
uint32_t shader_input_wg_index = 0;
uint32_t device_index = 0;
uint32_t enable_frag_output_mask = 0xffffffff;
@@ -387,6 +400,11 @@ public:
// builtins are processed, but should result in more efficient usage of the GPU.
bool multi_patch_workgroup = false;
+ // Use storage buffers instead of vertex-style attributes for tessellation evaluation
+ // input. This may require conversion of inputs in the generated post-tessellation
+ // vertex shader, but allows the use of nested arrays.
+ bool raw_buffer_tese_input = false;
+
// If set, a vertex shader will be compiled as part of a tessellation pipeline.
// It will be translated as a compute kernel, so it can use the global invocation ID
// to index the output buffer.
@@ -820,6 +838,9 @@ protected:
std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type, uint32_t physical_type_id,
bool is_packed) override;
+ bool is_tesc_shader() const;
+ bool is_tese_shader() const;
+
void preprocess_op_codes();
void localize_global_variables();
void extract_global_variables_from_functions();
@@ -876,6 +897,7 @@ protected:
const std::string &var_chain_qual,
uint32_t &location, uint32_t &var_mbr_idx);
void add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var);
+ void add_tess_level_input(const std::string &base_ref, const std::string &mbr_name, SPIRVariable &var);
void fix_up_interface_member_indices(spv::StorageClass storage, uint32_t ib_type_id);
@@ -1063,6 +1085,8 @@ protected:
VariableID patch_stage_out_var_id = 0;
VariableID stage_in_ptr_var_id = 0;
VariableID stage_out_ptr_var_id = 0;
+ VariableID tess_level_inner_var_id = 0;
+ VariableID tess_level_outer_var_id = 0;
VariableID stage_out_masked_builtin_type_id = 0;
// Handle HLSL-style 0-based vertex/instance index.
@@ -1101,6 +1125,7 @@ protected:
std::string input_wg_var_name = "gl_in";
std::string input_buffer_var_name = "spvIn";
std::string output_buffer_var_name = "spvOut";
+ std::string patch_input_buffer_var_name = "spvPatchIn";
std::string patch_output_buffer_var_name = "spvPatchOut";
std::string tess_factor_buffer_var_name = "spvTessLevel";
std::string index_buffer_var_name = "spvIndices";
diff --git a/test_shaders.py b/test_shaders.py
index 537693f1..31ec70a0 100755
--- a/test_shaders.py
+++ b/test_shaders.py
@@ -321,6 +321,8 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths):
msl_args.append('1')
msl_args.append('any16')
msl_args.append('2')
+ if '.raw-tess-in.' in shader:
+ msl_args.append('--msl-raw-buffer-tese-input')
if '.for-tess.' in shader:
msl_args.append('--msl-vertex-for-tessellation')
if '.fixed-sample-mask.' in shader: