From c2d0dd658bbb8caebf0cc9d5cf4b98b1bda616e7 Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Wed, 7 Mar 2018 07:46:10 -0700 Subject: [PATCH] Add a shader cap for incomplete short int precision Bug: skia: Change-Id: Iac36eb763e687f6ecc3acbd4afced66f95596be2 Reviewed-on: https://skia-review.googlesource.com/109003 Reviewed-by: Brian Salomon Reviewed-by: Ethan Nicholas Commit-Queue: Chris Dalton --- include/gpu/GrShaderCaps.h | 5 ++++ src/gpu/GrShaderCaps.cpp | 3 +++ src/gpu/gl/GrGLCaps.cpp | 6 +++++ src/sksl/SkSLGLSLCodeGenerator.cpp | 10 +++++-- src/sksl/SkSLUtil.h | 8 ++++++ tests/SkSLGLSLTest.cpp | 43 ++++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 2 deletions(-) diff --git a/include/gpu/GrShaderCaps.h b/include/gpu/GrShaderCaps.h index 86a2566675..f86e87c461 100644 --- a/include/gpu/GrShaderCaps.h +++ b/include/gpu/GrShaderCaps.h @@ -119,6 +119,10 @@ public: // If true interpolated vertex shader outputs are inaccurate. bool interpolantsAreInaccurate() const { return fInterpolantsAreInaccurate; } + // If true, short ints can't represent every integer in the 16-bit two's complement range as + // required by the spec. SKSL will always emit full ints. + bool incompleteShortIntPrecision() const { return fIncompleteShortIntPrecision; } + bool requiresLocalOutputColorForFBFetch() const { return fRequiresLocalOutputColorForFBFetch; } bool mustObfuscateUniformColor() const { return fMustObfuscateUniformColor; } @@ -261,6 +265,7 @@ private: bool fMustGuardDivisionEvenAfterExplicitZeroCheck : 1; bool fCanUseFragCoord : 1; bool fInterpolantsAreInaccurate : 1; + bool fIncompleteShortIntPrecision : 1; const char* fVersionDeclString; diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp index 517deaddc6..5c6d0b9ce7 100644 --- a/src/gpu/GrShaderCaps.cpp +++ b/src/gpu/GrShaderCaps.cpp @@ -39,6 +39,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fMustGuardDivisionEvenAfterExplicitZeroCheck = false; fCanUseFragCoord = true; fInterpolantsAreInaccurate = false; + fIncompleteShortIntPrecision = false; fFlatInterpolationSupport = false; fPreferFlatInterpolation = false; fNoPerspectiveInterpolationSupport = false; @@ -110,6 +111,7 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const { fMustGuardDivisionEvenAfterExplicitZeroCheck); writer->appendBool("Can use gl_FragCoord", fCanUseFragCoord); writer->appendBool("Interpolants are inaccurate", fInterpolantsAreInaccurate); + writer->appendBool("Incomplete short int precision", fIncompleteShortIntPrecision); writer->appendBool("Flat interpolation support", fFlatInterpolationSupport); writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation); writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport); @@ -144,6 +146,7 @@ void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) { SkASSERT(!fMustGuardDivisionEvenAfterExplicitZeroCheck); SkASSERT(fCanUseFragCoord); SkASSERT(!fInterpolantsAreInaccurate); + SkASSERT(!fIncompleteShortIntPrecision); } #if GR_TEST_UTILS fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending; diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 3b5f6b2278..4def7b7427 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -2371,6 +2371,12 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, shaderCaps->fInterpolantsAreInaccurate = true; } + // On Mali G71, mediump ints don't appear capable of representing every integer beyond +/-2048. + // (Are they implemented with fp16?) + if (kARM_GrGLVendor == ctxInfo.vendor()) { + shaderCaps->fIncompleteShortIntPrecision = true; + } + // Disabling advanced blend on various platforms with major known issues. We also block Chrome // for now until its own blacklists can be updated. if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer() || diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp index 2fa7492b20..996714ec62 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -1015,8 +1015,14 @@ const char* GLSLCodeGenerator::getTypePrecision(const Type& type) { if (usesPrecisionModifiers()) { switch (type.kind()) { case Type::kScalar_Kind: - if (type == *fContext.fHalf_Type || type == *fContext.fShort_Type || - type == *fContext.fUShort_Type) { + if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type) { + if (fProgram.fSettings.fForceHighPrecision || + fProgram.fSettings.fCaps->incompleteShortIntPrecision()) { + return "highp "; + } + return "mediump "; + } + if (type == *fContext.fHalf_Type) { return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump "; } if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type || diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h index c16156a413..113b13a644 100644 --- a/src/sksl/SkSLUtil.h +++ b/src/sksl/SkSLUtil.h @@ -299,6 +299,14 @@ public: result->fCanUseFragCoord = false; return result; } + + static sk_sp IncompleteShortIntPrecision() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 310es"; + result->fUsesPrecisionModifiers = true; + result->fIncompleteShortIntPrecision = true; + return result; + } }; #endif diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp index e63719781d..27797b6189 100644 --- a/tests/SkSLGLSLTest.cpp +++ b/tests/SkSLGLSLTest.cpp @@ -1902,4 +1902,47 @@ DEF_TEST(SkSLTernaryLValue, r) { "}\n"); } +DEF_TEST(SkSLIncompleteShortIntPrecision, r) { + test(r, + "uniform sampler2D tex;" + "in float2 texcoord;" + "in short2 offset;" + "void main() {" + " short scalar = offset.y;" + " sk_FragColor = texture(tex, texcoord + float2(offset * scalar));" + "}", + *SkSL::ShaderCapsFactory::UsesPrecisionModifiers(), + "#version 400\n" + "precision mediump float;\n" + "out mediump vec4 sk_FragColor;\n" + "uniform sampler2D tex;\n" + "in highp vec2 texcoord;\n" + "in mediump ivec2 offset;\n" + "void main() {\n" + " mediump int scalar = offset.y;\n" + " sk_FragColor = texture(tex, texcoord + vec2(offset * scalar));\n" + "}\n", + SkSL::Program::kFragment_Kind); + test(r, + "uniform sampler2D tex;" + "in float2 texcoord;" + "in short2 offset;" + "void main() {" + " short scalar = offset.y;" + " sk_FragColor = texture(tex, texcoord + float2(offset * scalar));" + "}", + *SkSL::ShaderCapsFactory::IncompleteShortIntPrecision(), + "#version 310es\n" + "precision mediump float;\n" + "out mediump vec4 sk_FragColor;\n" + "uniform sampler2D tex;\n" + "in highp vec2 texcoord;\n" + "in highp ivec2 offset;\n" + "void main() {\n" + " highp int scalar = offset.y;\n" + " sk_FragColor = texture(tex, texcoord + vec2(offset * scalar));\n" + "}\n", + SkSL::Program::kFragment_Kind); +} + #endif