• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/BuiltInFunctionEmulatorGLSL.h"
8 
9 #include "angle_gl.h"
10 #include "compiler/translator/BuiltInFunctionEmulator.h"
11 #include "compiler/translator/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     static const std::array<TSymbolUniqueId, 4> ids = {
84         BuiltInId::atan_Float1_Float1,
85         BuiltInId::atan_Float2_Float2,
86         BuiltInId::atan_Float3_Float3,
87         BuiltInId::atan_Float4_Float4,
88     };
89     for (int dim = 2; dim <= 4; ++dim)
90     {
91         std::stringstream ss = sh::InitializeStream<std::stringstream>();
92         ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim
93            << " y, emu_precision vec" << dim << " x)\n"
94            << "{\n"
95               "    return vec"
96            << dim << "(";
97         for (int i = 0; i < dim; ++i)
98         {
99             ss << "atan_emu(y[" << i << "], x[" << i << "])";
100             if (i < dim - 1)
101             {
102                 ss << ", ";
103             }
104         }
105         ss << ");\n"
106               "}\n";
107         emu->addEmulatedFunctionWithDependency(BuiltInId::atan_Float1_Float1, ids[dim - 1],
108                                                ss.str().c_str());
109     }
110 }
111 
112 // Emulate built-in functions missing from GLSL 1.30 and higher
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator * emu,sh::GLenum shaderType,int targetGLSLVersion)113 void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu,
114                                                         sh::GLenum shaderType,
115                                                         int targetGLSLVersion)
116 {
117     // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
118     if (targetGLSLVersion < GLSL_VERSION_410)
119     {
120         // clang-format off
121         emu->addEmulatedFunction(BuiltInId::packUnorm2x16_Float2,
122             "uint packUnorm2x16_emu(vec2 v)\n"
123             "{\n"
124             "    int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n"
125             "    int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n"
126             "    return uint((y << 16) | (x & 0xFFFF));\n"
127             "}\n");
128 
129         emu->addEmulatedFunction(BuiltInId::unpackUnorm2x16_UInt1,
130             "vec2 unpackUnorm2x16_emu(uint u)\n"
131             "{\n"
132             "    float x = float(u & 0xFFFFu) / 65535.0;\n"
133             "    float y = float(u >> 16) / 65535.0;\n"
134             "    return vec2(x, y);\n"
135             "}\n");
136         // clang-format on
137     }
138 
139     // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
140     // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
141     if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
142     {
143         // clang-format off
144         emu->addEmulatedFunction(BuiltInId::packSnorm2x16_Float2,
145             "uint packSnorm2x16_emu(vec2 v)\n"
146             "{\n"
147             "    #if defined(GL_ARB_shading_language_packing)\n"
148             "        return packSnorm2x16(v);\n"
149             "    #else\n"
150             "        int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
151             "        int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
152             "        return uint((y << 16) | (x & 0xFFFF));\n"
153             "    #endif\n"
154             "}\n");
155         emu->addEmulatedFunction(BuiltInId::unpackSnorm2x16_UInt1,
156             "#if !defined(GL_ARB_shading_language_packing)\n"
157             "    float fromSnorm(uint x)\n"
158             "    {\n"
159             "        int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
160             "        return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
161             "    }\n"
162             "#endif\n"
163             "\n"
164             "vec2 unpackSnorm2x16_emu(uint u)\n"
165             "{\n"
166             "    #if defined(GL_ARB_shading_language_packing)\n"
167             "        return unpackSnorm2x16(u);\n"
168             "    #else\n"
169             "        uint y = (u >> 16);\n"
170             "        uint x = u;\n"
171             "        return vec2(fromSnorm(x), fromSnorm(y));\n"
172             "    #endif\n"
173             "}\n");
174         // Functions uint f32tof16(float val) and float f16tof32(uint val) are
175         // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
176         emu->addEmulatedFunction(BuiltInId::packHalf2x16_Float2,
177             "#if !defined(GL_ARB_shading_language_packing)\n"
178             "    uint f32tof16(float val)\n"
179             "    {\n"
180             "        uint f32 = floatBitsToUint(val);\n"
181             "        uint f16 = 0u;\n"
182             "        uint sign = (f32 >> 16) & 0x8000u;\n"
183             "        int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
184             "        uint mantissa = f32 & 0x007FFFFFu;\n"
185             "        if (exponent == 128)\n"
186             "        {\n"
187             "            // Infinity or NaN\n"
188             "            // NaN bits that are masked out by 0x3FF get discarded.\n"
189             "            // This can turn some NaNs to infinity, but this is allowed by the spec.\n"
190             "            f16 = sign | (0x1Fu << 10);\n"
191             "            f16 |= (mantissa & 0x3FFu);\n"
192             "        }\n"
193             "        else if (exponent > 15)\n"
194             "        {\n"
195             "            // Overflow - flush to Infinity\n"
196             "            f16 = sign | (0x1Fu << 10);\n"
197             "        }\n"
198             "        else if (exponent > -15)\n"
199             "        {\n"
200             "            // Representable value\n"
201             "            exponent += 15;\n"
202             "            mantissa >>= 13;\n"
203             "            f16 = sign | uint(exponent << 10) | mantissa;\n"
204             "        }\n"
205             "        else\n"
206             "        {\n"
207             "            f16 = sign;\n"
208             "        }\n"
209             "        return f16;\n"
210             "    }\n"
211             "#endif\n"
212             "\n"
213             "uint packHalf2x16_emu(vec2 v)\n"
214             "{\n"
215             "    #if defined(GL_ARB_shading_language_packing)\n"
216             "        return packHalf2x16(v);\n"
217             "    #else\n"
218             "        uint x = f32tof16(v.x);\n"
219             "        uint y = f32tof16(v.y);\n"
220             "        return (y << 16) | x;\n"
221             "    #endif\n"
222             "}\n");
223         emu->addEmulatedFunction(BuiltInId::unpackHalf2x16_UInt1,
224             "#if !defined(GL_ARB_shading_language_packing)\n"
225             "    float f16tof32(uint val)\n"
226             "    {\n"
227             "        uint sign = (val & 0x8000u) << 16;\n"
228             "        int exponent = int((val & 0x7C00u) >> 10);\n"
229             "        uint mantissa = val & 0x03FFu;\n"
230             "        float f32 = 0.0;\n"
231             "        if(exponent == 0)\n"
232             "        {\n"
233             "            if (mantissa != 0u)\n"
234             "            {\n"
235             "                const float scale = 1.0 / (1 << 24);\n"
236             "                f32 = scale * mantissa;\n"
237             "            }\n"
238             "        }\n"
239             "        else if (exponent == 31)\n"
240             "        {\n"
241             "            return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
242             "        }\n"
243             "        else\n"
244             "        {\n"
245             "            exponent -= 15;\n"
246             "            float scale;\n"
247             "            if(exponent < 0)\n"
248             "            {\n"
249             "                // The negative unary operator is buggy on OSX.\n"
250             "                // Work around this by using abs instead.\n"
251             "                scale = 1.0 / (1 << abs(exponent));\n"
252             "            }\n"
253             "            else\n"
254             "            {\n"
255             "                scale = 1 << exponent;\n"
256             "            }\n"
257             "            float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
258             "            f32 = scale * decimal;\n"
259             "        }\n"
260             "\n"
261             "        if (sign != 0u)\n"
262             "        {\n"
263             "            f32 = -f32;\n"
264             "        }\n"
265             "\n"
266             "        return f32;\n"
267             "    }\n"
268             "#endif\n"
269             "\n"
270             "vec2 unpackHalf2x16_emu(uint u)\n"
271             "{\n"
272             "    #if defined(GL_ARB_shading_language_packing)\n"
273             "        return unpackHalf2x16(u);\n"
274             "    #else\n"
275             "        uint y = (u >> 16);\n"
276             "        uint x = u & 0xFFFFu;\n"
277             "        return vec2(f16tof32(x), f16tof32(y));\n"
278             "    #endif\n"
279             "}\n");
280         // clang-format on
281     }
282 }
283 
284 }  // namespace sh
285