Commit 7b9b284b by Geoff Lang

Refactor GLSL version calculations for emulated functions.

Pass the target GLSL version to InitBuiltInFunctionEmulatorForGLSL so that it can be updated to generate emulated functions for multiple versions. BUG=angleproject:1044 Change-Id: I34c408df52fd0f7d6c2f66d0579ac854afd93b87 Reviewed-on: https://chromium-review.googlesource.com/277700Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 12425d25
......@@ -8,8 +8,9 @@
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
{
// 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
......@@ -36,72 +37,76 @@ void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum
emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
}
// emulate built-in functions missing from OpenGL 4.1
void InitBuiltInFunctionEmulatorForGLSL4_1(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
// Emulate built-in functions missing from GLSL 1.30 and higher
void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
int targetGLSLVersion)
{
TType *float2 = new TType(EbtFloat, 2);
TType *uint1 = new TType(EbtUInt);
if (targetGLSLVersion == GLSL_VERSION_410)
{
TType *float2 = new TType(EbtFloat, 2);
TType *uint1 = new TType(EbtUInt);
emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
"uint webgl_packSnorm2x16_emu(vec2 v){\n"
" int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
" int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
" return uint((y << 16) | (x & 0xffff));\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm(uint x){\n"
" int xi = (int(x) & 0x7fff) - (int(x) & 0x8000);\n"
" return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
"}\n"
"vec2 webgl_unpackSnorm2x16_emu(uint u){\n"
" uint y = (u >> 16);\n"
" uint x = u;\n"
" return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
"}\n");
// Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
// based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
emu->addEmulatedFunction(EOpPackHalf2x16, float2,
"uint webgl_f32tof16(float val){\n"
" uint f32 = floatBitsToInt(val);\n"
" uint f16 = 0;\n"
" uint sign = (f32 >> 16) & 0x8000u;\n"
" int exponent = int((f32 >> 23) & 0xff) - 127;\n"
" uint mantissa = f32 & 0x007fffffu;\n"
" if (exponent == 128) { /* Infinity or NaN */\n"
" // NaN bits that are masked out by 0x3ff get discarded. This can turn some NaNs to infinity, but this is allowed by the spec.\n"
" f16 = sign | (0x1F << 10); f16 |= (mantissa & 0x3ff);\n"
" }\n"
" else if (exponent > 15) { /* Overflow - flush to Infinity */ f16 = sign | (0x1F << 10); }\n"
" else if (exponent > -15) { /* Representable value */ exponent += 15; mantissa >>= 13; f16 = sign | exponent << 10 | mantissa; }\n"
" else { f16 = sign; }\n"
" return f16;\n"
"}\n"
"uint webgl_packHalf2x16_emu(vec2 v){\n"
" uint x = webgl_f32tof16(v.x);\n"
" uint y = webgl_f32tof16(v.y);\n"
" return (y << 16) | x;\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
"float webgl_f16tof32(uint val){\n"
" uint sign = (val & 0x8000u) << 16;\n"
" int exponent = int((val & 0x7c00) >> 10);\n"
" uint mantissa = val & 0x03ffu;\n"
" float f32 = 0.0;\n"
" if(exponent == 0) { if (mantissa != 0) { const float scale = 1.0 / (1 << 24); f32 = scale * mantissa; } }\n"
" else if (exponent == 31) { return uintBitsToFloat(sign | 0x7f800000 | mantissa); }\n"
" else{\n"
" float scale, decimal; exponent -= 15;\n"
" if(exponent < 0) { scale = 1.0 / (1 << -exponent); }\n"
" else { scale = 1 << exponent; }\n"
" decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
" f32 = scale * decimal;\n"
" }\n"
" if (sign != 0) f32 = -f32;\n"
" return f32;\n"
"}\n"
"vec2 webgl_unpackHalf2x16_emu(uint u){\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
"}\n");
emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
"uint webgl_packSnorm2x16_emu(vec2 v){\n"
" int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
" int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
" return uint((y << 16) | (x & 0xffff));\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm(uint x){\n"
" int xi = (int(x) & 0x7fff) - (int(x) & 0x8000);\n"
" return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
"}\n"
"vec2 webgl_unpackSnorm2x16_emu(uint u){\n"
" uint y = (u >> 16);\n"
" uint x = u;\n"
" return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
"}\n");
// Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
// based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
emu->addEmulatedFunction(EOpPackHalf2x16, float2,
"uint webgl_f32tof16(float val){\n"
" uint f32 = floatBitsToInt(val);\n"
" uint f16 = 0;\n"
" uint sign = (f32 >> 16) & 0x8000u;\n"
" int exponent = int((f32 >> 23) & 0xff) - 127;\n"
" uint mantissa = f32 & 0x007fffffu;\n"
" if (exponent == 128) { /* Infinity or NaN */\n"
" // NaN bits that are masked out by 0x3ff get discarded. This can turn some NaNs to infinity, but this is allowed by the spec.\n"
" f16 = sign | (0x1F << 10); f16 |= (mantissa & 0x3ff);\n"
" }\n"
" else if (exponent > 15) { /* Overflow - flush to Infinity */ f16 = sign | (0x1F << 10); }\n"
" else if (exponent > -15) { /* Representable value */ exponent += 15; mantissa >>= 13; f16 = sign | exponent << 10 | mantissa; }\n"
" else { f16 = sign; }\n"
" return f16;\n"
"}\n"
"uint webgl_packHalf2x16_emu(vec2 v){\n"
" uint x = webgl_f32tof16(v.x);\n"
" uint y = webgl_f32tof16(v.y);\n"
" return (y << 16) | x;\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
"float webgl_f16tof32(uint val){\n"
" uint sign = (val & 0x8000u) << 16;\n"
" int exponent = int((val & 0x7c00) >> 10);\n"
" uint mantissa = val & 0x03ffu;\n"
" float f32 = 0.0;\n"
" if(exponent == 0) { if (mantissa != 0) { const float scale = 1.0 / (1 << 24); f32 = scale * mantissa; } }\n"
" else if (exponent == 31) { return uintBitsToFloat(sign | 0x7f800000 | mantissa); }\n"
" else{\n"
" float scale, decimal; exponent -= 15;\n"
" if(exponent < 0) { scale = 1.0 / (1 << -exponent); }\n"
" else { scale = 1 << exponent; }\n"
" decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
" f32 = scale * decimal;\n"
" }\n"
" if (sign != 0) f32 = -f32;\n"
" return f32;\n"
"}\n"
"vec2 webgl_unpackHalf2x16_emu(uint u){\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
"}\n");
}
}
......@@ -14,11 +14,12 @@ class BuiltInFunctionEmulator;
//
// This is only a workaround for OpenGL driver bugs, and isn't needed in general.
//
void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
//
// This function is emulating built-in functions missing from OpenGL 4.1.
// This function is emulating built-in functions missing from GLSL 1.30 and higher.
//
void InitBuiltInFunctionEmulatorForGLSL4_1(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
int targetGLSLVersion);
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
......@@ -20,7 +20,9 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
{
InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
}
}
void TranslatorESSL::translate(TIntermNode *root, int) {
......
......@@ -66,9 +66,12 @@ TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
if (getOutputType() == SH_GLSL_410_CORE_OUTPUT)
InitBuiltInFunctionEmulatorForGLSL4_1(emu, getShaderType());
{
InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
}
int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
}
void TranslatorGLSL::translate(TIntermNode *root, int) {
......
......@@ -6,11 +6,17 @@
#include "compiler/translator/VersionGLSL.h"
static const int GLSL_VERSION_110 = 110;
static const int GLSL_VERSION_120 = 120;
static const int GLSL_VERSION_130 = 130;
static const int GLSL_VERSION_410 = 410;
static const int GLSL_VERSION_420 = 420;
int ShaderOutputTypeToGLSLVersion(ShShaderOutput output)
{
switch (output)
{
case SH_GLSL_130_OUTPUT: return GLSL_VERSION_130;
case SH_GLSL_410_CORE_OUTPUT: return GLSL_VERSION_410;
case SH_GLSL_420_CORE_OUTPUT: return GLSL_VERSION_420;
case SH_GLSL_COMPATIBILITY_OUTPUT: return GLSL_VERSION_110;
default: UNREACHABLE(); return 0;
}
}
// We need to scan for the following:
// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
......@@ -34,32 +40,19 @@ TVersionGLSL::TVersionGLSL(sh::GLenum type,
ShShaderOutput output)
: TIntermTraverser(true, false, false)
{
if (output == SH_GLSL_130_OUTPUT)
{
mVersion = GLSL_VERSION_130;
}
else if (output == SH_GLSL_410_CORE_OUTPUT)
mVersion = ShaderOutputTypeToGLSLVersion(output);
if (pragma.stdgl.invariantAll)
{
mVersion = GLSL_VERSION_410;
}
else if (output == SH_GLSL_420_CORE_OUTPUT)
{
mVersion = GLSL_VERSION_420;
}
else
{
ASSERT(output == SH_GLSL_COMPATIBILITY_OUTPUT);
if (pragma.stdgl.invariantAll)
mVersion = GLSL_VERSION_120;
else
mVersion = GLSL_VERSION_110;
ensureVersionIsAtLeast(GLSL_VERSION_120);
}
}
void TVersionGLSL::visitSymbol(TIntermSymbol *node)
{
if (node->getSymbol() == "gl_PointCoord")
updateVersion(GLSL_VERSION_120);
{
ensureVersionIsAtLeast(GLSL_VERSION_120);
}
}
bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
......@@ -77,12 +70,12 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
const TIntermSequence &sequence = *(node->getSequence());
if (sequence.front()->getAsTyped()->getType().isInvariant())
{
updateVersion(GLSL_VERSION_120);
ensureVersionIsAtLeast(GLSL_VERSION_120);
}
break;
}
case EOpInvariantDeclaration:
updateVersion(GLSL_VERSION_120);
ensureVersionIsAtLeast(GLSL_VERSION_120);
break;
case EOpParameters:
{
......@@ -96,7 +89,7 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
TQualifier qualifier = param->getQualifier();
if ((qualifier == EvqOut) || (qualifier == EvqInOut))
{
updateVersion(GLSL_VERSION_120);
ensureVersionIsAtLeast(GLSL_VERSION_120);
break;
}
}
......@@ -115,7 +108,7 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
TIntermTyped *typed = sequence.front()->getAsTyped();
if (typed && typed->isMatrix())
{
updateVersion(GLSL_VERSION_120);
ensureVersionIsAtLeast(GLSL_VERSION_120);
}
}
break;
......@@ -127,7 +120,7 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
return visitChildren;
}
void TVersionGLSL::updateVersion(int version)
void TVersionGLSL::ensureVersionIsAtLeast(int version)
{
mVersion = std::max(version, mVersion);
}
......
......@@ -11,6 +11,14 @@
#include "compiler/translator/Pragma.h"
static const int GLSL_VERSION_110 = 110;
static const int GLSL_VERSION_120 = 120;
static const int GLSL_VERSION_130 = 130;
static const int GLSL_VERSION_410 = 410;
static const int GLSL_VERSION_420 = 420;
int ShaderOutputTypeToGLSLVersion(ShShaderOutput output);
// Traverses the intermediate tree to return the minimum GLSL version
// required to legally access all built-in features used in the shader.
// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
......@@ -39,15 +47,14 @@ class TVersionGLSL : public TIntermTraverser
// - matrix/matrix constructors
// - array "out" parameters
// Else 110 is returned.
int getVersion() { return mVersion; }
int getVersion() const { return mVersion; }
virtual void visitSymbol(TIntermSymbol *);
virtual bool visitAggregate(Visit, TIntermAggregate *);
protected:
void updateVersion(int version);
private:
void ensureVersionIsAtLeast(int version);
int mVersion;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment