/*
* 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 "glsl/GrGLSL.h"
#include "GrCaps.h"
#include "GrGLStencilAttachment.h"
#include "GrSwizzle.h"
#include "SkChecksum.h"
#include "SkTHash.h"
#include "SkTArray.h"
class GrGLContextInfo;
class GrGLSLCaps;
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,
/**
* GL3.0-style MSAA FBO (GL_ARB_framebuffer_object).
*/
kDesktop_ARB_MSFBOType,
/**
* earlier GL_EXT_framebuffer* extensions
*/
kDesktop_EXT_MSFBOType,
/**
* Similar to kDesktop_ARB but with additional restrictions on glBlitFramebuffer.
*/
kES_3_0_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 BlitFramebufferSupport {
kNone_BlitFramebufferSupport,
/**
* ANGLE exposes a limited blit framebuffer extension that does not allow for stretching
* or mirroring.
*/
kNoScalingNoMirroring_BlitFramebufferSupport,
kFull_BlitFramebufferSupport
};
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 {
SkASSERT(kGrPixelConfigCnt > config);
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag);
}
bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
SkASSERT(kGrPixelConfigCnt > config);
if (withMSAA) {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderableWithMSAA_Flag);
} else {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag);
}
}
/** Returns the mapping between GrPixelConfig components and GL internal format components. */
const GrSwizzle& configSwizzle(GrPixelConfig config) const {
return fConfigTable[config].fSwizzle;
}
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;
bool getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const;
/**
* 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].fFlags |= ConfigInfo::kVerifiedColorAttachment_Flag;
}
/**
* Call to check whether a config has been verified as a valid color
* attachment.
*/
bool isConfigVerifiedColorAttachment(GrPixelConfig config) const {
return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kVerifiedColorAttachment_Flag);
}
/**
* 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.
*/
BlitFramebufferSupport blitFramebufferSupport() const { return fBlitFramebufferSupport; }
/**
* 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; }
/// maximum number of attribute values per vertex
int maxVertexAttributes() const { return fMaxVertexAttributes; }
/// maximum number of texture units accessible in the fragment shader.
int maxFragmentTextureUnits() const { return fMaxFragmentTextureUnits; }
/**
* 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_UNPACK_FLIP_Y
bool unpackFlipYSupport() const { return fUnpackFlipYSupport; }
/// 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 there support for glTexStorage
bool texStorageSupport() const { return fTexStorageSupport; }
/// Is there support for GL_RED and GL_R8
bool textureRedSupport() const { return fTextureRedSupport; }
/// 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_EXT_direct_state_access?
bool directStateAccessSupport() const { return fDirectStateAccessSupport; }
/// Is there support for GL_KHR_debug?
bool debugSupport() const { return fDebugSupport; }
/// Is there support for ES2 compatability?
bool ES2CompatibilitySupport() const { return fES2CompatibilitySupport; }
/// Can we call glDisable(GL_MULTISAMPLE)?
bool multisampleDisableSupport() const { return fMultisampleDisableSupport; }
/// 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; }
/// 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; }
/// Does ReadPixels support reading readConfig pixels from a FBO that is renderTargetConfig?
bool readPixelsSupported(GrPixelConfig renderTargetConfig,
GrPixelConfig readConfig,
std::function<void (GrGLenum, GrGLint*)> getIntegerv,
std::function<bool ()> bindRenderTarget) const;
bool isCoreProfile() const { return fIsCoreProfile; }
bool bindFragDataLocationSupport() const { return fBindFragDataLocationSupport; }
bool bindUniformLocationSupport() const { return fBindUniformLocationSupport; }
/// Are textures with GL_TEXTURE_EXTERNAL_OES type supported.
bool externalTextureSupport() const { return fExternalTextureSupport; }
/// Are textures with GL_TEXTURE_RECTANGLE type supported.
bool rectangleTextureSupport() const { return fRectangleTextureSupport; }
/// GL_ARB_texture_swizzle
bool textureSwizzleSupport() const { return fTextureSwizzleSupport; }
/**
* Is there support for enabling/disabling sRGB writes for sRGB-capable color attachments?
* If false this does not mean sRGB is not supported but rather that if it is supported
* it cannot be turned off for configs that support it.
*/
bool srgbWriteControl() const { return fSRGBWriteControl; }
/**
* Returns a string containing the caps info.
*/
SkString dump() const override;
bool rgba8888PixelsOpsAreSlow() const { return fRGBA8888PixelsOpsAreSlow; }
bool partialFBOReadIsSlow() const { return fPartialFBOReadIsSlow; }
const GrGLSLCaps* glslCaps() const { return reinterpret_cast<GrGLSLCaps*>(fShaderCaps.get()); }
private:
enum ExternalFormatUsage {
kTexImage_ExternalFormatUsage,
kOther_ExternalFormatUsage,
kLast_ExternalFormatUsage = kOther_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&);
bool hasPathRenderingSupport(const GrGLContextInfo&, const GrGLInterface*);
void onApplyOptionsOverrides(const GrContextOptions& options) override;
void initFSAASupport(const GrGLContextInfo&, const GrGLInterface*);
void initBlendEqationSupport(const GrGLContextInfo&);
void initStencilFormats(const GrGLContextInfo&);
// This must be called after initFSAASupport().
void initConfigTable(const GrGLContextInfo&, const GrGLInterface* gli, GrGLSLCaps* glslCaps);
void initShaderPrecisionTable(const GrGLContextInfo& ctxInfo,
const GrGLInterface* intf,
GrGLSLCaps* glslCaps);
GrGLStandard fStandard;
SkTArray<StencilFormat, true> fStencilFormats;
int fMaxFragmentUniformVectors;
int fMaxVertexAttributes;
int fMaxFragmentTextureUnits;
MSFBOType fMSFBOType;
InvalidateFBType fInvalidateFBType;
MapBufferType fMapBufferType;
TransferBufferType fTransferBufferType;
bool fUnpackRowLengthSupport : 1;
bool fUnpackFlipYSupport : 1;
bool fPackRowLengthSupport : 1;
bool fPackFlipYSupport : 1;
bool fTextureUsageSupport : 1;
bool fTexStorageSupport : 1;
bool fTextureRedSupport : 1;
bool fImagingSupport : 1;
bool fVertexArrayObjectSupport : 1;
bool fDirectStateAccessSupport : 1;
bool fDebugSupport : 1;
bool fES2CompatibilitySupport : 1;
bool fMultisampleDisableSupport : 1;
bool fDrawIndirectSupport : 1;
bool fMultiDrawIndirectSupport : 1;
bool fBaseInstanceSupport : 1;
bool fUseNonVBOVertexAndIndexDynamicData : 1;
bool fIsCoreProfile : 1;
bool fBindFragDataLocationSupport : 1;
bool fSRGBWriteControl : 1;
bool fRGBA8888PixelsOpsAreSlow : 1;
bool fPartialFBOReadIsSlow : 1;
bool fBindUniformLocationSupport : 1;
bool fExternalTextureSupport : 1;
bool fRectangleTextureSupport : 1;
bool fTextureSwizzleSupport : 1;
BlitFramebufferSupport fBlitFramebufferSupport;
/** 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;
enum {
kVerifiedColorAttachment_Flag = 0x1,
kTextureable_Flag = 0x2,
kRenderable_Flag = 0x4,
kRenderableWithMSAA_Flag = 0x8,
};
uint32_t fFlags;
GrSwizzle fSwizzle;
};
ConfigInfo fConfigTable[kGrPixelConfigCnt];
typedef GrCaps INHERITED;
};
#endif