Commit 6f0a0dca by Shao Committed by Commit Bot

Workaround isnan() on Intel drivers

On some Intel drivers, calling function isnan() on highp float will get wrong answer. This patch work arounds this bug by using an expression to emulate this function. BUG=chromium:650547 Change-Id: I5bc5e0352c434f42cd2c55103a74f9f7ba51a72c Reviewed-on: https://chromium-review.googlesource.com/389834 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 42fad76d
......@@ -49,7 +49,7 @@ typedef unsigned int GLenum;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 161
#define ANGLE_SH_VERSION 162
typedef enum {
SH_GLES2_SPEC,
......@@ -204,6 +204,10 @@ const ShCompileOptions SH_ADD_AND_TRUE_TO_LOOP_CONDITION = UINT64_C(1) << 25;
// drivers. It works by translating -(int) into ~(int) + 1.
const ShCompileOptions SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR = UINT64_C(1) << 26;
// This flag works around a bug in evaluating isnan() on some INTEL D3D and Mac OSX drivers.
// It works by using an expression to emulate this function.
const ShCompileOptions SH_EMULATE_ISNAN_FLOAT_FUNCTION = UINT64_C(1) << 27;
// Defines alternate strategies for implementing array index clamping.
typedef enum {
// Use the clamp intrinsic for array index clamping.
......
......@@ -21,6 +21,57 @@ void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *e
}
}
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);
// !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
emu->addEmulatedFunction(
EOpIsNan, float1,
"bool webgl_isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
emu->addEmulatedFunction(
EOpIsNan, float2,
"bvec2 webgl_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 webgl_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 webgl_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");
}
// Emulate built-in functions missing from GLSL 1.30 and higher
void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
int targetGLSLVersion)
......
......@@ -18,6 +18,12 @@ void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *e
sh::GLenum shaderType);
//
// This works around isnan() bug in Intel Mac drivers
//
void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion);
//
// This function is emulating built-in functions missing from GLSL 1.30 and higher.
//
void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
......
......@@ -8,6 +8,59 @@
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion)
{
if (targetGLSLVersion < GLSL_VERSION_130)
return;
TType *float1 = new TType(EbtFloat);
TType *float2 = new TType(EbtFloat, 2);
TType *float3 = new TType(EbtFloat, 3);
TType *float4 = new TType(EbtFloat, 4);
emu->addEmulatedFunction(EOpIsNan, float1,
"bool webgl_isnan_emu(float x)\n"
"{\n"
" return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpIsNan, float2,
"bool2 webgl_isnan_emu(float2 x)\n"
"{\n"
" bool2 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,
"bool3 webgl_isnan_emu(float3 x)\n"
"{\n"
" bool3 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,
"bool4 webgl_isnan_emu(float4 x)\n"
"{\n"
" bool4 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 InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
{
......
......@@ -13,4 +13,10 @@ class BuiltInFunctionEmulator;
void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu);
//
// This works around isnan() bug on some Intel drivers.
//
void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion);
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_
......@@ -161,6 +161,12 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
BuiltInFunctionEmulator builtInFunctionEmulator;
InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
{
InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
mShaderVersion);
}
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
// Now that we are done changing the AST, do the analyses need for HLSL generation
......@@ -1299,9 +1305,12 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
outputTriplet(out, visit, "frac(", "", ")");
break;
case EOpIsNan:
outputTriplet(out, visit, "isnan(", "", ")");
mRequiresIEEEStrictCompiling = true;
break;
if (node->getUseEmulatedFunction())
writeEmulatedFunctionTriplet(out, visit, "isnan(");
else
outputTriplet(out, visit, "isnan(", "", ")");
mRequiresIEEEStrictCompiling = true;
break;
case EOpIsInf:
outputTriplet(out, visit, "isinf(", "", ")");
break;
......
......@@ -28,6 +28,11 @@ void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
}
if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION)
{
InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion());
}
int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
}
......
......@@ -63,6 +63,10 @@ ShaderD3D::ShaderD3D(const gl::ShaderState &data, const WorkaroundsD3D &workarou
{
mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR;
}
if (workarounds.emulateIsnanFloat)
{
mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
}
}
ShaderD3D::~ShaderD3D()
......
......@@ -89,6 +89,11 @@ struct WorkaroundsD3D
// On some Intel drivers, evaluating unary minus operator on integer may get wrong answer in
// vertex shaders. To work around this bug, we translate -(int) into ~(int)+1.
bool rewriteUnaryMinusOperator = false;
// On some Intel drivers, using isnan() on highp float will get wrong answer. To work around
// this bug, we use an expression to emulate function isnan(). Tracking bug:
// https://crbug.com/650547
bool emulateIsnanFloat = false;
};
} // namespace rx
......
......@@ -1543,6 +1543,7 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps,
workarounds.preAddTexelFetchOffsets = (adapterDesc.VendorId == VENDOR_ID_INTEL);
workarounds.disableB5G6R5Support = (adapterDesc.VendorId == VENDOR_ID_INTEL);
workarounds.rewriteUnaryMinusOperator = (adapterDesc.VendorId == VENDOR_ID_INTEL);
workarounds.emulateIsnanFloat = (adapterDesc.VendorId == VENDOR_ID_INTEL);
// TODO(jmadill): Disable when we have a fixed driver version.
workarounds.emulateTinyStencilTextures = (adapterDesc.VendorId == VENDOR_ID_AMD);
......
......@@ -65,6 +65,11 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(std::stringstream *sour
options |= SH_ADD_AND_TRUE_TO_LOOP_CONDITION;
}
if (mWorkarounds.emulateIsnanFloat)
{
options |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
}
return options;
}
......
......@@ -23,7 +23,8 @@ struct WorkaroundsGL
alwaysCallUseProgramAfterLink(false),
unpackOverlappingRowsSeparatelyUnpackBuffer(false),
emulateAbsIntFunction(false),
addAndTrueToLoopCondition(false)
addAndTrueToLoopCondition(false),
emulateIsnanFloat(false)
{
}
......@@ -96,8 +97,14 @@ struct WorkaroundsGL
// The last pixel read will be A, but the driver will think it is B, causing it to generate an
// error when the pixel buffer is just big enough.
bool unpackLastRowSeparatelyForPaddingInclusion;
// Equivalent workaround when uploading data from a pixel pack buffer.
bool packLastRowSeparatelyForPaddingInclusion;
// On some Intel drivers, using isnan() on highp float will get wrong answer. To work around
// this bug, we use an expression to emulate function isnan().
// Tracking bug: http://crbug.com/650547
bool emulateIsnanFloat;
};
}
......
......@@ -885,6 +885,8 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
workarounds->addAndTrueToLoopCondition = vendor == VENDOR_ID_INTEL;
workarounds->emulateIsnanFloat = vendor == VENDOR_ID_INTEL;
workarounds->doesSRGBClearsOnLinearFramebufferAttachments =
functions->standard == STANDARD_GL_DESKTOP &&
(vendor == VENDOR_ID_INTEL || vendor == VENDOR_ID_AMD);
......
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