* 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 <list>
#include "include/core/SkTypes.h"
#include "include/private/SkTArray.h"
#include "src/core/SkLRUCache.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrMesh.h"
#include "src/gpu/GrWindowRectsState.h"
#include "src/gpu/GrXferProcessor.h"
#include "src/gpu/gl/GrGLContext.h"
#include "src/gpu/gl/GrGLIRect.h"
#include "src/gpu/gl/GrGLPathRendering.h"
#include "src/gpu/gl/GrGLProgram.h"
#include "src/gpu/gl/GrGLRenderTarget.h"
#include "src/gpu/gl/GrGLStencilAttachment.h"
#include "src/gpu/gl/GrGLTexture.h"
#include "src/gpu/gl/GrGLVertexArray.h"
class GrGLBuffer;
class GrGLGpuRTCommandBuffer;
class GrGLGpuTextureCommandBuffer;
class GrPipeline;
class GrSwizzle;
#ifdef SK_DEBUG
#define PROGRAM_CACHE_STATS
#endif
class GrGLGpu final : public GrGpu, private GrMesh::SendToGpuImpl {
public:
static sk_sp<GrGpu> Make(sk_sp<const GrGLInterface>, const GrContextOptions&, GrContext*);
~GrGLGpu() override;
void disconnect(DisconnectType) override;
const GrGLContext& glContext() const { return *fGLContext; }
const GrGLInterface* glInterface() const { return fGLContext->interface(); }
const GrGLContextInfo& ctxInfo() const { return *fGLContext; }
GrGLStandard glStandard() const { return fGLContext->standard(); }
GrGLVersion glVersion() const { return fGLContext->version(); }
GrGLSLGeneration glslGeneration() const { return fGLContext->glslGeneration(); }
const GrGLCaps& glCaps() const { return *fGLContext->caps(); }
GrGLPathRendering* glPathRendering() {
SkASSERT(glCaps().shaderCaps()->pathRenderingSupport());
return static_cast<GrGLPathRendering*>(pathRendering());
}
void bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwizzle&, GrGLTexture*);
void bindVertexArray(GrGLuint id) {
fHWVertexArrayState.setVertexArrayID(this, id);
}
void notifyVertexArrayDelete(GrGLuint id) {
fHWVertexArrayState.notifyVertexArrayDelete(id);
}
GrGLenum bindBuffer(GrGpuBufferType type, const GrBuffer*);
void draw(GrRenderTarget*, GrSurfaceOrigin,
const GrPrimitiveProcessor&,
const GrPipeline&,
const GrPipeline::FixedDynamicState*,
const GrPipeline::DynamicStateArrays*,
const GrMesh[],
int meshCount);
void sendMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount,
int baseVertex) final;
void sendIndexedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount,
int baseIndex, uint16_t minIndexValue, uint16_t maxIndexValue,
const GrBuffer* vertexBuffer, int baseVertex,
GrPrimitiveRestart) final;
void sendInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* vertexBuffer, int vertexCount,
int baseVertex, const GrBuffer* instanceBuffer, int instanceCount,
int baseInstance) final;
void sendIndexedInstancedMeshToGpu(GrPrimitiveType, const GrBuffer* indexBuffer, int indexCount,
int baseIndex, const GrBuffer* vertexBuffer, int baseVertex,
const GrBuffer* instanceBuffer, int instanceCount,
int baseInstance, GrPrimitiveRestart) final;
void clear(const GrFixedClip&, const SkPMColor4f&, GrRenderTarget*, GrSurfaceOrigin);
void clearStencilClip(const GrFixedClip&, bool insideStencilMask,
GrRenderTarget*, GrSurfaceOrigin);
void clearStencil(GrRenderTarget*, int clearValue);
GrGpuRTCommandBuffer* getCommandBuffer(
GrRenderTarget*, GrSurfaceOrigin, const SkRect&,
const GrGpuRTCommandBuffer::LoadAndStoreInfo&,
const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo&) override;
GrGpuTextureCommandBuffer* getCommandBuffer(GrTexture*, GrSurfaceOrigin) override;
void invalidateBoundRenderTarget() {
fHWBoundRenderTargetUniqueID.makeInvalid();
}
GrStencilAttachment* createStencilAttachmentForRenderTarget(
const GrRenderTarget* rt, int width, int height, int numStencilSamples) override;
GrBackendTexture createBackendTexture(int w, int h, const GrBackendFormat&,
GrMipMapped, GrRenderable,
const void* pixels, size_t rowBytes,
const SkColor4f* color,
GrProtected isProtected) override;
void deleteBackendTexture(const GrBackendTexture&) override;
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
const GrGLContext* glContextForTesting() const override { return &this->glContext(); }
void resetShaderCacheForTesting() const override { fProgramCache->reset(); }
void testingOnly_flushGpuAndSync() override;
#endif
void submit(GrGpuCommandBuffer* buffer) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence, uint64_t timeout) override;
void deleteFence(GrFence) const override;
sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrResourceProvider::SemaphoreWrapType wrapType,
GrWrapOwnership ownership) override;
void insertSemaphore(sk_sp<GrSemaphore> semaphore) override;
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
void checkFinishProcs() override;
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
void deleteSync(GrGLsync) const;
void insertEventMarker(const char*);
void bindFramebuffer(GrGLenum fboTarget, GrGLuint fboid);
void deleteFramebuffer(GrGLuint fboid);
private:
GrGLGpu(std::unique_ptr<GrGLContext>, GrContext*);
void onResetContext(uint32_t resetBits) override;
void onResetTextureBindings() override;
void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override;
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override;
sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&,
const GrBackendFormat&,
GrRenderable,
int renderTargetSampleCnt,
SkBudgeted,
GrProtected,
const GrMipLevel[],
int mipLevelCount) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType compression, SkBudgeted,
const void* data) override;
sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType intendedType, GrAccessPattern,
const void* data) override;
sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrColorType, GrWrapOwnership,
GrWrapCacheable, GrIOType) override;
sk_sp<GrTexture> onWrapRenderableBackendTexture(const GrBackendTexture&, int sampleCnt,
GrColorType, GrWrapOwnership,
GrWrapCacheable) override;
sk_sp<GrRenderTarget> onWrapBackendRenderTarget(const GrBackendRenderTarget&,
GrColorType) override;
sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTexture&,
int sampleCnt, GrColorType) override;
int getCompatibleStencilIndex(GrGLFormat format);
void onFBOChanged();
GrGLuint createTexture2D(const SkISize& size,
GrGLFormat format,
GrRenderable,
GrGLTextureParameters::SamplerOverriddenState* initialState,
GrColorType textureColorType,
GrColorType srcColorType,
const GrMipLevel texels[],
int mipLevelCount,
GrMipMapsStatus* mipMapsStatus);
GrGLuint createCompressedTexture2D(const SkISize& size, GrGLFormat format,
SkImage::CompressionType compression,
GrGLTextureParameters::SamplerOverriddenState* initialState,
const void* data);
bool onReadPixels(GrSurface*, int left, int top, int width, int height,
GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
size_t rowBytes) override;
bool onWritePixels(GrSurface*, int left, int top, int width, int height,
GrColorType surfaceColorType, GrColorType srcColorType,
const GrMipLevel texels[], int mipLevelCount) override;
bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
GrColorType textureColorType, GrColorType bufferColorType,
GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) override;
bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
GrColorType surfaceColorType, GrColorType bufferColorType,
GrGpuBuffer* transferBuffer, size_t offset) override;
bool readOrTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
GrColorType surfaceColorType, GrColorType dstColorType,
void* offsetOrPtr, int rowWidthInPixels);
void unbindCpuToGpuXferBuffer();
void onResolveRenderTarget(GrRenderTarget* target) override;
bool onRegenerateMipMapLevels(GrTexture*) override;
bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint, bool canDiscardOutsideDstRect) override;
void setTextureUnit(int unitIdx);
* primitiveProcessorTextures must contain GrPrimitiveProcessor::numTextureSamplers() *
* numPrimitiveProcessorTextureSets entries.
*/
void resolveAndGenerateMipMapsForProcessorTextures(
const GrPrimitiveProcessor&, const GrPipeline&,
const GrTextureProxy* const primitiveProcessorTextures[],
int numPrimitiveProcessorTextureSets);
bool flushGLState(GrRenderTarget*, GrSurfaceOrigin, const GrPrimitiveProcessor&,
const GrPipeline&, const GrPipeline::FixedDynamicState*,
const GrPipeline::DynamicStateArrays*, int dynamicStateArraysLength,
bool willDrawPoints);
void flushProgram(sk_sp<GrGLProgram>);
void flushProgram(GrGLuint);
void setupGeometry(const GrBuffer* indexBuffer,
const GrBuffer* vertexBuffer,
int baseVertex,
const GrBuffer* instanceBuffer,
int baseInstance,
GrPrimitiveRestart);
void flushBlendAndColorWrite(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&);
void onFinishFlush(GrSurfaceProxy*[], int n, SkSurface::BackendSurfaceAccess access,
const GrFlushInfo&, const GrPrepareForExternalIORequests&) override;
bool waitSync(GrGLsync, uint64_t timeout, bool flush);
bool copySurfaceAsDraw(GrSurface* dst, 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);
static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
class ProgramCache : public ::SkNoncopyable {
public:
ProgramCache(GrGLGpu* gpu);
~ProgramCache();
void abandon();
void reset();
GrGLProgram* refProgram(GrGLGpu*, GrRenderTarget*, GrSurfaceOrigin,
const GrPrimitiveProcessor&,
const GrTextureProxy* const primProcProxies[],
const GrPipeline&, bool hasPointSize);
private:
static const int kMaxEntries = 128;
struct Entry;
int search(const GrProgramDesc& desc) const;
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;
GrGLGpu* fGpu;
#ifdef PROGRAM_CACHE_STATS
int fTotalRequests;
int fCacheMisses;
int fHashMisses;
#endif
};
void flushColorWrite(bool writeColor);
void flushClearColor(GrGLfloat r, GrGLfloat g, GrGLfloat b, GrGLfloat a);
void flushScissor(const GrScissorState&, int rtWidth, int rtHeight, GrSurfaceOrigin rtOrigin);
void disableScissor();
void flushWindowRectangles(const GrWindowRectsState&, const GrGLRenderTarget*, GrSurfaceOrigin);
void disableWindowRectangles();
int numTextureUnits() const { return this->caps()->shaderCaps()->maxFragmentSamplers(); }
void bindTextureToScratchUnit(GrGLenum target, GrGLint textureID);
void flushRenderTarget(GrGLRenderTarget*, GrSurfaceOrigin, const SkIRect& bounds);
void flushRenderTarget(GrGLRenderTarget*);
void flushRenderTargetNoColorWrites(GrGLRenderTarget*);
void flushViewport(int width, int height);
void flushStencil(const GrStencilSettings&, GrSurfaceOrigin);
void disableStencil();
void flushHWAAState(GrRenderTarget* rt, bool useHWAA);
void flushFramebufferSRGB(bool enable);
enum UploadType {
kNewTexture_UploadType,
kWrite_UploadType,
};
bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType,
int texWidth, int texHeight, GrGLenum target, UploadType uploadType,
int left, int top, int width, int height, GrColorType srcColorType,
const GrMipLevel texels[], int mipLevelCount,
GrMipMapsStatus* mipMapsStatus = nullptr);
bool uploadCompressedTexData(GrGLFormat,
SkImage::CompressionType,
const SkISize& size,
GrGLenum target,
const void* data);
bool createRenderTargetObjects(const GrGLTexture::Desc&,
int sampleCount,
GrGLRenderTarget::IDs*);
enum TempFBOTarget {
kSrc_TempFBOTarget,
kDst_TempFBOTarget
};
void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget);
void unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface);
#ifdef SK_ENABLE_DUMP_GPU
void onDumpJSON(SkJSONWriter*) const override;
#endif
bool createCopyProgram(GrTexture* srcTexture);
bool createMipmapProgram(int progIdx);
std::unique_ptr<GrGLContext> fGLContext;
ProgramCache* fProgramCache;
int fHWActiveTextureUnitIdx;
GrGLuint fHWProgramID;
sk_sp<GrGLProgram> fHWProgram;
enum TriState {
kNo_TriState,
kYes_TriState,
kUnknown_TriState
};
GrGLuint fTempSrcFBOID;
GrGLuint fTempDstFBOID;
GrGLuint fStencilClearFBOID;
struct {
TriState fEnabled;
GrGLIRect 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;
GrGLIRect 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) {
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 dummy array instead.
*
* If an index buffer is privided, 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;
GrGLAttribArrayState fDefaultVertexArrayAttribState;
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));
return &fHWBufferState[typeAsUInt];
}
struct {
GrBlendEquation fEquation;
GrBlendCoeff fSrcCoeff;
GrBlendCoeff fDstCoeff;
SkPMColor4f fConstColor;
bool fConstColorValid;
TriState fEnabled;
void invalidate() {
fEquation = kIllegal_GrBlendEquation;
fSrcCoeff = kIllegal_GrBlendCoeff;
fDstCoeff = kIllegal_GrBlendCoeff;
fConstColorValid = false;
fEnabled = kUnknown_TriState;
}
} fHWBlendState;
TriState fMSAAEnabled;
GrStencilSettings fHWStencilSettings;
GrSurfaceOrigin fHWStencilOrigin;
TriState fHWStencilTestEnabled;
TriState fHWWriteToColor;
GrGpuResource::UniqueID fHWBoundRenderTargetUniqueID;
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;
struct {
GrGLuint fProgram = 0;
GrGLint fTextureUniform = 0;
GrGLint fTexCoordXformUniform = 0;
GrGLint fPosXformUniform = 0;
} fCopyPrograms[3];
sk_sp<GrGLBuffer> fCopyProgramArrayBuffer;
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<GrGLGpuRTCommandBuffer> fCachedRTCommandBuffer;
std::unique_ptr<GrGLGpuTextureCommandBuffer> fCachedTexCommandBuffer;
struct FinishCallback {
GrGpuFinishedProc fCallback;
GrGpuFinishedContext fContext;
GrGLsync fSync;
};
std::list<FinishCallback> fFinishCallbacks;
friend class GrGLPathRendering;
typedef GrGpu INHERITED;
};
#endif