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 = pow((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 else if (color < 0.0031308f)
139 return 12.92f * color;
140 else if (color < 1.0f)
141 return 1.055f * pow(color, 0.41666f) - 0.055f;
142 else
143 return 1.0f;
144 }
145
linearToSRGB(float4 color)146 static inline float4 linearToSRGB(float4 color)
147 {
148 return float4(linearToSRGB(color.r), linearToSRGB(color.g), linearToSRGB(color.b), color.a);
149 }
150
151 template <typename Short>
bytesToShort(constant uchar * input,uint offset)152 static inline Short bytesToShort(constant uchar *input, uint offset)
153 {
154 Short inputLo = input[offset];
155 Short inputHi = input[offset + 1];
156 // Little endian conversion:
157 return inputLo | (inputHi << 8);
158 }
159
160 template <typename Int>
bytesToInt(constant uchar * input,uint offset)161 static inline Int bytesToInt(constant uchar *input, uint offset)
162 {
163 Int input0 = input[offset];
164 Int input1 = input[offset + 1];
165 Int input2 = input[offset + 2];
166 Int input3 = input[offset + 3];
167 // Little endian conversion:
168 return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
169 }
170
171 template <typename Short>
shortToBytes(Short val,uint offset,device uchar * output)172 static inline void shortToBytes(Short val, uint offset, device uchar *output)
173 {
174 ushort valUnsigned = as_type<ushort>(val);
175 output[offset] = valUnsigned & 0xff;
176 output[offset + 1] = (valUnsigned >> 8) & 0xff;
177 }
178
179 template <typename Int>
intToBytes(Int val,uint offset,device uchar * output)180 static inline void intToBytes(Int val, uint offset, device uchar *output)
181 {
182 uint valUnsigned = as_type<uint>(val);
183 output[offset] = valUnsigned & 0xff;
184 output[offset + 1] = (valUnsigned >> 8) & 0xff;
185 output[offset + 2] = (valUnsigned >> 16) & 0xff;
186 output[offset + 3] = (valUnsigned >> 24) & 0xff;
187 }
188
floatToBytes(float val,uint offset,device uchar * output)189 static inline void floatToBytes(float val, uint offset, device uchar *output)
190 {
191 intToBytes(as_type<uint>(val), offset, output);
192 }
193
int24bitToBytes(uint val,uint offset,device uchar * output)194 static inline void int24bitToBytes(uint val, uint offset, device uchar *output)
195 {
196 output[offset] = val & 0xff;
197 output[offset + 1] = (val >> 8) & 0xff;
198 output[offset + 2] = (val >> 16) & 0xff;
199 }
200
201 template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
getShiftedData(T input)202 static inline T getShiftedData(T input)
203 {
204 static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8),
205 "T must have at least as many bits as inputBitCount + inputBitStart.");
206 const T mask = (1 << inputBitCount) - 1;
207 return (input >> inputBitStart) & mask;
208 }
209
210 template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
shiftData(T input)211 static inline T shiftData(T input)
212 {
213 static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8),
214 "T must have at least as many bits as inputBitCount + inputBitStart.");
215 const T mask = (1 << inputBitCount) - 1;
216 return (input & mask) << inputBitStart;
217 }
218
219 template <unsigned int inputBitCount, typename T>
normalizedToFloat(T input)220 static inline float normalizedToFloat(T input)
221 {
222 static_assert(inputBitCount <= (sizeof(T) * 8),
223 "T must have more bits than or same bits as inputBitCount.");
224 static_assert(inputBitCount <= 23, "Only single precision is supported");
225
226 constexpr float inverseMax = 1.0f / ((1 << inputBitCount) - 1);
227 return input * inverseMax;
228 }
229
230 template <typename T>
normalizedToFloat(T input)231 static inline float normalizedToFloat(T input)
232 {
233 return normalizedToFloat<sizeof(T) * 8, T>(input);
234 }
235
236 template <>
normalizedToFloat(short input)237 inline float normalizedToFloat(short input)
238 {
239 constexpr float inverseMax = 1.0f / 0x7fff;
240 return static_cast<float>(input) * inverseMax;
241 }
242
243 template <>
normalizedToFloat(int input)244 inline float normalizedToFloat(int input)
245 {
246 constexpr float inverseMax = 1.0f / 0x7fffffff;
247 return static_cast<float>(input) * inverseMax;
248 }
249
250 template <>
normalizedToFloat(uint input)251 inline float normalizedToFloat(uint input)
252 {
253 constexpr float inverseMax = 1.0f / 0xffffffff;
254 return static_cast<float>(input) * inverseMax;
255 }
256
257 template <unsigned int outputBitCount, typename T>
floatToNormalized(float input)258 static inline T floatToNormalized(float input)
259 {
260 static_assert(outputBitCount <= (sizeof(T) * 8),
261 "T must have more bits than or same bits as inputBitCount.");
262 static_assert(outputBitCount <= 23, "Only single precision is supported");
263
264 return static_cast<T>(((1 << outputBitCount) - 1) * input + 0.5f);
265 }
266
267 template <typename T>
floatToNormalized(float input)268 static inline T floatToNormalized(float input)
269 {
270 return floatToNormalized<sizeof(T) * 8, T>(input);
271 }
272
273 } // namespace mtl_shader
274 } // namespace rx
275
276 #endif /* LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_ */
277