diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/gpu/gl/GrGpuGL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/gpu/gl/GrGpuGL.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,464 @@ +/* + * 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 GrGpuGL_DEFINED +#define GrGpuGL_DEFINED + +#include "GrBinHashKey.h" +#include "GrDrawState.h" +#include "GrGLContext.h" +#include "GrGLIRect.h" +#include "GrGLIndexBuffer.h" +#include "GrGLProgram.h" +#include "GrGLStencilBuffer.h" +#include "GrGLTexture.h" +#include "GrGLVertexArray.h" +#include "GrGLVertexBuffer.h" +#include "GrGpu.h" +#include "GrTHashTable.h" +#include "SkTypes.h" + +#ifdef SK_DEVELOPER +#define PROGRAM_CACHE_STATS +#endif + +class GrGpuGL : public GrGpu { +public: + GrGpuGL(const GrGLContext& ctx, GrContext* context); + virtual ~GrGpuGL(); + + 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(); } + + // Used by GrGLProgram and GrGLTexGenProgramEffects to configure OpenGL state. + void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture); + void setProjectionMatrix(const SkMatrix& matrix, + const SkISize& renderTargetSize, + GrSurfaceOrigin renderTargetOrigin); + enum TexGenComponents { + kS_TexGenComponents = 1, + kST_TexGenComponents = 2, + kSTR_TexGenComponents = 3 + }; + void enableTexGen(int unitIdx, TexGenComponents, const GrGLfloat* coefficients); + void enableTexGen(int unitIdx, TexGenComponents, const SkMatrix& matrix); + void flushTexGenSettings(int numUsedTexCoordSets); + bool shouldUseFixedFunctionTexturing() const { + return this->glCaps().fixedFunctionSupport() && + this->glCaps().pathRenderingSupport(); + } + + bool programUnitTest(int maxStages); + + // GrGpu overrides + virtual GrPixelConfig preferredReadPixelsConfig(GrPixelConfig readConfig, + GrPixelConfig surfaceConfig) const SK_OVERRIDE; + virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig writeConfig, + GrPixelConfig surfaceConfig) const SK_OVERRIDE; + virtual bool canWriteTexturePixels(const GrTexture*, GrPixelConfig srcConfig) const SK_OVERRIDE; + virtual bool readPixelsWillPayForYFlip( + GrRenderTarget* renderTarget, + int left, int top, + int width, int height, + GrPixelConfig config, + size_t rowBytes) const SK_OVERRIDE; + virtual bool fullReadPixelsIsFasterThanPartial() const SK_OVERRIDE; + + virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE; + + virtual void abandonResources() SK_OVERRIDE; + + // 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) { + fHWGeometryState.setVertexArrayID(this, id); + } + void bindIndexBufferAndDefaultVertexArray(GrGLuint id) { + fHWGeometryState.setIndexBufferIDOnDefaultVertexArray(this, id); + } + void bindVertexBuffer(GrGLuint id) { + fHWGeometryState.setVertexBufferID(this, id); + } + + // These callbacks update state tracking when GL objects are deleted. They are called from + // GrGLResource onRelease functions. + void notifyVertexArrayDelete(GrGLuint id) { + fHWGeometryState.notifyVertexArrayDelete(id); + } + void notifyVertexBufferDelete(GrGLuint id) { + fHWGeometryState.notifyVertexBufferDelete(id); + } + void notifyIndexBufferDelete(GrGLuint id) { + fHWGeometryState.notifyIndexBufferDelete(id); + } + void notifyTextureDelete(GrGLTexture* texture); + void notifyRenderTargetDelete(GrRenderTarget* renderTarget); + +protected: + virtual bool onCopySurface(GrSurface* dst, + GrSurface* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) SK_OVERRIDE; + + virtual bool onCanCopySurface(GrSurface* dst, + GrSurface* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) SK_OVERRIDE; + +private: + // GrGpu overrides + virtual void onResetContext(uint32_t resetBits) SK_OVERRIDE; + + virtual GrTexture* onCreateTexture(const GrTextureDesc& desc, + const void* srcData, + size_t rowBytes) SK_OVERRIDE; + virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) SK_OVERRIDE; + virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) SK_OVERRIDE; + virtual GrPath* onCreatePath(const SkPath&, const SkStrokeRec&) SK_OVERRIDE; + virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) SK_OVERRIDE; + virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) SK_OVERRIDE; + virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt, + int width, + int height) SK_OVERRIDE; + virtual bool attachStencilBufferToRenderTarget( + GrStencilBuffer* sb, + GrRenderTarget* rt) SK_OVERRIDE; + + virtual void onClear(const SkIRect* rect, GrColor color, bool canIgnoreRect) SK_OVERRIDE; + + virtual void onForceRenderTargetFlush() SK_OVERRIDE; + + virtual bool onReadPixels(GrRenderTarget* target, + int left, int top, + int width, int height, + GrPixelConfig, + void* buffer, + size_t rowBytes) SK_OVERRIDE; + + virtual bool onWriteTexturePixels(GrTexture* texture, + int left, int top, int width, int height, + GrPixelConfig config, const void* buffer, + size_t rowBytes) SK_OVERRIDE; + + virtual void onResolveRenderTarget(GrRenderTarget* target) SK_OVERRIDE; + + virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE; + + virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; + virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; + + virtual void clearStencil() SK_OVERRIDE; + virtual void clearStencilClip(const SkIRect& rect, + bool insideClip) SK_OVERRIDE; + virtual bool flushGraphicsState(DrawType, const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE; + + // GrDrawTarget ovverides + virtual void onInstantGpuTraceEvent(const char* marker) SK_OVERRIDE; + virtual void onPushGpuTraceEvent(const char* marker) SK_OVERRIDE; + virtual void onPopGpuTraceEvent() SK_OVERRIDE; + + + // binds texture unit in GL + void setTextureUnit(int unitIdx); + + // Sets up vertex attribute pointers and strides. On return indexOffsetInBytes gives the offset + // an into the index buffer. It does not account for drawInfo.startIndex() but rather the start + // index is relative to the returned offset. + void setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes); + + // Subclasses should call this to flush the blend state. + // The params should be the final coefficients to apply + // (after any blending optimizations or dual source blending considerations + // have been accounted for). + void flushBlend(bool isLines, GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff); + + bool hasExtension(const char* ext) const { return fGLContext.hasExtension(ext); } + + static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff); + + class ProgramCache : public ::SkNoncopyable { + public: + ProgramCache(GrGpuGL* gpu); + ~ProgramCache(); + + void abandon(); + GrGLProgram* getProgram(const GrGLProgramDesc& desc, + const GrEffectStage* colorStages[], + const GrEffectStage* coverageStages[]); + + private: + enum { + // We may actually have kMaxEntries+1 shaders in the GL context because we create a new + // shader before evicting from the cache. + kMaxEntries = 32, + kHashBits = 6, + }; + + struct Entry; + + struct ProgDescLess; + + // binary search for entry matching desc. returns index into fEntries that matches desc or ~ + // of the index of where it should be inserted. + int search(const GrGLProgramDesc& desc) const; + + // sorted array of all the entries + Entry* fEntries[kMaxEntries]; + // hash table based on lowest kHashBits bits of the program key. Used to avoid binary + // searching fEntries. + Entry* fHashTable[1 << kHashBits]; + + int fCount; + unsigned int fCurrLRUStamp; + GrGpuGL* fGpu; +#ifdef PROGRAM_CACHE_STATS + int fTotalRequests; + int fCacheMisses; + int fHashMisses; // cache hit but hash table missed +#endif + }; + + // flushes dithering, color-mask, and face culling stat + void flushMiscFixedFunctionState(); + + // flushes the scissor. see the note on flushBoundTextureAndParams about + // flushing the scissor after that function is called. + void flushScissor(); + + void initFSAASupport(); + + // determines valid stencil formats + void initStencilFormats(); + + // sets a texture unit to use for texture operations other than binding a texture to a program. + // ensures that such operations don't negatively interact with tracking bound textures. + void setScratchTextureUnit(); + + // bound is region that may be modified and therefore has to be resolved. + // NULL means whole target. Can be an empty rect. + void flushRenderTarget(const SkIRect* bound); + void flushStencil(DrawType); + void flushAAState(DrawType); + void flushPathStencilSettings(SkPath::FillType fill); + + bool configToGLFormats(GrPixelConfig config, + bool getSizedInternal, + GrGLenum* internalFormat, + GrGLenum* externalFormat, + GrGLenum* externalType); + // helper for onCreateTexture and writeTexturePixels + bool uploadTexData(const GrGLTexture::Desc& desc, + bool isNewTexture, + int left, int top, int width, int height, + GrPixelConfig dataConfig, + const void* data, + size_t rowBytes); + + bool createRenderTargetObjects(int width, int height, + GrGLuint texID, + GrGLRenderTarget::Desc* desc); + + GrGLContext fGLContext; + + // GL program-related state + ProgramCache* fProgramCache; + SkAutoTUnref fCurrentProgram; + + /////////////////////////////////////////////////////////////////////////// + ///@name Caching of GL State + ///@{ + int fHWActiveTextureUnitIdx; + GrGLuint fHWProgramID; + + GrGLProgram::SharedGLState fSharedGLProgramState; + + enum TriState { + kNo_TriState, + kYes_TriState, + kUnknown_TriState + }; + + // last scissor / viewport scissor state seen by the GL. + struct { + TriState fEnabled; + GrGLIRect fRect; + void invalidate() { + fEnabled = kUnknown_TriState; + fRect.invalidate(); + } + } fHWScissorSettings; + + GrGLIRect fHWViewport; + + /** + * Tracks bound vertex and index buffers and vertex attrib array state. + */ + class HWGeometryState { + public: + HWGeometryState() { fVBOVertexArray = NULL; this->invalidate(); } + + ~HWGeometryState() { SkSafeUnref(fVBOVertexArray); } + + void invalidate() { + fBoundVertexArrayIDIsValid = false; + fBoundVertexBufferIDIsValid = false; + fDefaultVertexArrayBoundIndexBufferID = false; + fDefaultVertexArrayBoundIndexBufferIDIsValid = false; + fDefaultVertexArrayAttribState.invalidate(); + if (NULL != fVBOVertexArray) { + fVBOVertexArray->invalidateCachedState(); + } + } + + void notifyVertexArrayDelete(GrGLuint id) { + if (fBoundVertexArrayIDIsValid && fBoundVertexArrayID == id) { + // Does implicit bind to 0 + fBoundVertexArrayID = 0; + } + } + + void setVertexArrayID(GrGpuGL* 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; + } + } + + void notifyVertexBufferDelete(GrGLuint id) { + if (fBoundVertexBufferIDIsValid && id == fBoundVertexBufferID) { + fBoundVertexBufferID = 0; + } + if (NULL != fVBOVertexArray) { + fVBOVertexArray->notifyVertexBufferDelete(id); + } + fDefaultVertexArrayAttribState.notifyVertexBufferDelete(id); + } + + void notifyIndexBufferDelete(GrGLuint id) { + if (fDefaultVertexArrayBoundIndexBufferIDIsValid && + id == fDefaultVertexArrayBoundIndexBufferID) { + fDefaultVertexArrayBoundIndexBufferID = 0; + } + if (NULL != fVBOVertexArray) { + fVBOVertexArray->notifyIndexBufferDelete(id); + } + } + + void setVertexBufferID(GrGpuGL* gpu, GrGLuint id) { + if (!fBoundVertexBufferIDIsValid || id != fBoundVertexBufferID) { + GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ARRAY_BUFFER, id)); + fBoundVertexBufferIDIsValid = true; + fBoundVertexBufferID = id; + } + } + + /** + * Binds the default vertex array and binds the index buffer. This is used when binding + * an index buffer in order to update it. + */ + void setIndexBufferIDOnDefaultVertexArray(GrGpuGL* gpu, GrGLuint id) { + this->setVertexArrayID(gpu, 0); + if (!fDefaultVertexArrayBoundIndexBufferIDIsValid || + id != fDefaultVertexArrayBoundIndexBufferID) { + GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, id)); + fDefaultVertexArrayBoundIndexBufferIDIsValid = true; + fDefaultVertexArrayBoundIndexBufferID = id; + } + } + + /** + * Binds the vertex array object that should be used to render from the vertex buffer. + * The vertex array is bound and its attrib array state object is returned. The vertex + * buffer is bound. The index buffer (if non-NULL) is bound to the vertex array. The + * returned GrGLAttribArrayState should be used to set vertex attribute arrays. + */ + GrGLAttribArrayState* bindArrayAndBuffersToDraw(GrGpuGL* gpu, + const GrGLVertexBuffer* vbuffer, + const GrGLIndexBuffer* ibuffer); + + private: + GrGLuint fBoundVertexArrayID; + GrGLuint fBoundVertexBufferID; + bool fBoundVertexArrayIDIsValid; + bool fBoundVertexBufferIDIsValid; + + GrGLuint fDefaultVertexArrayBoundIndexBufferID; + bool fDefaultVertexArrayBoundIndexBufferIDIsValid; + // We return a non-const pointer to this from bindArrayAndBuffersToDraw when vertex array 0 + // is bound. However, this class is internal to GrGpuGL and this object never leaks out of + // GrGpuGL. + GrGLAttribArrayState fDefaultVertexArrayAttribState; + + // This is used when we're using a core profile and the vertices are in a VBO. + GrGLVertexArray* fVBOVertexArray; + } fHWGeometryState; + + struct { + GrBlendCoeff fSrcCoeff; + GrBlendCoeff fDstCoeff; + GrColor fConstColor; + bool fConstColorValid; + TriState fEnabled; + + void invalidate() { + fSrcCoeff = kInvalid_GrBlendCoeff; + fDstCoeff = kInvalid_GrBlendCoeff; + fConstColorValid = false; + fEnabled = kUnknown_TriState; + } + } fHWBlendState; + + struct { + TriState fMSAAEnabled; + TriState fSmoothLineEnabled; + void invalidate() { + fMSAAEnabled = kUnknown_TriState; + fSmoothLineEnabled = kUnknown_TriState; + } + } fHWAAState; + + + GrGLProgram::MatrixState fHWProjectionMatrixState; + + GrStencilSettings fHWStencilSettings; + TriState fHWStencilTestEnabled; + GrStencilSettings fHWPathStencilSettings; + + GrDrawState::DrawFace fHWDrawFace; + TriState fHWWriteToColor; + TriState fHWDitherEnabled; + GrRenderTarget* fHWBoundRenderTarget; + SkTArray fHWBoundTextures; + + struct TexGenData { + GrGLenum fMode; + GrGLint fNumComponents; + GrGLfloat fCoefficients[3 * 3]; + }; + int fHWActiveTexGenSets; + SkTArray fHWTexGenSettings; + ///@} + + // we record what stencil format worked last time to hopefully exit early + // from our loop that tries stencil formats and calls check fb status. + int fLastSuccessfulStencilFmtIdx; + + typedef GrGpu INHERITED; +}; + +#endif