aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-03-17 15:55:42 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-03-17 15:55:42 -0700
commit160f24ce0e8d6dd7ca80b78871e063d4f4609cfb (patch)
tree536d98947826b92b1bb8f489d0d331bd8d7462ad /src
parent9251d4e9c6191aa26680911ed938dafdaebf5f61 (diff)
Improve tracking of bound FBOs in GrGLGpu.
Diffstat (limited to 'src')
-rw-r--r--src/gpu/gl/GrGLCaps.cpp9
-rw-r--r--src/gpu/gl/GrGLCaps.h5
-rw-r--r--src/gpu/gl/GrGLGpu.cpp390
-rw-r--r--src/gpu/gl/GrGLGpu.h51
-rw-r--r--src/gpu/gl/GrGLNoOpInterface.cpp3
-rw-r--r--src/gpu/gl/GrGLRenderTarget.cpp61
-rw-r--r--src/gpu/gl/GrGLRenderTarget.h100
-rw-r--r--src/gpu/gl/debug/GrGLCreateDebugInterface.cpp6
8 files changed, 385 insertions, 240 deletions
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 9911d53f43..e70e6f04fb 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -52,6 +52,8 @@ void GrGLCaps::reset() {
fDropsTileOnZeroDivide = false;
fFBFetchSupport = false;
fFBFetchNeedsCustomOutput = false;
+ fPreferBindingToReadAndDrawFramebuffer = false;
+
fFBFetchColorName = NULL;
fFBFetchExtensionString = NULL;
@@ -99,6 +101,7 @@ GrGLCaps& GrGLCaps::operator= (const GrGLCaps& caps) {
fFBFetchNeedsCustomOutput = caps.fFBFetchNeedsCustomOutput;
fFBFetchColorName = caps.fFBFetchColorName;
fFBFetchExtensionString = caps.fFBFetchExtensionString;
+ fPreferBindingToReadAndDrawFramebuffer = caps.fPreferBindingToReadAndDrawFramebuffer;
return *this;
}
@@ -279,6 +282,12 @@ bool GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
this->initFSAASupport(ctxInfo, gli);
this->initStencilFormats(ctxInfo);
+ // Workaround for Mac/Chromium issue.
+#ifdef SK_BUILD_FOR_MAC
+ // This relies on the fact that initFSAASupport() was already called.
+ fPreferBindingToReadAndDrawFramebuffer = ctxInfo.isChromium() && this->usesMSAARenderBuffers();
+#endif
+
/**************************************************************************
* GrDrawTargetCaps fields
**************************************************************************/
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 1b77ed0e32..932e66fdfc 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -267,6 +267,10 @@ public:
bool fullClearIsFree() const { return fFullClearIsFree; }
bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; }
+
+ bool preferBindingToReadAndDrawFramebuffer() const {
+ return fPreferBindingToReadAndDrawFramebuffer;
+ }
/**
* Returns a string containing the caps info.
@@ -389,6 +393,7 @@ private:
bool fDropsTileOnZeroDivide : 1;
bool fFBFetchSupport : 1;
bool fFBFetchNeedsCustomOutput : 1;
+ bool fPreferBindingToReadAndDrawFramebuffer : 1;
const char* fFBFetchColorName;
const char* fFBFetchExtensionString;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index a2c8d7f3ea..5ebbe1f3b4 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));
}
@@ -1208,28 +1215,29 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width,
GrGLuint tempRB;
GL_CALL(GenRenderbuffers(1, &tempRB));
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB));
+
if (samples > 0) {
renderbuffer_storage_msaa(fGLContext, samples, GR_GL_RGBA8, width, height);
} else {
GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height));
}
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, tempRB));
GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, 0));
GL_CALL(DeleteRenderbuffers(1, &tempRB));
// 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));
}
@@ -1249,9 +1257,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,
@@ -1270,19 +1275,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));
}
@@ -1291,13 +1294,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 {
@@ -1429,20 +1432,23 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
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());
// 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;
}
@@ -1539,7 +1545,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);
@@ -1567,40 +1574,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;
@@ -1615,7 +1618,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();
@@ -1651,7 +1654,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);
@@ -1721,22 +1724,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();
@@ -1801,7 +1795,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);
@@ -1822,41 +1817,69 @@ 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());
+
+ enum {
+ kDraw = 0,
+ kRead = 1
+ };
- 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[kDraw].fFBO.reset(SkRef(fbo));
+ fHWFBOBinding[kRead].fFBO.reset(SkRef(fbo));
+ return GR_GL_FRAMEBUFFER;
+ }
+ 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[kDraw];
+ break;
+
+ case kReadPixels_FBOBinding:
+ case kBlitSrc_FBOBinding:
+ case kCopyTexSrc_FBOBinding:
+ target = GR_GL_READ_FRAMEBUFFER;
+ hwFBOBinding = &fHWFBOBinding[kRead];
+ break;
}
- if (NULL == bound || !bound->isEmpty()) {
- target->flagAsNeedingResolve(bound);
+ fStats.incRenderTargetBinds();
+ GL_CALL(BindFramebuffer(target, fbo->fboID()));
+ hwFBOBinding->fFBO.reset(SkRef(fbo));
+ return target;
+}
+
+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);
+ }
}
}
@@ -1938,8 +1961,8 @@ 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);
- this->flushRenderTarget(rt, NULL);
-
+ this->bindFBO(kDraw_FBOBinding, rt->renderFBO());
+ this->setViewport(rt->getViewport());
fPathRendering->stencilPath(path, *state.fStencil);
}
@@ -1971,14 +1994,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();
@@ -2532,13 +2550,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) &&
@@ -2555,22 +2573,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 || kCopyTexSrc_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,
@@ -2579,18 +2606,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,
@@ -2621,7 +2651,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)) {
@@ -2645,14 +2675,14 @@ 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, kCopyTexSrc_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,
@@ -2674,28 +2704,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,
@@ -2733,15 +2756,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;
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index c9e280c3cb..6bd8e4db66 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -244,11 +244,29 @@ private:
// ensures that such operations don't negatively interact with tracking bound textures.
void setScratchTextureUnit();
- // 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);
+ // Enumerates the reasons for binding an FBO.
+ enum FBOBinding {
+ kDraw_FBOBinding,
+ kClear_FBOBinding,
+ kDiscard_FBOBinding,
+ kChangeAttachments_FBOBinding,
+ kReadPixels_FBOBinding,
+ kCopyTexSrc_FBOBinding,
+ kBlitSrc_FBOBinding,
+ kBlitDst_FBOBinding,
+ };
+
+ // binds the FBO and returns the GL enum of the framebuffer target it was bound to.
+ GrGLenum bindFBO(FBOBinding, const GrGLFBO*);
+
+ // Tracks dirty area for resolve, and tracks whether mip maps need rebuilding. bounds is the
+ // region that may be modified. NULL means whole surface. Can be an empty rect.
+ void markSurfaceContentsDirty(GrSurface*, const SkIRect* bounds);
+
+ void setViewport(const GrGLIRect& viewport);
void flushStencil(const GrStencilSettings&);
+
void flushHWAAState(GrRenderTarget* rt, bool useHWAA);
bool configToGLFormats(GrPixelConfig config,
@@ -279,15 +297,14 @@ private:
bool createRenderTargetObjects(const GrSurfaceDesc&, bool budgeted, GrGLuint texID,
GrGLRenderTarget::IDDesc*);
- enum TempFBOTarget {
- kSrc_TempFBOTarget,
- kDst_TempFBOTarget
- };
+ static const FBOBinding kInvalidFBOBinding = static_cast<FBOBinding>(-1);
- GrGLuint bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
- TempFBOTarget 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);
- void unbindTextureFromFBO(GrGLenum fboTarget);
+ // Must be matched with bindSurfaceAsFBOForCopy.
+ void unbindSurfaceAsFBOForCopy(FBOBinding);
GrGLContext fGLContext;
@@ -307,10 +324,9 @@ private:
kUnknown_TriState
};
- GrGLuint fTempSrcFBOID;
- GrGLuint fTempDstFBOID;
-
- GrGLuint fStencilClearFBOID;
+ SkAutoTUnref<GrGLFBO> fTempSrcFBO;
+ SkAutoTUnref<GrGLFBO> fTempDstFBO;
+ SkAutoTUnref<GrGLFBO> fStencilClearFBO;
// last scissor / viewport scissor state seen by the GL.
struct {
@@ -456,9 +472,14 @@ private:
GrPipelineBuilder::DrawFace fHWDrawFace;
TriState fHWWriteToColor;
TriState fHWDitherEnabled;
- uint32_t fHWBoundRenderTargetUniqueID;
SkTArray<uint32_t, true> fHWBoundTextureUniqueIDs;
+ // Track fbo binding state for GL_DRAW_FRAMEBUFFER and GL_READ_FRAMEBUFFER
+ struct HWFBOBinding {
+ SkAutoTUnref<const GrGLFBO> fFBO;
+ void invalidate() { fFBO.reset(NULL); }
+ } fHWFBOBinding[2];
+
///@}
// we record what stencil format worked last time to hopefully exit early
diff --git a/src/gpu/gl/GrGLNoOpInterface.cpp b/src/gpu/gl/GrGLNoOpInterface.cpp
index 6b8880ed81..38ad65e5c1 100644
--- a/src/gpu/gl/GrGLNoOpInterface.cpp
+++ b/src/gpu/gl/GrGLNoOpInterface.cpp
@@ -440,7 +440,8 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLBindFragDataLocationIndexed(GrGLuint program,
GrGLenum GR_GL_FUNCTION_TYPE noOpGLCheckFramebufferStatus(GrGLenum target) {
- GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target || GR_GL_READ_FRAMEBUFFER == target ||
+ GR_GL_DRAW_FRAMEBUFFER == target);
return GR_GL_FRAMEBUFFER_COMPLETE;
}
diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp
index 3eb2ae09fe..8b9bb98b6b 100644
--- a/src/gpu/gl/GrGLRenderTarget.cpp
+++ b/src/gpu/gl/GrGLRenderTarget.cpp
@@ -9,8 +9,20 @@
#include "GrGLGpu.h"
-#define GPUGL static_cast<GrGLGpu*>(this->getGpu())
-#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
+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<GrGLGpu*>(this->getGpu())
+#define GL_CALL(X) GR_GL_CALL(GLGPU->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)
@@ -28,8 +40,10 @@ GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, cons
}
void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
- fRTFBOID = idDesc.fRTFBOID;
- fTexFBOID = idDesc.fTexFBOID;
+ fRenderFBO.reset(SkRef(idDesc.fRenderFBO.get()));
+ fTextureFBO.reset(SkSafeRef(idDesc.fTextureFBO.get()));
+ SkASSERT(fRenderFBO->isValid());
+ SkASSERT(!fTextureFBO || fTextureFBO->isValid());
fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID;
fIsWrapped = kWrapped_LifeCycle == idDesc.fLifeCycle;
@@ -40,7 +54,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 (fTexFBOID != fRTFBOID) {
+ if (fTextureFBO && fTextureFBO != fRenderFBO) {
// If we own the resolve buffer then that is one more sample per pixel.
fColorValuesPerPixel += 1;
}
@@ -56,27 +70,42 @@ size_t GrGLRenderTarget::onGpuMemorySize() const {
void GrGLRenderTarget::onRelease() {
if (!fIsWrapped) {
- if (fTexFBOID) {
- GL_CALL(DeleteFramebuffers(1, &fTexFBOID));
+ const GrGLInterface* gl = GLGPU->glInterface();
+ if (fRenderFBO) {
+ fRenderFBO->release(gl);
+ fRenderFBO.reset(NULL);
}
- if (fRTFBOID && fRTFBOID != fTexFBOID) {
- GL_CALL(DeleteFramebuffers(1, &fRTFBOID));
+ if (fTextureFBO) {
+ fTextureFBO->release(gl);
+ fTextureFBO.reset(NULL);
}
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() {
- fRTFBOID = 0;
- fTexFBOID = 0;
+ if (fRenderFBO) {
+ fRenderFBO->abandon();
+ fRenderFBO.reset(NULL);
+ }
+ if (fTextureFBO) {
+ fTextureFBO->abandon();
+ fTextureFBO.reset(NULL);
+ }
fMSColorRenderbufferID = 0;
- fIsWrapped = false;
INHERITED::onAbandon();
}
diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h
index 7e7349257f..485ae4a791 100644
--- a/src/gpu/gl/GrGLRenderTarget.h
+++ b/src/gpu/gl/GrGLRenderTarget.h
@@ -15,15 +15,59 @@
class GrGLGpu;
-class GrGLRenderTarget : public GrRenderTarget {
+/** 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<GrGLFBO> {
public:
- // set fTexFBOID to this value to indicate that it is multisampled but
- // Gr doesn't know how to resolve it.
- enum { kUnresolvableFBOID = 0 };
+ 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<uint32_t>(sk_atomic_inc(&gGenID));
+ }
+
+ GrGLuint fID;
+ bool fIsValid;
+
+ typedef SkRefCnt INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+/** GL-specific subclass of GrRenderTarget. */
+class GrGLRenderTarget : public GrRenderTarget {
+public:
struct IDDesc {
- GrGLuint fRTFBOID;
- GrGLuint fTexFBOID;
+ SkAutoTUnref<GrGLFBO> fRenderFBO;
+ SkAutoTUnref<GrGLFBO> fTextureFBO;
GrGLuint fMSColorRenderbufferID;
GrGpuResource::LifeCycle fLifeCycle;
};
@@ -33,21 +77,33 @@ public:
void setViewport(const GrGLIRect& rect) { fViewport = rect; }
const GrGLIRect& getViewport() const { return fViewport; }
- // 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; }
+ // 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;
+ }
// override of GrRenderTarget
ResolveType getResolveType() const SK_OVERRIDE {
- if (!this->isMultisampled() ||
- fRTFBOID == fTexFBOID) {
+ if (!this->isMultisampled() || this->renderFBO() == this->textureFBO()) {
// catches FBO 0 and non MSAA case
return kAutoResolves_ResolveType;
- } else if (kUnresolvableFBOID == fTexFBOID) {
+ } else if (!this->textureFBO()) {
return kCantResolve_ResolveType;
} else {
return kCanResolve_ResolveType;
@@ -73,23 +129,23 @@ protected:
size_t onGpuMemorySize() const SK_OVERRIDE;
private:
- GrGLuint fRTFBOID;
- GrGLuint fTexFBOID;
- GrGLuint fMSColorRenderbufferID;
+ SkAutoTUnref<GrGLFBO> fRenderFBO;
+ SkAutoTUnref<GrGLFBO> fTextureFBO;
+ 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;
};
diff --git a/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
index 77a1422af1..b4643cc6d7 100644
--- a/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
+++ b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
@@ -382,7 +382,8 @@ GrGLvoid GR_GL_FUNCTION_TYPE debugGLReadPixels(GrGLint x,
GrGLenum renderbuffertarget,
GrGLuint renderBufferID) {
- GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target || GR_GL_READ_FRAMEBUFFER == target ||
+ GR_GL_DRAW_FRAMEBUFFER == target);
GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
GR_GL_DEPTH_ATTACHMENT == attachment ||
GR_GL_STENCIL_ATTACHMENT == attachment);
@@ -422,7 +423,8 @@ GrGLvoid GR_GL_FUNCTION_TYPE debugGLReadPixels(GrGLint x,
GrGLuint textureID,
GrGLint level) {
- GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target || GR_GL_READ_FRAMEBUFFER == target ||
+ GR_GL_DRAW_FRAMEBUFFER == target);
GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
GR_GL_DEPTH_ATTACHMENT == attachment ||
GR_GL_STENCIL_ATTACHMENT == attachment);