From bb8bca36b7eb8015f40e6ce2cfa229b673b19a34 Mon Sep 17 00:00:00 2001 From: bsalomon Date: Fri, 27 Feb 2015 16:28:42 -0800 Subject: Revert of Improve tracking of bound FBOs in GrGLGpu. (patchset #8 id:140001 of https://codereview.chromium.org/949263002/) Reason for revert: breaking things Original issue's description: > Improve tracking of bound FBOs in GrGLGpu. > > Committed: https://skia.googlesource.com/skia/+/d2ad8eb5801e2c8c0fa544a6a776bb46eedde2a0 > > Committed: https://skia.googlesource.com/skia/+/b2af2d8b83ca4774c3b3bb1e49bc72605faa9589 TBR=egdaniel@google.com NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true Review URL: https://codereview.chromium.org/963973002 --- src/gpu/gl/GrGLGpu.cpp | 339 ++++++++++++++++++++-------------------- src/gpu/gl/GrGLGpu.h | 49 ++---- src/gpu/gl/GrGLRenderTarget.cpp | 61 ++------ src/gpu/gl/GrGLRenderTarget.h | 100 +++--------- 4 files changed, 222 insertions(+), 327 deletions(-) (limited to 'src/gpu/gl') diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index cbc904e8c1..a952c4f768 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -151,6 +151,9 @@ 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)); @@ -165,17 +168,14 @@ GrGLGpu::~GrGLGpu() { GL_CALL(UseProgram(0)); } - if (fTempSrcFBO) { - fTempSrcFBO->release(this->glInterface()); - fTempSrcFBO.reset(NULL); + if (0 != fTempSrcFBOID) { + GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); } - if (fTempDstFBO) { - fTempDstFBO->release(this->glInterface()); - fTempDstFBO.reset(NULL); + if (0 != fTempDstFBOID) { + GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); } - if (fStencilClearFBO) { - fStencilClearFBO->release(this->glInterface()); - fStencilClearFBO.reset(NULL); + if (0 != fStencilClearFBOID) { + GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); } delete fProgramCache; @@ -185,19 +185,9 @@ void GrGLGpu::contextAbandoned() { INHERITED::contextAbandoned(); fProgramCache->abandon(); fHWProgramID = 0; - if (fTempSrcFBO) { - fTempSrcFBO->abandon(); - fTempSrcFBO.reset(NULL); - } - if (fTempDstFBO) { - fTempDstFBO->abandon(); - fTempDstFBO.reset(NULL); - } - if (fStencilClearFBO) { - fStencilClearFBO->abandon(); - fStencilClearFBO.reset(NULL); - } - + fTempSrcFBOID = 0; + fTempDstFBOID = 0; + fStencilClearFBOID = 0; if (this->glCaps().pathRenderingSupport()) { this->glPathRendering()->abandonGpuResources(); } @@ -341,9 +331,7 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { } if (resetBits & kRenderTarget_GrGLBackendState) { - for (size_t i = 0; i < SK_ARRAY_COUNT(fHWFBOBinding); ++i) { - fHWFBOBinding[i].invalidate(); - } + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; } if (resetBits & kPathRendering_GrGLBackendState) { @@ -444,9 +432,9 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc) { GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc) { GrGLRenderTarget::IDDesc idDesc; - GrGLuint fboID = static_cast(wrapDesc.fRenderTargetHandle); - idDesc.fRenderFBO.reset(SkNEW_ARGS(GrGLFBO, (fboID))); + idDesc.fRTFBOID = static_cast(wrapDesc.fRenderTargetHandle); idDesc.fMSColorRenderbufferID = 0; + idDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID; idDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle; GrSurfaceDesc desc; @@ -826,34 +814,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; } - idDesc->fTextureFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); - if (!idDesc->fTextureFBO->isValid()) { + GL_CALL(GenFramebuffers(1, &idDesc->fTexFBOID)); + if (!idDesc->fTexFBOID) { 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()) { - idDesc->fRenderFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); - if (!idDesc->fRenderFBO->isValid()) { - goto FAILED; - } + GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID)); GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); - if (!idDesc->fMSColorRenderbufferID || + if (!idDesc->fRTFBOID || + !idDesc->fMSColorRenderbufferID || !this->configToGLFormats(desc.fConfig, // ES2 and ES3 require sized internal formats for rb storage. kGLES_GrGLStandard == this->glStandard(), @@ -863,10 +851,12 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted goto FAILED; } } else { - idDesc->fRenderFBO.reset(SkRef(idDesc->fTextureFBO.get())); + idDesc->fRTFBOID = idDesc->fTexFBOID; } - if (idDesc->fRenderFBO != idDesc->fTextureFBO) { + // below here we may bind the FBO + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + if (idDesc->fRTFBOID != idDesc->fTexFBOID) { SkASSERT(desc.fSampleCnt > 0); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID)); if (!renderbuffer_storage_msaa(fGLContext, @@ -875,11 +865,12 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted desc.fWidth, desc.fHeight)) { goto FAILED; } - fboTarget = this->bindFBO(kDraw_FBOBinding, idDesc->fRenderFBO); - GL_CALL(FramebufferRenderbuffer(fboTarget, - GR_GL_COLOR_ATTACHMENT0, - GR_GL_RENDERBUFFER, - idDesc->fMSColorRenderbufferID)); + 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)); if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || !this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) { GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); @@ -889,22 +880,23 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted fGLContext.caps()->markConfigAsValidColorAttachment(desc.fConfig); } } - fboTarget = this->bindFBO(kDraw_FBOBinding, idDesc->fTextureFBO); + fStats.incRenderTargetBinds(); + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fTexFBOID)); if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) { - GL_CALL(FramebufferTexture2DMultisample(fboTarget, + GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, texID, 0, desc.fSampleCnt)); } else { - GL_CALL(FramebufferTexture2D(fboTarget, + GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, 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(fboTarget)); + GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); if (status != GR_GL_FRAMEBUFFER_COMPLETE) { goto FAILED; } @@ -917,11 +909,11 @@ FAILED: if (idDesc->fMSColorRenderbufferID) { GL_CALL(DeleteRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); } - if (idDesc->fRenderFBO) { - idDesc->fRenderFBO->release(this->glInterface()); + if (idDesc->fRTFBOID != idDesc->fTexFBOID) { + GL_CALL(DeleteFramebuffers(1, &idDesc->fRTFBOID)); } - if (idDesc->fTextureFBO) { - idDesc->fTextureFBO->release(this->glInterface()); + if (idDesc->fTexFBOID) { + GL_CALL(DeleteFramebuffers(1, &idDesc->fTexFBOID)); } return false; } @@ -1194,16 +1186,18 @@ 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 (!fStencilClearFBO) { - fStencilClearFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); + if (0 == fStencilClearFBOID) { + GL_CALL(GenFramebuffers(1, &fStencilClearFBOID)); } - SkASSERT(fStencilClearFBO->isValid()); - GrGLenum fboTarget = this->bindFBO(kDraw_FBOBinding, fStencilClearFBO); - GL_CALL(FramebufferRenderbuffer(fboTarget, + + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID)); + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fStats.incRenderTargetBinds(); + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); if (sFmt.fPacked) { - GL_CALL(FramebufferRenderbuffer(fboTarget, + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); } @@ -1212,11 +1206,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(fboTarget, + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); if (sFmt.fPacked) { - GL_CALL(FramebufferRenderbuffer(fboTarget, + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); } @@ -1236,6 +1230,9 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) { GrGLRenderTarget* glrt = static_cast(rt); + + GrGLuint fbo = glrt->renderFBOID(); + if (NULL == sb) { if (rt->renderTargetPriv().getStencilBuffer()) { GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, @@ -1255,17 +1252,18 @@ bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTar GrGLStencilBuffer* glsb = static_cast(sb); GrGLuint rb = glsb->renderbufferID(); - GrGLenum fboTarget = this->bindFBO(kDraw_FBOBinding, glrt->renderFBO()); - - GL_CALL(FramebufferRenderbuffer(fboTarget, + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fStats.incRenderTargetBinds(); + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo)); + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, rb)); if (glsb->format().fPacked) { - GL_CALL(FramebufferRenderbuffer(fboTarget, + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, rb)); } else { - GL_CALL(FramebufferRenderbuffer(fboTarget, + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); } @@ -1274,13 +1272,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(fboTarget, - GR_GL_STENCIL_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_STENCIL_ATTACHMENT, + GR_GL_RENDERBUFFER, 0)); if (glsb->format().fPacked) { - GL_CALL(FramebufferRenderbuffer(fboTarget, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_DEPTH_ATTACHMENT, + GR_GL_RENDERBUFFER, 0)); } return false; } else { @@ -1425,7 +1423,7 @@ bool GrGLGpu::flushGLState(const DrawArgs& args, bool isLineDraw) { // This must come after textures are flushed because a texture may need // to be msaa-resolved (which will modify bound FBO state). - this->prepareToDrawToRenderTarget(glRT, NULL); + this->flushRenderTarget(glRT, NULL); return true; } @@ -1522,7 +1520,7 @@ void GrGLGpu::onClear(GrRenderTarget* target, const SkIRect* rect, GrColor color } } - this->prepareToDrawToRenderTarget(glRT, rect); + this->flushRenderTarget(glRT, rect); GrScissorState scissorState; if (rect) { scissorState.set(*rect); @@ -1550,36 +1548,40 @@ void GrGLGpu::discard(GrRenderTarget* renderTarget) { } GrGLRenderTarget* glRT = static_cast(renderTarget); - GrGLenum fboTarget = this->bindFBO(kDraw_FBOBinding, glRT->renderFBO()); + if (renderTarget->getUniqueID() != fHWBoundRenderTargetUniqueID) { + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + fStats.incRenderTargetBinds(); + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRT->renderFBOID())); + } switch (this->glCaps().invalidateFBType()) { case GrGLCaps::kNone_InvalidateFBType: SkFAIL("Should never get here."); break; case GrGLCaps::kInvalidate_InvalidateFBType: - if (glRT->renderFBO()->isDefaultFramebuffer()) { + if (0 == glRT->renderFBOID()) { // 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(fboTarget, SK_ARRAY_COUNT(attachments), + GL_CALL(InvalidateFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), attachments)); } else { static const GrGLenum attachments[] = { GR_GL_COLOR_ATTACHMENT0 }; - GL_CALL(InvalidateFramebuffer(fboTarget, SK_ARRAY_COUNT(attachments), + GL_CALL(InvalidateFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), attachments)); } break; case GrGLCaps::kDiscard_InvalidateFBType: { - if (glRT->renderFBO()->isDefaultFramebuffer()) { + if (0 == glRT->renderFBOID()) { // 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(fboTarget, SK_ARRAY_COUNT(attachments), + GL_CALL(DiscardFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), attachments)); } else { static const GrGLenum attachments[] = { GR_GL_COLOR_ATTACHMENT0 }; - GL_CALL(DiscardFramebuffer(fboTarget, SK_ARRAY_COUNT(attachments), + GL_CALL(DiscardFramebuffer(GR_GL_FRAMEBUFFER, SK_ARRAY_COUNT(attachments), attachments)); } break; @@ -1594,7 +1596,7 @@ void GrGLGpu::clearStencil(GrRenderTarget* target) { return; } GrGLRenderTarget* glRT = static_cast(target); - this->prepareToDrawToRenderTarget(glRT, &SkIRect::EmptyIRect()); + this->flushRenderTarget(glRT, &SkIRect::EmptyIRect()); this->disableScissor(); @@ -1630,7 +1632,7 @@ void GrGLGpu::onClearStencilClip(GrRenderTarget* target, const SkIRect& rect, bo value = 0; } GrGLRenderTarget* glRT = static_cast(target); - this->prepareToDrawToRenderTarget(glRT, &SkIRect::EmptyIRect()); + this->flushRenderTarget(glRT, &SkIRect::EmptyIRect()); GrScissorState scissorState; scissorState.set(rect); @@ -1700,13 +1702,22 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target, // resolve the render target if necessary GrGLRenderTarget* tgt = static_cast(target); - if (tgt->getResolveType() == GrGLRenderTarget::kCantResolve_ResolveType) { - return false; - } - if (tgt->getResolveType() == GrGLRenderTarget::kCanResolve_ResolveType) { - this->onResolveRenderTarget(tgt); + switch (tgt->getResolveType()) { + case GrGLRenderTarget::kCantResolve_ResolveType: + return false; + case GrGLRenderTarget::kAutoResolves_ResolveType: + this->flushRenderTarget(static_cast(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"); } - this->bindFBO(kRead_FBOBinding, tgt->textureFBO()); const GrGLIRect& glvp = tgt->getViewport(); @@ -1771,8 +1782,7 @@ 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(readDst); @@ -1793,52 +1803,34 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target, return true; } -GrGLenum GrGLGpu::bindFBO(FBOBinding binding, const GrGLFBO* fbo) { - SkASSERT(fbo); - SkASSERT(fbo->isValid()); - GrGLenum target; - HWFBOBinding* hwFBOState; - if (!this->glCaps().usesMSAARenderBuffers()) { - target = GR_GL_FRAMEBUFFER; - hwFBOState = &fHWFBOBinding[0]; - } else { - target = kDraw_FBOBinding == binding ? GR_GL_DRAW_FRAMEBUFFER : GR_GL_READ_FRAMEBUFFER; - hwFBOState = &fHWFBOBinding[binding]; - } - - if (hwFBOState->fFBO != fbo) { - fStats.incRenderTargetBinds(); - GL_CALL(BindFramebuffer(target, fbo->fboID())); - hwFBOState->fFBO.reset(SkRef(fbo)); - } - return target; -} - -void GrGLGpu::setViewport(const GrGLIRect& viewport) { - if (viewport != fHWViewport) { - viewport.pushToGLViewport(this->glInterface()); - fHWViewport = viewport; - } -} +void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { -void GrGLGpu::prepareToDrawToRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { SkASSERT(target); - this->bindFBO(kDraw_FBOBinding, target->renderFBO()); + uint32_t rtID = target->getUniqueID(); + if (fHWBoundRenderTargetUniqueID != rtID) { + 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); + // 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 - this->setViewport(target->getViewport()); + fHWBoundRenderTargetUniqueID = rtID; + const GrGLIRect& vp = target->getViewport(); + if (fHWViewport != vp) { + vp.pushToGLViewport(this->glInterface()); + fHWViewport = vp; + } + } if (NULL == bound || !bound->isEmpty()) { target->flagAsNeedingResolve(bound); } @@ -1927,7 +1919,7 @@ 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->prepareToDrawToRenderTarget(rt, NULL); + this->flushRenderTarget(rt, NULL); fPathRendering->stencilPath(path, *state.fStencil); } @@ -1960,9 +1952,14 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { if (rt->needsResolve()) { // Some extensions automatically resolves the texture when it is read. if (this->glCaps().usesMSAARenderBuffers()) { - SkASSERT(rt->textureFBO() != rt->renderFBO()); - this->bindFBO(kRead_FBOBinding, rt->renderFBO()); - this->bindFBO(kDraw_FBOBinding, rt->textureFBO()); + 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; const GrGLIRect& vp = rt->getViewport(); const SkIRect dirtyRect = rt->getResolveRect(); @@ -2525,13 +2522,13 @@ inline bool can_copy_texsubimage(const GrSurface* dst, const GrGLRenderTarget* dstRT = static_cast(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->renderFBO() != dstRT->textureFBO()) { + if (dstRT && dstRT->renderFBOID() != dstRT->textureFBOID()) { return false; } const GrGLRenderTarget* srcRT = static_cast(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->renderFBO() != srcRT->textureFBO()) { + if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) { return false; } if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) && @@ -2548,31 +2545,22 @@ 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. -GrGLGpu::FBOBinding GrGLGpu::bindSurfaceAsFBOForCopy(GrSurface* surface, FBOBinding binding, - GrGLIRect* viewport) { +GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, + TempFBOTarget tempFBOTarget) { GrGLRenderTarget* rt = static_cast(surface->asRenderTarget()); if (NULL == rt) { SkASSERT(surface->asTexture()); GrGLuint texID = static_cast(surface->asTexture())->textureID(); - GrGLFBO* tempFBO; + GrGLuint* tempFBOID; + tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID; - if (kRead_FBOBinding == binding) { - if (!fTempSrcFBO) { - fTempSrcFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); - SkASSERT(fTempSrcFBO->isValid()); - } - tempFBO = fTempSrcFBO; - } else { - SkASSERT(kDraw_FBOBinding == binding); - if (!fTempDstFBO) { - fTempDstFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface()))); - SkASSERT(fTempDstFBO->isValid()); - } - tempFBO = fTempDstFBO; + if (0 == *tempFBOID) { + GR_GL_CALL(this->glInterface(), GenFramebuffers(1, tempFBOID)); } - GrGLenum target = this->bindFBO(binding, tempFBO); - GR_GL_CALL(this->glInterface(), FramebufferTexture2D(target, + fStats.incRenderTargetBinds(); + GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, *tempFBOID)); + GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, texID, @@ -2581,21 +2569,18 @@ GrGLGpu::FBOBinding GrGLGpu::bindSurfaceAsFBOForCopy(GrSurface* surface, FBOBind viewport->fBottom = 0; viewport->fWidth = surface->width(); viewport->fHeight = surface->height(); - return binding; + return *tempFBOID; } else { - this->bindFBO(binding, rt->renderFBO()); + GrGLuint tempFBOID = 0; + fStats.incRenderTargetBinds(); + GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, rt->renderFBOID())); *viewport = rt->getViewport(); - return kInvalidFBOBinding; + return tempFBOID; } } -void GrGLGpu::unbindSurfaceAsFBOForCopy(FBOBinding binding) { - if (kInvalidFBOBinding == binding) { - return; - } - GrGLFBO* tempFBO = kDraw_FBOBinding == binding ? fTempSrcFBO : fTempDstFBO; - GrGLenum target = this->bindFBO(binding, tempFBO); - GR_GL_CALL(this->glInterface(), FramebufferTexture2D(target, +void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) { + GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, 0, @@ -2626,7 +2611,7 @@ bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) } const GrGLRenderTarget* srcRT = static_cast(src->asRenderTarget()); - if (srcRT && srcRT->renderFBO() != srcRT->textureFBO()) { + if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) { // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO blit or // fail. if (this->caps()->isConfigRenderable(src->config(), false)) { @@ -2651,10 +2636,13 @@ bool GrGLGpu::copySurface(GrSurface* dst, const SkIPoint& dstPoint) { bool copied = false; if (can_copy_texsubimage(dst, src, this)) { + GrGLuint srcFBO; GrGLIRect srcVP; - FBOBinding srcFBOBinding = this->bindSurfaceAsFBOForCopy(src, kRead_FBOBinding, &srcVP); + srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); GrGLTexture* dstTex = static_cast(dst->asTexture()); SkASSERT(dstTex); + // We modified the bound FBO + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; GrGLIRect srcGLRect; srcGLRect.setRelativeTo(srcVP, srcRect.fLeft, @@ -2676,7 +2664,9 @@ bool GrGLGpu::copySurface(GrSurface* dst, srcGLRect.fLeft, srcGLRect.fBottom, srcGLRect.fWidth, srcGLRect.fHeight)); copied = true; - this->unbindSurfaceAsFBOForCopy(srcFBOBinding); + if (srcFBO) { + this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER); + } } else if (can_blit_framebuffer(dst, src, this)) { SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height()); @@ -2686,11 +2676,16 @@ bool GrGLGpu::copySurface(GrSurface* dst, } if (!selfOverlap) { + GrGLuint dstFBO; + GrGLuint srcFBO; GrGLIRect dstVP; GrGLIRect srcVP; - FBOBinding dstFBOBinding = this->bindSurfaceAsFBOForCopy(dst, kDraw_FBOBinding, &dstVP); - FBOBinding srcFBOBinding = this->bindSurfaceAsFBOForCopy(src, kRead_FBOBinding, &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; GrGLIRect srcGLRect; GrGLIRect dstGLRect; srcGLRect.setRelativeTo(srcVP, @@ -2728,8 +2723,12 @@ bool GrGLGpu::copySurface(GrSurface* dst, dstGLRect.fLeft + dstGLRect.fWidth, dstGLRect.fBottom + dstGLRect.fHeight, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); - this->unbindSurfaceAsFBOForCopy(dstFBOBinding); - this->unbindSurfaceAsFBOForCopy(srcFBOBinding); + if (dstFBO) { + this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER); + } + if (srcFBO) { + this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER); + } copied = true; } } diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 0ec69c0660..b93080b700 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -246,25 +246,9 @@ private: // ensures that such operations don't negatively interact with tracking bound textures. void setScratchTextureUnit(); - // Binds the render target, sets the viewport, tracks dirty are for resolve, and tracks whether - // mip maps need rebuilding. bounds is region that may be modified by the draw. NULL means whole - // target. Can be an empty rect. - void prepareToDrawToRenderTarget(GrGLRenderTarget*, const SkIRect* bounds); - - // On older GLs there may not be separate FBO bindings for draw and read. In that case these - // alias each other. - enum FBOBinding { - kDraw_FBOBinding, // drawing or dst of blit - kRead_FBOBinding, // src of blit, read pixels. - - kLast_FBOBinding = kRead_FBOBinding - }; - static const int kFBOBindingCnt = kLast_FBOBinding + 1; - - // binds the FBO and returns the GL enum of the framebuffer target it was bound to. - GrGLenum bindFBO(FBOBinding, const GrGLFBO*); - - void setViewport(const GrGLIRect& viewport); + // bounds is region that may be modified and therefore has to be resolved. + // NULL means whole target. Can be an empty rect. + void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds); void flushStencil(const GrStencilSettings&); void flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool isLineDraw); @@ -297,14 +281,15 @@ private: bool createRenderTargetObjects(const GrSurfaceDesc&, bool budgeted, GrGLuint texID, GrGLRenderTarget::IDDesc*); - static const FBOBinding kInvalidFBOBinding = static_cast(-1); + enum TempFBOTarget { + kSrc_TempFBOTarget, + kDst_TempFBOTarget + }; - // Binds a surface as an FBO. A temporary FBO ID may be used if the surface is not already - // a render target. Afterwards unbindSurfaceAsFBOForCopy must be called with the value returned. - FBOBinding bindSurfaceAsFBOForCopy(GrSurface*, FBOBinding, GrGLIRect* viewport); + GrGLuint bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, + TempFBOTarget tempFBOTarget); - // Must be matched with bindSurfaceAsFBOForCopy. - void unbindSurfaceAsFBOForCopy(FBOBinding); + void unbindTextureFromFBO(GrGLenum fboTarget); GrGLContext fGLContext; @@ -324,9 +309,10 @@ private: kUnknown_TriState }; - SkAutoTUnref fTempSrcFBO; - SkAutoTUnref fTempDstFBO; - SkAutoTUnref fStencilClearFBO; + GrGLuint fTempSrcFBOID; + GrGLuint fTempDstFBOID; + + GrGLuint fStencilClearFBOID; // last scissor / viewport scissor state seen by the GL. struct { @@ -472,14 +458,9 @@ private: GrPipelineBuilder::DrawFace fHWDrawFace; TriState fHWWriteToColor; TriState fHWDitherEnabled; + uint32_t fHWBoundRenderTargetUniqueID; SkTArray fHWBoundTextureUniqueIDs; - // Track fbo binding state. - struct HWFBOBinding { - SkAutoTUnref fFBO; - void invalidate() { fFBO.reset(NULL); } - } fHWFBOBinding[kFBOBindingCnt]; - ///@} // we record what stencil format worked last time to hopefully exit early diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp index 8b9bb98b6b..3eb2ae09fe 100644 --- a/src/gpu/gl/GrGLRenderTarget.cpp +++ b/src/gpu/gl/GrGLRenderTarget.cpp @@ -9,20 +9,8 @@ #include "GrGLGpu.h" -void GrGLFBO::release(const GrGLInterface* gl) { - SkASSERT(gl); - if (this->isValid()) { - GR_GL_CALL(gl, DeleteFramebuffers(1, &fID)); - fIsValid = false; - } -} - -void GrGLFBO::abandon() { fIsValid = false; } - -////////////////////////////////////////////////////////////////////////////// - -#define GLGPU static_cast(this->getGpu()) -#define GL_CALL(X) GR_GL_CALL(GLGPU->glInterface(), X) +#define GPUGL static_cast(this->getGpu()) +#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) // Because this class is virtually derived from GrSurface we must explicitly call its constructor. GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc) @@ -40,10 +28,8 @@ GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, cons } void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { - fRenderFBO.reset(SkRef(idDesc.fRenderFBO.get())); - fTextureFBO.reset(SkSafeRef(idDesc.fTextureFBO.get())); - SkASSERT(fRenderFBO->isValid()); - SkASSERT(!fTextureFBO || fTextureFBO->isValid()); + fRTFBOID = idDesc.fRTFBOID; + fTexFBOID = idDesc.fTexFBOID; fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID; fIsWrapped = kWrapped_LifeCycle == idDesc.fLifeCycle; @@ -54,7 +40,7 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { // We own one color value for each MSAA sample. fColorValuesPerPixel = SkTMax(1, fDesc.fSampleCnt); - if (fTextureFBO && fTextureFBO != fRenderFBO) { + if (fTexFBOID != fRTFBOID) { // If we own the resolve buffer then that is one more sample per pixel. fColorValuesPerPixel += 1; } @@ -70,42 +56,27 @@ size_t GrGLRenderTarget::onGpuMemorySize() const { void GrGLRenderTarget::onRelease() { if (!fIsWrapped) { - const GrGLInterface* gl = GLGPU->glInterface(); - if (fRenderFBO) { - fRenderFBO->release(gl); - fRenderFBO.reset(NULL); + if (fTexFBOID) { + GL_CALL(DeleteFramebuffers(1, &fTexFBOID)); } - if (fTextureFBO) { - fTextureFBO->release(gl); - fTextureFBO.reset(NULL); + if (fRTFBOID && fRTFBOID != fTexFBOID) { + GL_CALL(DeleteFramebuffers(1, &fRTFBOID)); } if (fMSColorRenderbufferID) { GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID)); - fMSColorRenderbufferID = 0; } - } else { - if (fRenderFBO) { - fRenderFBO->abandon(); - fRenderFBO.reset(NULL); - } - if (fTextureFBO) { - fTextureFBO->abandon(); - fTextureFBO.reset(NULL); - } - fMSColorRenderbufferID = 0; } + fRTFBOID = 0; + fTexFBOID = 0; + fMSColorRenderbufferID = 0; + fIsWrapped = false; INHERITED::onRelease(); } void GrGLRenderTarget::onAbandon() { - if (fRenderFBO) { - fRenderFBO->abandon(); - fRenderFBO.reset(NULL); - } - if (fTextureFBO) { - fTextureFBO->abandon(); - fTextureFBO.reset(NULL); - } + fRTFBOID = 0; + fTexFBOID = 0; fMSColorRenderbufferID = 0; + fIsWrapped = false; INHERITED::onAbandon(); } diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h index 485ae4a791..7e7349257f 100644 --- a/src/gpu/gl/GrGLRenderTarget.h +++ b/src/gpu/gl/GrGLRenderTarget.h @@ -15,59 +15,15 @@ class GrGLGpu; -/** Represents a GL FBO object. It has a gen ID which is valid whenever the FBO ID owned by the - object is valid. The gen IDs are not recycled after FBOs are freed, unlike FBO IDs, and so - can be used to uniquely identity FBO ID instantiations. If this object owns an FBO ID, the ID - must be deleted or abandoned before this object is freed. FBO IDs should never be owned by - more than one instance. */ -class GrGLFBO : public SkNVRefCnt { -public: - SK_DECLARE_INST_COUNT(GrGLFBO); - - /** Initializes to an FBO. The FBO should already be valid in the relevant GL context. */ - GrGLFBO(GrGLint id) : fID(id), fIsValid(true) {} - - /** Initializes to an FBO ID generated using the interface. */ - GrGLFBO(const GrGLInterface* gl) { - GR_GL_CALL(gl, GenFramebuffers(1, &fID)); - fIsValid = SkToBool(fID); - } - - ~GrGLFBO() { SkASSERT(!this->isValid()); } - - /** Has this object been released or abandoned? */ - bool isValid() const { return fIsValid; } - - GrGLint fboID() const { SkASSERT(this->isValid()); return fID; } - - bool isDefaultFramebuffer() const { return fIsValid && 0 == fID; } - - /** Give up ownership of the FBO ID owned by this object without deleting it. */ - void abandon(); - - /** Delete and give up ownership of the the FBO ID if it is valid. */ - void release(const GrGLInterface*); - -private: - static uint32_t NextGenID() { - static int32_t gGenID = SK_InvalidGenID + 1; - return static_cast(sk_atomic_inc(&gGenID)); - } - - GrGLuint fID; - bool fIsValid; - - typedef SkRefCnt INHERITED; -}; - -////////////////////////////////////////////////////////////////////////////// - -/** GL-specific subclass of GrRenderTarget. */ class GrGLRenderTarget : public GrRenderTarget { public: + // set fTexFBOID to this value to indicate that it is multisampled but + // Gr doesn't know how to resolve it. + enum { kUnresolvableFBOID = 0 }; + struct IDDesc { - SkAutoTUnref fRenderFBO; - SkAutoTUnref fTextureFBO; + GrGLuint fRTFBOID; + GrGLuint fTexFBOID; GrGLuint fMSColorRenderbufferID; GrGpuResource::LifeCycle fLifeCycle; }; @@ -77,33 +33,21 @@ public: void setViewport(const GrGLIRect& rect) { fViewport = rect; } const GrGLIRect& getViewport() const { return fViewport; } - // For multisampled renderbuffer render targets, these will return different GrGLFBO objects. If - // the render target is not texturable, textureFBO() returns NULL. If the render target auto - // resolves to a texture, the same object is returned. - - // FBO that should be rendered into. Always non-NULL unless this resource is destroyed - // (this->wasDestroyed()). - const GrGLFBO* renderFBO() const { - SkASSERT(fRenderFBO && fRenderFBO->isValid()); - return fRenderFBO; - } - - // FBO that has the target's texture ID attached. The return value may be: - // * NULL when this render target is not a texture, - // * the same as renderFBO() when this surface is not multisampled or auto-resolves, - // * or different than renderFBO() when it requires explicit resolving via - // glBlitFramebuffer. - const GrGLFBO* textureFBO() const { - SkASSERT(!fTextureFBO || fTextureFBO->isValid()); - return fTextureFBO; - } + // The following two functions return the same ID when a + // texture/render target is multisampled, and different IDs when + // it is. + // FBO ID used to render into + GrGLuint renderFBOID() const { return fRTFBOID; } + // FBO ID that has texture ID attached. + GrGLuint textureFBOID() const { return fTexFBOID; } // override of GrRenderTarget ResolveType getResolveType() const SK_OVERRIDE { - if (!this->isMultisampled() || this->renderFBO() == this->textureFBO()) { + if (!this->isMultisampled() || + fRTFBOID == fTexFBOID) { // catches FBO 0 and non MSAA case return kAutoResolves_ResolveType; - } else if (!this->textureFBO()) { + } else if (kUnresolvableFBOID == fTexFBOID) { return kCantResolve_ResolveType; } else { return kCanResolve_ResolveType; @@ -129,23 +73,23 @@ protected: size_t onGpuMemorySize() const SK_OVERRIDE; private: - SkAutoTUnref fRenderFBO; - SkAutoTUnref fTextureFBO; - GrGLuint fMSColorRenderbufferID; + GrGLuint fRTFBOID; + GrGLuint fTexFBOID; + GrGLuint fMSColorRenderbufferID; // We track this separately from GrGpuResource because this may be both a texture and a render // target, and the texture may be wrapped while the render target is not. - bool fIsWrapped; + bool fIsWrapped; // when we switch to this render target we want to set the viewport to // only render to content area (as opposed to the whole allocation) and // we want the rendering to be at top left (GL has origin in bottom left) - GrGLIRect fViewport; + GrGLIRect fViewport; // onGpuMemorySize() needs to know what how many color values are owned per pixel. However, // abandon and release zero out the IDs and the cache needs to know the size even after those // actions. - uint8_t fColorValuesPerPixel; + uint8_t fColorValuesPerPixel; typedef GrRenderTarget INHERITED; }; -- cgit v1.2.3