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
35 namespace rx
36 {
37 namespace mtl_shader
38 {
39
40 // Full screen triangle's vertices
41 constant float2 gCorners[3] = {float2(-1.0f, -1.0f), float2(3.0f, -1.0f), float2(-1.0f, 3.0f)};
42
43 template <typename T>
44 struct MultipleColorOutputs
45 {
46 vec<T, 4> color0 [[color(0), function_constant(kColorOutputAvailable0)]];
47 vec<T, 4> color1 [[color(1), function_constant(kColorOutputAvailable1)]];
48 vec<T, 4> color2 [[color(2), function_constant(kColorOutputAvailable2)]];
49 vec<T, 4> color3 [[color(3), function_constant(kColorOutputAvailable3)]];
50 };
51
52 #define ANGLE_ASSIGN_COLOR_OUPUT(STRUCT_VARIABLE, COLOR_INDEX, VALUE) \
53 do \
54 { \
55 if (kColorOutputAvailable##COLOR_INDEX) \
56 { \
57 STRUCT_VARIABLE.color##COLOR_INDEX = VALUE; \
58 } \
59 } while (0)
60
61 template <typename T>
toMultipleColorOutputs(vec<T,4> color)62 static inline MultipleColorOutputs<T> toMultipleColorOutputs(vec<T, 4> color)
63 {
64 MultipleColorOutputs<T> re;
65
66 ANGLE_ASSIGN_COLOR_OUPUT(re, 0, color);
67 ANGLE_ASSIGN_COLOR_OUPUT(re, 1, color);
68 ANGLE_ASSIGN_COLOR_OUPUT(re, 2, color);
69 ANGLE_ASSIGN_COLOR_OUPUT(re, 3, color);
70
71 return re;
72 }
73
cubeTexcoords(float2 texcoords,int face)74 static inline float3 cubeTexcoords(float2 texcoords, int face)
75 {
76 texcoords = 2.0 * texcoords - 1.0;
77 switch (face)
78 {
79 case 0:
80 return float3(1.0, -texcoords.y, -texcoords.x);
81 case 1:
82 return float3(-1.0, -texcoords.y, texcoords.x);
83 case 2:
84 return float3(texcoords.x, 1.0, texcoords.y);
85 case 3:
86 return float3(texcoords.x, -1.0, -texcoords.y);
87 case 4:
88 return float3(texcoords.x, -texcoords.y, 1.0);
89 case 5:
90 return float3(-texcoords.x, -texcoords.y, -1.0);
91 }
92 return float3(texcoords, 0);
93 }
94
95 template <typename T>
resolveTextureMS(texture2d_ms<T> srcTexture,uint2 coords)96 static inline vec<T, 4> resolveTextureMS(texture2d_ms<T> srcTexture, uint2 coords)
97 {
98 uint samples = srcTexture.get_num_samples();
99
100 vec<T, 4> output(0);
101
102 for (uint sample = 0; sample < samples; ++sample)
103 {
104 output += srcTexture.read(coords, sample);
105 }
106
107 output = output / samples;
108
109 return output;
110 }
111
sRGBtoLinear(float4 color)112 static inline float4 sRGBtoLinear(float4 color)
113 {
114 float3 linear1 = color.rgb / 12.92;
115 float3 linear2 = pow((color.rgb + float3(0.055)) / 1.055, 2.4);
116 float3 factor = float3(color.rgb <= float3(0.04045));
117 float4 linear = float4(factor * linear1 + float3(1.0 - factor) * linear2, color.a);
118
119 return linear;
120 }
121
linearToSRGB(float color)122 static inline float linearToSRGB(float color)
123 {
124 if (color <= 0.0f)
125 return 0.0f;
126 else if (color < 0.0031308f)
127 return 12.92f * color;
128 else if (color < 1.0f)
129 return 1.055f * pow(color, 0.41666f) - 0.055f;
130 else
131 return 1.0f;
132 }
133
linearToSRGB(float4 color)134 static inline float4 linearToSRGB(float4 color)
135 {
136 return float4(linearToSRGB(color.r), linearToSRGB(color.g), linearToSRGB(color.b), color.a);
137 }
138
139 template <typename Short>
bytesToShort(constant uchar * input,uint offset)140 static inline Short bytesToShort(constant uchar *input, uint offset)
141 {
142 Short inputLo = input[offset];
143 Short inputHi = input[offset + 1];
144 // Little endian conversion:
145 return inputLo | (inputHi << 8);
146 }
147
148 template <typename Int>
bytesToInt(constant uchar * input,uint offset)149 static inline Int bytesToInt(constant uchar *input, uint offset)
150 {
151 Int input0 = input[offset];
152 Int input1 = input[offset + 1];
153 Int input2 = input[offset + 2];
154 Int input3 = input[offset + 3];
155 // Little endian conversion:
156 return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
157 }
158
159 template <typename Short>
shortToBytes(Short val,uint offset,device uchar * output)160 static inline void shortToBytes(Short val, uint offset, device uchar *output)
161 {
162 ushort valUnsigned = as_type<ushort>(val);
163 output[offset] = valUnsigned & 0xff;
164 output[offset + 1] = (valUnsigned >> 8) & 0xff;
165 }
166
167 template <typename Int>
intToBytes(Int val,uint offset,device uchar * output)168 static inline void intToBytes(Int val, uint offset, device uchar *output)
169 {
170 uint valUnsigned = as_type<uint>(val);
171 output[offset] = valUnsigned & 0xff;
172 output[offset + 1] = (valUnsigned >> 8) & 0xff;
173 output[offset + 2] = (valUnsigned >> 16) & 0xff;
174 output[offset + 3] = (valUnsigned >> 24) & 0xff;
175 }
176
floatToBytes(float val,uint offset,device uchar * output)177 static inline void floatToBytes(float val, uint offset, device uchar *output)
178 {
179 intToBytes(as_type<uint>(val), offset, output);
180 }
181
int24bitToBytes(uint val,uint offset,device uchar * output)182 static inline void int24bitToBytes(uint val, uint offset, device uchar *output)
183 {
184 output[offset] = val & 0xff;
185 output[offset + 1] = (val >> 8) & 0xff;
186 output[offset + 2] = (val >> 16) & 0xff;
187 }
188
189 template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
getShiftedData(T input)190 static inline T getShiftedData(T input)
191 {
192 static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8),
193 "T must have at least as many bits as inputBitCount + inputBitStart.");
194 const T mask = (1 << inputBitCount) - 1;
195 return (input >> inputBitStart) & mask;
196 }
197
198 template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
shiftData(T input)199 static inline T shiftData(T input)
200 {
201 static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8),
202 "T must have at least as many bits as inputBitCount + inputBitStart.");
203 const T mask = (1 << inputBitCount) - 1;
204 return (input & mask) << inputBitStart;
205 }
206
207 template <unsigned int inputBitCount, typename T>
normalizedToFloat(T input)208 static inline float normalizedToFloat(T input)
209 {
210 static_assert(inputBitCount <= (sizeof(T) * 8),
211 "T must have more bits than or same bits as inputBitCount.");
212 static_assert(inputBitCount <= 23, "Only single precision is supported");
213
214 constexpr float inverseMax = 1.0f / ((1 << inputBitCount) - 1);
215 return input * inverseMax;
216 }
217
218 template <typename T>
normalizedToFloat(T input)219 static inline float normalizedToFloat(T input)
220 {
221 return normalizedToFloat<sizeof(T) * 8, T>(input);
222 }
223
224 template <>
normalizedToFloat(short input)225 inline float normalizedToFloat(short input)
226 {
227 constexpr float inverseMax = 1.0f / 0x7fff;
228 return static_cast<float>(input) * inverseMax;
229 }
230
231 template <>
normalizedToFloat(int input)232 inline float normalizedToFloat(int input)
233 {
234 constexpr float inverseMax = 1.0f / 0x7fffffff;
235 return static_cast<float>(input) * inverseMax;
236 }
237
238 template <>
normalizedToFloat(uint input)239 inline float normalizedToFloat(uint input)
240 {
241 constexpr float inverseMax = 1.0f / 0xffffffff;
242 return static_cast<float>(input) * inverseMax;
243 }
244
245 template <unsigned int outputBitCount, typename T>
floatToNormalized(float input)246 static inline T floatToNormalized(float input)
247 {
248 static_assert(outputBitCount <= (sizeof(T) * 8),
249 "T must have more bits than or same bits as inputBitCount.");
250 static_assert(outputBitCount <= 23, "Only single precision is supported");
251
252 return static_cast<T>(((1 << outputBitCount) - 1) * input + 0.5f);
253 }
254
255 template <typename T>
floatToNormalized(float input)256 static inline T floatToNormalized(float input)
257 {
258 return floatToNormalized<sizeof(T) * 8, T>(input);
259 }
260
261 } // namespace mtl_shader
262 } // namespace rx
263
264 #endif /* LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_ */
265