1#pragma clang diagnostic ignored "-Wmissing-prototypes"
2
3#include <metal_stdlib>
4#include <simd/simd.h>
5
6using namespace metal;
7
8// Returns 2D texture coords corresponding to 1D texel buffer coords
9static inline __attribute__((always_inline))
10uint2 spvTexelBufferCoord(uint tc)
11{
12    return uint2(tc % 4096, tc / 4096);
13}
14
15template<typename T> struct spvRemoveReference { typedef T type; };
16template<typename T> struct spvRemoveReference<thread T&> { typedef T type; };
17template<typename T> struct spvRemoveReference<thread T&&> { typedef T type; };
18template<typename T> inline constexpr thread T&& spvForward(thread typename spvRemoveReference<T>::type& x)
19{
20    return static_cast<thread T&&>(x);
21}
22template<typename T> inline constexpr thread T&& spvForward(thread typename spvRemoveReference<T>::type&& x)
23{
24    return static_cast<thread T&&>(x);
25}
26
27enum class spvSwizzle : uint
28{
29    none = 0,
30    zero,
31    one,
32    red,
33    green,
34    blue,
35    alpha
36};
37
38template<typename T>
39inline T spvGetSwizzle(vec<T, 4> x, T c, spvSwizzle s)
40{
41    switch (s)
42    {
43        case spvSwizzle::none:
44            return c;
45        case spvSwizzle::zero:
46            return 0;
47        case spvSwizzle::one:
48            return 1;
49        case spvSwizzle::red:
50            return x.r;
51        case spvSwizzle::green:
52            return x.g;
53        case spvSwizzle::blue:
54            return x.b;
55        case spvSwizzle::alpha:
56            return x.a;
57    }
58}
59
60// Wrapper function that swizzles texture samples and fetches.
61template<typename T>
62inline vec<T, 4> spvTextureSwizzle(vec<T, 4> x, uint s)
63{
64    if (!s)
65        return x;
66    return vec<T, 4>(spvGetSwizzle(x, x.r, spvSwizzle((s >> 0) & 0xFF)), spvGetSwizzle(x, x.g, spvSwizzle((s >> 8) & 0xFF)), spvGetSwizzle(x, x.b, spvSwizzle((s >> 16) & 0xFF)), spvGetSwizzle(x, x.a, spvSwizzle((s >> 24) & 0xFF)));
67}
68
69template<typename T>
70inline T spvTextureSwizzle(T x, uint s)
71{
72    return spvTextureSwizzle(vec<T, 4>(x, 0, 0, 1), s).x;
73}
74
75// Wrapper function that swizzles texture gathers.
76template<typename T, template<typename, access = access::sample, typename = void> class Tex, typename... Ts>
77inline vec<T, 4> spvGatherSwizzle(const thread Tex<T>& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c)
78{
79    if (sw)
80    {
81        switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF))
82        {
83            case spvSwizzle::none:
84                break;
85            case spvSwizzle::zero:
86                return vec<T, 4>(0, 0, 0, 0);
87            case spvSwizzle::one:
88                return vec<T, 4>(1, 1, 1, 1);
89            case spvSwizzle::red:
90                return t.gather(s, spvForward<Ts>(params)..., component::x);
91            case spvSwizzle::green:
92                return t.gather(s, spvForward<Ts>(params)..., component::y);
93            case spvSwizzle::blue:
94                return t.gather(s, spvForward<Ts>(params)..., component::z);
95            case spvSwizzle::alpha:
96                return t.gather(s, spvForward<Ts>(params)..., component::w);
97        }
98    }
99    switch (c)
100    {
101        case component::x:
102            return t.gather(s, spvForward<Ts>(params)..., component::x);
103        case component::y:
104            return t.gather(s, spvForward<Ts>(params)..., component::y);
105        case component::z:
106            return t.gather(s, spvForward<Ts>(params)..., component::z);
107        case component::w:
108            return t.gather(s, spvForward<Ts>(params)..., component::w);
109    }
110}
111
112// Wrapper function that swizzles depth texture gathers.
113template<typename T, template<typename, access = access::sample, typename = void> class Tex, typename... Ts>
114inline vec<T, 4> spvGatherCompareSwizzle(const thread Tex<T>& t, sampler s, uint sw, Ts... params) 
115{
116    if (sw)
117    {
118        switch (spvSwizzle(sw & 0xFF))
119        {
120            case spvSwizzle::none:
121            case spvSwizzle::red:
122                break;
123            case spvSwizzle::zero:
124            case spvSwizzle::green:
125            case spvSwizzle::blue:
126            case spvSwizzle::alpha:
127                return vec<T, 4>(0, 0, 0, 0);
128            case spvSwizzle::one:
129                return vec<T, 4>(1, 1, 1, 1);
130        }
131    }
132    return t.gather_compare(s, spvForward<Ts>(params)...);
133}
134
135static inline __attribute__((always_inline))
136float4 doSwizzle(thread texture1d<float> tex1d, thread const sampler tex1dSmplr, constant uint& tex1dSwzl, thread texture2d<float> tex2d, thread const sampler tex2dSmplr, constant uint& tex2dSwzl, thread texture3d<float> tex3d, thread const sampler tex3dSmplr, constant uint& tex3dSwzl, thread texturecube<float> texCube, thread const sampler texCubeSmplr, constant uint& texCubeSwzl, thread texture2d_array<float> tex2dArray, thread const sampler tex2dArraySmplr, constant uint& tex2dArraySwzl, thread texturecube_array<float> texCubeArray, thread const sampler texCubeArraySmplr, constant uint& texCubeArraySwzl, thread depth2d<float> depth2d, thread const sampler depth2dSmplr, constant uint& depth2dSwzl, thread depthcube<float> depthCube, thread const sampler depthCubeSmplr, constant uint& depthCubeSwzl, thread depth2d_array<float> depth2dArray, thread const sampler depth2dArraySmplr, constant uint& depth2dArraySwzl, thread depthcube_array<float> depthCubeArray, thread const sampler depthCubeArraySmplr, constant uint& depthCubeArraySwzl, thread texture2d<float> texBuffer)
137{
138    float4 c = spvTextureSwizzle(tex1d.sample(tex1dSmplr, 0.0), tex1dSwzl);
139    c = spvTextureSwizzle(tex2d.sample(tex2dSmplr, float2(0.0)), tex2dSwzl);
140    c = spvTextureSwizzle(tex3d.sample(tex3dSmplr, float3(0.0)), tex3dSwzl);
141    c = spvTextureSwizzle(texCube.sample(texCubeSmplr, float3(0.0)), texCubeSwzl);
142    c = spvTextureSwizzle(tex2dArray.sample(tex2dArraySmplr, float3(0.0).xy, uint(round(float3(0.0).z))), tex2dArraySwzl);
143    c = spvTextureSwizzle(texCubeArray.sample(texCubeArraySmplr, float4(0.0).xyz, uint(round(float4(0.0).w))), texCubeArraySwzl);
144    c.x = spvTextureSwizzle(depth2d.sample_compare(depth2dSmplr, float3(0.0, 0.0, 1.0).xy, 1.0), depth2dSwzl);
145    c.x = spvTextureSwizzle(depthCube.sample_compare(depthCubeSmplr, float4(0.0, 0.0, 0.0, 1.0).xyz, 1.0), depthCubeSwzl);
146    c.x = spvTextureSwizzle(depth2dArray.sample_compare(depth2dArraySmplr, float4(0.0, 0.0, 0.0, 1.0).xy, uint(round(float4(0.0, 0.0, 0.0, 1.0).z)), 1.0), depth2dArraySwzl);
147    c.x = spvTextureSwizzle(depthCubeArray.sample_compare(depthCubeArraySmplr, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0), depthCubeArraySwzl);
148    c = spvTextureSwizzle(tex1d.sample(tex1dSmplr, float2(0.0, 1.0).x / float2(0.0, 1.0).y), tex1dSwzl);
149    c = spvTextureSwizzle(tex2d.sample(tex2dSmplr, float3(0.0, 0.0, 1.0).xy / float3(0.0, 0.0, 1.0).z), tex2dSwzl);
150    c = spvTextureSwizzle(tex3d.sample(tex3dSmplr, float4(0.0, 0.0, 0.0, 1.0).xyz / float4(0.0, 0.0, 0.0, 1.0).w), tex3dSwzl);
151    float4 _103 = float4(0.0, 0.0, 1.0, 1.0);
152    _103.z = 1.0;
153    c.x = spvTextureSwizzle(depth2d.sample_compare(depth2dSmplr, _103.xy / _103.z, 1.0 / _103.z), depth2dSwzl);
154    c = spvTextureSwizzle(tex1d.sample(tex1dSmplr, 0.0), tex1dSwzl);
155    c = spvTextureSwizzle(tex2d.sample(tex2dSmplr, float2(0.0), level(0.0)), tex2dSwzl);
156    c = spvTextureSwizzle(tex3d.sample(tex3dSmplr, float3(0.0), level(0.0)), tex3dSwzl);
157    c = spvTextureSwizzle(texCube.sample(texCubeSmplr, float3(0.0), level(0.0)), texCubeSwzl);
158    c = spvTextureSwizzle(tex2dArray.sample(tex2dArraySmplr, float3(0.0).xy, uint(round(float3(0.0).z)), level(0.0)), tex2dArraySwzl);
159    c = spvTextureSwizzle(texCubeArray.sample(texCubeArraySmplr, float4(0.0).xyz, uint(round(float4(0.0).w)), level(0.0)), texCubeArraySwzl);
160    c.x = spvTextureSwizzle(depth2d.sample_compare(depth2dSmplr, float3(0.0, 0.0, 1.0).xy, 1.0, level(0.0)), depth2dSwzl);
161    c = spvTextureSwizzle(tex1d.sample(tex1dSmplr, float2(0.0, 1.0).x / float2(0.0, 1.0).y), tex1dSwzl);
162    c = spvTextureSwizzle(tex2d.sample(tex2dSmplr, float3(0.0, 0.0, 1.0).xy / float3(0.0, 0.0, 1.0).z, level(0.0)), tex2dSwzl);
163    c = spvTextureSwizzle(tex3d.sample(tex3dSmplr, float4(0.0, 0.0, 0.0, 1.0).xyz / float4(0.0, 0.0, 0.0, 1.0).w, level(0.0)), tex3dSwzl);
164    float4 _131 = float4(0.0, 0.0, 1.0, 1.0);
165    _131.z = 1.0;
166    c.x = spvTextureSwizzle(depth2d.sample_compare(depth2dSmplr, _131.xy / _131.z, 1.0 / _131.z, level(0.0)), depth2dSwzl);
167    c = spvTextureSwizzle(tex1d.read(uint(0)), tex1dSwzl);
168    c = spvTextureSwizzle(tex2d.read(uint2(int2(0)), 0), tex2dSwzl);
169    c = spvTextureSwizzle(tex3d.read(uint3(int3(0)), 0), tex3dSwzl);
170    c = spvTextureSwizzle(tex2dArray.read(uint2(int3(0).xy), uint(int3(0).z), 0), tex2dArraySwzl);
171    c = texBuffer.read(spvTexelBufferCoord(0));
172    c = spvGatherSwizzle(tex2d, tex2dSmplr, tex2dSwzl, component::x, float2(0.0), int2(0));
173    c = spvGatherSwizzle(texCube, texCubeSmplr, texCubeSwzl, component::y, float3(0.0));
174    c = spvGatherSwizzle(tex2dArray, tex2dArraySmplr, tex2dArraySwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0));
175    c = spvGatherSwizzle(texCubeArray, texCubeArraySmplr, texCubeArraySwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w)));
176    c = spvGatherCompareSwizzle(depth2d, depth2dSmplr, depth2dSwzl, float2(0.0), 1.0);
177    c = spvGatherCompareSwizzle(depthCube, depthCubeSmplr, depthCubeSwzl, float3(0.0), 1.0);
178    c = spvGatherCompareSwizzle(depth2dArray, depth2dArraySmplr, depth2dArraySwzl, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0);
179    c = spvGatherCompareSwizzle(depthCubeArray, depthCubeArraySmplr, depthCubeArraySwzl, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0);
180    return c;
181}
182
183fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], depth2d<float> depth2d [[texture(6)]], depthcube<float> depthCube [[texture(7)]], depth2d_array<float> depth2dArray [[texture(8)]], depthcube_array<float> depthCubeArray [[texture(9)]], texture2d<float> texBuffer [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(6)]], sampler depthCubeSmplr [[sampler(7)]], sampler depth2dArraySmplr [[sampler(8)]], sampler depthCubeArraySmplr [[sampler(9)]])
184{
185    constant uint& tex1dSwzl = spvSwizzleConstants[0];
186    constant uint& tex2dSwzl = spvSwizzleConstants[1];
187    constant uint& tex3dSwzl = spvSwizzleConstants[2];
188    constant uint& texCubeSwzl = spvSwizzleConstants[3];
189    constant uint& tex2dArraySwzl = spvSwizzleConstants[4];
190    constant uint& texCubeArraySwzl = spvSwizzleConstants[5];
191    constant uint& depth2dSwzl = spvSwizzleConstants[6];
192    constant uint& depthCubeSwzl = spvSwizzleConstants[7];
193    constant uint& depth2dArraySwzl = spvSwizzleConstants[8];
194    constant uint& depthCubeArraySwzl = spvSwizzleConstants[9];
195    float4 c = doSwizzle(tex1d, tex1dSmplr, tex1dSwzl, tex2d, tex2dSmplr, tex2dSwzl, tex3d, tex3dSmplr, tex3dSwzl, texCube, texCubeSmplr, texCubeSwzl, tex2dArray, tex2dArraySmplr, tex2dArraySwzl, texCubeArray, texCubeArraySmplr, texCubeArraySwzl, depth2d, depth2dSmplr, depth2dSwzl, depthCube, depthCubeSmplr, depthCubeSwzl, depth2dArray, depth2dArraySmplr, depth2dArraySwzl, depthCubeArray, depthCubeArraySmplr, depthCubeArraySwzl, texBuffer);
196}
197
198