xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/shaders/common.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2019 The ANGLE Project. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // common.h: Common header for other metal source code.
7 
8 #ifndef LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_
9 #define LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_
10 
11 // clang-format off
12 #ifndef SKIP_STD_HEADERS
13 @@#    include <simd/simd.h>
14 @@#    include <metal_stdlib>
15 #endif
16 
17 #include "constants.h"
18 
19 #define ANGLE_KERNEL_GUARD(IDX, MAX_COUNT) \
20     if (IDX >= MAX_COUNT)                  \
21     {                                      \
22         return;                            \
23     }
24 
25 using namespace metal;
26 // clang-format on
27 
28 // Common constant defined number of color outputs
29 constant uint32_t kNumColorOutputs [[function_constant(0)]];
30 constant bool kColorOutputAvailable0 = kNumColorOutputs > 0;
31 constant bool kColorOutputAvailable1 = kNumColorOutputs > 1;
32 constant bool kColorOutputAvailable2 = kNumColorOutputs > 2;
33 constant bool kColorOutputAvailable3 = kNumColorOutputs > 3;
34 constant bool kColorOutputAvailable4 = kNumColorOutputs > 4;
35 constant bool kColorOutputAvailable5 = kNumColorOutputs > 5;
36 constant bool kColorOutputAvailable6 = kNumColorOutputs > 6;
37 constant bool kColorOutputAvailable7 = kNumColorOutputs > 7;
38 
39 namespace rx
40 {
41 namespace mtl_shader
42 {
43 
44 // Full screen triangle's vertices
45 constant float2 gCorners[3] = {float2(-1.0f, -1.0f), float2(3.0f, -1.0f), float2(-1.0f, 3.0f)};
46 
47 template <typename T>
48 struct MultipleColorOutputs
49 {
50     vec<T, 4> color0 [[color(0), function_constant(kColorOutputAvailable0)]];
51     vec<T, 4> color1 [[color(1), function_constant(kColorOutputAvailable1)]];
52     vec<T, 4> color2 [[color(2), function_constant(kColorOutputAvailable2)]];
53     vec<T, 4> color3 [[color(3), function_constant(kColorOutputAvailable3)]];
54     vec<T, 4> color4 [[color(4), function_constant(kColorOutputAvailable4)]];
55     vec<T, 4> color5 [[color(5), function_constant(kColorOutputAvailable5)]];
56     vec<T, 4> color6 [[color(6), function_constant(kColorOutputAvailable6)]];
57     vec<T, 4> color7 [[color(7), function_constant(kColorOutputAvailable7)]];
58 };
59 
60 #define ANGLE_ASSIGN_COLOR_OUPUT(STRUCT_VARIABLE, COLOR_INDEX, VALUE) \
61     do                                                                \
62     {                                                                 \
63         if (kColorOutputAvailable##COLOR_INDEX)                       \
64         {                                                             \
65             STRUCT_VARIABLE.color##COLOR_INDEX = VALUE;               \
66         }                                                             \
67     } while (0)
68 
69 template <typename T>
toMultipleColorOutputs(vec<T,4> color)70 static inline MultipleColorOutputs<T> toMultipleColorOutputs(vec<T, 4> color)
71 {
72     MultipleColorOutputs<T> re;
73 
74     ANGLE_ASSIGN_COLOR_OUPUT(re, 0, color);
75     ANGLE_ASSIGN_COLOR_OUPUT(re, 1, color);
76     ANGLE_ASSIGN_COLOR_OUPUT(re, 2, color);
77     ANGLE_ASSIGN_COLOR_OUPUT(re, 3, color);
78     ANGLE_ASSIGN_COLOR_OUPUT(re, 4, color);
79     ANGLE_ASSIGN_COLOR_OUPUT(re, 5, color);
80     ANGLE_ASSIGN_COLOR_OUPUT(re, 6, color);
81     ANGLE_ASSIGN_COLOR_OUPUT(re, 7, color);
82 
83     return re;
84 }
85 
cubeTexcoords(float2 texcoords,int face)86 static inline float3 cubeTexcoords(float2 texcoords, int face)
87 {
88     texcoords = 2.0 * texcoords - 1.0;
89     switch (face)
90     {
91         case 0:
92             return float3(1.0, -texcoords.y, -texcoords.x);
93         case 1:
94             return float3(-1.0, -texcoords.y, texcoords.x);
95         case 2:
96             return float3(texcoords.x, 1.0, texcoords.y);
97         case 3:
98             return float3(texcoords.x, -1.0, -texcoords.y);
99         case 4:
100             return float3(texcoords.x, -texcoords.y, 1.0);
101         case 5:
102             return float3(-texcoords.x, -texcoords.y, -1.0);
103     }
104     return float3(texcoords, 0);
105 }
106 
107 template <typename T>
resolveTextureMS(texture2d_ms<T> srcTexture,uint2 coords)108 static inline vec<T, 4> resolveTextureMS(texture2d_ms<T> srcTexture, uint2 coords)
109 {
110     uint samples = srcTexture.get_num_samples();
111 
112     vec<T, 4> output(0);
113 
114     for (uint sample = 0; sample < samples; ++sample)
115     {
116         output += srcTexture.read(coords, sample);
117     }
118 
119     output = output / samples;
120 
121     return output;
122 }
123 
sRGBtoLinear(float4 color)124 static inline float4 sRGBtoLinear(float4 color)
125 {
126     float3 linear1 = color.rgb / 12.92;
127     float3 linear2 = powr((color.rgb + float3(0.055)) / 1.055, 2.4);
128     float3 factor  = float3(color.rgb <= float3(0.04045));
129     float4 linear  = float4(factor * linear1 + float3(1.0 - factor) * linear2, color.a);
130 
131     return linear;
132 }
133 
linearToSRGB(float color)134 static inline float linearToSRGB(float color)
135 {
136     if (color <= 0.0f)
137         return 0.0f;
138     if (color < 0.0031308f)
139         return 12.92f * color;
140     if (color < 1.0f)
141         return 1.055f * powr(color, 0.41666f) - 0.055f;
142     return 1.0f;
143 }
144 
linearToSRGB(float4 color)145 static inline float4 linearToSRGB(float4 color)
146 {
147     return float4(linearToSRGB(color.r), linearToSRGB(color.g), linearToSRGB(color.b), color.a);
148 }
149 
150 template <typename Short>
bytesToShort(constant uchar * input,uint offset)151 static inline Short bytesToShort(constant uchar *input, uint offset)
152 {
153     Short inputLo = input[offset];
154     Short inputHi = input[offset + 1];
155     // Little endian conversion:
156     return inputLo | (inputHi << 8);
157 }
158 
159 template <typename Int>
bytesToInt(constant uchar * input,uint offset)160 static inline Int bytesToInt(constant uchar *input, uint offset)
161 {
162     Int input0 = input[offset];
163     Int input1 = input[offset + 1];
164     Int input2 = input[offset + 2];
165     Int input3 = input[offset + 3];
166     // Little endian conversion:
167     return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
168 }
169 
170 template <typename Short>
shortToBytes(Short val,uint offset,device uchar * output)171 static inline void shortToBytes(Short val, uint offset, device uchar *output)
172 {
173     ushort valUnsigned = as_type<ushort>(val);
174     output[offset]     = valUnsigned & 0xff;
175     output[offset + 1] = (valUnsigned >> 8) & 0xff;
176 }
177 
178 template <typename Int>
intToBytes(Int val,uint offset,device uchar * output)179 static inline void intToBytes(Int val, uint offset, device uchar *output)
180 {
181     uint valUnsigned   = as_type<uint>(val);
182     output[offset]     = valUnsigned & 0xff;
183     output[offset + 1] = (valUnsigned >> 8) & 0xff;
184     output[offset + 2] = (valUnsigned >> 16) & 0xff;
185     output[offset + 3] = (valUnsigned >> 24) & 0xff;
186 }
187 
floatToBytes(float val,uint offset,device uchar * output)188 static inline void floatToBytes(float val, uint offset, device uchar *output)
189 {
190     intToBytes(as_type<uint>(val), offset, output);
191 }
192 
int24bitToBytes(uint val,uint offset,device uchar * output)193 static inline void int24bitToBytes(uint val, uint offset, device uchar *output)
194 {
195     output[offset]     = val & 0xff;
196     output[offset + 1] = (val >> 8) & 0xff;
197     output[offset + 2] = (val >> 16) & 0xff;
198 }
199 
200 template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
getShiftedData(T input)201 static inline T getShiftedData(T input)
202 {
203     static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8),
204                   "T must have at least as many bits as inputBitCount + inputBitStart.");
205     const T mask = (1 << inputBitCount) - 1;
206     return (input >> inputBitStart) & mask;
207 }
208 
209 template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
shiftData(T input)210 static inline T shiftData(T input)
211 {
212     static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8),
213                   "T must have at least as many bits as inputBitCount + inputBitStart.");
214     const T mask = (1 << inputBitCount) - 1;
215     return (input & mask) << inputBitStart;
216 }
217 
218 template <unsigned int inputBitCount, typename T>
normalizedToFloat(T input)219 static inline float normalizedToFloat(T input)
220 {
221     static_assert(inputBitCount <= (sizeof(T) * 8),
222                   "T must have more bits than or same bits as inputBitCount.");
223     static_assert(inputBitCount <= 23, "Only single precision is supported");
224 
225     constexpr float inverseMax = 1.0f / ((1 << inputBitCount) - 1);
226     return input * inverseMax;
227 }
228 
229 template <typename T>
normalizedToFloat(T input)230 static inline float normalizedToFloat(T input)
231 {
232     return normalizedToFloat<sizeof(T) * 8, T>(input);
233 }
234 
235 template <>
normalizedToFloat(short input)236 inline float normalizedToFloat(short input)
237 {
238     constexpr float inverseMax = 1.0f / 0x7fff;
239     return static_cast<float>(input) * inverseMax;
240 }
241 
242 template <>
normalizedToFloat(int input)243 inline float normalizedToFloat(int input)
244 {
245     constexpr float inverseMax = 1.0f / 0x7fffffff;
246     return static_cast<float>(input) * inverseMax;
247 }
248 
249 template <>
normalizedToFloat(uint input)250 inline float normalizedToFloat(uint input)
251 {
252     constexpr float inverseMax = 1.0f / 0xffffffff;
253     return static_cast<float>(input) * inverseMax;
254 }
255 
256 template <unsigned int outputBitCount, typename T>
floatToNormalized(float input)257 static inline T floatToNormalized(float input)
258 {
259     static_assert(outputBitCount <= (sizeof(T) * 8),
260                   "T must have more bits than or same bits as inputBitCount.");
261     static_assert(outputBitCount > (metal::is_unsigned<T>::value ? 0 : 1),
262                   "outputBitCount must be at least 1 not counting the sign bit.");
263     constexpr unsigned int bits =
264         metal::is_unsigned<T>::value ? outputBitCount : outputBitCount - 1;
265     static_assert(bits <= 23, "Only single precision is supported");
266 
267     return static_cast<T>(metal::round(((1 << bits) - 1) * input));
268 }
269 
270 template <typename T>
floatToNormalized(float input)271 static inline T floatToNormalized(float input)
272 {
273     return floatToNormalized<sizeof(T) * 8, T>(input);
274 }
275 
276 }  // namespace mtl_shader
277 }  // namespace rx
278 
279 #endif /* LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_ */
280