/*
* 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 GrGLCaps_DEFINED
#define GrGLCaps_DEFINED
#include <functional>
#include "GrCaps.h"
#include "GrGLStencilAttachment.h"
#include "GrSwizzle.h"
#include "SkChecksum.h"
#include "SkTHash.h"
#include "SkTArray.h"
class GrGLContextInfo;
class GrGLRenderTarget;
/**
* Stores some capabilities of a GL context. Most are determined by the GL
* version and the extensions string. It also tracks formats that have passed
* the FBO completeness test.
*/
class GrGLCaps : public GrCaps {
public:
typedef GrGLStencilAttachment::Format StencilFormat;
/**
* The type of MSAA for FBOs supported. Different extensions have different
* semantics of how / when a resolve is performed.
*/
enum MSFBOType {
/**
* no support for MSAA FBOs
*/
kNone_MSFBOType = 0,
/**
* OpenGL 3.0+, OpenGL ES 3.0+, GL_ARB_framebuffer_object,
* GL_CHROMIUM_framebuffer_multisample, GL_ANGLE_framebuffer_multisample,
* or GL_EXT_framebuffer_multisample
*/
kStandard_MSFBOType,
/**
* GL_APPLE_framebuffer_multisample ES extension
*/
kES_Apple_MSFBOType,
/**
* GL_IMG_multisampled_render_to_texture. This variation does not have MSAA renderbuffers.
* Instead the texture is multisampled when bound to the FBO and then resolved automatically
* when read. It also defines an alternate value for GL_MAX_SAMPLES (which we call
* GR_GL_MAX_SAMPLES_IMG).
*/
kES_IMG_MsToTexture_MSFBOType,
/**
* GL_EXT_multisampled_render_to_texture. Same as the IMG one above but uses the standard
* GL_MAX_SAMPLES value.
*/
kES_EXT_MsToTexture_MSFBOType,
/**
* GL_NV_framebuffer_mixed_samples.
*/
kMixedSamples_MSFBOType,
kLast_MSFBOType = kMixedSamples_MSFBOType
};
enum BlitFramebufferFlags {
kNoSupport_BlitFramebufferFlag = 1 << 0,
kNoScalingOrMirroring_BlitFramebufferFlag = 1 << 1,
kResolveMustBeFull_BlitFrambufferFlag = 1 << 2,
kNoMSAADst_BlitFramebufferFlag = 1 << 3,
kNoFormatConversion_BlitFramebufferFlag = 1 << 4,
kNoFormatConversionForMSAASrc_BlitFramebufferFlag = 1 << 5,
kRectsMustMatchForMSAASrc_BlitFramebufferFlag = 1 << 6,
};
enum InvalidateFBType {
kNone_InvalidateFBType,
kDiscard_InvalidateFBType, //<! glDiscardFramebuffer()
kInvalidate_InvalidateFBType, //<! glInvalidateFramebuffer()
kLast_InvalidateFBType = kInvalidate_InvalidateFBType
};
enum MapBufferType {
kNone_MapBufferType,
kMapBuffer_MapBufferType, // glMapBuffer()
kMapBufferRange_MapBufferType, // glMapBufferRange()
kChromium_MapBufferType, // GL_CHROMIUM_map_sub
kLast_MapBufferType = kChromium_MapBufferType,
};
enum TransferBufferType {
kNone_TransferBufferType,
kPBO_TransferBufferType, // ARB_pixel_buffer_object
kChromium_TransferBufferType, // CHROMIUM_pixel_transfer_buffer_object
kLast_TransferBufferType = kChromium_TransferBufferType,
};
/**
* Initializes the GrGLCaps to the set of features supported in the current
* OpenGL context accessible via ctxInfo.
*/
GrGLCaps(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo,
const GrGLInterface* glInterface);
bool isConfigTexturable(GrPixelConfig config) const override {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag);
}
int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override;
int maxRenderTargetSampleCount(GrPixelConfig config) const override;
bool isConfigCopyable(GrPixelConfig config) const override {
// In GL we have three ways to be able to copy. CopyTexImage, blit, and draw. CopyTexImage
// requires the src to be an FBO attachment, blit requires both src and dst to be FBO
// attachments, and draw requires the dst to be an FBO attachment. Thus to copy from and to
// the same config, we need that config to be bindable to an FBO.
return this->canConfigBeFBOColorAttachment(config);
}
bool canConfigBeFBOColorAttachment(GrPixelConfig config) const {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kFBOColorAttachment_Flag);
}
bool isConfigTexSupportEnabled(GrPixelConfig config) const {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseTexStorage_Flag);
}
/** Returns the mapping between GrPixelConfig components and GL internal format components. */
const GrSwizzle& configSwizzle(GrPixelConfig config) const {
return fConfigTable[config].fSwizzle;
}
GrGLenum configSizedInternalFormat(GrPixelConfig config) const {
return fConfigTable[config].fFormats.fSizedInternalFormat;
}
bool getTexImageFormats(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig,
GrGLenum* internalFormat, GrGLenum* externalFormat,
GrGLenum* externalType) const;
bool getCompressedTexImageFormats(GrPixelConfig surfaceConfig, GrGLenum* internalFormat) const;
bool getReadPixelsFormat(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig,
GrGLenum* externalFormat, GrGLenum* externalType) const;
void getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const;
void getSizedInternalFormat(GrPixelConfig config, GrGLenum* internalFormat) const;
/** The format to use read/write a texture as an image in a shader */
GrGLenum getImageFormat(GrPixelConfig config) const {
return fConfigTable[config].fFormats.fSizedInternalFormat;
}
/**
* Gets an array of legal stencil formats. These formats are not guaranteed
* to be supported by the driver but are legal GLenum names given the GL
* version and extensions supported.
*/
const SkTArray<StencilFormat, true>& stencilFormats() const {
return fStencilFormats;
}
/**
* Has a stencil format index been found for the config (or we've found that no format works).
*/
bool hasStencilFormatBeenDeterminedForConfig(GrPixelConfig config) const {
return fConfigTable[config].fStencilFormatIndex != ConfigInfo::kUnknown_StencilIndex;
}
/**
* Gets the stencil format index for the config. This assumes
* hasStencilFormatBeenDeterminedForConfig has already been checked. Returns a value < 0 if
* no stencil format is supported with the config. Otherwise, returned index refers to the array
* returned by stencilFormats().
*/
int getStencilFormatIndexForConfig(GrPixelConfig config) const {
SkASSERT(this->hasStencilFormatBeenDeterminedForConfig(config));
return fConfigTable[config].fStencilFormatIndex;
}
/**
* If index is >= 0 this records an index into stencilFormats() as the best stencil format for
* the config. If < 0 it records that the config has no supported stencil format index.
*/
void setStencilFormatIndexForConfig(GrPixelConfig config, int index) {
SkASSERT(!this->hasStencilFormatBeenDeterminedForConfig(config));
if (index < 0) {
fConfigTable[config].fStencilFormatIndex = ConfigInfo::kUnsupported_StencilFormatIndex;
} else {
fConfigTable[config].fStencilFormatIndex = index;
}
}
/**
* Call to note that a color config has been verified as a valid color
* attachment. This may save future calls to glCheckFramebufferStatus
* using isConfigVerifiedColorAttachment().
*/
void markConfigAsValidColorAttachment(GrPixelConfig config) {
fConfigTable[config].fVerifiedColorAttachment = true;
}
/**
* Call to check whether a config has been verified as a valid color
* attachment.
*/
bool isConfigVerifiedColorAttachment(GrPixelConfig config) const {
return fConfigTable[config].fVerifiedColorAttachment;
}
/**
* Reports the type of MSAA FBO support.
*/
MSFBOType msFBOType() const { return fMSFBOType; }
/**
* Does the preferred MSAA FBO extension have MSAA renderbuffers?
*/
bool usesMSAARenderBuffers() const {
return kNone_MSFBOType != fMSFBOType &&
kES_IMG_MsToTexture_MSFBOType != fMSFBOType &&
kES_EXT_MsToTexture_MSFBOType != fMSFBOType &&
kMixedSamples_MSFBOType != fMSFBOType;
}
/**
* What functionality is supported by glBlitFramebuffer.
*/
uint32_t blitFramebufferSupportFlags() const { return fBlitFramebufferFlags; }
/**
* Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and
* then implicitly resolved when read.
*/
bool usesImplicitMSAAResolve() const {
return kES_IMG_MsToTexture_MSFBOType == fMSFBOType ||
kES_EXT_MsToTexture_MSFBOType == fMSFBOType;
}
InvalidateFBType invalidateFBType() const { return fInvalidateFBType; }
/// What type of buffer mapping is supported?
MapBufferType mapBufferType() const { return fMapBufferType; }
/// What type of transfer buffer is supported?
TransferBufferType transferBufferType() const { return fTransferBufferType; }
/// The maximum number of fragment uniform vectors (GLES has min. 16).
int maxFragmentUniformVectors() const { return fMaxFragmentUniformVectors; }
/**
* Depending on the ES extensions present the BGRA external format may
* correspond to either a BGRA or RGBA internalFormat. On desktop GL it is
* RGBA.
*/
bool bgraIsInternalFormat() const;
/// Is there support for GL_UNPACK_ROW_LENGTH
bool unpackRowLengthSupport() const { return fUnpackRowLengthSupport; }
/// Is there support for GL_PACK_ROW_LENGTH
bool packRowLengthSupport() const { return fPackRowLengthSupport; }
/// Is there support for GL_PACK_REVERSE_ROW_ORDER
bool packFlipYSupport() const { return fPackFlipYSupport; }
/// Is there support for texture parameter GL_TEXTURE_USAGE
bool textureUsageSupport() const { return fTextureUsageSupport; }
/// Is GL_ALPHA8 renderable
bool alpha8IsRenderable() const { return fAlpha8IsRenderable; }
/// Is GL_ARB_IMAGING supported
bool imagingSupport() const { return fImagingSupport; }
/// Is there support for Vertex Array Objects?
bool vertexArrayObjectSupport() const { return fVertexArrayObjectSupport; }
/// Is there support for GL_KHR_debug?
bool debugSupport() const { return fDebugSupport; }
/// Is there support for ES2 compatability?
bool ES2CompatibilitySupport() const { return fES2CompatibilitySupport; }
/// Is there support for glDraw*Instanced?
bool drawInstancedSupport() const { return fDrawInstancedSupport; }
/// Is there support for glDraw*Indirect? Note that the baseInstance fields of indirect draw
/// commands cannot be used unless we have base instance support.
bool drawIndirectSupport() const { return fDrawIndirectSupport; }
/// Is there support for glMultiDraw*Indirect? Note that the baseInstance fields of indirect
/// draw commands cannot be used unless we have base instance support.
bool multiDrawIndirectSupport() const { return fMultiDrawIndirectSupport; }
/// Is there support for glDrawRangeElements?
bool drawRangeElementsSupport() const { return fDrawRangeElementsSupport; }
/// Are the baseInstance fields supported in indirect draw commands?
bool baseInstanceSupport() const { return fBaseInstanceSupport; }
/// Use indices or vertices in CPU arrays rather than VBOs for dynamic content.
bool useNonVBOVertexAndIndexDynamicData() const { return fUseNonVBOVertexAndIndexDynamicData; }
bool surfaceSupportsReadPixels(const GrSurface*) const override;
GrColorType supportedReadPixelsColorType(GrPixelConfig, GrColorType) const override;
/// Does ReadPixels support reading readConfig pixels from a FBO that is surfaceConfig?
bool readPixelsSupported(GrPixelConfig surfaceConfig,
GrPixelConfig readConfig,
std::function<void (GrGLenum, GrGLint*)> getIntegerv,
std::function<bool ()> bindRenderTarget,
std::function<void ()> unbindRenderTarget) const;
bool isCoreProfile() const { return fIsCoreProfile; }
bool bindFragDataLocationSupport() const { return fBindFragDataLocationSupport; }
bool bindUniformLocationSupport() const { return fBindUniformLocationSupport; }
/// Are textures with GL_TEXTURE_RECTANGLE type supported.
bool rectangleTextureSupport() const { return fRectangleTextureSupport; }
/// GL_ARB_texture_swizzle
bool textureSwizzleSupport() const { return fTextureSwizzleSupport; }
bool mipMapLevelAndLodControlSupport() const { return fMipMapLevelAndLodControlSupport; }
bool doManualMipmapping() const { return fDoManualMipmapping; }
void onDumpJSON(SkJSONWriter*) const override;
bool rgba8888PixelsOpsAreSlow() const { return fRGBA8888PixelsOpsAreSlow; }
bool partialFBOReadIsSlow() const { return fPartialFBOReadIsSlow; }
bool rgbaToBgraReadbackConversionsAreSlow() const {
return fRGBAToBGRAReadbackConversionsAreSlow;
}
bool useBufferDataNullHint() const { return fUseBufferDataNullHint; }
// Certain Intel GPUs on Mac fail to clear if the glClearColor is made up of only 1s and 0s.
bool clearToBoundaryValuesIsBroken() const { return fClearToBoundaryValuesIsBroken; }
/// glClearTex(Sub)Image support
bool clearTextureSupport() const { return fClearTextureSupport; }
// Adreno/MSAA drops a draw on the imagefiltersbase GM if the base vertex param to
// glDrawArrays is nonzero.
// https://bugs.chromium.org/p/skia/issues/detail?id=6650
bool drawArraysBaseVertexIsBroken() const { return fDrawArraysBaseVertexIsBroken; }
// If true then we must use an intermediate surface to perform partial updates to unorm textures
// that have ever been bound to a FBO.
bool disallowTexSubImageForUnormConfigTexturesEverBoundToFBO() const {
return fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO;
}
// Use an intermediate surface to write pixels (full or partial overwrite) to into a texture
// that is bound to an FBO.
bool useDrawInsteadOfAllRenderTargetWrites() const {
return fUseDrawInsteadOfAllRenderTargetWrites;
}
// At least some Adreno 3xx drivers draw lines incorrectly after drawing non-lines. Toggling
// face culling on and off seems to resolve this.
bool requiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines() const {
return fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines;
}
// Some Adreno drivers refuse to ReadPixels from an MSAA buffer that has stencil attached.
bool detachStencilFromMSAABuffersBeforeReadPixels() const {
return fDetachStencilFromMSAABuffersBeforeReadPixels;
}
// Older Android versions seem to have an issue with setting GL_TEXTURE_BASE_LEVEL or
// GL_TEXTURE_MAX_LEVEL for GL_TEXTURE_EXTERNAL_OES textures.
bool dontSetBaseOrMaxLevelForExternalTextures() const {
return fDontSetBaseOrMaxLevelForExternalTextures;
}
// Returns the observed maximum number of instances the driver can handle in a single draw call
// without crashing, or 'pendingInstanceCount' if this workaround is not necessary.
// NOTE: the return value may be larger than pendingInstanceCount.
int maxInstancesPerDrawWithoutCrashing(int pendingInstanceCount) const {
return (fMaxInstancesPerDrawWithoutCrashing)
? fMaxInstancesPerDrawWithoutCrashing : pendingInstanceCount;
}
bool canCopyTexSubImage(GrPixelConfig dstConfig, bool dstHasMSAARenderBuffer,
bool dstIsTextureable, bool dstIsGLTexture2D,
GrSurfaceOrigin dstOrigin,
GrPixelConfig srcConfig, bool srcHasMSAARenderBuffer,
bool srcIsTextureable, bool srcIsGLTexture2D,
GrSurfaceOrigin srcOrigin) const;
bool canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCnt,
bool dstIsTextureable, bool dstIsGLTexture2D,
GrSurfaceOrigin dstOrigin,
GrPixelConfig srcConfig, int srcSampleCnt,
bool srcIsTextureable, bool srcIsGLTexture2D,
GrSurfaceOrigin srcOrigin, const SkRect& srcBounds,
const SkIRect& srcRect, const SkIPoint& dstPoint) const;
bool canCopyAsDraw(GrPixelConfig dstConfig, bool srcIsTextureable) const;
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, GrSurfaceOrigin*,
bool* rectsMustMatch, bool* disallowSubrect) const override;
bool programBinarySupport() const { return fProgramBinarySupport; }
bool samplerObjectSupport() const { return fSamplerObjectSupport; }
bool fbFetchRequiresEnablePerSample() const { return fFBFetchRequiresEnablePerSample; }
GrPixelConfig validateBackendRenderTarget(const GrBackendRenderTarget&,
SkColorType) const override;
GrPixelConfig getConfigFromBackendFormat(const GrBackendFormat&, SkColorType) const override;
GrPixelConfig getYUVAConfigFromBackendFormat(const GrBackendFormat&) const override;
GrBackendFormat getBackendFormatFromGrColorType(GrColorType ct,
GrSRGBEncoded srgbEncoded) const override;
#if GR_TEST_UTILS
GrGLStandard standard() const { return fStandard; }
#endif
private:
enum ExternalFormatUsage {
kTexImage_ExternalFormatUsage,
kReadPixels_ExternalFormatUsage,
kLast_ExternalFormatUsage = kReadPixels_ExternalFormatUsage
};
static const int kExternalFormatUsageCnt = kLast_ExternalFormatUsage + 1;
bool getExternalFormat(GrPixelConfig surfaceConfig, GrPixelConfig memoryConfig,
ExternalFormatUsage usage, GrGLenum* externalFormat,
GrGLenum* externalType) const;
void init(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*);
void initGLSL(const GrGLContextInfo&, const GrGLInterface*);
bool hasPathRenderingSupport(const GrGLContextInfo&, const GrGLInterface*);
void applyDriverCorrectnessWorkarounds(const GrGLContextInfo&, const GrContextOptions&,
GrShaderCaps*);
void onApplyOptionsOverrides(const GrContextOptions& options) override;
bool onIsWindowRectanglesSupportedForRT(const GrBackendRenderTarget&) const override;
void initFSAASupport(const GrContextOptions& contextOptions, const GrGLContextInfo&,
const GrGLInterface*);
void initBlendEqationSupport(const GrGLContextInfo&);
void initStencilSupport(const GrGLContextInfo&);
// This must be called after initFSAASupport().
void initConfigTable(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*,
GrShaderCaps*);
bool onSurfaceSupportsWritePixels(const GrSurface*) const override;
bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
GrGLStandard fStandard;
SkTArray<StencilFormat, true> fStencilFormats;
int fMaxFragmentUniformVectors;
MSFBOType fMSFBOType;
InvalidateFBType fInvalidateFBType;
MapBufferType fMapBufferType;
TransferBufferType fTransferBufferType;
bool fUnpackRowLengthSupport : 1;
bool fPackRowLengthSupport : 1;
bool fPackFlipYSupport : 1;
bool fTextureUsageSupport : 1;
bool fAlpha8IsRenderable: 1;
bool fImagingSupport : 1;
bool fVertexArrayObjectSupport : 1;
bool fDebugSupport : 1;
bool fES2CompatibilitySupport : 1;
bool fDrawInstancedSupport : 1;
bool fDrawIndirectSupport : 1;
bool fDrawRangeElementsSupport : 1;
bool fMultiDrawIndirectSupport : 1;
bool fBaseInstanceSupport : 1;
bool fUseNonVBOVertexAndIndexDynamicData : 1;
bool fIsCoreProfile : 1;
bool fBindFragDataLocationSupport : 1;
bool fRGBA8888PixelsOpsAreSlow : 1;
bool fPartialFBOReadIsSlow : 1;
bool fBindUniformLocationSupport : 1;
bool fRectangleTextureSupport : 1;
bool fTextureSwizzleSupport : 1;
bool fMipMapLevelAndLodControlSupport : 1;
bool fRGBAToBGRAReadbackConversionsAreSlow : 1;
bool fUseBufferDataNullHint : 1;
bool fClearTextureSupport : 1;
bool fProgramBinarySupport : 1;
bool fSamplerObjectSupport : 1;
bool fFBFetchRequiresEnablePerSample : 1;
// Driver workarounds
bool fDoManualMipmapping : 1;
bool fClearToBoundaryValuesIsBroken : 1;
bool fDrawArraysBaseVertexIsBroken : 1;
bool fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO : 1;
bool fUseDrawInsteadOfAllRenderTargetWrites : 1;
bool fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines : 1;
bool fDetachStencilFromMSAABuffersBeforeReadPixels : 1;
bool fDontSetBaseOrMaxLevelForExternalTextures : 1;
int fMaxInstancesPerDrawWithoutCrashing;
uint32_t fBlitFramebufferFlags;
/** Number type of the components (with out considering number of bits.) */
enum FormatType {
kNormalizedFixedPoint_FormatType,
kFloat_FormatType,
};
struct ReadPixelsFormat {
ReadPixelsFormat() : fFormat(0), fType(0) {}
GrGLenum fFormat;
GrGLenum fType;
};
struct ConfigFormats {
ConfigFormats() {
// Inits to known bad GL enum values.
memset(this, 0xAB, sizeof(ConfigFormats));
}
GrGLenum fBaseInternalFormat;
GrGLenum fSizedInternalFormat;
/** The external format and type are to be used when uploading/downloading data using this
config where both the CPU data and GrSurface are the same config. To get the external
format and type when converting between configs while copying to/from memory use
getExternalFormat().
The kTexImage external format is usually the same as kOther except for kSRGBA on some
GL contexts. */
GrGLenum fExternalFormat[kExternalFormatUsageCnt];
GrGLenum fExternalType;
// Either the base or sized internal format depending on the GL and config.
GrGLenum fInternalFormatTexImage;
GrGLenum fInternalFormatRenderbuffer;
};
struct ConfigInfo {
ConfigInfo() : fStencilFormatIndex(kUnknown_StencilIndex), fFlags(0) {}
ConfigFormats fFormats;
FormatType fFormatType;
// On ES contexts there are restrictions on type type/format that may be used for
// ReadPixels. One is implicitly specified by the current FBO's format. The other is
// queryable. This stores the queried option (lazily).
ReadPixelsFormat fSecondReadPixelsFormat;
enum {
// This indicates that a stencil format has not yet been determined for the config.
kUnknown_StencilIndex = -1,
// This indicates that there is no supported stencil format for the config.
kUnsupported_StencilFormatIndex = -2
};
// Index fStencilFormats.
int fStencilFormatIndex;
SkTDArray<int> fColorSampleCounts;
enum {
kTextureable_Flag = 0x1,
kRenderable_Flag = 0x2,
kRenderableWithMSAA_Flag = 0x4,
/** kFBOColorAttachment means that even if the config cannot be a GrRenderTarget, we can
still attach it to a FBO for blitting or reading pixels. */
kFBOColorAttachment_Flag = 0x8,
kCanUseTexStorage_Flag = 0x10,
};
uint32_t fFlags;
// verification of color attachment validity is done while flushing. Although only ever
// used in the (sole) rendering thread it can cause races if it is glommed into fFlags.
bool fVerifiedColorAttachment = false;
GrSwizzle fSwizzle;
};
ConfigInfo fConfigTable[kGrPixelConfigCnt];
typedef GrCaps INHERITED;
};
#endif