Add workaround flag for color space transform math on Mali G GPUs
This will let us use GrGLColorSpaceXform in place of GrSRGBEffect.
Change-Id: I478cde3cf5009e4af97056fbc733ac0ee0ba7785
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/279139
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp
index 049d823..7837601 100644
--- a/src/gpu/GrShaderCaps.cpp
+++ b/src/gpu/GrShaderCaps.cpp
@@ -56,6 +56,7 @@
fFloatIs32Bits = true;
fHalfIs32Bits = false;
fHasLowFragmentPrecision = false;
+ fColorSpaceMathNeedsFloat = false;
// Backed API support is required to be able to make swizzle-neutral shaders (e.g.
// GL_ARB_texture_swizzle).
fTextureSwizzleAppliedInShader = true;
@@ -138,6 +139,7 @@
writer->appendBool("float == fp32", fFloatIs32Bits);
writer->appendBool("half == fp32", fHalfIs32Bits);
writer->appendBool("Has poor fragment precision", fHasLowFragmentPrecision);
+ writer->appendBool("Color space math needs float", fColorSpaceMathNeedsFloat);
writer->appendBool("Texture swizzle applied in shader", fTextureSwizzleAppliedInShader);
writer->appendBool("Builtin fma() support", fBuiltinFMASupport);
diff --git a/src/gpu/GrShaderCaps.h b/src/gpu/GrShaderCaps.h
index 2563d66..b6a3cc0 100644
--- a/src/gpu/GrShaderCaps.h
+++ b/src/gpu/GrShaderCaps.h
@@ -128,6 +128,8 @@
// required by the spec. SKSL will always emit full ints.
bool incompleteShortIntPrecision() const { return fIncompleteShortIntPrecision; }
+ bool colorSpaceMathNeedsFloat() const { return fColorSpaceMathNeedsFloat; }
+
// If true, then conditions in for loops need "&& true" to work around driver bugs.
bool addAndTrueToLoopCondition() const { return fAddAndTrueToLoopCondition; }
@@ -298,6 +300,7 @@
bool fMustWriteToFragColor : 1;
bool fNoDefaultPrecisionForExternalSamplers : 1;
bool fCanOnlyUseSampleMaskWithStencil : 1;
+ bool fColorSpaceMathNeedsFloat : 1;
const char* fVersionDeclString;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 18c9657..06f37e2 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -3600,6 +3600,14 @@
if (kMaliT_GrGLRenderer == ctxInfo.renderer()) {
shaderCaps->fMustObfuscateUniformColor = true;
}
+
+ // On Mali G series GPUs, applying transfer functions in the fragment shader with half-floats
+ // produces answers that are much less accurate than expected/required. This forces full floats
+ // for some intermediate values to get acceptable results.
+ if (kMaliG_GrGLRenderer == ctxInfo.renderer()) {
+ fShaderCaps->fColorSpaceMathNeedsFloat = true;
+ }
+
#ifdef SK_BUILD_FOR_WIN
// Check for ANGLE on Windows, so we can workaround a bug in D3D itself (anglebug.com/2098).
//
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index a132c46..e04e4af 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -512,6 +512,10 @@
if (strstr(rendererString, "llvmpipe")) {
return kGalliumLLVM_GrGLRenderer;
}
+ static const char kMaliGStr[] = "Mali-G";
+ if (0 == strncmp(rendererString, kMaliGStr, SK_ARRAY_COUNT(kMaliGStr) - 1)) {
+ return kMaliG_GrGLRenderer;
+ }
static const char kMaliTStr[] = "Mali-T";
if (0 == strncmp(rendererString, kMaliTStr, SK_ARRAY_COUNT(kMaliTStr) - 1)) {
return kMaliT_GrGLRenderer;
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index d9172e6..921f0d5 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -91,6 +91,8 @@
kGalliumLLVM_GrGLRenderer,
kMali4xx_GrGLRenderer,
+ /** G-7x */
+ kMaliG_GrGLRenderer,
/** T-6xx, T-7xx, or T-8xx */
kMaliT_GrGLRenderer,
kANGLE_GrGLRenderer,
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
index 42ac1eb..95f97fe 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
@@ -188,29 +188,37 @@
// Now define a wrapper function that applies all the intermediate steps
{
- const GrShaderVar gColorXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) };
+ // Some GPUs require full float to get results that are as accurate as expected/required.
+ // Most GPUs work just fine with half float. Strangely, the GPUs that have this bug
+ // (Mali G series) only require us to promote the type of a few temporaries here --
+ // the helper functions above can always be written to use half.
+ bool useFloat = fProgramBuilder->shaderCaps()->colorSpaceMathNeedsFloat();
+
+ const GrShaderVar gColorXformArgs[] = {
+ GrShaderVar("color", useFloat ? kFloat4_GrSLType : kHalf4_GrSLType)};
SkString body;
if (colorXformHelper->applyUnpremul()) {
- body.append("half nonZeroAlpha = max(color.a, 0.0001);");
- body.append("color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha);");
+ body.appendf("%s nonZeroAlpha = max(color.a, 0.0001);", useFloat ? "float" : "half");
+ body.appendf("color = %s(color.rgb / nonZeroAlpha, nonZeroAlpha);",
+ useFloat ? "float4" : "half4");
}
if (colorXformHelper->applySrcTF()) {
- body.appendf("color.r = %s(color.r);", srcTFFuncName.c_str());
- body.appendf("color.g = %s(color.g);", srcTFFuncName.c_str());
- body.appendf("color.b = %s(color.b);", srcTFFuncName.c_str());
+ body.appendf("color.r = %s(half(color.r));", srcTFFuncName.c_str());
+ body.appendf("color.g = %s(half(color.g));", srcTFFuncName.c_str());
+ body.appendf("color.b = %s(half(color.b));", srcTFFuncName.c_str());
}
if (colorXformHelper->applyGamutXform()) {
- body.appendf("color = %s(color);", gamutXformFuncName.c_str());
+ body.appendf("color = %s(half4(color));", gamutXformFuncName.c_str());
}
if (colorXformHelper->applyDstTF()) {
- body.appendf("color.r = %s(color.r);", dstTFFuncName.c_str());
- body.appendf("color.g = %s(color.g);", dstTFFuncName.c_str());
- body.appendf("color.b = %s(color.b);", dstTFFuncName.c_str());
+ body.appendf("color.r = %s(half(color.r));", dstTFFuncName.c_str());
+ body.appendf("color.g = %s(half(color.g));", dstTFFuncName.c_str());
+ body.appendf("color.b = %s(half(color.b));", dstTFFuncName.c_str());
}
if (colorXformHelper->applyPremul()) {
body.append("color.rgb *= color.a;");
}
- body.append("return color;");
+ body.append("return half4(color);");
SkString colorXformFuncName;
this->emitFunction(kHalf4_GrSLType, "color_xform", SK_ARRAY_COUNT(gColorXformArgs),
gColorXformArgs, body.c_str(), &colorXformFuncName);
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index ddb4f2d..cdac50f 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -444,6 +444,13 @@
fPreferPrimaryOverSecondaryCommandBuffers = false;
}
+ // On Mali G series GPUs, applying transfer functions in the fragment shader with half-floats
+ // produces answers that are much less accurate than expected/required. This forces full floats
+ // for some intermediate values to get acceptable results.
+ if (kARM_VkVendor == properties.vendorID) {
+ fShaderCaps->fColorSpaceMathNeedsFloat = true;
+ }
+
// On various devices, when calling vkCmdClearAttachments on a primary command buffer, it
// corrupts the bound buffers on the command buffer. As a workaround we invalidate our knowledge
// of bound buffers so that we will rebind them on the next draw.