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