xref: /aosp_15_r20/external/angle/src/compiler/translator/glsl/BuiltInFunctionEmulatorGLSL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2002 The ANGLE Project Authors. 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 
7 #include "compiler/translator/glsl/BuiltInFunctionEmulatorGLSL.h"
8 
9 #include "angle_gl.h"
10 #include "compiler/translator/BuiltInFunctionEmulator.h"
11 #include "compiler/translator/glsl/VersionGLSL.h"
12 #include "compiler/translator/tree_util/BuiltIn.h"
13 
14 namespace sh
15 {
16 
InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator * emu,sh::GLenum shaderType)17 void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
18                                                       sh::GLenum shaderType)
19 {
20     if (shaderType == GL_VERTEX_SHADER)
21     {
22         emu->addEmulatedFunction(BuiltInId::abs_Int1, "int abs_emu(int x) { return x * sign(x); }");
23     }
24 }
25 
InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator * emu,int targetGLSLVersion)26 void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
27                                                         int targetGLSLVersion)
28 {
29     // isnan() is supported since GLSL 1.3.
30     if (targetGLSLVersion < GLSL_VERSION_130)
31         return;
32 
33     // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
34     emu->addEmulatedFunction(
35         BuiltInId::isnan_Float1,
36         "bool isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
37     emu->addEmulatedFunction(
38         BuiltInId::isnan_Float2,
39         "bvec2 isnan_emu(vec2 x)\n"
40         "{\n"
41         "    bvec2 isnan;\n"
42         "    for (int i = 0; i < 2; i++)\n"
43         "    {\n"
44         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
45         "    }\n"
46         "    return isnan;\n"
47         "}\n");
48     emu->addEmulatedFunction(
49         BuiltInId::isnan_Float3,
50         "bvec3 isnan_emu(vec3 x)\n"
51         "{\n"
52         "    bvec3 isnan;\n"
53         "    for (int i = 0; i < 3; i++)\n"
54         "    {\n"
55         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
56         "    }\n"
57         "    return isnan;\n"
58         "}\n");
59     emu->addEmulatedFunction(
60         BuiltInId::isnan_Float4,
61         "bvec4 isnan_emu(vec4 x)\n"
62         "{\n"
63         "    bvec4 isnan;\n"
64         "    for (int i = 0; i < 4; i++)\n"
65         "    {\n"
66         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
67         "    }\n"
68         "    return isnan;\n"
69         "}\n");
70 }
71 
InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator * emu)72 void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu)
73 {
74     emu->addEmulatedFunction(BuiltInId::atan_Float1_Float1,
75                              "emu_precision float atan_emu(emu_precision float y, emu_precision "
76                              "float x)\n"
77                              "{\n"
78                              "    if (x > 0.0) return atan(y / x);\n"
79                              "    else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n"
80                              "    else if (x < 0.0 && y < 0.0) return atan(y / x) - 3.14159265;\n"
81                              "    else return 1.57079632 * sign(y);\n"
82                              "}\n");
83 
84     emu->addEmulatedFunctionWithDependency(
85         BuiltInId::atan_Float1_Float1, BuiltInId::atan_Float2_Float2,
86         "emu_precision vec2 atan_emu(emu_precision vec2 y, emu_precision vec2 x)\n"
87         "{\n"
88         "    return vec2(atan_emu(y[0], x[0]), atan_emu(y[1], x[1]));\n"
89         "}\n");
90 
91     emu->addEmulatedFunctionWithDependency(
92         BuiltInId::atan_Float1_Float1, BuiltInId::atan_Float3_Float3,
93         "emu_precision vec3 atan_emu(emu_precision vec3 y, emu_precision vec3 x)\n"
94         "{\n"
95         "    return vec3(atan_emu(y[0], x[0]), atan_emu(y[1], x[1]), atan_emu(y[2], x[2]));\n"
96         "}\n");
97 
98     emu->addEmulatedFunctionWithDependency(
99         BuiltInId::atan_Float1_Float1, BuiltInId::atan_Float4_Float4,
100         "emu_precision vec4 atan_emu(emu_precision vec4 y, emu_precision vec4 x)\n"
101         "{\n"
102         "    return vec4(atan_emu(y[0], x[0]), atan_emu(y[1], x[1]), atan_emu(y[2], x[2]), "
103         "atan_emu(y[3], x[3]))\n;"
104         "}\n");
105 }
106 
107 // Emulate built-in functions missing from GLSL 1.30 and higher
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator * emu,sh::GLenum shaderType,int targetGLSLVersion)108 void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu,
109                                                         sh::GLenum shaderType,
110                                                         int targetGLSLVersion)
111 {
112     // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
113     if (targetGLSLVersion < GLSL_VERSION_410)
114     {
115         // clang-format off
116         emu->addEmulatedFunction(BuiltInId::packUnorm2x16_Float2,
117             "uint packUnorm2x16_emu(vec2 v)\n"
118             "{\n"
119             "    int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n"
120             "    int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n"
121             "    return uint((y << 16) | (x & 0xFFFF));\n"
122             "}\n");
123 
124         emu->addEmulatedFunction(BuiltInId::unpackUnorm2x16_UInt1,
125             "vec2 unpackUnorm2x16_emu(uint u)\n"
126             "{\n"
127             "    float x = float(u & 0xFFFFu) / 65535.0;\n"
128             "    float y = float(u >> 16) / 65535.0;\n"
129             "    return vec2(x, y);\n"
130             "}\n");
131         // clang-format on
132     }
133 
134     // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
135     // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
136     if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
137     {
138         // clang-format off
139         emu->addEmulatedFunction(BuiltInId::packSnorm2x16_Float2,
140             "uint packSnorm2x16_emu(vec2 v)\n"
141             "{\n"
142             "    #if defined(GL_ARB_shading_language_packing)\n"
143             "        return packSnorm2x16(v);\n"
144             "    #else\n"
145             "        int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
146             "        int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
147             "        return uint((y << 16) | (x & 0xFFFF));\n"
148             "    #endif\n"
149             "}\n");
150         emu->addEmulatedFunction(BuiltInId::unpackSnorm2x16_UInt1,
151             "#if !defined(GL_ARB_shading_language_packing)\n"
152             "    float fromSnorm(uint x)\n"
153             "    {\n"
154             "        int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
155             "        return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
156             "    }\n"
157             "#endif\n"
158             "\n"
159             "vec2 unpackSnorm2x16_emu(uint u)\n"
160             "{\n"
161             "    #if defined(GL_ARB_shading_language_packing)\n"
162             "        return unpackSnorm2x16(u);\n"
163             "    #else\n"
164             "        uint y = (u >> 16);\n"
165             "        uint x = u;\n"
166             "        return vec2(fromSnorm(x), fromSnorm(y));\n"
167             "    #endif\n"
168             "}\n");
169         // Functions uint f32tof16(float val) and float f16tof32(uint val) are
170         // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
171         emu->addEmulatedFunction(BuiltInId::packHalf2x16_Float2,
172             "#if !defined(GL_ARB_shading_language_packing)\n"
173             "    uint f32tof16(float val)\n"
174             "    {\n"
175             "        uint f32 = floatBitsToUint(val);\n"
176             "        uint f16 = 0u;\n"
177             "        uint sign = (f32 >> 16) & 0x8000u;\n"
178             "        int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
179             "        uint mantissa = f32 & 0x007FFFFFu;\n"
180             "        if (exponent == 128)\n"
181             "        {\n"
182             "            // Infinity or NaN\n"
183             "            // NaN bits that are masked out by 0x3FF get discarded.\n"
184             "            // This can turn some NaNs to infinity, but this is allowed by the spec.\n"
185             "            f16 = sign | (0x1Fu << 10);\n"
186             "            f16 |= (mantissa & 0x3FFu);\n"
187             "        }\n"
188             "        else if (exponent > 15)\n"
189             "        {\n"
190             "            // Overflow - flush to Infinity\n"
191             "            f16 = sign | (0x1Fu << 10);\n"
192             "        }\n"
193             "        else if (exponent > -15)\n"
194             "        {\n"
195             "            // Representable value\n"
196             "            exponent += 15;\n"
197             "            mantissa >>= 13;\n"
198             "            f16 = sign | uint(exponent << 10) | mantissa;\n"
199             "        }\n"
200             "        else\n"
201             "        {\n"
202             "            f16 = sign;\n"
203             "        }\n"
204             "        return f16;\n"
205             "    }\n"
206             "#endif\n"
207             "\n"
208             "uint packHalf2x16_emu(vec2 v)\n"
209             "{\n"
210             "    #if defined(GL_ARB_shading_language_packing)\n"
211             "        return packHalf2x16(v);\n"
212             "    #else\n"
213             "        uint x = f32tof16(v.x);\n"
214             "        uint y = f32tof16(v.y);\n"
215             "        return (y << 16) | x;\n"
216             "    #endif\n"
217             "}\n");
218         emu->addEmulatedFunction(BuiltInId::unpackHalf2x16_UInt1,
219             "#if !defined(GL_ARB_shading_language_packing)\n"
220             "    float f16tof32(uint val)\n"
221             "    {\n"
222             "        uint sign = (val & 0x8000u) << 16;\n"
223             "        int exponent = int((val & 0x7C00u) >> 10);\n"
224             "        uint mantissa = val & 0x03FFu;\n"
225             "        float f32 = 0.0;\n"
226             "        if(exponent == 0)\n"
227             "        {\n"
228             "            if (mantissa != 0u)\n"
229             "            {\n"
230             "                const float scale = 1.0 / (1 << 24);\n"
231             "                f32 = scale * mantissa;\n"
232             "            }\n"
233             "        }\n"
234             "        else if (exponent == 31)\n"
235             "        {\n"
236             "            return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
237             "        }\n"
238             "        else\n"
239             "        {\n"
240             "            exponent -= 15;\n"
241             "            float scale;\n"
242             "            if(exponent < 0)\n"
243             "            {\n"
244             "                // The negative unary operator is buggy on OSX.\n"
245             "                // Work around this by using abs instead.\n"
246             "                scale = 1.0 / (1 << abs(exponent));\n"
247             "            }\n"
248             "            else\n"
249             "            {\n"
250             "                scale = 1 << exponent;\n"
251             "            }\n"
252             "            float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
253             "            f32 = scale * decimal;\n"
254             "        }\n"
255             "\n"
256             "        if (sign != 0u)\n"
257             "        {\n"
258             "            f32 = -f32;\n"
259             "        }\n"
260             "\n"
261             "        return f32;\n"
262             "    }\n"
263             "#endif\n"
264             "\n"
265             "vec2 unpackHalf2x16_emu(uint u)\n"
266             "{\n"
267             "    #if defined(GL_ARB_shading_language_packing)\n"
268             "        return unpackHalf2x16(u);\n"
269             "    #else\n"
270             "        uint y = (u >> 16);\n"
271             "        uint x = u & 0xFFFFu;\n"
272             "        return vec2(f16tof32(x), f16tof32(y));\n"
273             "    #endif\n"
274             "}\n");
275         // clang-format on
276     }
277 }
278 
279 }  // namespace sh
280