|  | /* | 
|  | * 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 "../private/GrSwizzle.h" | 
|  | #include "../private/GrGLSL.h" | 
|  |  | 
|  | namespace SkSL { | 
|  | class ShaderCapsFactory; | 
|  | } | 
|  | struct GrContextOptions; | 
|  |  | 
|  | class GrShaderCaps : public SkRefCnt { | 
|  | public: | 
|  | /** Info about shader variable precision within a given shader stage. That is, this info | 
|  | is relevant to a float (or vecNf) variable declared with a GrSLPrecision | 
|  | in a given GrShaderType. The info here is hoisted from the OpenGL spec. */ | 
|  | struct PrecisionInfo { | 
|  | PrecisionInfo() { | 
|  | fLogRangeLow = 0; | 
|  | fLogRangeHigh = 0; | 
|  | fBits = 0; | 
|  | } | 
|  |  | 
|  | /** Is this precision level allowed in the shader stage? */ | 
|  | bool supported() const { return 0 != fBits; } | 
|  |  | 
|  | bool operator==(const PrecisionInfo& that) const { | 
|  | return fLogRangeLow == that.fLogRangeLow && fLogRangeHigh == that.fLogRangeHigh && | 
|  | fBits == that.fBits; | 
|  | } | 
|  | bool operator!=(const PrecisionInfo& that) const { return !(*this == that); } | 
|  |  | 
|  | /** floor(log2(|min_value|)) */ | 
|  | int fLogRangeLow; | 
|  | /** floor(log2(|max_value|)) */ | 
|  | int fLogRangeHigh; | 
|  | /** Number of bits of precision. As defined in OpenGL (with names modified to reflect this | 
|  | struct) : | 
|  | """ | 
|  | If the smallest representable value greater than 1 is 1 + e, then fBits will | 
|  | contain floor(log2(e)), and every value in the range [2^fLogRangeLow, | 
|  | 2^fLogRangeHigh] can be represented to at least one part in 2^fBits. | 
|  | """ | 
|  | */ | 
|  | int fBits; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Indicates how GLSL must interact with advanced blend equations. The KHR extension requires | 
|  | * special layout qualifiers in the fragment shader. | 
|  | */ | 
|  | enum AdvBlendEqInteraction { | 
|  | kNotSupported_AdvBlendEqInteraction,     //<! No _blend_equation_advanced extension | 
|  | kAutomatic_AdvBlendEqInteraction,        //<! No interaction required | 
|  | kGeneralEnable_AdvBlendEqInteraction,    //<! layout(blend_support_all_equations) out | 
|  | kSpecificEnables_AdvBlendEqInteraction,  //<! Specific layout qualifiers per equation | 
|  |  | 
|  | kLast_AdvBlendEqInteraction = kSpecificEnables_AdvBlendEqInteraction | 
|  | }; | 
|  |  | 
|  | GrShaderCaps(const GrContextOptions&); | 
|  |  | 
|  | SkString dump() const; | 
|  |  | 
|  | bool shaderDerivativeSupport() const { return fShaderDerivativeSupport; } | 
|  | bool geometryShaderSupport() const { return fGeometryShaderSupport; } | 
|  | bool pathRenderingSupport() const { return fPathRenderingSupport; } | 
|  | bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; } | 
|  | bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; } | 
|  | bool integerSupport() const { return fIntegerSupport; } | 
|  | bool texelBufferSupport() const { return fTexelBufferSupport; } | 
|  | int imageLoadStoreSupport() const { return fImageLoadStoreSupport; } | 
|  |  | 
|  | /** | 
|  | * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a | 
|  | * given shader type. If the shader type is not supported or the precision level is not | 
|  | * supported in that shader type then the returned struct will report false when supported() is | 
|  | * called. | 
|  | */ | 
|  | const PrecisionInfo& getFloatShaderPrecisionInfo(GrShaderType shaderType, | 
|  | GrSLPrecision precision) const { | 
|  | return fFloatPrecisions[shaderType][precision]; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Is there any difference between the float shader variable precision types? If this is true | 
|  | * then unless the shader type is not supported, any call to getFloatShaderPrecisionInfo() would | 
|  | * report the same info for all precisions in all shader types. | 
|  | */ | 
|  | bool floatPrecisionVaries() const { return fShaderPrecisionVaries; } | 
|  |  | 
|  | /** | 
|  | * Some helper functions for encapsulating various extensions to read FB Buffer on openglES | 
|  | * | 
|  | * TODO(joshualitt) On desktop opengl 4.2+ we can achieve something similar to this effect | 
|  | */ | 
|  | bool fbFetchSupport() const { return fFBFetchSupport; } | 
|  |  | 
|  | bool fbFetchNeedsCustomOutput() const { return fFBFetchNeedsCustomOutput; } | 
|  |  | 
|  | bool bindlessTextureSupport() const { return fBindlessTextureSupport; } | 
|  |  | 
|  | const char* versionDeclString() const { return fVersionDeclString; } | 
|  |  | 
|  | const char* fbFetchColorName() const { return fFBFetchColorName; } | 
|  |  | 
|  | const char* fbFetchExtensionString() const { return fFBFetchExtensionString; } | 
|  |  | 
|  | bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; } | 
|  |  | 
|  | bool flatInterpolationSupport() const { return fFlatInterpolationSupport; } | 
|  |  | 
|  | bool noperspectiveInterpolationSupport() const { return fNoPerspectiveInterpolationSupport; } | 
|  |  | 
|  | bool multisampleInterpolationSupport() const { return fMultisampleInterpolationSupport; } | 
|  |  | 
|  | bool sampleVariablesSupport() const { return fSampleVariablesSupport; } | 
|  |  | 
|  | bool sampleMaskOverrideCoverageSupport() const { return fSampleMaskOverrideCoverageSupport; } | 
|  |  | 
|  | bool externalTextureSupport() const { return fExternalTextureSupport; } | 
|  |  | 
|  | bool texelFetchSupport() const { return fTexelFetchSupport; } | 
|  |  | 
|  | AdvBlendEqInteraction advBlendEqInteraction() const { return fAdvBlendEqInteraction; } | 
|  |  | 
|  | bool mustEnableAdvBlendEqs() const { | 
|  | return fAdvBlendEqInteraction >= kGeneralEnable_AdvBlendEqInteraction; | 
|  | } | 
|  |  | 
|  | bool mustEnableSpecificAdvBlendEqs() const { | 
|  | return fAdvBlendEqInteraction == kSpecificEnables_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 mustForceNegatedAtanParamToFloat() const { return fMustForceNegatedAtanParamToFloat; } | 
|  |  | 
|  | // Returns whether a device incorrectly implements atan(y,x) as atan(y/x) | 
|  | bool atan2ImplementedAsAtanYOverX() const { return fAtan2ImplementedAsAtanYOverX; } | 
|  |  | 
|  | bool requiresLocalOutputColorForFBFetch() const { return fRequiresLocalOutputColorForFBFetch; } | 
|  |  | 
|  | // On MacBook, geometry shaders break if they have more than one invocation. | 
|  | bool mustImplementGSInvocationsWithLoop() const { return fMustImplementGSInvocationsWithLoop; } | 
|  |  | 
|  | // 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 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; | 
|  | } | 
|  |  | 
|  | const char* externalTextureExtensionString() const { | 
|  | SkASSERT(this->externalTextureSupport()); | 
|  | return fExternalTextureExtensionString; | 
|  | } | 
|  |  | 
|  | const char* texelBufferExtensionString() const { | 
|  | SkASSERT(this->texelBufferSupport()); | 
|  | return fTexelBufferExtensionString; | 
|  | } | 
|  |  | 
|  | const char* noperspectiveInterpolationExtensionString() const { | 
|  | SkASSERT(this->noperspectiveInterpolationSupport()); | 
|  | return fNoPerspectiveInterpolationExtensionString; | 
|  | } | 
|  |  | 
|  | const char* multisampleInterpolationExtensionString() const { | 
|  | SkASSERT(this->multisampleInterpolationSupport()); | 
|  | return fMultisampleInterpolationExtensionString; | 
|  | } | 
|  |  | 
|  | const char* sampleVariablesExtensionString() const { | 
|  | SkASSERT(this->sampleVariablesSupport()); | 
|  | return fSampleVariablesExtensionString; | 
|  | } | 
|  |  | 
|  | const char* imageLoadStoreExtensionString() const { | 
|  | SkASSERT(this->imageLoadStoreSupport()); | 
|  | return fImageLoadStoreExtensionString; | 
|  | } | 
|  |  | 
|  | int maxVertexSamplers() const { return fMaxVertexSamplers; } | 
|  |  | 
|  | int maxGeometrySamplers() const { return fMaxGeometrySamplers; } | 
|  |  | 
|  | int maxFragmentSamplers() const { return fMaxFragmentSamplers; } | 
|  |  | 
|  | int maxCombinedSamplers() const { return fMaxCombinedSamplers; } | 
|  |  | 
|  | int maxVertexImageStorages() const { return fMaxVertexImageStorages; } | 
|  |  | 
|  | int maxGeometryImageStorages() const { return fMaxGeometryImageStorages; } | 
|  |  | 
|  | int maxFragmentImageStorages() const { return fMaxFragmentImageStorages; } | 
|  |  | 
|  | int maxCombinedImageStorages() const { return fMaxCombinedImageStorages; } | 
|  |  | 
|  | /** | 
|  | * Given a texture's config, this determines what swizzle must be appended to accesses to the | 
|  | * texture in generated shader code. Swizzling may be implemented in texture parameters or a | 
|  | * sampler rather than in the shader. In this case the returned swizzle will always be "rgba". | 
|  | */ | 
|  | const GrSwizzle& configTextureSwizzle(GrPixelConfig config) const { | 
|  | return fConfigTextureSwizzle[config]; | 
|  | } | 
|  |  | 
|  | /** Swizzle that should occur on the fragment shader outputs for a given config. */ | 
|  | const GrSwizzle& configOutputSwizzle(GrPixelConfig config) const { | 
|  | return fConfigOutputSwizzle[config]; | 
|  | } | 
|  |  | 
|  | /** Precision qualifier that should be used with a sampler, given its config and visibility. */ | 
|  | GrSLPrecision samplerPrecision(GrPixelConfig config, GrShaderFlags visibility) const { | 
|  | return static_cast<GrSLPrecision>(fSamplerPrecisions[visibility][config]); | 
|  | } | 
|  |  | 
|  | GrGLSLGeneration generation() const { return fGLSLGeneration; } | 
|  |  | 
|  | private: | 
|  | /** GrCaps subclasses must call this after filling in the shader precision table. */ | 
|  | void initSamplerPrecisionTable(); | 
|  |  | 
|  | void applyOptionsOverrides(const GrContextOptions& options); | 
|  |  | 
|  | GrGLSLGeneration fGLSLGeneration; | 
|  |  | 
|  | bool fShaderDerivativeSupport   : 1; | 
|  | bool fGeometryShaderSupport     : 1; | 
|  | bool fPathRenderingSupport      : 1; | 
|  | bool fDstReadInShaderSupport    : 1; | 
|  | bool fDualSourceBlendingSupport : 1; | 
|  | bool fIntegerSupport            : 1; | 
|  | bool fTexelBufferSupport        : 1; | 
|  | bool fImageLoadStoreSupport     : 1; | 
|  | bool fShaderPrecisionVaries     : 1; | 
|  | bool fDropsTileOnZeroDivide : 1; | 
|  | bool fFBFetchSupport : 1; | 
|  | bool fFBFetchNeedsCustomOutput : 1; | 
|  | bool fBindlessTextureSupport : 1; | 
|  | bool fUsesPrecisionModifiers : 1; | 
|  | bool fCanUseAnyFunctionInShader : 1; | 
|  | bool fFlatInterpolationSupport : 1; | 
|  | bool fNoPerspectiveInterpolationSupport : 1; | 
|  | bool fMultisampleInterpolationSupport : 1; | 
|  | bool fSampleVariablesSupport : 1; | 
|  | bool fSampleMaskOverrideCoverageSupport : 1; | 
|  | bool fExternalTextureSupport : 1; | 
|  | bool fTexelFetchSupport : 1; | 
|  |  | 
|  | // Used for specific driver bug work arounds | 
|  | bool fCanUseMinAndAbsTogether : 1; | 
|  | bool fMustForceNegatedAtanParamToFloat : 1; | 
|  | bool fAtan2ImplementedAsAtanYOverX : 1; | 
|  | bool fRequiresLocalOutputColorForFBFetch : 1; | 
|  | bool fMustImplementGSInvocationsWithLoop : 1; | 
|  |  | 
|  | PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount]; | 
|  |  | 
|  | const char* fVersionDeclString; | 
|  |  | 
|  | const char* fShaderDerivativeExtensionString; | 
|  | const char* fFragCoordConventionsExtensionString; | 
|  | const char* fSecondaryOutputExtensionString; | 
|  | const char* fExternalTextureExtensionString; | 
|  | const char* fTexelBufferExtensionString; | 
|  | const char* fNoPerspectiveInterpolationExtensionString; | 
|  | const char* fMultisampleInterpolationExtensionString; | 
|  | const char* fSampleVariablesExtensionString; | 
|  | const char* fImageLoadStoreExtensionString; | 
|  |  | 
|  | const char* fFBFetchColorName; | 
|  | const char* fFBFetchExtensionString; | 
|  |  | 
|  | int fMaxVertexSamplers; | 
|  | int fMaxGeometrySamplers; | 
|  | int fMaxFragmentSamplers; | 
|  | int fMaxCombinedSamplers; | 
|  |  | 
|  | int fMaxVertexImageStorages; | 
|  | int fMaxGeometryImageStorages; | 
|  | int fMaxFragmentImageStorages; | 
|  | int fMaxCombinedImageStorages; | 
|  |  | 
|  | AdvBlendEqInteraction fAdvBlendEqInteraction; | 
|  |  | 
|  | GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt]; | 
|  | GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt]; | 
|  |  | 
|  | uint8_t fSamplerPrecisions[(1 << kGrShaderTypeCount)][kGrPixelConfigCnt]; | 
|  |  | 
|  | friend class GrGLCaps;  // For initialization. | 
|  | friend class GrVkCaps; | 
|  | friend class SkSL::ShaderCapsFactory; | 
|  | }; | 
|  |  | 
|  | #endif |