/* SPDX-FileCopyrightText: 2024 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * GLSL to C++ stubs. * * The goal of this header is to make the GLSL source file compile using a modern C++ compiler. * This allows for linting and IDE functionalities to work. * * This file can be included inside any GLSL file to make the GLSL syntax to work. * Then your IDE must to be configured to associate `.glsl` files to C++ so that the * C++ linter does the analysis. * * This is why the implementation of each function is not needed. However, we make sure that type * casting is always explicit. This is because implicit casts are not always supported on all * implementations. * * Float types are set to double to accept float literals without trailing f and avoid casting * issues. * * Some of the features of GLSL are omitted by design. They are either: * - Not needed (e.g. per component matrix multiplication). * - Against our code-style (e.g. `stpq` swizzle). * - Unsupported by our Metal Shading Language layer (e.g. mixed vector-scalar matrix constructor). * * IMPORTANT: Please ask the module team if you need some feature that are not listed in this file. */ #pragma once #include #define assert(assertion) #define printf(...) /* Some compilers complain about lack of return values. Keep it short. */ #define RET \ { \ return {}; \ } /* -------------------------------------------------------------------- */ /** \name Vector Types * \{ */ template struct VecBase {}; template struct VecOp { using VecT = VecBase; const T &operator[](int) const { return *reinterpret_cast(this); } T &operator[](int) { return *reinterpret_cast(this); } #define STD_OP \ template> * = nullptr> STD_OP VecT operator+() const RET; STD_OP VecT operator-() const RET; STD_OP friend VecT operator+(VecT, VecT) RET; STD_OP friend VecT operator-(VecT, VecT) RET; STD_OP friend VecT operator/(VecT, VecT) RET; STD_OP friend VecT operator*(VecT, VecT) RET; STD_OP friend VecT operator+(VecT, T) RET; STD_OP friend VecT operator-(VecT, T) RET; STD_OP friend VecT operator/(VecT, T) RET; STD_OP friend VecT operator*(VecT, T) RET; STD_OP friend VecT operator+(T, VecT) RET; STD_OP friend VecT operator-(T, VecT) RET; STD_OP friend VecT operator/(T, VecT) RET; STD_OP friend VecT operator*(T, VecT) RET; STD_OP friend VecT operator+=(VecT, VecT) RET; STD_OP friend VecT operator-=(VecT, VecT) RET; STD_OP friend VecT operator/=(VecT, VecT) RET; STD_OP friend VecT operator*=(VecT, VecT) RET; STD_OP friend VecT operator+=(VecT, T) RET; STD_OP friend VecT operator-=(VecT, T) RET; STD_OP friend VecT operator/=(VecT, T) RET; STD_OP friend VecT operator*=(VecT, T) RET; #define INT_OP \ template> * = nullptr, \ typename std::enable_if_t> * = nullptr> INT_OP friend VecT operator~(VecT) RET; INT_OP friend VecT operator%(VecT, VecT) RET; INT_OP friend VecT operator&(VecT, VecT) RET; INT_OP friend VecT operator|(VecT, VecT) RET; INT_OP friend VecT operator^(VecT, VecT) RET; INT_OP friend VecT operator%(VecT, T) RET; INT_OP friend VecT operator&(VecT, T) RET; INT_OP friend VecT operator|(VecT, T) RET; INT_OP friend VecT operator^(VecT, T) RET; INT_OP friend VecT operator%(T, VecT) RET; INT_OP friend VecT operator&(T, VecT) RET; INT_OP friend VecT operator|(T, VecT) RET; INT_OP friend VecT operator^(T, VecT) RET; INT_OP friend VecT operator%=(VecT, VecT) RET; INT_OP friend VecT operator&=(VecT, VecT) RET; INT_OP friend VecT operator|=(VecT, VecT) RET; INT_OP friend VecT operator^=(VecT, VecT) RET; INT_OP friend VecT operator%=(VecT, T) RET; INT_OP friend VecT operator&=(VecT, T) RET; INT_OP friend VecT operator|=(VecT, T) RET; INT_OP friend VecT operator^=(VecT, T) RET; INT_OP friend VecT operator<<(VecT, VecT) RET; INT_OP friend VecT operator>>(VecT, VecT) RET; INT_OP friend VecT operator<<=(VecT, VecT) RET; INT_OP friend VecT operator>>=(VecT, VecT) RET; INT_OP friend VecT operator<<(T, VecT) RET; INT_OP friend VecT operator>>(T, VecT) RET; INT_OP friend VecT operator<<=(T, VecT) RET; INT_OP friend VecT operator>>=(T, VecT) RET; INT_OP friend VecT operator<<(VecT, T) RET; INT_OP friend VecT operator>>(VecT, T) RET; INT_OP friend VecT operator<<=(VecT, T) RET; INT_OP friend VecT operator>>=(VecT, T) RET; #undef INT_OP }; template struct SwizzleBase : VecOp { using VecT = VecBase; constexpr VecT operator=(const VecT &) RET; operator VecT() const RET; }; #define SWIZZLE_XY(T) \ SwizzleBase xx, xy, yx, yy; \ SwizzleBase xxx, xxy, xyx, xyy, yxx, yxy, yyx, yyy; \ SwizzleBase xxxx, xxxy, xxyx, xxyy, xyxx, xyxy, xyyx, xyyy, yxxx, yxxy, yxyx, yxyy, yyxx, \ yyxy, yyyx, yyyy; #define SWIZZLE_RG(T) \ SwizzleBase rr, rg, gr, gg; \ SwizzleBase rrr, rrg, rgr, rgg, grr, grg, ggr, ggg; \ SwizzleBase rrrr, rrrg, rrgr, rrgg, rgrr, rgrg, rggr, rggg, grrr, grrg, grgr, grgg, ggrr, \ ggrg, gggr, gggg; #define SWIZZLE_XYZ(T) \ SWIZZLE_XY(T) \ SwizzleBase xz, yz, zx, zy, zz, zw; \ SwizzleBase xxz, xyz, xzx, xzy, xzz, yxz, yyz, yzx, yzy, yzz, zxx, zxy, zxz, zyx, zyy, \ zyz, zzx, zzy, zzz; \ SwizzleBase xxxz, xxyz, xxzx, xxzy, xxzz, xyxz, xyyz, xyzx, xyzy, xyzz, xzxx, xzxy, xzxz, \ xzyx, xzyy, xzyz, xzzx, xzzy, xzzz, yxxz, yxyz, yxzx, yxzy, yxzz, yyxz, yyyz, yyzx, yyzy, \ yyzz, yzxx, yzxy, yzxz, yzyx, yzyy, yzyz, yzzx, yzzy, yzzz, zxxx, zxxy, zxxz, zxyx, zxyy, \ zxyz, zxzx, zxzy, zxzz, zyxx, zyxy, zyxz, zyyx, zyyy, zyyz, zyzx, zyzy, zyzz, zzxx, zzxy, \ zzxz, zzyx, zzyy, zzyz, zzzx, zzzy, zzzz; #define SWIZZLE_RGB(T) \ SWIZZLE_RG(T) \ SwizzleBase rb, gb, br, bg, bb; \ SwizzleBase rrb, rgb, rbr, rbg, rbb, grb, ggb, gbr, gbg, gbb, brr, brg, brb, bgr, bgg, \ bgb, bbr, bbg, bbb; \ SwizzleBase rrrb, rrgb, rrbr, rrbg, rrbb, rgrb, rggb, rgbr, rgbg, rgbb, rbrr, rbrg, rbrb, \ rbgr, rbgg, rbgb, rbbr, rbbg, rbbb, grrb, grgb, grbr, grbg, grbb, ggrb, gggb, ggbr, ggbg, \ ggbb, gbrr, gbrg, gbrb, gbgr, gbgg, gbgb, gbbr, gbbg, gbbb, brrr, brrg, brrb, brgr, brgg, \ brgb, brbr, brbg, brbb, bgrr, bgrg, bgrb, bggr, bggg, bggb, bgbr, bgbg, bgbb, bbrr, bbrg, \ bbrb, bbgr, bbgg, bbgb, bbbr, bbbg, bbbb; #define SWIZZLE_XYZW(T) \ SWIZZLE_XYZ(T) \ SwizzleBase xw, yw, wx, wy, wz, ww; \ SwizzleBase xxw, xyw, xzw, xwx, xwy, xwz, xww, yxw, yyw, yzw, ywx, ywy, ywz, yww, zxw, \ zyw, zzw, zwx, zwy, zwz, zww, wxx, wxy, wxz, wxw, wyx, wyy, wyz, wyw, wzx, wzy, wzz, wzw, \ wwx, wwy, wwz, www; \ SwizzleBase xxxw, xxyw, xxzw, xxwx, xxwy, xxwz, xxww, xyxw, xyyw, xyzw, xywx, xywy, xywz, \ xyww, xzxw, xzyw, xzzw, xzwx, xzwy, xzwz, xzww, xwxx, xwxy, xwxz, xwxw, xwyx, xwyy, xwyz, \ xwyw, xwzx, xwzy, xwzz, xwzw, xwwx, xwwy, xwwz, xwww, yxxw, yxyw, yxzw, yxwx, yxwy, yxwz, \ yxww, yyxw, yyyw, yyzw, yywx, yywy, yywz, yyww, yzxw, yzyw, yzzw, yzwx, yzwy, yzwz, yzww, \ ywxx, ywxy, ywxz, ywxw, ywyx, ywyy, ywyz, ywyw, ywzx, ywzy, ywzz, ywzw, ywwx, ywwy, ywwz, \ ywww, zxxw, zxyw, zxzw, zxwx, zxwy, zxwz, zxww, zyxw, zyyw, zyzw, zywx, zywy, zywz, zyww, \ zzxw, zzyw, zzzw, zzwx, zzwy, zzwz, zzww, zwxx, zwxy, zwxz, zwxw, zwyx, zwyy, zwyz, zwyw, \ zwzx, zwzy, zwzz, zwzw, zwwx, zwwy, zwwz, zwww, wxxx, wxxy, wxxz, wxxw, wxyx, wxyy, wxyz, \ wxyw, wxzx, wxzy, wxzz, wxzw, wxwx, wxwy, wxwz, wxww, wyxx, wyxy, wyxz, wyxw, wyyx, wyyy, \ wyyz, wyyw, wyzx, wyzy, wyzz, wyzw, wywx, wywy, wywz, wyww, wzxx, wzxy, wzxz, wzxw, wzyx, \ wzyy, wzyz, wzyw, wzzx, wzzy, wzzz, wzzw, wzwx, wzwy, wzwz, wzww, wwxx, wwxy, wwxz, wwxw, \ wwyx, wwyy, wwyz, wwyw, wwzx, wwzy, wwzz, wwzw, wwwx, wwwy, wwwz, wwww; #define SWIZZLE_RGBA(T) \ SWIZZLE_RGB(T) \ SwizzleBase ra, ga, ba, ar, ag, ab, aa; \ SwizzleBase rra, rga, rba, rar, rag, rab, raa, gra, gga, gba, gar, gag, gab, gaa, bra, \ bga, bba, bar, bag, bab, baa, arr, arg, arb, ara, agr, agg, agb, aga, abr, abg, abb, aba, \ aar, aag, aab, aaa; \ SwizzleBase rrra, rrga, rrba, rrar, rrag, rrab, rraa, rgra, rgga, rgba, rgar, rgag, rgab, \ rgaa, rbra, rbga, rbba, rbar, rbag, rbab, rbaa, rarr, rarg, rarb, rara, ragr, ragg, ragb, \ raga, rabr, rabg, rabb, raba, raar, raag, raab, raaa, grra, grga, grba, grar, grag, grab, \ graa, ggra, ggga, ggba, ggar, ggag, ggab, ggaa, gbra, gbga, gbba, gbar, gbag, gbab, gbaa, \ garr, garg, garb, gara, gagr, gagg, gagb, gaga, gabr, gabg, gabb, gaba, gaar, gaag, gaab, \ gaaa, brra, brga, brba, brar, brag, brab, braa, bgra, bgga, bgba, bgar, bgag, bgab, bgaa, \ bbra, bbga, bbba, bbar, bbag, bbab, bbaa, barr, barg, barb, bara, bagr, bagg, bagb, baga, \ babr, babg, babb, baba, baar, baag, baab, baaa, arrr, arrg, arrb, arra, argr, argg, argb, \ arga, arbr, arbg, arbb, arba, arar, arag, arab, araa, agrr, agrg, agrb, agra, aggr, aggg, \ aggb, agga, agbr, agbg, agbb, agba, agar, agag, agab, agaa, abrr, abrg, abrb, abra, abgr, \ abgg, abgb, abga, abbr, abbg, abbb, abba, abar, abag, abab, abaa, aarr, aarg, aarb, aara, \ aagr, aagg, aagb, aaga, aabr, aabg, aabb, aaba, aaar, aaag, aaab, aaaa; template struct VecBase { VecBase() = default; template explicit VecBase(VecOp) {} VecBase(T) {} operator T() RET; }; template struct VecBase : VecOp { union { struct { T x, y; }; struct { T r, g; }; SWIZZLE_XY(T); SWIZZLE_RG(T); }; VecBase() = default; template explicit VecBase(VecOp) {} explicit VecBase(T) {} explicit VecBase(T, T) {} }; template struct VecBase : VecOp { union { struct { T x, y, z; }; struct { T r, g, b; }; SWIZZLE_XYZ(T); SWIZZLE_RGB(T); }; VecBase() = default; template explicit VecBase(VecOp) {} explicit VecBase(T) {} /* Implemented correctly for GCC to compile the constexpr gl_WorkGroupSize. */ constexpr explicit VecBase(T x_, T y_, T z_) : x(x_), y(y_), z(z_) {} explicit VecBase(VecOp, T) {} explicit VecBase(T, VecOp) {} }; template struct VecBase : VecOp { union { struct { T x, y, z, w; }; struct { T r, g, b, a; }; SWIZZLE_XYZW(T); SWIZZLE_RGBA(T); }; VecBase() = default; template explicit VecBase(VecOp) {} explicit VecBase(T) {} explicit VecBase(T, T, T, T) {} explicit VecBase(VecOp, T, T) {} explicit VecBase(T, VecOp, T) {} explicit VecBase(T, T, VecOp) {} explicit VecBase(VecOp, VecOp) {} explicit VecBase(VecOp, T) {} explicit VecBase(T, VecOp) {} }; /* Boolean vectors do not have operators and are not convertible from other types. */ template<> struct VecBase : VecOp { union { struct { bool x, y; }; SWIZZLE_XY(bool); }; VecBase() = default; explicit VecBase(bool) {} explicit VecBase(bool, bool) {} /* Should be forbidden, but is used by SMAA. */ explicit VecBase(VecOp) {} }; template<> struct VecBase : VecOp { union { struct { bool x, y, z; }; SWIZZLE_XYZ(bool); }; VecBase() = default; explicit VecBase(bool) {} explicit VecBase(bool, bool, bool) {} explicit VecBase(VecOp, bool) {} explicit VecBase(bool, VecOp) {} }; template<> struct VecBase : VecOp { union { struct { bool x, y, z, w; }; SWIZZLE_XYZW(bool); }; VecBase() = default; explicit VecBase(bool) {} explicit VecBase(bool, bool, bool, bool) {} explicit VecBase(VecOp, bool, bool) {} explicit VecBase(bool, VecOp, bool) {} explicit VecBase(bool, bool, VecOp) {} explicit VecBase(VecOp, VecOp) {} explicit VecBase(VecOp, bool) {} explicit VecBase(bool, VecOp) {} }; using uint = unsigned int; using uint32_t = unsigned int; /* For typed enums. */ using float2 = VecBase; using float3 = VecBase; using float4 = VecBase; using uint2 = VecBase; using uint3 = VecBase; using uint4 = VecBase; using int2 = VecBase; using int3 = VecBase; using int4 = VecBase; using uchar = unsigned int; using uchar2 = VecBase; using uchar3 = VecBase; using uchar4 = VecBase; using char2 = VecBase; using char3 = VecBase; using char4 = VecBase; using ushort = unsigned short; using ushort2 = VecBase; using ushort3 = VecBase; using ushort4 = VecBase; using short2 = VecBase; using short3 = VecBase; using short4 = VecBase; using half = double; using half2 = VecBase; using half3 = VecBase; using half4 = VecBase; using bool2 = VecBase; using bool3 = VecBase; using bool4 = VecBase; using vec2 = float2; using vec3 = float3; using vec4 = float4; using ivec2 = int2; using ivec3 = int3; using ivec4 = int4; using uvec2 = uint2; using uvec3 = uint3; using uvec4 = uint4; using bvec2 = bool2; using bvec3 = bool3; using bvec4 = bool4; using FLOAT = float; using VEC2 = float2; using VEC3 = float3; using VEC4 = float4; using INT = int; using IVEC2 = int2; using IVEC3 = int3; using IVEC4 = int4; using UINT = uint; using UVEC2 = uint2; using UVEC3 = uint3; using UVEC4 = uint4; using BOOL = bool; using BVEC2 = bool2; using BVEC3 = bool3; using BVEC4 = bool4; using bool32_t = uint; /** Packed types are needed for MSL which have different alignment rules for float3. */ using packed_float2 = float2; using packed_float3 = float3; using packed_float4 = float4; using packed_int2 = int2; using packed_int3 = int3; using packed_int4 = int4; using packed_uint2 = uint2; using packed_uint3 = uint3; using packed_uint4 = uint4; /** \} */ /* -------------------------------------------------------------------- */ /** \name Matrix Types * \{ */ template struct MatBase {}; template struct MatOp { using MatT = MatBase; using ColT = VecBase; using RowT = VecBase; const ColT &operator[](int) const { return *reinterpret_cast(this); } ColT &operator[](int) { return *reinterpret_cast(this); } MatT operator+() RET; MatT operator-() RET; MatT operator*(MatT) const RET; friend RowT operator*(ColT, MatT) RET; friend ColT operator*(MatT, RowT) RET; }; template struct MatBase<2, R> : MatOp<2, R> { using T = double; using ColT = VecBase; ColT x, y; MatBase() = default; explicit MatBase(T) {} explicit MatBase(T, T, T, T) {} explicit MatBase(ColT, ColT) {} template explicit MatBase(const MatBase &) {} }; template struct MatBase<3, R> : MatOp<3, R> { using T = double; using ColT = VecBase; ColT x, y, z; MatBase() = default; explicit MatBase(T) {} explicit MatBase(T, T, T, T, T, T, T, T, T) {} explicit MatBase(ColT, ColT, ColT) {} template explicit MatBase(const MatBase &) {} }; template struct MatBase<4, R> : MatOp<4, R> { using T = double; using ColT = VecBase; ColT x, y, z, w; MatBase() = default; explicit MatBase(T) {} explicit MatBase(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) {} explicit MatBase(ColT, ColT, ColT, ColT) {} template explicit MatBase(const MatBase &) {} }; using float2x2 = MatBase<2, 2>; using float2x3 = MatBase<2, 3>; using float2x4 = MatBase<2, 4>; using float3x2 = MatBase<3, 2>; using float3x3 = MatBase<3, 3>; using float3x4 = MatBase<3, 4>; using float4x2 = MatBase<4, 2>; using float4x3 = MatBase<4, 3>; using float4x4 = MatBase<4, 4>; using mat2x2 = float2x2; using mat2x3 = float2x3; using mat2x4 = float2x4; using mat3x2 = float3x2; using mat3x3 = float3x3; using mat3x4 = float3x4; using mat4x2 = float4x2; using mat4x3 = float4x3; using mat4x4 = float4x4; using mat2 = float2x2; using mat3 = float3x3; using mat4 = float4x4; using MAT4 = float4x4; using MAT3 = float3x3; /* Matrix reshaping functions. */ #define RESHAPE(mat_to, mat_from, ...) \ mat_to to_##mat_to(mat_from m) \ { \ return mat_to(__VA_ARGS__); \ } /* clang-format off */ RESHAPE(float2x2, float3x3, m[0].xy, m[1].xy) RESHAPE(float2x2, float4x4, m[0].xy, m[1].xy) RESHAPE(float3x3, float4x4, m[0].xyz, m[1].xyz, m[2].xyz) RESHAPE(float3x3, float2x2, m[0].x, m[0].y, 0, m[1].x, m[1].y, 0, 0, 0, 1) RESHAPE(float4x4, float2x2, m[0].x, m[0].y, 0, 0, m[1].x, m[1].y, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) RESHAPE(float4x4, float3x3, m[0].x, m[0].y, m[0].z, 0, m[1].x, m[1].y, m[1].z, 0, m[2].x, m[2].y, m[2].z, 0, 0, 0, 0, 1) /* clang-format on */ /* TODO(fclem): Remove. Use Transform instead. */ RESHAPE(float3x3, float3x4, m[0].xyz, m[1].xyz, m[2].xyz) #undef RESHAPE /** \} */ /* -------------------------------------------------------------------- */ /** \name Sampler Types * \{ */ template struct SamplerBase { static constexpr int coord_dim = Dimensions + int(Cube) + int(Array); static constexpr int deriv_dim = Dimensions + int(Cube); static constexpr int extent_dim = Dimensions + int(Array); using int_coord_type = VecBase; using flt_coord_type = VecBase; using derivative_type = VecBase; using data_vec_type = VecBase; using size_vec_type = VecBase; }; #define TEX_TEMPLATE \ template TEX_TEMPLATE SizeVec textureSize(T, int) RET; TEX_TEMPLATE DataVec texelFetch(T, IntCoord, int) RET; TEX_TEMPLATE DataVec texelFetchOffset(T, IntCoord, int, IntCoord) RET; TEX_TEMPLATE DataVec texture(T, FltCoord, double /*bias*/ = 0.0) RET; TEX_TEMPLATE DataVec textureGather(T, FltCoord) RET; TEX_TEMPLATE DataVec textureGrad(T, FltCoord, DerivVec, DerivVec) RET; TEX_TEMPLATE DataVec textureLod(T, FltCoord, double) RET; TEX_TEMPLATE DataVec textureLodOffset(T, FltCoord, double, IntCoord) RET; #undef TEX_TEMPLATE using samplerBuffer = SamplerBase; using sampler1D = SamplerBase; using sampler2D = SamplerBase; using sampler3D = SamplerBase; using isamplerBuffer = SamplerBase; using isampler1D = SamplerBase; using isampler2D = SamplerBase; using isampler3D = SamplerBase; using usamplerBuffer = SamplerBase; using usampler1D = SamplerBase; using usampler2D = SamplerBase; using usampler3D = SamplerBase; using sampler1DArray = SamplerBase; using sampler2DArray = SamplerBase; using isampler1DArray = SamplerBase; using isampler2DArray = SamplerBase; using usampler1DArray = SamplerBase; using usampler2DArray = SamplerBase; using samplerCube = SamplerBase; using isamplerCube = SamplerBase; using usamplerCube = SamplerBase; using samplerCubeArray = SamplerBase; using isamplerCubeArray = SamplerBase; using usamplerCubeArray = SamplerBase; using usampler1DAtomic = SamplerBase; using usampler2DAtomic = SamplerBase; using usampler2DArrayAtomic = SamplerBase; using usampler3DAtomic = SamplerBase; using isampler1DAtomic = SamplerBase; using isampler2DAtomic = SamplerBase; using isampler2DArrayAtomic = SamplerBase; using isampler3DAtomic = SamplerBase; using depth2D = sampler2D; using depth2DArray = sampler2DArray; using depthCube = samplerCube; using depthCubeArray = samplerCubeArray; /* Sampler Buffers do not have LOD. */ float4 texelFetch(samplerBuffer, int) RET; int4 texelFetch(isamplerBuffer, int) RET; uint4 texelFetch(usamplerBuffer, int) RET; /** \} */ /* -------------------------------------------------------------------- */ /** \name Image Types * \{ */ template struct ImageBase { static constexpr int coord_dim = Dimensions + int(Array); using int_coord_type = VecBase; using data_vec_type = VecBase; using size_vec_type = VecBase; }; #define IMG_TEMPLATE \ template IMG_TEMPLATE SizeVec imageSize(const T &) RET; IMG_TEMPLATE DataVec imageLoad(const T &, IntCoord) RET; IMG_TEMPLATE void imageStore(T &, IntCoord, DataVec) {} IMG_TEMPLATE void imageFence(T &) {} /* Cannot write to a read only image. */ IMG_TEMPLATE void imageStore(const T &, IntCoord, DataVec) = delete; IMG_TEMPLATE void imageFence(const T &) = delete; #define imageLoadFast imageLoad #define imageStoreFast imageStore IMG_TEMPLATE uint imageAtomicAdd(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicMin(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicMax(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicAnd(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicXor(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicOr(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicExchange(T &, IntCoord, uint) RET; IMG_TEMPLATE uint imageAtomicCompSwap(T &, IntCoord, uint, uint) RET; /* Cannot write to a read only image. */ IMG_TEMPLATE uint imageAtomicAdd(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicMin(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicMax(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicAnd(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicXor(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicOr(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicExchange(const T &, IntCoord, uint) = delete; IMG_TEMPLATE uint imageAtomicCompSwap(const T &, IntCoord, uint, uint) = delete; #undef IMG_TEMPLATE using image1D = ImageBase; using image2D = ImageBase; using image3D = ImageBase; using iimage1D = ImageBase; using iimage2D = ImageBase; using iimage3D = ImageBase; using uimage1D = ImageBase; using uimage2D = ImageBase; using uimage3D = ImageBase; using image1DArray = ImageBase; using image2DArray = ImageBase; using iimage1DArray = ImageBase; using iimage2DArray = ImageBase; using uimage1DArray = ImageBase; using uimage2DArray = ImageBase; /* Forbid Cube and cube arrays. Bind them as 3D textures instead. */ /** \} */ /* -------------------------------------------------------------------- */ /** \name Builtin Functions * \{ */ template VecBase greaterThan(VecOp, VecOp) RET; template VecBase lessThan(VecOp, VecOp) RET; template VecBase lessThanEqual(VecOp, VecOp) RET; template VecBase greaterThanEqual(VecOp, VecOp) RET; template VecBase equal(VecOp, VecOp) RET; template VecBase notEqual(VecOp, VecOp) RET; template bool any(VecOp) RET; template bool all(VecOp) RET; /* `not` is a C++ keyword that aliases the `!` operator. Simply overload it. */ template VecBase operator!(VecOp) RET; template VecBase bitCount(VecOp) RET; template VecBase bitCount(VecOp) RET; template VecBase bitfieldExtract(VecOp, int, int) RET; template VecBase bitfieldExtract(VecOp, int, int) RET; template VecBase bitfieldInsert(VecOp, VecOp, int, int) RET; template VecBase bitfieldInsert(VecOp, VecOp, int, int) RET; template VecBase bitfieldReverse(VecOp) RET; template VecBase bitfieldReverse(VecOp) RET; int bitCount(int) RET; int bitCount(uint) RET; int bitfieldExtract(int) RET; int bitfieldExtract(uint) RET; int bitfieldInsert(int) RET; int bitfieldInsert(uint) RET; int bitfieldReverse(int) RET; int bitfieldReverse(uint) RET; template VecBase findLSB(VecOp) RET; template VecBase findLSB(VecOp) RET; template VecBase findMSB(VecOp) RET; template VecBase findMSB(VecOp) RET; int findLSB(int) RET; int findLSB(uint) RET; int findMSB(int) RET; int findMSB(uint) RET; /* Math Functions. */ /* NOTE: Declared inside a namespace and exposed behind macros to prevent * errors on VS2019 due to `corecrt_math` conflicting functions. */ namespace glsl { template T abs(T) RET; /* TODO(fclem): These should be restricted to floats. */ template T ceil(T) RET; template T exp(T) RET; template T exp2(T) RET; template T floor(T) RET; template T fma(T, T, T) RET; double fma(double, double, double) RET; template T frexp(T, T) RET; bool isinf(double) RET; template VecBase isinf(VecOp) RET; bool isnan(double) RET; template VecBase isnan(VecOp) RET; template T log(T) RET; template T log2(T) RET; template T modf(T, T); template T pow(T, U) RET; template T round(T) RET; template T sqrt(T) RET; template T trunc(T) RET; template T ldexp(T, U) RET; template T acos(T) RET; template T acosh(T) RET; template T asin(T) RET; template T asinh(T) RET; template T atan(T, T) RET; template T atan(T) RET; template T atanh(T) RET; template T cos(T) RET; template T cosh(T) RET; template T sin(T) RET; template T sinh(T) RET; template T tan(T) RET; template T tanh(T) RET; } // namespace glsl #define abs glsl::abs #define ceil glsl::ceil #define exp glsl::exp #define exp2 glsl::exp2 #define floor glsl::floor #define fma glsl::fma #define frexp glsl::frexp #define isinf glsl::isinf #define isnan glsl::isnan #define log glsl::log #define log2 glsl::log2 #define modf glsl::modf #define pow glsl::pow #define round glsl::round #define sqrt glsl::sqrt #define trunc glsl::trunc #define ldexp glsl::ldexp #define acos glsl::acos #define acosh glsl::acosh #define asin glsl::asin #define asinh glsl::asinh #define atan glsl::atan #define atanh glsl::atanh #define cos glsl::cos #define cosh glsl::cosh #define sin glsl::sin #define sinh glsl::sinh #define tan glsl::tan #define tanh glsl::tanh template T max(T, T) RET; template T min(T, T) RET; template T sign(T) RET; template T clamp(T, U, U) RET; template T clamp(T, double, double) RET; template T max(T, U) RET; template T min(T, U) RET; /* TODO(fclem): These should be restricted to floats. */ template T fract(T) RET; template T inversesqrt(T) RET; double mod(double, double) RET; template VecBase mod(VecOp, double) RET; template VecBase mod(VecOp, VecOp) RET; template T smoothstep(T, T, T) RET; double step(double, double) RET; template VecBase step(VecOp, VecOp) RET; template VecBase step(double, VecOp) RET; double smoothstep(double, double, double) RET; template VecBase smoothstep(double, double, VecOp) RET; template T degrees(T) RET; template T radians(T) RET; /* Declared explicitly to avoid type errors. */ double mix(double, double, double) RET; template VecBase mix(VecOp, VecOp, double) RET; template VecBase mix(VecOp, VecOp, VecOp) RET; template VecBase mix(VecOp, VecOp, VecOp) RET; #define select(A, B, C) mix(A, B, C) VecBase cross(VecOp, VecOp) RET; template double dot(VecOp, VecOp) RET; template double distance(VecOp, VecOp) RET; template double length(VecOp) RET; template VecBase normalize(VecOp) RET; template VecBase floatBitsToInt(VecOp) RET; template VecBase floatBitsToUint(VecOp) RET; template VecBase intBitsToFloat(VecOp) RET; template VecBase uintBitsToFloat(VecOp) RET; int floatBitsToInt(double) RET; uint floatBitsToUint(double) RET; double intBitsToFloat(int) RET; double uintBitsToFloat(uint) RET; namespace gl_FragmentShader { /* Derivative functions. */ template T dFdx(T) RET; template T dFdy(T) RET; template T fwidth(T) RET; } // namespace gl_FragmentShader /* Geometric functions. */ template VecBase faceforward(VecOp, VecOp, VecOp) RET; template VecBase reflect(VecOp, VecOp) RET; template VecBase refract(VecOp, VecOp, double) RET; /* Atomic operations. */ int atomicAdd(int &, int) RET; int atomicAnd(int &, int) RET; int atomicOr(int &, int) RET; int atomicXor(int &, int) RET; int atomicMin(int &, int) RET; int atomicMax(int &, int) RET; int atomicExchange(int &, int) RET; int atomicCompSwap(int &, int, int) RET; uint atomicAdd(uint &, uint) RET; uint atomicAnd(uint &, uint) RET; uint atomicOr(uint &, uint) RET; uint atomicXor(uint &, uint) RET; uint atomicMin(uint &, uint) RET; uint atomicMax(uint &, uint) RET; uint atomicExchange(uint &, uint) RET; uint atomicCompSwap(uint &, uint, uint) RET; /* Packing functions. */ uint packHalf2x16(float2) RET; uint packUnorm2x16(float2) RET; uint packSnorm2x16(float2) RET; uint packUnorm4x8(float4) RET; uint packSnorm4x8(float4) RET; float2 unpackHalf2x16(uint) RET; float2 unpackUnorm2x16(uint) RET; float2 unpackSnorm2x16(uint) RET; float4 unpackUnorm4x8(uint) RET; float4 unpackSnorm4x8(uint) RET; /* Matrices functions. */ template float determinant(MatBase) RET; template MatBase inverse(MatBase) RET; template MatBase transpose(MatBase) RET; #undef RET /** \} */ /* -------------------------------------------------------------------- */ /** \name Special Variables * \{ */ namespace gl_VertexShader { extern const int gl_VertexID; extern const int gl_InstanceID; extern const int gl_BaseVertex; extern const int gpu_BaseInstance; extern const int gpu_InstanceIndex; float4 gl_Position = float4(0); double gl_PointSize = 0; float gl_ClipDistance[6] = {0}; int gpu_Layer = 0; int gpu_ViewportIndex = 0; } // namespace gl_VertexShader namespace gl_FragmentShader { extern const float4 gl_FragCoord; const bool gl_FrontFacing = true; const float2 gl_PointCoord = float2(0); const int gl_PrimitiveID = 0; float gl_FragDepth = 0; const float gl_ClipDistance[6] = {0}; const int gpu_Layer = 0; const int gpu_ViewportIndex = 0; } // namespace gl_FragmentShader namespace gl_ComputeShader { constexpr uint3 gl_WorkGroupSize = uint3(16, 16, 16); extern const uint3 gl_NumWorkGroups; extern const uint3 gl_WorkGroupID; extern const uint3 gl_LocalInvocationID; extern const uint3 gl_GlobalInvocationID; extern const uint gl_LocalInvocationIndex; } // namespace gl_ComputeShader /** \} */ /* -------------------------------------------------------------------- */ /** \name Keywords * \{ */ /* Note: Cannot easily mutate them. Pass every by copy for now. */ /* Pass argument by reference. */ #define inout /* Pass argument by reference but only write to it. Its initial value is undefined. */ #define out /* Pass argument by copy (default). */ #define in /* Discards the output of the current fragment shader invocation and halts its execution. */ #define discard /* Decorate a variable in global scope that is common to all threads in a thread-group. */ #define shared namespace gl_ComputeShader { void barrier() {} void memoryBarrier() {} void memoryBarrierShared() {} void memoryBarrierImage() {} void memoryBarrierBuffer() {} void groupMemoryBarrier() {} } // namespace gl_ComputeShader /** \} */ /* -------------------------------------------------------------------- */ /** \name Compatibility * \{ */ /* Array syntax compatibility. */ /* clang-format off */ #define float_array(...) { __VA_ARGS__ } #define float2_array(...) { __VA_ARGS__ } #define float3_array(...) { __VA_ARGS__ } #define float4_array(...) { __VA_ARGS__ } #define int_array(...) { __VA_ARGS__ } #define int2_array(...) { __VA_ARGS__ } #define int3_array(...) { __VA_ARGS__ } #define int4_array(...) { __VA_ARGS__ } #define uint_array(...) { __VA_ARGS__ } #define uint2_array(...) { __VA_ARGS__ } #define uint3_array(...) { __VA_ARGS__ } #define uint4_array(...) { __VA_ARGS__ } #define bool_array(...) { __VA_ARGS__ } #define bool2_array(...) { __VA_ARGS__ } #define bool3_array(...) { __VA_ARGS__ } #define bool4_array(...) { __VA_ARGS__ } /* clang-format on */ #define METAL_CONSTRUCTOR_1(class_name, t1, m1) \ class_name() = default; \ class_name(t1 m1##_) : m1(m1##_){}; #define METAL_CONSTRUCTOR_2(class_name, t1, m1, t2, m2) \ class_name() = default; \ class_name(t1 m1##_, t2 m2##_) : m1(m1##_), m2(m2##_){}; #define METAL_CONSTRUCTOR_3(class_name, t1, m1, t2, m2, t3, m3) \ class_name() = default; \ class_name(t1 m1##_, t2 m2##_, t3 m3##_) : m1(m1##_), m2(m2##_), m3(m3##_){}; #define METAL_CONSTRUCTOR_4(class_name, t1, m1, t2, m2, t3, m3, t4, m4) \ class_name() = default; \ class_name(t1 m1##_, t2 m2##_, t3 m3##_, t4 m4##_) \ : m1(m1##_), m2(m2##_), m3(m3##_), m4(m4##_){}; /** \} */ /* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */ #ifndef ATTR_FALLTHROUGH # ifdef __GNUC__ # define ATTR_FALLTHROUGH __attribute__((fallthrough)) # else # define ATTR_FALLTHROUGH ((void)0) # endif #endif /* GLSL main function must return void. C++ need to return int. * Inject real main (C++) inside the GLSL main definition. */ #define main() \ /* Fake main prototype. */ \ /* void */ _fake_main(); \ /* Real main. */ \ int main() \ { \ _fake_main(); \ return 0; \ } \ /* Fake main definition. */ \ void _fake_main() #define GLSL_CPP_STUBS #include "GPU_shader_shared_utils.hh"