blob: 18493b5a762672b534547b8618553857b09d1677 [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrGLGpu_DEFINED
#define GrGLGpu_DEFINED
#include "include/core/SkTypes.h"
#include "include/private/SkTArray.h"
#include "src/core/SkLRUCache.h"
#include "src/gpu/ganesh/GrFinishCallbacks.h"
#include "src/gpu/ganesh/GrGpu.h"
#include "src/gpu/ganesh/GrNativeRect.h"
#include "src/gpu/ganesh/GrProgramDesc.h"
#include "src/gpu/ganesh/GrThreadSafePipelineBuilder.h"
#include "src/gpu/ganesh/GrWindowRectsState.h"
#include "src/gpu/ganesh/GrXferProcessor.h"
#include "src/gpu/ganesh/gl/GrGLAttachment.h"
#include "src/gpu/ganesh/gl/GrGLContext.h"
#include "src/gpu/ganesh/gl/GrGLProgram.h"
#include "src/gpu/ganesh/gl/GrGLRenderTarget.h"
#include "src/gpu/ganesh/gl/GrGLTexture.h"
#include "src/gpu/ganesh/gl/GrGLVertexArray.h"
class GrGLBuffer;
class GrGLOpsRenderPass;
class GrPipeline;
namespace skgpu {
class Swizzle;
}
class GrGLGpu final : public GrGpu {
public:
static sk_sp<GrGpu> Make(sk_sp<const GrGLInterface>, const GrContextOptions&, GrDirectContext*);
~GrGLGpu() override;
void disconnect(DisconnectType) override;
GrThreadSafePipelineBuilder* pipelineBuilder() override;
sk_sp<GrThreadSafePipelineBuilder> refPipelineBuilder() override;
const GrGLContext& glContext() const { return *fGLContext; }
const GrGLInterface* glInterface() const { return fGLContext->glInterface(); }
const GrGLContextInfo& ctxInfo() const { return *fGLContext; }
GrGLStandard glStandard() const { return fGLContext->standard(); }
GrGLVersion glVersion() const { return fGLContext->version(); }
SkSL::GLSLGeneration glslGeneration() const { return fGLContext->glslGeneration(); }
const GrGLCaps& glCaps() const { return *fGLContext->caps(); }
// Used by GrGLProgram to configure OpenGL state.
void bindTexture(int unitIdx, GrSamplerState samplerState, const skgpu::Swizzle&, GrGLTexture*);
// These functions should be used to bind GL objects. They track the GL state and skip redundant
// bindings. Making the equivalent glBind calls directly will confuse the state tracking.
void bindVertexArray(GrGLuint id) {
fHWVertexArrayState.setVertexArrayID(this, id);
}
// These callbacks update state tracking when GL objects are deleted. They are called from
// GrGLResource onRelease functions.
void notifyVertexArrayDelete(GrGLuint id) {
fHWVertexArrayState.notifyVertexArrayDelete(id);
}
// Binds a buffer to the GL target corresponding to 'type', updates internal state tracking, and
// returns the GL target the buffer was bound to.
// When 'type' is kIndex_GrBufferType, this function will also implicitly bind the default VAO.
// If the caller wishes to bind an index buffer to a specific VAO, it can call glBind directly.
GrGLenum bindBuffer(GrGpuBufferType type, const GrBuffer*);
// Flushes state from GrProgramInfo to GL. Returns false if the state couldn't be set.
bool flushGLState(GrRenderTarget*, bool useMultisampleFBO, const GrProgramInfo&);
void flushScissorRect(const SkIRect& scissor, int rtHeight, GrSurfaceOrigin);
// The flushRenderTarget methods will all set the initial viewport to the full extent of the
// backing render target.
void flushViewport(const SkIRect& viewport, int rtHeight, GrSurfaceOrigin);
// Returns the last program bound by flushGLState(), or nullptr if a different program has since
// been put into use via some other method (e.g., resetContext, copySurfaceAsDraw).
// The returned GrGLProgram can be used for binding textures and vertex attributes.
GrGLProgram* currentProgram() {
this->handleDirtyContext();
return fHWProgram.get();
}
// Binds the vertex array that should be used for internal draws, enables 'numAttribs' vertex
// arrays, and flushes the desired primitive restart settings. If an index buffer is provided,
// it will be bound to the vertex array. Otherwise the index buffer binding will be left
// unchanged.
//
// NOTE: This binds the default VAO (ID=zero) unless we are on a core profile, in which case we
// use a placeholder array instead.
GrGLAttribArrayState* bindInternalVertexArray(const GrBuffer* indexBuffer, int numAttribs,
GrPrimitiveRestart primitiveRestart) {
auto* attribState = fHWVertexArrayState.bindInternalVertexArray(this, indexBuffer);
attribState->enableVertexArrays(this, numAttribs, primitiveRestart);
return attribState;
}
// Applies any necessary workarounds and returns the GL primitive type to use in draw calls.
GrGLenum prepareToDraw(GrPrimitiveType primitiveType);
using ResolveDirection = GrGLRenderTarget::ResolveDirection;
// Resolves the render target's single sample FBO into the MSAA, or vice versa.
// If glCaps.framebufferResolvesMustBeFullSize() is true, resolveRect must be equal the render
// target's bounds rect.
// If blitting single to MSAA, glCaps.canResolveSingleToMSAA() must be true.
void resolveRenderFBOs(GrGLRenderTarget*, const SkIRect& resolveRect, ResolveDirection,
bool invalidateReadBufferAfterBlit = false);
// For loading a dynamic MSAA framebuffer when glCaps.canResolveSingleToMSAA() is false.
// NOTE: If glCaps.framebufferResolvesMustBeFullSize() is also true, the drawBounds should be
// equal to the proxy bounds. This is because the render pass will have to do a full size
// resolve back into the single sample FBO when rendering is complete.
void drawSingleIntoMSAAFBO(GrGLRenderTarget* rt, const SkIRect& drawBounds) {
this->copySurfaceAsDraw(rt, true/*drawToMultisampleFBO*/, rt, drawBounds,
drawBounds.topLeft());
}
// The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu.
// Thus this is the implementation of the clear call for the corresponding passthrough function
// on GrGLOpsRenderPass.
void clear(const GrScissorState&, std::array<float, 4> color, GrRenderTarget*,
bool useMultisampleFBO, GrSurfaceOrigin);
// The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu.
// Thus this is the implementation of the clearStencil call for the corresponding passthrough
// function on GrGLOpsrenderPass.
void clearStencilClip(const GrScissorState&, bool insideStencilMask,
GrRenderTarget*, bool useMultisampleFBO, GrSurfaceOrigin);
void beginCommandBuffer(GrGLRenderTarget*, bool useMultisampleFBO,
const SkIRect& bounds, GrSurfaceOrigin,
const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore);
void endCommandBuffer(GrGLRenderTarget*, bool useMultisampleFBO,
const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore);
void invalidateBoundRenderTarget() {
fHWBoundRenderTargetUniqueID.makeInvalid();
}
sk_sp<GrAttachment> makeStencilAttachment(const GrBackendFormat& colorFormat,
SkISize dimensions, int numStencilSamples) override;
sk_sp<GrAttachment> makeMSAAAttachment(SkISize dimensions,
const GrBackendFormat& format,
int numSamples,
GrProtected isProtected,
GrMemoryless) override;
void deleteBackendTexture(const GrBackendTexture&) override;
bool compile(const GrProgramDesc&, const GrProgramInfo&) override;
bool precompileShader(const SkData& key, const SkData& data) override {
return fProgramCache->precompileShader(this->getContext(), key, data);
}
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType,
int sampleCnt,
GrProtected) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
const GrGLContext* glContextForTesting() const override { return &this->glContext(); }
void resetShaderCacheForTesting() const override { fProgramCache->reset(); }
#endif
void submit(GrOpsRenderPass* renderPass) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence) override;
void deleteFence(GrFence) override;
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
std::unique_ptr<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore&,
GrSemaphoreWrapType,
GrWrapOwnership) override;
void insertSemaphore(GrSemaphore* semaphore) override;
void waitSemaphore(GrSemaphore* semaphore) override;
void checkFinishProcs() override;
void finishOutstandingGpuWork() override;
// Calls glGetError() until no errors are reported. Also looks for OOMs.
void clearErrorsAndCheckForOOM();
// Calls glGetError() once and returns the result. Also looks for an OOM.
GrGLenum getErrorAndCheckForOOM();
std::unique_ptr<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
void deleteSync(GrGLsync);
void bindFramebuffer(GrGLenum fboTarget, GrGLuint fboid);
void deleteFramebuffer(GrGLuint fboid);
void flushProgram(sk_sp<GrGLProgram>);
// Version for programs that aren't GrGLProgram.
void flushProgram(GrGLuint);
private:
GrGLGpu(std::unique_ptr<GrGLContext>, GrDirectContext*);
// GrGpu overrides
GrBackendTexture onCreateBackendTexture(SkISize dimensions,
const GrBackendFormat&,
GrRenderable,
GrMipmapped,
GrProtected) override;
GrBackendTexture onCreateCompressedBackendTexture(SkISize dimensions,
const GrBackendFormat&,
GrMipmapped,
GrProtected) override;
bool onClearBackendTexture(const GrBackendTexture&,
sk_sp<skgpu::RefCntedCallback> finishedCallback,
std::array<float, 4> color) override;
bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
sk_sp<skgpu::RefCntedCallback> finishedCallback,
const void* data,
size_t length) override;
void onResetContext(uint32_t resetBits) override;
void onResetTextureBindings() override;
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override;
sk_sp<GrTexture> onCreateTexture(SkISize dimensions,
const GrBackendFormat&,
GrRenderable,
int renderTargetSampleCnt,
SkBudgeted,
GrProtected,
int mipLevelCount,
uint32_t levelClearMask,
std::string_view label) override;
sk_sp<GrTexture> onCreateCompressedTexture(SkISize dimensions,
const GrBackendFormat&,
SkBudgeted,
GrMipmapped,
GrProtected,
const void* data, size_t dataSize) override;
sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType, GrAccessPattern) override;
sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&,
GrWrapOwnership,
GrWrapCacheable,
GrIOType) override;
sk_sp<GrTexture> onWrapCompressedBackendTexture(const GrBackendTexture&,
GrWrapOwnership,
GrWrapCacheable) override;
sk_sp<GrTexture> onWrapRenderableBackendTexture(const GrBackendTexture&,
int sampleCnt,
GrWrapOwnership,
GrWrapCacheable) override;
sk_sp<GrRenderTarget> onWrapBackendRenderTarget(const GrBackendRenderTarget&) override;
// Given a GL format return the index into the stencil format array on GrGLCaps to a
// compatible stencil format, or negative if there is no compatible stencil format.
int getCompatibleStencilIndex(GrGLFormat format);
GrBackendFormat getPreferredStencilFormat(const GrBackendFormat& format) override {
int idx = this->getCompatibleStencilIndex(format.asGLFormat());
if (idx < 0) {
return {};
}
return GrBackendFormat::MakeGL(GrGLFormatToEnum(this->glCaps().stencilFormats()[idx]),
GR_GL_TEXTURE_NONE);
}
void onFBOChanged();
// Returns whether the texture is successfully created. On success, a non-zero texture ID is
// returned. On failure, zero is returned.
// The texture is populated with |texels|, if it is non-null.
// The texture parameters are cached in |initialTexParams|.
GrGLuint createTexture(SkISize dimensions,
GrGLFormat,
GrGLenum target,
GrRenderable,
GrGLTextureParameters::SamplerOverriddenState*,
int mipLevelCount,
GrProtected isProtected);
GrGLuint createCompressedTexture2D(SkISize dimensions,
SkImage::CompressionType compression,
GrGLFormat,
GrMipmapped,
GrGLTextureParameters::SamplerOverriddenState*);
bool onReadPixels(GrSurface*,
SkIRect,
GrColorType surfaceColorType,
GrColorType dstColorType,
void*,
size_t rowBytes) override;
bool onWritePixels(GrSurface*,
SkIRect,
GrColorType surfaceColorType,
GrColorType srcColorType,
const GrMipLevel[],
int mipLevelCount,
bool prepForTexSampling) override;
bool onTransferFromBufferToBuffer(sk_sp<GrGpuBuffer> src,
size_t srcOffset,
sk_sp<GrGpuBuffer> dst,
size_t dstOffset,
size_t size) override;
bool onTransferPixelsTo(GrTexture*,
SkIRect,
GrColorType textureColorType,
GrColorType bufferColorType,
sk_sp<GrGpuBuffer>,
size_t offset,
size_t rowBytes) override;
bool onTransferPixelsFrom(GrSurface*,
SkIRect,
GrColorType surfaceColorType,
GrColorType bufferColorType,
sk_sp<GrGpuBuffer>,
size_t offset) override;
bool readOrTransferPixelsFrom(GrSurface*,
SkIRect rect,
GrColorType surfaceColorType,
GrColorType dstColorType,
void* offsetOrPtr,
int rowWidthInPixels);
// Unbinds xfer buffers from GL for operations that don't need them.
// Before calling any variation of TexImage, TexSubImage, etc..., call this with
// GrGpuBufferType::kXferCpuToGpu to ensure that the PIXEL_UNPACK_BUFFER is unbound.
// Before calling ReadPixels and reading back into cpu memory call this with
// GrGpuBufferType::kXferGpuToCpu to ensure that the PIXEL_PACK_BUFFER is unbound.
void unbindXferBuffer(GrGpuBufferType type);
void onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) override;
bool onRegenerateMipMapLevels(GrTexture*) override;
bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
// binds texture unit in GL
void setTextureUnit(int unitIdx);
void flushBlendAndColorWrite(const skgpu::BlendInfo&, const skgpu::Swizzle&);
void addFinishedProc(GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) override;
GrOpsRenderPass* onGetOpsRenderPass(GrRenderTarget*,
bool useMultisampleFBO,
GrAttachment*,
GrSurfaceOrigin,
const SkIRect&,
const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
GrXferBarrierFlags renderPassXferBarriers) override;
bool onSubmitToGpu(bool syncCpu) override;
bool waitSync(GrGLsync, uint64_t timeout, bool flush);
bool copySurfaceAsDraw(GrSurface* dst, bool drawToMultisampleFBO, GrSurface* src,
const SkIRect& srcRect, const SkIPoint& dstPoint);
void copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint);
bool copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint);
class ProgramCache : public GrThreadSafePipelineBuilder {
public:
ProgramCache(int runtimeProgramCacheSize);
~ProgramCache() override;
void abandon();
void reset();
sk_sp<GrGLProgram> findOrCreateProgram(GrDirectContext*,
const GrProgramInfo&);
sk_sp<GrGLProgram> findOrCreateProgram(GrDirectContext*,
const GrProgramDesc&,
const GrProgramInfo&,
Stats::ProgramCacheResult*);
bool precompileShader(GrDirectContext*, const SkData& key, const SkData& data);
private:
struct Entry;
sk_sp<GrGLProgram> findOrCreateProgramImpl(GrDirectContext*,
const GrProgramDesc&,
const GrProgramInfo&,
Stats::ProgramCacheResult*);
struct DescHash {
uint32_t operator()(const GrProgramDesc& desc) const {
return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
}
};
SkLRUCache<GrProgramDesc, std::unique_ptr<Entry>, DescHash> fMap;
};
void flushColorWrite(bool writeColor);
void flushClearColor(std::array<float, 4>);
// flushes the scissor. see the note on flushBoundTextureAndParams about
// flushing the scissor after that function is called.
void flushScissor(const GrScissorState& scissorState, int rtHeight, GrSurfaceOrigin rtOrigin) {
this->flushScissorTest(GrScissorTest(scissorState.enabled()));
if (scissorState.enabled()) {
this->flushScissorRect(scissorState.rect(), rtHeight, rtOrigin);
}
}
void flushScissorTest(GrScissorTest);
void flushWindowRectangles(const GrWindowRectsState&, const GrGLRenderTarget*, GrSurfaceOrigin);
void disableWindowRectangles();
int numTextureUnits() const { return this->caps()->shaderCaps()->fMaxFragmentSamplers; }
// Binds a texture to a target on the "scratch" texture unit to use for texture operations
// other than usual draw flow (i.e. a GrGLProgram derived from a GrPipeline used to draw). It
// ensures that such operations don't negatively interact with draws. The active texture unit
// and the binding for 'target' will change.
void bindTextureToScratchUnit(GrGLenum target, GrGLint textureID);
// The passed bounds contains the render target's color values that will subsequently be
// written.
void flushRenderTarget(GrGLRenderTarget*, bool useMultisampleFBO, GrSurfaceOrigin,
const SkIRect& bounds);
// This version has an implicit bounds of the entire render target.
void flushRenderTarget(GrGLRenderTarget*, bool useMultisampleFBO);
// This version can be used when the render target's colors will not be written.
void flushRenderTargetNoColorWrites(GrGLRenderTarget*, bool useMultisampleFBO);
void flushStencil(const GrStencilSettings&, GrSurfaceOrigin);
void disableStencil();
void flushConservativeRasterState(bool enable);
void flushWireframeState(bool enable);
void flushFramebufferSRGB(bool enable);
// Uploads src data of a color type to the currently bound texture on the active texture unit.
// The caller specifies color type that the texture is being used with, which may be different
// than the src color type. This fails if the combination of texture format, texture color type,
// and src data color type are not valid. No conversion is performed on the data before passing
// it to GL. 'dstRect' must be the texture bounds if mipLevelCount is greater than 1.
bool uploadColorTypeTexData(GrGLFormat textureFormat,
GrColorType textureColorType,
SkISize texDims,
GrGLenum target,
SkIRect dstRect,
GrColorType srcColorType,
const GrMipLevel texels[],
int mipLevelCount);
// Uploads a constant color to a texture using the "default" format and color type. Overwrites
// entire levels. Bit n in 'levelMask' indicates whether level n should be written. This
// function doesn't know if MIP levels have been allocated, thus levelMask should not have bits
// beyond the low bit set if the texture is not MIP mapped.
bool uploadColorToTex(GrGLFormat textureFormat,
SkISize texDims,
GrGLenum target,
std::array<float, 4> color,
uint32_t levelMask);
// Pushes data to the currently bound texture to the currently active unit. 'dstRect' must be
// the texture bounds if mipLevelCount is greater than 1.
void uploadTexData(SkISize dimensions,
GrGLenum target,
SkIRect dstRect,
GrGLenum externalFormat,
GrGLenum externalType,
size_t bpp,
const GrMipLevel texels[],
int mipLevelCount);
// Helper for onCreateCompressedTexture. Compressed textures are read-only so we only use this
// to populate a new texture. Returns false if we failed to create and upload the texture.
bool uploadCompressedTexData(SkImage::CompressionType compressionType,
GrGLFormat,
SkISize dimensions,
GrMipmapped,
GrGLenum target,
const void* data, size_t dataSize);
// Calls one of various versions of renderBufferStorageMultisample.
bool renderbufferStorageMSAA(const GrGLContext& ctx, int sampleCount, GrGLenum format,
int width, int height);
bool createRenderTargetObjects(const GrGLTexture::Desc&,
int sampleCount,
GrGLRenderTarget::IDs*);
enum TempFBOTarget {
kSrc_TempFBOTarget,
kDst_TempFBOTarget
};
// Binds a surface as a FBO for copying, reading, or clearing. If the surface already owns an
// FBO ID then that ID is bound. If not the surface is temporarily bound to a FBO and that FBO
// is bound. This must be paired with a call to unbindSurfaceFBOForPixelOps().
void bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget);
// Must be called if bindSurfaceFBOForPixelOps was used to bind a surface for copying.
void unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget);
#ifdef SK_ENABLE_DUMP_GPU
void onDumpJSON(SkJSONWriter*) const override;
#endif
bool createCopyProgram(GrTexture* srcTexture);
bool createMipmapProgram(int progIdx);
std::unique_ptr<GrGLContext> fGLContext;
// GL program-related state
sk_sp<ProgramCache> fProgramCache;
///////////////////////////////////////////////////////////////////////////
///@name Caching of GL State
///@{
int fHWActiveTextureUnitIdx;
GrGLuint fHWProgramID;
sk_sp<GrGLProgram> fHWProgram;
enum TriState {
kNo_TriState,
kYes_TriState,
kUnknown_TriState
};
GrGLuint fTempSrcFBOID;
GrGLuint fTempDstFBOID;
GrGLuint fStencilClearFBOID;
// last scissor / viewport scissor state seen by the GL.
struct {
TriState fEnabled;
GrNativeRect fRect;
void invalidate() {
fEnabled = kUnknown_TriState;
fRect.invalidate();
}
} fHWScissorSettings;
class {
public:
bool valid() const { return kInvalidSurfaceOrigin != fRTOrigin; }
void invalidate() { fRTOrigin = kInvalidSurfaceOrigin; }
bool knownDisabled() const { return this->valid() && !fWindowState.enabled(); }
void setDisabled() {
fRTOrigin = kTopLeft_GrSurfaceOrigin;
fWindowState.setDisabled();
}
void set(GrSurfaceOrigin rtOrigin, int width, int height,
const GrWindowRectsState& windowState) {
fRTOrigin = rtOrigin;
fWidth = width;
fHeight = height;
fWindowState = windowState;
}
bool knownEqualTo(GrSurfaceOrigin rtOrigin, int width, int height,
const GrWindowRectsState& windowState) const {
if (!this->valid()) {
return false;
}
if (fWindowState.numWindows() &&
(fRTOrigin != rtOrigin || fWidth != width || fHeight != height)) {
return false;
}
return fWindowState == windowState;
}
private:
enum { kInvalidSurfaceOrigin = -1 };
int fRTOrigin;
int fWidth;
int fHeight;
GrWindowRectsState fWindowState;
} fHWWindowRectsState;
GrNativeRect fHWViewport;
/**
* Tracks vertex attrib array state.
*/
class HWVertexArrayState {
public:
HWVertexArrayState() : fCoreProfileVertexArray(nullptr) { this->invalidate(); }
~HWVertexArrayState() { delete fCoreProfileVertexArray; }
void invalidate() {
fBoundVertexArrayIDIsValid = false;
fDefaultVertexArrayAttribState.invalidate();
if (fCoreProfileVertexArray) {
fCoreProfileVertexArray->invalidateCachedState();
}
}
void notifyVertexArrayDelete(GrGLuint id) {
if (fBoundVertexArrayIDIsValid && fBoundVertexArrayID == id) {
// Does implicit bind to 0
fBoundVertexArrayID = 0;
}
}
void setVertexArrayID(GrGLGpu* gpu, GrGLuint arrayID) {
if (!gpu->glCaps().vertexArrayObjectSupport()) {
SkASSERT(0 == arrayID);
return;
}
if (!fBoundVertexArrayIDIsValid || arrayID != fBoundVertexArrayID) {
GR_GL_CALL(gpu->glInterface(), BindVertexArray(arrayID));
fBoundVertexArrayIDIsValid = true;
fBoundVertexArrayID = arrayID;
}
}
/**
* Binds the vertex array that should be used for internal draws, and returns its attrib
* state. This binds the default VAO (ID=zero) unless we are on a core profile, in which
* case we use a placeholder array instead.
*
* If an index buffer is provided, it will be bound to the vertex array. Otherwise the
* index buffer binding will be left unchanged.
*
* The returned GrGLAttribArrayState should be used to set vertex attribute arrays.
*/
GrGLAttribArrayState* bindInternalVertexArray(GrGLGpu*, const GrBuffer* ibuff = nullptr);
private:
GrGLuint fBoundVertexArrayID;
bool fBoundVertexArrayIDIsValid;
// We return a non-const pointer to this from bindArrayAndBuffersToDraw when vertex array 0
// is bound. However, this class is internal to GrGLGpu and this object never leaks out of
// GrGLGpu.
GrGLAttribArrayState fDefaultVertexArrayAttribState;
// This is used when we're using a core profile.
GrGLVertexArray* fCoreProfileVertexArray;
} fHWVertexArrayState;
struct {
GrGLenum fGLTarget;
GrGpuResource::UniqueID fBoundBufferUniqueID;
bool fBufferZeroKnownBound;
void invalidate() {
fBoundBufferUniqueID.makeInvalid();
fBufferZeroKnownBound = false;
}
} fHWBufferState[kGrGpuBufferTypeCount];
auto* hwBufferState(GrGpuBufferType type) {
unsigned typeAsUInt = static_cast<unsigned>(type);
SkASSERT(typeAsUInt < SK_ARRAY_COUNT(fHWBufferState));
SkASSERT(type != GrGpuBufferType::kUniform);
return &fHWBufferState[typeAsUInt];
}
enum class FlushType {
kIfRequired,
kForce,
};
// This calls glFlush if it is required for previous operations or kForce is passed.
void flush(FlushType flushType = FlushType::kIfRequired);
void setNeedsFlush() { fNeedsGLFlush = true; }
struct {
skgpu::BlendEquation fEquation;
skgpu::BlendCoeff fSrcCoeff;
skgpu::BlendCoeff fDstCoeff;
SkPMColor4f fConstColor;
bool fConstColorValid;
TriState fEnabled;
void invalidate() {
fEquation = skgpu::BlendEquation::kIllegal;
fSrcCoeff = skgpu::BlendCoeff::kIllegal;
fDstCoeff = skgpu::BlendCoeff::kIllegal;
fConstColorValid = false;
fEnabled = kUnknown_TriState;
}
} fHWBlendState;
TriState fHWConservativeRasterEnabled;
TriState fHWWireframeEnabled;
GrStencilSettings fHWStencilSettings;
GrSurfaceOrigin fHWStencilOrigin;
TriState fHWStencilTestEnabled;
TriState fHWWriteToColor;
GrGpuResource::UniqueID fHWBoundRenderTargetUniqueID;
bool fHWBoundFramebufferIsMSAA;
TriState fHWSRGBFramebuffer;
class TextureUnitBindings {
public:
TextureUnitBindings() = default;
TextureUnitBindings(const TextureUnitBindings&) = delete;
TextureUnitBindings& operator=(const TextureUnitBindings&) = delete;
GrGpuResource::UniqueID boundID(GrGLenum target) const;
bool hasBeenModified(GrGLenum target) const;
void setBoundID(GrGLenum target, GrGpuResource::UniqueID);
void invalidateForScratchUse(GrGLenum target);
void invalidateAllTargets(bool markUnmodified);
private:
struct TargetBinding {
GrGpuResource::UniqueID fBoundResourceID;
bool fHasBeenModified = false;
};
TargetBinding fTargetBindings[3];
};
SkAutoTArray<TextureUnitBindings> fHWTextureUnitBindings;
GrGLfloat fHWClearColor[4];
GrGLuint fBoundDrawFramebuffer = 0;
/** IDs for copy surface program. (3 sampler types) */
struct {
GrGLuint fProgram = 0;
GrGLint fTextureUniform = 0;
GrGLint fTexCoordXformUniform = 0;
GrGLint fPosXformUniform = 0;
} fCopyPrograms[3];
sk_sp<GrGLBuffer> fCopyProgramArrayBuffer;
/** IDs for texture mipmap program. (4 filter configurations) */
struct {
GrGLuint fProgram = 0;
GrGLint fTextureUniform = 0;
GrGLint fTexCoordXformUniform = 0;
} fMipmapPrograms[4];
sk_sp<GrGLBuffer> fMipmapProgramArrayBuffer;
static int TextureToCopyProgramIdx(GrTexture* texture);
static int TextureSizeToMipmapProgramIdx(int width, int height) {
const bool wide = (width > 1) && SkToBool(width & 0x1);
const bool tall = (height > 1) && SkToBool(height & 0x1);
return (wide ? 0x2 : 0x0) | (tall ? 0x1 : 0x0);
}
GrPrimitiveType fLastPrimitiveType;
GrGLTextureParameters::ResetTimestamp fResetTimestampForTextureParameters = 0;
class SamplerObjectCache;
std::unique_ptr<SamplerObjectCache> fSamplerObjectCache;
std::unique_ptr<GrGLOpsRenderPass> fCachedOpsRenderPass;
GrFinishCallbacks fFinishCallbacks;
// If we've called a command that requires us to call glFlush than this will be set to true
// since we defer calling flush until submit time. When we call submitToGpu if this is true then
// we call glFlush and reset this to false.
bool fNeedsGLFlush = false;
SkDEBUGCODE(bool fIsExecutingCommandBuffer_DebugOnly = false);
friend class GrGLPathRendering; // For accessing setTextureUnit.
using INHERITED = GrGpu;
};
#endif