• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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