MSL: Support "raw" buffer input in tessellation evaluation shaders.
Using vertex-style stage input is complex, and it doesn't support nesting of structures or arrays. By using raw buffer input instead, we get this support "for free," and everything becomes much simpler. Arguably, this is the way I should've done this in the first place. Eventually, I'd like to make this the default, and then remove the option altogether. (And I still need to do that with `multi_patch_workgroup`...) Should help fix 66 tests in the Vulkan CTS, under the following trees: - `dEQP-VK.pipeline.*.interface_matching.*` - `dEQP-VK.tessellation.user_defined_io.*` - `dEQP-VK.clipping.user_defined.*`
This commit is contained in:
Родитель
f09ba27777
Коммит
a171087180
|
@ -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)
|
||||
|
|
14
main.cpp
14
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;
|
||||
|
@ -886,12 +887,15 @@ static void print_help_msl()
|
|||
"\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
|
||||
"or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader.\n"
|
||||
"\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\n"
|
||||
"\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 +1174,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;
|
||||
|
@ -1645,6 +1650,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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -690,6 +690,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;
|
||||
|
||||
|
|
436
spirv_msl.cpp
436
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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -3474,8 +3488,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 +3509,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 +3547,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 +3636,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 +3733,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 +3778,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 +3806,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 +3958,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 (input.second.patch != 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 +4067,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 +4077,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 +4127,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 +4141,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 +4155,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 +4164,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 +4183,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 +7397,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))
|
||||
|
@ -7662,8 +7729,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
|
|||
patch = has_decoration(ops[2], DecorationPatch) || is_patch_block(get_variable_data_type(*var));
|
||||
|
||||
// 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))
|
||||
|
@ -7947,8 +8013,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 +8031,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 +8041,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 +8083,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 +9192,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 +9219,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 +9402,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 +9436,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 +11474,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 +11528,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 +11565,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 +11576,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 +11592,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 +11853,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 +11897,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 +11939,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 +11965,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 +12046,21 @@ 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) ||
|
||||
is_patch_block(get_variable_data_type(get<SPIRVariable>(var->basevariable)));
|
||||
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 +12125,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 +12171,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 +12326,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 +12368,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 +12402,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 +12453,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 +12942,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 +12954,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 +12964,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 +12987,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 +13717,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 +14474,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 +15212,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 +15244,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 +15253,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 +15497,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 +15540,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 +16517,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 +16547,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 += " })";
|
||||
|
|
|
@ -306,6 +306,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 +388,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 +826,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 +885,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 +1073,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 +1113,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";
|
||||
|
|
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче