summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp166
1 files changed, 135 insertions, 31 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
index 098560d110..27ee04da35 100644
--- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -11,47 +11,147 @@
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
-void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
+namespace sh
{
- // we use macros here instead of function definitions to work around more GLSL
- // compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
- // problematic because if the argument has side-effects they will be repeatedly
- // evaluated. This is unlikely to show up in real shaders, but is something to
- // consider.
+
+void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType)
+{
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ const TType *int1 = TCache::getType(EbtInt);
+ emu->addEmulatedFunction(EOpAbs, int1, "int abs_emu(int x) { return x * sign(x); }");
+ }
+}
+
+void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ int targetGLSLVersion)
+{
+ // isnan() is supported since GLSL 1.3.
+ if (targetGLSLVersion < GLSL_VERSION_130)
+ return;
const TType *float1 = TCache::getType(EbtFloat);
const TType *float2 = TCache::getType(EbtFloat, 2);
const TType *float3 = TCache::getType(EbtFloat, 3);
const TType *float4 = TCache::getType(EbtFloat, 4);
- if (shaderType == GL_FRAGMENT_SHADER)
+ // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
+ emu->addEmulatedFunction(
+ EOpIsNan, float1,
+ "bool isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
+ emu->addEmulatedFunction(
+ EOpIsNan, float2,
+ "bvec2 isnan_emu(vec2 x)\n"
+ "{\n"
+ " bvec2 isnan;\n"
+ " for (int i = 0; i < 2; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+ emu->addEmulatedFunction(
+ EOpIsNan, float3,
+ "bvec3 isnan_emu(vec3 x)\n"
+ "{\n"
+ " bvec3 isnan;\n"
+ " for (int i = 0; i < 3; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+ emu->addEmulatedFunction(
+ EOpIsNan, float4,
+ "bvec4 isnan_emu(vec4 x)\n"
+ "{\n"
+ " bvec4 isnan;\n"
+ " for (int i = 0; i < 4; i++)\n"
+ " {\n"
+ " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
+ " }\n"
+ " return isnan;\n"
+ "}\n");
+}
+
+void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu)
+{
+ const TType *float1 = TCache::getType(EbtFloat);
+ auto floatFuncId = emu->addEmulatedFunction(
+ EOpAtan, float1, float1,
+ "emu_precision float atan_emu(emu_precision float y, emu_precision "
+ "float x)\n"
+ "{\n"
+ " if (x > 0.0) return atan(y / x);\n"
+ " else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n"
+ " else if (x < 0.0 && y < 0.0) return atan(y / x) - 3.14159265;\n"
+ " else return 1.57079632 * sign(y);\n"
+ "}\n");
+ for (int dim = 2; dim <= 4; ++dim)
{
- emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }");
- emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }");
- emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }");
- emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }");
+ const TType *floatVec = TCache::getType(EbtFloat, static_cast<unsigned char>(dim));
+ std::stringstream ss;
+ ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim
+ << " y, emu_precision vec" << dim << " x)\n"
+ << "{\n"
+ " return vec"
+ << dim << "(";
+ for (int i = 0; i < dim; ++i)
+ {
+ ss << "atan_emu(y[" << i << "], x[" << i << "])";
+ if (i < dim - 1)
+ {
+ ss << ", ";
+ }
+ }
+ ss << ");\n"
+ "}\n";
+ emu->addEmulatedFunctionWithDependency(floatFuncId, EOpAtan, floatVec, floatVec,
+ ss.str().c_str());
}
- emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))");
- emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))");
- emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))");
- emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))");
- emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
}
// Emulate built-in functions missing from GLSL 1.30 and higher
-void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
+void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType,
int targetGLSLVersion)
{
+ // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
+ if (targetGLSLVersion < GLSL_VERSION_410)
+ {
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *uint1 = TCache::getType(EbtUInt);
+
+ // clang-format off
+ emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
+ "uint packUnorm2x16_emu(vec2 v)\n"
+ "{\n"
+ " int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n"
+ " int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n"
+ " return uint((y << 16) | (x & 0xFFFF));\n"
+ "}\n");
+
+ emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1,
+ "vec2 unpackUnorm2x16_emu(uint u)\n"
+ "{\n"
+ " float x = float(u & 0xFFFFu) / 65535.0;\n"
+ " float y = float(u >> 16) / 65535.0;\n"
+ " return vec2(x, y);\n"
+ "}\n");
+ // clang-format on
+ }
+
// Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
// by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
{
const TType *float2 = TCache::getType(EbtFloat, 2);
- const TType *uint1 = TCache::getType(EbtUInt);
+ const TType *uint1 = TCache::getType(EbtUInt);
// clang-format off
emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
- "uint webgl_packSnorm2x16_emu(vec2 v)\n"
+ "uint packSnorm2x16_emu(vec2 v)\n"
"{\n"
" #if defined(GL_ARB_shading_language_packing)\n"
" return packSnorm2x16(v);\n"
@@ -63,28 +163,28 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
"}\n");
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"#if !defined(GL_ARB_shading_language_packing)\n"
- " float webgl_fromSnorm(uint x)\n"
+ " float fromSnorm(uint x)\n"
" {\n"
" int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
" return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
" }\n"
"#endif\n"
"\n"
- "vec2 webgl_unpackSnorm2x16_emu(uint u)\n"
+ "vec2 unpackSnorm2x16_emu(uint u)\n"
"{\n"
" #if defined(GL_ARB_shading_language_packing)\n"
" return unpackSnorm2x16(u);\n"
" #else\n"
" uint y = (u >> 16);\n"
" uint x = u;\n"
- " return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+ " return vec2(fromSnorm(x), fromSnorm(y));\n"
" #endif\n"
"}\n");
- // Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
+ // Functions uint f32tof16(float val) and float f16tof32(uint val) are
// based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
emu->addEmulatedFunction(EOpPackHalf2x16, float2,
"#if !defined(GL_ARB_shading_language_packing)\n"
- " uint webgl_f32tof16(float val)\n"
+ " uint f32tof16(float val)\n"
" {\n"
" uint f32 = floatBitsToUint(val);\n"
" uint f16 = 0u;\n"
@@ -119,19 +219,19 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
" }\n"
"#endif\n"
"\n"
- "uint webgl_packHalf2x16_emu(vec2 v)\n"
+ "uint packHalf2x16_emu(vec2 v)\n"
"{\n"
" #if defined(GL_ARB_shading_language_packing)\n"
" return packHalf2x16(v);\n"
" #else\n"
- " uint x = webgl_f32tof16(v.x);\n"
- " uint y = webgl_f32tof16(v.y);\n"
+ " uint x = f32tof16(v.x);\n"
+ " uint y = f32tof16(v.y);\n"
" return (y << 16) | x;\n"
" #endif\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
"#if !defined(GL_ARB_shading_language_packing)\n"
- " float webgl_f16tof32(uint val)\n"
+ " float f16tof32(uint val)\n"
" {\n"
" uint sign = (val & 0x8000u) << 16;\n"
" int exponent = int((val & 0x7C00u) >> 10);\n"
@@ -155,7 +255,9 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
" float scale;\n"
" if(exponent < 0)\n"
" {\n"
- " scale = 1.0 / (1 << -exponent);\n"
+ " // The negative unary operator is buggy on OSX.\n"
+ " // Work around this by using abs instead.\n"
+ " scale = 1.0 / (1 << abs(exponent));\n"
" }\n"
" else\n"
" {\n"
@@ -174,16 +276,18 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
" }\n"
"#endif\n"
"\n"
- "vec2 webgl_unpackHalf2x16_emu(uint u)\n"
+ "vec2 unpackHalf2x16_emu(uint u)\n"
"{\n"
" #if defined(GL_ARB_shading_language_packing)\n"
" return unpackHalf2x16(u);\n"
" #else\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xFFFFu;\n"
- " return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
+ " return vec2(f16tof32(x), f16tof32(y));\n"
" #endif\n"
"}\n");
// clang-format on
}
}
+
+} // namespace sh