/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrShaderCaps_DEFINED #define GrShaderCaps_DEFINED #include "include/core/SkRefCnt.h" #include "include/private/GrTypesPriv.h" #include "src/gpu/GrSwizzle.h" #include "src/gpu/glsl/GrGLSL.h" namespace SkSL { class ShaderCapsFactory; class SharedCompiler; } // namespace SkSL struct GrContextOptions; class SkJSONWriter; class GrShaderCaps : public SkRefCnt { public: /** * Indicates how GLSL must interact with advanced blend equations. The KHR extension requires * special layout qualifiers in the fragment shader. */ enum AdvBlendEqInteraction { kNotSupported_AdvBlendEqInteraction, //= kGeneralEnable_AdvBlendEqInteraction; } bool mustDeclareFragmentShaderOutput() const { return fGLSLGeneration > k110_GrGLSLGeneration; } bool usesPrecisionModifiers() const { return fUsesPrecisionModifiers; } // Returns whether we can use the glsl function any() in our shader code. bool canUseAnyFunctionInShader() const { return fCanUseAnyFunctionInShader; } bool canUseMinAndAbsTogether() const { return fCanUseMinAndAbsTogether; } bool canUseFractForNegativeValues() const { return fCanUseFractForNegativeValues; } bool mustForceNegatedAtanParamToFloat() const { return fMustForceNegatedAtanParamToFloat; } // Returns whether a device incorrectly implements atan(y,x) as atan(y/x) bool atan2ImplementedAsAtanYOverX() const { return fAtan2ImplementedAsAtanYOverX; } // If this returns true some operation (could be a no op) must be called between floor and abs // to make sure the driver compiler doesn't inline them together which can cause a driver bug in // the shader. bool mustDoOpBetweenFloorAndAbs() const { return fMustDoOpBetweenFloorAndAbs; } // If false, SkSL uses a workaround so that sk_FragCoord doesn't actually query gl_FragCoord bool canUseFragCoord() const { return fCanUseFragCoord; } // 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 colorSpaceMathNeedsFloat() const { return fColorSpaceMathNeedsFloat; } // If true, then conditions in for loops need "&& true" to work around driver bugs. bool addAndTrueToLoopCondition() const { return fAddAndTrueToLoopCondition; } // If true, then expressions such as "x && y" or "x || y" are rewritten as // ternary to work around driver bugs. bool unfoldShortCircuitAsTernary() const { return fUnfoldShortCircuitAsTernary; } bool emulateAbsIntFunction() const { return fEmulateAbsIntFunction; } bool rewriteDoWhileLoops() const { return fRewriteDoWhileLoops; } bool removePowWithConstantExponent() const { return fRemovePowWithConstantExponent; } bool requiresLocalOutputColorForFBFetch() const { return fRequiresLocalOutputColorForFBFetch; } bool mustObfuscateUniformColor() const { return fMustObfuscateUniformColor; } // The D3D shader compiler, when targeting PS 3.0 (ie within ANGLE) fails to compile certain // constructs. See detailed comments in GrGLCaps.cpp. bool mustGuardDivisionEvenAfterExplicitZeroCheck() const { return fMustGuardDivisionEvenAfterExplicitZeroCheck; } // On Pixel 3, 3a, and 4 devices we've noticed that the simple function: // half4 blend(half4 a, half4 b) { return a.a * b; } // may return (0, 0, 0, 1) when b is (0, 0, 0, 0). bool inBlendModesFailRandomlyForAllZeroVec() const { return fInBlendModesFailRandomlyForAllZeroVec; } // On Nexus 6, the GL context can get lost if a shader does not write a value to gl_FragColor. // https://bugs.chromium.org/p/chromium/issues/detail?id=445377 bool mustWriteToFragColor() const { return fMustWriteToFragColor; } // The Android emulator claims samplerExternalOES is an unknown type if a default precision // statement is made for the type. bool noDefaultPrecisionForExternalSamplers() const { return fNoDefaultPrecisionForExternalSamplers; } // ARM GPUs calculate `matrix * vector` in SPIR-V at full precision, even when the inputs are // RelaxedPrecision. Rewriting the multiply as a sum of vector*scalar fixes this. (skia:11769) bool rewriteMatrixVectorMultiply() const { return fRewriteMatrixVectorMultiply; } // ANGLE disallows do loops altogether, and we're seeing crashes on Tegra3 with do loops in at // least some cases. bool canUseDoLoops() const { return fCanUseDoLoops; } // Some GPUs produce poor results when enabling Metal's fastmath option bool canUseFastMath() const { return fCanUseFastMath; } // By default, SkSL pools IR nodes per-program. To debug memory corruption, it is sometimes // helpful to disable that feature. bool useNodePools() const { return fUseNodePools; } // When we have the option of using either dFdx or dfDy in a shader, this returns whether we // should avoid using dFdx. We have found some drivers have bugs or lower precision when using // dFdx. bool avoidDfDxForGradientsWhenPossible() const { return fAvoidDfDxForGradientsWhenPossible; } // Returns the string of an extension that must be enabled in the shader to support // derivatives. If nullptr is returned then no extension needs to be enabled. Before calling // this function, the caller should check that shaderDerivativeSupport exists. const char* shaderDerivativeExtensionString() const { SkASSERT(this->shaderDerivativeSupport()); return fShaderDerivativeExtensionString; } // Returns the string of an extension that must be enabled in the shader to support geometry // shaders. If nullptr is returned then no extension needs to be enabled. Before calling this // function, the caller must verify that geometryShaderSupport exists. const char* geometryShaderExtensionString() const { SkASSERT(this->geometryShaderSupport()); return fGeometryShaderExtensionString; } // Returns the string of an extension that must be enabled in the shader to support // geometry shader invocations. If nullptr is returned then no extension needs to be enabled. // Before calling this function, the caller must verify that gsInvocationsSupport exists. const char* gsInvocationsExtensionString() const { SkASSERT(this->gsInvocationsSupport()); return fGSInvocationsExtensionString; } // Returns the string of an extension that will do all necessary coord transfomations needed // when reading the fragment position. If such an extension does not exisits, this function // returns a nullptr, and all transforms of the frag position must be done manually in the // shader. const char* fragCoordConventionsExtensionString() const { return fFragCoordConventionsExtensionString; } // This returns the name of an extension that must be enabled in the shader, if such a thing is // required in order to use a secondary output in the shader. This returns a nullptr if no such // extension is required. However, the return value of this function does not say whether dual // source blending is supported. const char* secondaryOutputExtensionString() const { return fSecondaryOutputExtensionString; } // This returns the name of an extension that must be enabled in the shader to support external // textures. In some cases, two extensions must be enabled - the second extension is returned // by secondExternalTextureExtensionString(). If that function returns nullptr, then only one // extension is required. const char* externalTextureExtensionString() const { SkASSERT(this->externalTextureSupport()); return fExternalTextureExtensionString; } const char* secondExternalTextureExtensionString() const { SkASSERT(this->externalTextureSupport()); return fSecondExternalTextureExtensionString; } const char* noperspectiveInterpolationExtensionString() const { SkASSERT(this->noperspectiveInterpolationSupport()); return fNoPerspectiveInterpolationExtensionString; } const char* sampleVariablesExtensionString() const { SkASSERT(this->sampleMaskSupport()); return fSampleVariablesExtensionString; } const char* tessellationExtensionString() const { SkASSERT(this->tessellationSupport()); return fTessellationExtensionString; } int maxFragmentSamplers() const { return fMaxFragmentSamplers; } // Maximum number of segments a tessellation edge can be divided into. int maxTessellationSegments() const { return fMaxTessellationSegments; } bool tessellationSupport() const { return SkToBool(fMaxTessellationSegments);} GrGLSLGeneration generation() const { return fGLSLGeneration; } private: void applyOptionsOverrides(const GrContextOptions& options); GrGLSLGeneration fGLSLGeneration; bool fShaderDerivativeSupport : 1; bool fGeometryShaderSupport : 1; bool fGSInvocationsSupport : 1; bool fDstReadInShaderSupport : 1; bool fDualSourceBlendingSupport : 1; bool fIntegerSupport : 1; bool fNonsquareMatrixSupport : 1; bool fFBFetchSupport : 1; bool fFBFetchNeedsCustomOutput : 1; bool fUsesPrecisionModifiers : 1; bool fFlatInterpolationSupport : 1; bool fPreferFlatInterpolation : 1; bool fNoPerspectiveInterpolationSupport : 1; bool fSampleMaskSupport : 1; bool fExternalTextureSupport : 1; bool fVertexIDSupport : 1; bool fFPManipulationSupport : 1; bool fFloatIs32Bits : 1; bool fHalfIs32Bits : 1; bool fHasLowFragmentPrecision : 1; bool fReducedShaderMode : 1; // Used by SkSL to know when to generate polyfills. bool fBuiltinFMASupport : 1; bool fBuiltinDeterminantSupport : 1; // Used for specific driver bug work arounds bool fCanUseAnyFunctionInShader : 1; bool fCanUseMinAndAbsTogether : 1; bool fCanUseFractForNegativeValues : 1; bool fMustForceNegatedAtanParamToFloat : 1; bool fAtan2ImplementedAsAtanYOverX : 1; bool fMustDoOpBetweenFloorAndAbs : 1; bool fRequiresLocalOutputColorForFBFetch : 1; bool fMustObfuscateUniformColor : 1; bool fMustGuardDivisionEvenAfterExplicitZeroCheck : 1; bool fInBlendModesFailRandomlyForAllZeroVec : 1; bool fCanUseFragCoord : 1; bool fIncompleteShortIntPrecision : 1; bool fAddAndTrueToLoopCondition : 1; bool fUnfoldShortCircuitAsTernary : 1; bool fEmulateAbsIntFunction : 1; bool fRewriteDoWhileLoops : 1; bool fRemovePowWithConstantExponent : 1; bool fMustWriteToFragColor : 1; bool fNoDefaultPrecisionForExternalSamplers : 1; bool fRewriteMatrixVectorMultiply : 1; bool fColorSpaceMathNeedsFloat : 1; bool fCanUseDoLoops : 1; bool fCanUseFastMath : 1; bool fAvoidDfDxForGradientsWhenPossible : 1; // This controls behavior of the SkSL compiler, not the code we generate bool fUseNodePools : 1; const char* fVersionDeclString; const char* fShaderDerivativeExtensionString; const char* fGeometryShaderExtensionString; const char* fGSInvocationsExtensionString; const char* fFragCoordConventionsExtensionString; const char* fSecondaryOutputExtensionString; const char* fExternalTextureExtensionString; const char* fSecondExternalTextureExtensionString; const char* fNoPerspectiveInterpolationExtensionString; const char* fSampleVariablesExtensionString; const char* fTessellationExtensionString; const char* fFBFetchColorName; const char* fFBFetchExtensionString; int fMaxFragmentSamplers; int fMaxTessellationSegments; AdvBlendEqInteraction fAdvBlendEqInteraction; friend class GrCaps; // For initialization. friend class GrDawnCaps; friend class GrD3DCaps; friend class GrGLCaps; friend class GrMockCaps; friend class GrMtlCaps; friend class GrVkCaps; friend class SkSL::ShaderCapsFactory; friend class SkSL::SharedCompiler; }; #endif