| /* |
| * Copyright 2023 Rive |
| */ |
| |
| // This header provides Metal-specific #defines and declarations that enable our shaders to be |
| // compiled on MSL and GLSL both. |
| |
| #define METAL |
| |
| // #define native metal types if their names are being rewritten. |
| #define _ARE_TOKEN_NAMES_PRESERVED |
| #ifndef $_ARE_TOKEN_NAMES_PRESERVED |
| #define half half |
| #define half2 half2 |
| #define half3 half3 |
| #define half4 half4 |
| #define short short |
| #define short2 short2 |
| #define short3 short3 |
| #define short4 short4 |
| #define ushort ushort |
| #define ushort2 ushort2 |
| #define ushort3 ushort3 |
| #define ushort4 ushort4 |
| #define float2 float2 |
| #define float3 float3 |
| #define packed_float3 packed_float3 |
| #define float4 float4 |
| #define bool2 bool2 |
| #define bool3 bool3 |
| #define bool4 bool4 |
| #define uint2 uint2 |
| #define uint3 uint3 |
| #define uint4 uint4 |
| #define int2 int2 |
| #define int3 int3 |
| #define int4 int4 |
| #define float4x2 float4x2 |
| #define ushort ushort |
| #define float2x2 float2x2 |
| #define half3x4 half3x4 |
| #endif |
| |
| #define make_half4 half4 |
| #define make_half3 half3 |
| #define make_half2 half2 |
| #define make_half half |
| |
| #define make_ushort ushort |
| |
| #define INLINE inline |
| |
| #define notEqual(A, B) ((A) != (B)) |
| #define lessThanEqual(A, B) ((A) <= (B)) |
| #define greaterThanEqual(A, B) ((A) >= (B)) |
| #define MUL(A, B) ((A) * (B)) |
| #define atan atan2 |
| #define inversesqrt rsqrt |
| |
| #define UNIFORM_BLOCK_BEGIN(N) \ |
| struct N \ |
| { |
| #define UNIFORM_BLOCK_END(N) \ |
| } \ |
| ; |
| |
| #define ATTR_BLOCK_BEGIN(N) \ |
| struct N \ |
| { |
| #define ATTR(IDX, TYPE, NAME) TYPE NAME |
| #define ATTR_BLOCK_END \ |
| } \ |
| ; |
| #define ATTR_UNPACK(ID, attrs, NAME, TYPE) TYPE NAME = attrs[ID].NAME |
| |
| #define VARYING_BLOCK_BEGIN(N) \ |
| struct N \ |
| { |
| #define VARYING(TYPE, NAME) TYPE NAME |
| #define FLAT [[flat]] |
| #define NO_PERSPECTIVE [[center_no_perspective]] |
| // No-persective interpolation appears to break the guarantee that a varying == "x" when all |
| // barycentric values also == "x". Using default (perspective-correct) interpolation is also faster |
| // than flat on M1. |
| #define @OPTIONALLY_FLAT |
| #define VARYING_BLOCK_END(_pos) \ |
| float4 _pos [[position]]; \ |
| } \ |
| ; |
| |
| #define VARYING_INIT(varyings, NAME, TYPE) thread TYPE& NAME = varyings.NAME |
| #define VARYING_PACK(varyings, NAME) |
| #define VARYING_UNPACK(varyings, NAME, TYPE) TYPE NAME = varyings.NAME |
| |
| #define VERTEX_TEXTURE_BLOCK_BEGIN(N) \ |
| struct N \ |
| { |
| #define VERTEX_TEXTURE_BLOCK_END \ |
| } \ |
| ; |
| |
| #define FRAG_TEXTURE_BLOCK_BEGIN(N) \ |
| struct N \ |
| { |
| #define FRAG_TEXTURE_BLOCK_END \ |
| } \ |
| ; |
| |
| #define TEXTURE_RGBA32UI(IDX, NAME) [[texture(IDX)]] texture2d<uint> NAME |
| #define TEXTURE_RGBA32F(IDX, NAME) [[texture(IDX)]] texture2d<float> NAME |
| #define TEXTURE_RGBA8(IDX, NAME) [[texture(IDX)]] texture2d<half> NAME |
| |
| #define TEXEL_FETCH(TEXTURE_BLOCK, NAME, COORD) TEXTURE_BLOCK.NAME.read(uint2(COORD)) |
| #define GRADIENT_SAMPLER_DECL(IDX, NAME) |
| #define TEXTURE_SAMPLE(TEXTURE_BLOCK, NAME, SAMPLER_NAME, COORD) \ |
| TEXTURE_BLOCK.NAME.sample(sampler(mag_filter::linear, min_filter::linear), COORD) |
| |
| #define PLS_BLOCK_BEGIN \ |
| struct PLS \ |
| { |
| #define PLS_DECL4F(IDX, NAME) [[color(IDX)]] half4 NAME |
| #define PLS_DECL2F(IDX, NAME) [[color(IDX)]] half2 NAME |
| #define PLS_BLOCK_END \ |
| } \ |
| ; |
| |
| #define PLS_LOAD4F(P) _inpls.P |
| #define PLS_LOAD2F(P) _inpls.P |
| #define PLS_STORE4F(P, V) _pls.P = (V) |
| #define PLS_STORE2F(P, X, Y) _pls.P = half2(X, Y) |
| #define PLS_PRESERVE_VALUE(P) _pls.P = _inpls.P |
| #define PLS_INTERLOCK_BEGIN |
| #define PLS_INTERLOCK_END |
| |
| #define VERTEX_MAIN(NAME, \ |
| Uniforms, \ |
| uniforms, \ |
| Attrs, \ |
| attrs, \ |
| Varyings, \ |
| varyings, \ |
| VertexTextures, \ |
| textures, \ |
| _vertexID, \ |
| _instanceID, \ |
| _pos) \ |
| __attribute__((visibility("default"))) Varyings vertex NAME( \ |
| uint _vertexID [[vertex_id]], \ |
| uint _instanceID [[instance_id]], \ |
| constant Uniforms& uniforms [[buffer(0)]], \ |
| constant Attrs* attrs [[buffer(1)]], \ |
| VertexTextures textures) \ |
| { \ |
| Varyings varyings; \ |
| float4 _pos; |
| |
| #define EMIT_VERTEX(varyings, _pos) \ |
| } \ |
| varyings._pos = _pos; \ |
| return varyings; |
| |
| #define EMIT_OFFSCREEN_VERTEX(varyings, _pos) \ |
| varyings._pos.xzw = _pos.xzw; \ |
| varyings._pos.y = -_pos.y; \ |
| return varyings; \ |
| } |
| |
| #define FRAG_DATA_MAIN(DATA_TYPE, NAME, Varyings, varyings) \ |
| DATA_TYPE __attribute__((visibility("default"))) fragment NAME(Varyings varyings [[stage_in]]) \ |
| { |
| |
| #define EMIT_FRAG_DATA(VALUE) \ |
| return VALUE; \ |
| } |
| |
| #define PLS_MAIN(NAME, Varyings, varyings, FragmentTextures, textures, _pos, _clockwise) \ |
| __attribute__((visibility("default"))) PLS fragment NAME(PLS _inpls, \ |
| Varyings varyings [[stage_in]], \ |
| bool _clockwise [[front_facing]], \ |
| FragmentTextures textures) \ |
| { \ |
| PLS _pls; |
| |
| #define EMIT_PLS \ |
| } \ |
| return _pls; |
| |
| using namespace metal; |
| |
| template <int N> inline vec<uint, N> floatBitsToUint(vec<float, N> x) |
| { |
| return as_type<vec<uint, N>>(x); |
| } |
| |
| template <int N> inline vec<int, N> floatBitsToInt(vec<float, N> x) |
| { |
| return as_type<vec<int, N>>(x); |
| } |
| |
| inline uint floatBitsToUint(float x) { return as_type<uint>(x); } |
| |
| inline int floatBitsToInt(float x) { return as_type<int>(x); } |
| |
| template <int N> inline vec<float, N> uintBitsToFloat(vec<uint, N> x) |
| { |
| return as_type<vec<float, N>>(x); |
| } |
| |
| inline float uintBitsToFloat(uint x) { return as_type<float>(x); } |
| inline half2 unpackHalf2x16(uint x) { return as_type<half2>(x); } |
| inline uint packHalf2x16(half2 x) { return as_type<uint>(x); } |
| |
| inline float2x2 inverse(float2x2 m) |
| { |
| float2x2 m_ = float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]); |
| float det = (m_[0][0] * m[0][0]) + (m_[0][1] * m[1][0]); |
| return m_ * (1 / det); |
| } |
| |
| inline half3 mix(half3 a, half3 b, bool3 c) |
| { |
| half3 result; |
| for (int i = 0; i < 3; ++i) |
| result[i] = c[i] ? b[i] : a[i]; |
| return result; |
| } |
| |
| inline half3x4 make_half3x4(half3 a, half b, half3 c, half d, half3 e, half f) |
| { |
| return half3x4(a.x, a.y, a.z, b, c.x, c.y, c.z, d, e.x, e.y, e.z, f); |
| } |