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