 Chromium Code Reviews
 Chromium Code Reviews Issue 949263002:
  Improve tracking of bound FBOs in GrGLGpu.  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 949263002:
  Improve tracking of bound FBOs in GrGLGpu.  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| Index: src/gpu/gl/GrGLGpu.cpp | 
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp | 
| index 238ed9b3c6b3eac38548b022145001404e39eac3..0043a5c3cf15a877b5389bc4dab18cdf4cf23852 100644 | 
| --- a/src/gpu/gl/GrGLGpu.cpp | 
| +++ b/src/gpu/gl/GrGLGpu.cpp | 
| @@ -151,9 +151,6 @@ GrGLGpu::GrGLGpu(const GrGLContext& ctx, GrContext* context) | 
| fLastSuccessfulStencilFmtIdx = 0; | 
| fHWProgramID = 0; | 
| - fTempSrcFBOID = 0; | 
| - fTempDstFBOID = 0; | 
| - fStencilClearFBOID = 0; | 
| if (this->glCaps().pathRenderingSupport()) { | 
| fPathRendering.reset(new GrGLPathRendering(this)); | 
| @@ -168,14 +165,17 @@ GrGLGpu::~GrGLGpu() { | 
| GL_CALL(UseProgram(0)); | 
| } | 
| - if (0 != fTempSrcFBOID) { | 
| - GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); | 
| + if (fTempSrcFBO) { | 
| + fTempSrcFBO->release(this->glInterface()); | 
| + fTempSrcFBO.reset(NULL); | 
| } | 
| - if (0 != fTempDstFBOID) { | 
| - GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); | 
| + if (fTempDstFBO) { | 
| + fTempDstFBO->release(this->glInterface()); | 
| + fTempDstFBO.reset(NULL); | 
| } | 
| - if (0 != fStencilClearFBOID) { | 
| - GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); | 
| + if (fStencilClearFBO) { | 
| + fStencilClearFBO->release(this->glInterface()); | 
| + fStencilClearFBO.reset(NULL); | 
| } | 
| delete fProgramCache; | 
| @@ -185,9 +185,19 @@ void GrGLGpu::contextAbandoned() { | 
| INHERITED::contextAbandoned(); | 
| fProgramCache->abandon(); | 
| fHWProgramID = 0; | 
| - fTempSrcFBOID = 0; | 
| - fTempDstFBOID = 0; | 
| - fStencilClearFBOID = 0; | 
| + if (fTempSrcFBO) { | 
| + fTempSrcFBO->abandon(); | 
| + fTempSrcFBO.reset(NULL); | 
| + } | 
| + if (fTempDstFBO) { | 
| + fTempDstFBO->abandon(); | 
| + fTempDstFBO.reset(NULL); | 
| + } | 
| + if (fStencilClearFBO) { | 
| + fStencilClearFBO->abandon(); | 
| + fStencilClearFBO.reset(NULL); | 
| + } | 
| + | 
| if (this->glCaps().pathRenderingSupport()) { | 
| this->glPathRendering()->abandonGpuResources(); | 
| } | 
| @@ -331,7 +341,9 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { | 
| } | 
| if (resetBits & kRenderTarget_GrGLBackendState) { | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| + for (size_t i = 0; i < SK_ARRAY_COUNT(fHWFBOBinding); ++i) { | 
| + fHWFBOBinding[i].invalidate(); | 
| + } | 
| } | 
| if (resetBits & kPathRendering_GrGLBackendState) { | 
| @@ -432,9 +444,9 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc) { | 
| GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc) { | 
| GrGLRenderTarget::IDDesc idDesc; | 
| - idDesc.fRTFBOID = static_cast<GrGLuint>(wrapDesc.fRenderTargetHandle); | 
| + GrGLuint fboID = static_cast<GrGLuint>(wrapDesc.fRenderTargetHandle); | 
| + idDesc.fRenderFBO.reset(SkNEW_ARGS(GrGLFBO, (fboID))); | 
| idDesc.fMSColorRenderbufferID = 0; | 
| - idDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID; | 
| idDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle; | 
| GrSurfaceDesc desc; | 
| @@ -814,34 +826,34 @@ static bool renderbuffer_storage_msaa(GrGLContext& ctx, | 
| bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted, GrGLuint texID, | 
| GrGLRenderTarget::IDDesc* idDesc) { | 
| idDesc->fMSColorRenderbufferID = 0; | 
| - idDesc->fRTFBOID = 0; | 
| - idDesc->fTexFBOID = 0; | 
| idDesc->fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle : | 
| GrGpuResource::kUncached_LifeCycle; | 
| GrGLenum status; | 
| GrGLenum msColorFormat = 0; // suppress warning | 
| + GrGLenum fboTarget = 0; // suppress warning | 
| if (desc.fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) { | 
| goto FAILED; | 
| } | 
| - GL_CALL(GenFramebuffers(1, &idDesc->fTexFBOID)); | 
| - if (!idDesc->fTexFBOID) { | 
| + idDesc->fTextureFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); | 
| + if (!idDesc->fTextureFBO->isValid()) { | 
| goto FAILED; | 
| } | 
| - | 
| // If we are using multisampling we will create two FBOS. We render to one and then resolve to | 
| // the texture bound to the other. The exception is the IMG multisample extension. With this | 
| // extension the texture is multisampled when rendered to and then auto-resolves it when it is | 
| // rendered from. | 
| if (desc.fSampleCnt > 0 && this->glCaps().usesMSAARenderBuffers()) { | 
| - GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID)); | 
| + idDesc->fRenderFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); | 
| + if (!idDesc->fRenderFBO->isValid()) { | 
| + goto FAILED; | 
| + } | 
| GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); | 
| - if (!idDesc->fRTFBOID || | 
| - !idDesc->fMSColorRenderbufferID || | 
| + if (!idDesc->fMSColorRenderbufferID || | 
| !this->configToGLFormats(desc.fConfig, | 
| // ES2 and ES3 require sized internal formats for rb storage. | 
| kGLES_GrGLStandard == this->glStandard(), | 
| @@ -851,12 +863,10 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted | 
| goto FAILED; | 
| } | 
| } else { | 
| - idDesc->fRTFBOID = idDesc->fTexFBOID; | 
| + idDesc->fRenderFBO.reset(SkRef(idDesc->fTextureFBO.get())); | 
| } | 
| - // below here we may bind the FBO | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| - if (idDesc->fRTFBOID != idDesc->fTexFBOID) { | 
| + if (idDesc->fRenderFBO != idDesc->fTextureFBO) { | 
| SkASSERT(desc.fSampleCnt > 0); | 
| GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID)); | 
| if (!renderbuffer_storage_msaa(fGLContext, | 
| @@ -865,12 +875,11 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted | 
| desc.fWidth, desc.fHeight)) { | 
| goto FAILED; | 
| } | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fRTFBOID)); | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| - GR_GL_COLOR_ATTACHMENT0, | 
| - GR_GL_RENDERBUFFER, | 
| - idDesc->fMSColorRenderbufferID)); | 
| + fboTarget = this->bindFBO(kChangeAttachments_FBOBinding, idDesc->fRenderFBO); | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| + GR_GL_COLOR_ATTACHMENT0, | 
| + GR_GL_RENDERBUFFER, | 
| + idDesc->fMSColorRenderbufferID)); | 
| if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || | 
| !this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) { | 
| GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | 
| @@ -880,23 +889,22 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted | 
| fGLContext.caps()->markConfigAsValidColorAttachment(desc.fConfig); | 
| } | 
| } | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fTexFBOID)); | 
| + fboTarget = this->bindFBO(kChangeAttachments_FBOBinding, idDesc->fTextureFBO); | 
| if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) { | 
| - GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferTexture2DMultisample(fboTarget, | 
| GR_GL_COLOR_ATTACHMENT0, | 
| GR_GL_TEXTURE_2D, | 
| texID, 0, desc.fSampleCnt)); | 
| } else { | 
| - GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferTexture2D(fboTarget, | 
| GR_GL_COLOR_ATTACHMENT0, | 
| GR_GL_TEXTURE_2D, | 
| texID, 0)); | 
| } | 
| if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || | 
| !this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) { | 
| - GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | 
| + GL_CALL_RET(status, CheckFramebufferStatus(fboTarget)); | 
| if (status != GR_GL_FRAMEBUFFER_COMPLETE) { | 
| goto FAILED; | 
| } | 
| @@ -909,11 +917,11 @@ FAILED: | 
| if (idDesc->fMSColorRenderbufferID) { | 
| GL_CALL(DeleteRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); | 
| } | 
| - if (idDesc->fRTFBOID != idDesc->fTexFBOID) { | 
| - GL_CALL(DeleteFramebuffers(1, &idDesc->fRTFBOID)); | 
| + if (idDesc->fRenderFBO) { | 
| + idDesc->fRenderFBO->release(this->glInterface()); | 
| } | 
| - if (idDesc->fTexFBOID) { | 
| - GL_CALL(DeleteFramebuffers(1, &idDesc->fTexFBOID)); | 
| + if (idDesc->fTextureFBO) { | 
| + idDesc->fTextureFBO->release(this->glInterface()); | 
| } | 
| return false; | 
| } | 
| @@ -1186,18 +1194,17 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, | 
| // Clear the stencil buffer. We use a special purpose FBO for this so that the | 
| // entire stencil buffer is cleared, even if it is attached to an FBO with a | 
| // smaller color target. | 
| - if (0 == fStencilClearFBOID) { | 
| - GL_CALL(GenFramebuffers(1, &fStencilClearFBOID)); | 
| + if (!fStencilClearFBO) { | 
| + fStencilClearFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); | 
| } | 
| + SkASSERT(fStencilClearFBO->isValid()); | 
| + GrGLenum fboTarget = this->bindFBO(kClear_FBOBinding, fStencilClearFBO); | 
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID)); | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_STENCIL_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); | 
| if (sFmt.fPacked) { | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_DEPTH_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); | 
| } | 
| @@ -1206,11 +1213,11 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, | 
| GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT)); | 
| // Unbind the SB from the FBO so that we don't keep it alive. | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_STENCIL_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, 0)); | 
| if (sFmt.fPacked) { | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_DEPTH_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, 0)); | 
| } | 
| @@ -1230,9 +1237,6 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, | 
| bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) { | 
| GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt); | 
| - | 
| - GrGLuint fbo = glrt->renderFBOID(); | 
| - | 
| if (NULL == sb) { | 
| if (rt->renderTargetPriv().getStencilBuffer()) { | 
| GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| @@ -1251,19 +1255,17 @@ bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTar | 
| } else { | 
| GrGLStencilBuffer* glsb = static_cast<GrGLStencilBuffer*>(sb); | 
| GrGLuint rb = glsb->renderbufferID(); | 
| + GrGLenum fboTarget = this->bindFBO(kChangeAttachments_FBOBinding, glrt->renderFBO()); | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo)); | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_STENCIL_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, rb)); | 
| if (glsb->format().fPacked) { | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_DEPTH_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, rb)); | 
| } else { | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| GR_GL_DEPTH_ATTACHMENT, | 
| GR_GL_RENDERBUFFER, 0)); | 
| } | 
| @@ -1272,13 +1274,13 @@ bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTar | 
| if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(), glsb->format())) { | 
| GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | 
| if (status != GR_GL_FRAMEBUFFER_COMPLETE) { | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| - GR_GL_STENCIL_ATTACHMENT, | 
| - GR_GL_RENDERBUFFER, 0)); | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| + GR_GL_STENCIL_ATTACHMENT, | 
| + GR_GL_RENDERBUFFER, 0)); | 
| if (glsb->format().fPacked) { | 
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 
| - GR_GL_DEPTH_ATTACHMENT, | 
| - GR_GL_RENDERBUFFER, 0)); | 
| + GL_CALL(FramebufferRenderbuffer(fboTarget, | 
| + GR_GL_DEPTH_ATTACHMENT, | 
| + GR_GL_RENDERBUFFER, 0)); | 
| } | 
| return false; | 
| } else { | 
| @@ -1410,20 +1412,23 @@ bool GrGLGpu::flushGLState(const DrawArgs& args, bool isLineDraw) { | 
| fHWProgramID = programID; | 
| } | 
| - if (blendInfo.fWriteColor) { | 
| - this->flushBlend(blendInfo); | 
| - } | 
| fCurrentProgram->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTracker); | 
| GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget()); | 
| + | 
| this->flushStencil(pipeline.getStencil()); | 
| this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin()); | 
| this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), isLineDraw); | 
| // This must come after textures are flushed because a texture may need | 
| - // to be msaa-resolved (which will modify bound FBO state). | 
| - this->flushRenderTarget(glRT, NULL); | 
| + // to be msaa-resolved (which will modify bound FBO and scissor state). | 
| + this->bindFBO(kDraw_FBOBinding, glRT->renderFBO()); | 
| + this->setViewport(glRT->getViewport()); | 
| + if (blendInfo.fWriteColor) { | 
| + this->flushBlend(blendInfo); | 
| + this->markSurfaceContentsDirty(glRT, NULL); | 
| + } | 
| return true; | 
| } | 
| @@ -1520,7 +1525,8 @@ void GrGLGpu::onClear(GrRenderTarget* target, const SkIRect* rect, GrColor color | 
| } | 
| } | 
| - this->flushRenderTarget(glRT, rect); | 
| + this->bindFBO(kClear_FBOBinding, glRT->renderFBO()); | 
| + this->markSurfaceContentsDirty(glRT, rect); | 
| GrScissorState scissorState; | 
| if (rect) { | 
| scissorState.set(*rect); | 
| @@ -1548,40 +1554,36 @@ void GrGLGpu::discard(GrRenderTarget* renderTarget) { | 
| } | 
| GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget); | 
| - if (renderTarget->getUniqueID() != fHWBoundRenderTargetUniqueID) { | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRT->renderFBOID())); | 
| - } | 
| + GrGLenum fboTarget = this->bindFBO(kDiscard_FBOBinding, glRT->renderFBO()); | 
| switch (this->glCaps().invalidateFBType()) { | 
| case GrGLCaps::kNone_InvalidateFBType: | 
| SkFAIL("Should never get here."); | 
| break; | 
| case GrGLCaps::kInvalidate_InvalidateFBType: | 
| - if (0 == glRT->renderFBOID()) { | 
| + if (glRT->renderFBO()->isDefaultFramebuffer()) { | 
| // When rendering to the default framebuffer the legal values for attachments | 
| // are GL_COLOR, GL_DEPTH, GL_STENCIL, ... rather than the various FBO attachment | 
| // types. | 
| static const GrGLenum attachments[] = { GR_GL_COLOR }; | 
| - GL_CALL(InvalidateFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), | 
| + GL_CALL(InvalidateFramebuffer(fboTarget, SK_ARRAY_COUNT(attachments), | 
| attachments)); | 
| } else { | 
| static const GrGLenum attachments[] = { GR_GL_COLOR_ATTACHMENT0 }; | 
| - GL_CALL(InvalidateFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), | 
| + GL_CALL(InvalidateFramebuffer(fboTarget, SK_ARRAY_COUNT(attachments), | 
| attachments)); | 
| } | 
| break; | 
| case GrGLCaps::kDiscard_InvalidateFBType: { | 
| - if (0 == glRT->renderFBOID()) { | 
| + if (glRT->renderFBO()->isDefaultFramebuffer()) { | 
| // When rendering to the default framebuffer the legal values for attachments | 
| // are GL_COLOR, GL_DEPTH, GL_STENCIL, ... rather than the various FBO attachment | 
| // types. See glDiscardFramebuffer() spec. | 
| static const GrGLenum attachments[] = { GR_GL_COLOR }; | 
| - GL_CALL(DiscardFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), | 
| + GL_CALL(DiscardFramebuffer(fboTarget, SK_ARRAY_COUNT(attachments), | 
| attachments)); | 
| } else { | 
| static const GrGLenum attachments[] = { GR_GL_COLOR_ATTACHMENT0 }; | 
| - GL_CALL(DiscardFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), | 
| + GL_CALL(DiscardFramebuffer(fboTarget, SK_ARRAY_COUNT(attachments), | 
| attachments)); | 
| } | 
| break; | 
| @@ -1596,7 +1598,7 @@ void GrGLGpu::clearStencil(GrRenderTarget* target) { | 
| return; | 
| } | 
| GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); | 
| - this->flushRenderTarget(glRT, &SkIRect::EmptyIRect()); | 
| + this->bindFBO(kClear_FBOBinding, glRT->renderFBO()); | 
| this->disableScissor(); | 
| @@ -1632,7 +1634,7 @@ void GrGLGpu::onClearStencilClip(GrRenderTarget* target, const SkIRect& rect, bo | 
| value = 0; | 
| } | 
| GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); | 
| - this->flushRenderTarget(glRT, &SkIRect::EmptyIRect()); | 
| + this->bindFBO(kClear_FBOBinding, glRT->renderFBO()); | 
| GrScissorState scissorState; | 
| scissorState.set(rect); | 
| @@ -1702,22 +1704,13 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target, | 
| // resolve the render target if necessary | 
| GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target); | 
| - switch (tgt->getResolveType()) { | 
| - case GrGLRenderTarget::kCantResolve_ResolveType: | 
| - return false; | 
| - case GrGLRenderTarget::kAutoResolves_ResolveType: | 
| - this->flushRenderTarget(static_cast<GrGLRenderTarget*>(target), &SkIRect::EmptyIRect()); | 
| - break; | 
| - case GrGLRenderTarget::kCanResolve_ResolveType: | 
| - this->onResolveRenderTarget(tgt); | 
| - // we don't track the state of the READ FBO ID. | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, | 
| - tgt->textureFBOID())); | 
| - break; | 
| - default: | 
| - SkFAIL("Unknown resolve type"); | 
| + if (tgt->getResolveType() == GrGLRenderTarget::kCantResolve_ResolveType) { | 
| + return false; | 
| + } | 
| + if (tgt->getResolveType() == GrGLRenderTarget::kCanResolve_ResolveType) { | 
| + this->onResolveRenderTarget(tgt); | 
| } | 
| + this->bindFBO(kReadPixels_FBOBinding, tgt->textureFBO()); | 
| const GrGLIRect& glvp = tgt->getViewport(); | 
| @@ -1782,7 +1775,8 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target, | 
| } | 
| } | 
| } else { | 
| - SkASSERT(readDst != buffer); SkASSERT(rowBytes != tightRowBytes); | 
| + SkASSERT(readDst != buffer); | 
| + SkASSERT(rowBytes != tightRowBytes); | 
| // copy from readDst to buffer while flipping y | 
| // const int halfY = height >> 1; | 
| const char* src = reinterpret_cast<const char*>(readDst); | 
| @@ -1803,41 +1797,64 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target, | 
| return true; | 
| } | 
| -void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { | 
| +GrGLenum GrGLGpu::bindFBO(FBOBinding binding, const GrGLFBO* fbo) { | 
| + SkASSERT(fbo); | 
| + SkASSERT(fbo->isValid()); | 
| - SkASSERT(target); | 
| + bool useGLFramebuffer = !this->glCaps().usesMSAARenderBuffers() || | 
| + (this->glCaps().preferBindingToReadAndDrawFramebuffer() && | 
| + kBlitSrc_FBOBinding != binding && kBlitDst_FBOBinding != binding); | 
| - uint32_t rtID = target->getUniqueID(); | 
| - if (fHWBoundRenderTargetUniqueID != rtID) { | 
| + if (useGLFramebuffer) { | 
| + SkASSERT(kBlitSrc_FBOBinding != binding); | 
| fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, target->renderFBOID())); | 
| -#ifdef SK_DEBUG | 
| - // don't do this check in Chromium -- this is causing | 
| - // lots of repeated command buffer flushes when the compositor is | 
| - // rendering with Ganesh, which is really slow; even too slow for | 
| - // Debug mode. | 
| - if (!this->glContext().isChromium()) { | 
| - GrGLenum status; | 
| - GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | 
| - if (status != GR_GL_FRAMEBUFFER_COMPLETE) { | 
| - SkDebugf("GrGLGpu::flushRenderTarget glCheckFramebufferStatus %x\n", status); | 
| - } | 
| - } | 
| -#endif | 
| - fHWBoundRenderTargetUniqueID = rtID; | 
| - const GrGLIRect& vp = target->getViewport(); | 
| - if (fHWViewport != vp) { | 
| - vp.pushToGLViewport(this->glInterface()); | 
| - fHWViewport = vp; | 
| + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo->fboID())); | 
| + fHWFBOBinding[0].fFBO.reset(SkRef(fbo)); | 
| 
egdaniel
2015/03/17 17:44:58
maybe add some local enum for the draw and read in
 
bsalomon
2015/03/17 18:00:01
Done.
 | 
| + fHWFBOBinding[1].fFBO.reset(SkRef(fbo)); | 
| + return GR_GL_FRAMEBUFFER; | 
| + } else { | 
| 
egdaniel
2015/03/17 17:44:58
it is not needed, but do you want to explicitly us
 
bsalomon
2015/03/17 18:00:01
Done.
 | 
| + GrGLenum target = 0; | 
| + HWFBOBinding* hwFBOBinding = NULL; | 
| + switch (binding) { | 
| + case kDraw_FBOBinding: | 
| + case kClear_FBOBinding: | 
| + case kDiscard_FBOBinding: | 
| + case kChangeAttachments_FBOBinding: | 
| + case kBlitDst_FBOBinding: | 
| + target = GR_GL_DRAW_FRAMEBUFFER; | 
| + hwFBOBinding = &fHWFBOBinding[0]; | 
| + break; | 
| + | 
| + case kReadPixels_FBOBinding: | 
| + case kBlitSrc_FBOBinding: | 
| + target = GR_GL_READ_FRAMEBUFFER; | 
| + hwFBOBinding = &fHWFBOBinding[1]; | 
| + break; | 
| } | 
| + fStats.incRenderTargetBinds(); | 
| + GL_CALL(BindFramebuffer(target, fbo->fboID())); | 
| + hwFBOBinding->fFBO.reset(SkRef(fbo)); | 
| + return target; | 
| } | 
| - if (NULL == bound || !bound->isEmpty()) { | 
| - target->flagAsNeedingResolve(bound); | 
| +} | 
| + | 
| +void GrGLGpu::setViewport(const GrGLIRect& viewport) { | 
| + if (viewport != fHWViewport) { | 
| + viewport.pushToGLViewport(this->glInterface()); | 
| + fHWViewport = viewport; | 
| } | 
| +} | 
| - GrTexture *texture = target->asTexture(); | 
| - if (texture) { | 
| - texture->texturePriv().dirtyMipMaps(true); | 
| +void GrGLGpu::markSurfaceContentsDirty(GrSurface* surface, const SkIRect* bounds) { | 
| + if (NULL == bounds || !bounds->isEmpty()) { | 
| + GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget()); | 
| + if (rt) { | 
| + rt->flagAsNeedingResolve(bounds); | 
| + } | 
| + GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture()); | 
| + if (texture) { | 
| + texture->texturePriv().dirtyMipMaps(true); | 
| + } | 
| } | 
| } | 
| @@ -1919,8 +1936,9 @@ void GrGLGpu::onStencilPath(const GrPath* path, const StencilPathState& state) { | 
| this->glPathRendering()->setProjectionMatrix(*state.fViewMatrix, size, rt->origin()); | 
| this->flushScissor(*state.fScissor, rt->getViewport(), rt->origin()); | 
| this->flushHWAAState(rt, state.fUseHWAA, false); | 
| - this->flushRenderTarget(rt, NULL); | 
| - | 
| + this->bindFBO(kDraw_FBOBinding, rt->renderFBO()); | 
| + this->setViewport(rt->getViewport()); | 
| 
egdaniel
2015/03/17 17:44:58
Does stencilPath change the RT or texture at all?
 
bsalomon
2015/03/17 18:00:01
No, we only track dirtiness of the colorbuffer sin
 | 
| + | 
| fPathRendering->stencilPath(path, *state.fStencil); | 
| } | 
| @@ -1952,14 +1970,9 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { | 
| if (rt->needsResolve()) { | 
| // Some extensions automatically resolves the texture when it is read. | 
| if (this->glCaps().usesMSAARenderBuffers()) { | 
| - SkASSERT(rt->textureFBOID() != rt->renderFBOID()); | 
| - fStats.incRenderTargetBinds(); | 
| - fStats.incRenderTargetBinds(); | 
| - GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->renderFBOID())); | 
| - GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID())); | 
| - // make sure we go through flushRenderTarget() since we've modified | 
| - // the bound DRAW FBO ID. | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| + SkASSERT(rt->textureFBO() != rt->renderFBO()); | 
| + this->bindFBO(kBlitSrc_FBOBinding, rt->renderFBO()); | 
| + this->bindFBO(kBlitDst_FBOBinding, rt->textureFBO()); | 
| const GrGLIRect& vp = rt->getViewport(); | 
| const SkIRect dirtyRect = rt->getResolveRect(); | 
| @@ -2522,13 +2535,13 @@ inline bool can_copy_texsubimage(const GrSurface* dst, | 
| const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget()); | 
| // If dst is multisampled (and uses an extension where there is a separate MSAA renderbuffer) | 
| // then we don't want to copy to the texture but to the MSAA buffer. | 
| - if (dstRT && dstRT->renderFBOID() != dstRT->textureFBOID()) { | 
| + if (dstRT && dstRT->renderFBO() != dstRT->textureFBO()) { | 
| return false; | 
| } | 
| const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget()); | 
| // If the src is multisampled (and uses an extension where there is a separate MSAA | 
| // renderbuffer) then it is an invalid operation to call CopyTexSubImage | 
| - if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) { | 
| + if (srcRT && srcRT->renderFBO() != srcRT->textureFBO()) { | 
| return false; | 
| } | 
| if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) && | 
| @@ -2545,22 +2558,31 @@ inline bool can_copy_texsubimage(const GrSurface* dst, | 
| // If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is | 
| // relative to is output. | 
| -GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, | 
| - TempFBOTarget tempFBOTarget) { | 
| +GrGLGpu::FBOBinding GrGLGpu::bindSurfaceAsFBOForCopy(GrSurface* surface, FBOBinding binding, | 
| + GrGLIRect* viewport) { | 
| GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget()); | 
| if (NULL == rt) { | 
| SkASSERT(surface->asTexture()); | 
| GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID(); | 
| - GrGLuint* tempFBOID; | 
| - tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID; | 
| + GrGLFBO* tempFBO; | 
| - if (0 == *tempFBOID) { | 
| - GR_GL_CALL(this->glInterface(), GenFramebuffers(1, tempFBOID)); | 
| + if (kBlitSrc_FBOBinding == binding) { | 
| + if (!fTempSrcFBO) { | 
| + fTempSrcFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); | 
| + SkASSERT(fTempSrcFBO->isValid()); | 
| + } | 
| + tempFBO = fTempSrcFBO; | 
| + } else { | 
| + SkASSERT(kBlitDst_FBOBinding == binding); | 
| + if (!fTempDstFBO) { | 
| + fTempDstFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); | 
| + SkASSERT(fTempDstFBO->isValid()); | 
| + } | 
| + tempFBO = fTempDstFBO; | 
| } | 
| - fStats.incRenderTargetBinds(); | 
| - GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, *tempFBOID)); | 
| - GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, | 
| + GrGLenum target = this->bindFBO(binding, tempFBO); | 
| + GR_GL_CALL(this->glInterface(), FramebufferTexture2D(target, | 
| GR_GL_COLOR_ATTACHMENT0, | 
| GR_GL_TEXTURE_2D, | 
| texID, | 
| @@ -2569,18 +2591,21 @@ GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLI | 
| viewport->fBottom = 0; | 
| viewport->fWidth = surface->width(); | 
| viewport->fHeight = surface->height(); | 
| - return *tempFBOID; | 
| + return binding; | 
| } else { | 
| - GrGLuint tempFBOID = 0; | 
| - fStats.incRenderTargetBinds(); | 
| - GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, rt->renderFBOID())); | 
| + this->bindFBO(binding, rt->renderFBO()); | 
| *viewport = rt->getViewport(); | 
| - return tempFBOID; | 
| + return kInvalidFBOBinding; | 
| } | 
| } | 
| -void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) { | 
| - GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, | 
| +void GrGLGpu::unbindSurfaceAsFBOForCopy(FBOBinding binding) { | 
| + if (kInvalidFBOBinding == binding) { | 
| + return; | 
| + } | 
| + GrGLFBO* tempFBO = kBlitDst_FBOBinding == binding ? fTempSrcFBO : fTempDstFBO; | 
| + GrGLenum target = this->bindFBO(binding, tempFBO); | 
| + GR_GL_CALL(this->glInterface(), FramebufferTexture2D(target, | 
| GR_GL_COLOR_ATTACHMENT0, | 
| GR_GL_TEXTURE_2D, | 
| 0, | 
| @@ -2611,7 +2636,7 @@ bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) | 
| } | 
| const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget()); | 
| - if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) { | 
| + if (srcRT && srcRT->renderFBO() != srcRT->textureFBO()) { | 
| // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO blit or | 
| // fail. | 
| if (this->caps()->isConfigRenderable(src->config(), false)) { | 
| @@ -2635,14 +2660,13 @@ bool GrGLGpu::copySurface(GrSurface* dst, | 
| const SkIRect& srcRect, | 
| const SkIPoint& dstPoint) { | 
| bool copied = false; | 
| + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, | 
| + srcRect.width(), srcRect.height()); | 
| if (can_copy_texsubimage(dst, src, this)) { | 
| - GrGLuint srcFBO; | 
| GrGLIRect srcVP; | 
| - srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); | 
| + FBOBinding srcFBOBinding = this->bindSurfaceAsFBOForCopy(src, kBlitSrc_FBOBinding, &srcVP); | 
| GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture()); | 
| SkASSERT(dstTex); | 
| - // We modified the bound FBO | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| GrGLIRect srcGLRect; | 
| srcGLRect.setRelativeTo(srcVP, | 
| srcRect.fLeft, | 
| @@ -2664,28 +2688,21 @@ bool GrGLGpu::copySurface(GrSurface* dst, | 
| srcGLRect.fLeft, srcGLRect.fBottom, | 
| srcGLRect.fWidth, srcGLRect.fHeight)); | 
| copied = true; | 
| - if (srcFBO) { | 
| - this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER); | 
| - } | 
| + this->unbindSurfaceAsFBOForCopy(srcFBOBinding); | 
| } else if (can_blit_framebuffer(dst, src, this)) { | 
| - SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, | 
| - srcRect.width(), srcRect.height()); | 
| bool selfOverlap = false; | 
| if (dst == src) { | 
| selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect); | 
| } | 
| if (!selfOverlap) { | 
| - GrGLuint dstFBO; | 
| - GrGLuint srcFBO; | 
| GrGLIRect dstVP; | 
| GrGLIRect srcVP; | 
| - dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, | 
| - kDst_TempFBOTarget); | 
| - srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP, | 
| - kSrc_TempFBOTarget); | 
| - // We modified the bound FBO | 
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 
| + FBOBinding dstFBOBinding = this->bindSurfaceAsFBOForCopy(dst, kBlitDst_FBOBinding, | 
| + &dstVP); | 
| + FBOBinding srcFBOBinding = this->bindSurfaceAsFBOForCopy(src, kBlitSrc_FBOBinding, | 
| + &srcVP); | 
| + | 
| GrGLIRect srcGLRect; | 
| GrGLIRect dstGLRect; | 
| srcGLRect.setRelativeTo(srcVP, | 
| @@ -2723,15 +2740,14 @@ bool GrGLGpu::copySurface(GrSurface* dst, | 
| dstGLRect.fLeft + dstGLRect.fWidth, | 
| dstGLRect.fBottom + dstGLRect.fHeight, | 
| GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); | 
| - if (dstFBO) { | 
| - this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER); | 
| - } | 
| - if (srcFBO) { | 
| - this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER); | 
| - } | 
| + this->unbindSurfaceAsFBOForCopy(dstFBOBinding); | 
| + this->unbindSurfaceAsFBOForCopy(srcFBOBinding); | 
| copied = true; | 
| } | 
| } | 
| + if (copied) { | 
| + this->markSurfaceContentsDirty(dst, &dstRect); | 
| + } | 
| return copied; | 
| } |