bsalomon 2015-03-17 12:33:33 -07:00 committed by Commit bot
parent 9d2049db6e
commit dc963b9264
8 changed files with 382 additions and 241 deletions

View File

@ -52,6 +52,8 @@ void GrGLCaps::reset() {
fDropsTileOnZeroDivide = false; fDropsTileOnZeroDivide = false;
fFBFetchSupport = false; fFBFetchSupport = false;
fFBFetchNeedsCustomOutput = false; fFBFetchNeedsCustomOutput = false;
fPreferBindingToReadAndDrawFramebuffer = false;
fFBFetchColorName = NULL; fFBFetchColorName = NULL;
fFBFetchExtensionString = NULL; fFBFetchExtensionString = NULL;
@ -99,6 +101,7 @@ GrGLCaps& GrGLCaps::operator= (const GrGLCaps& caps) {
fFBFetchNeedsCustomOutput = caps.fFBFetchNeedsCustomOutput; fFBFetchNeedsCustomOutput = caps.fFBFetchNeedsCustomOutput;
fFBFetchColorName = caps.fFBFetchColorName; fFBFetchColorName = caps.fFBFetchColorName;
fFBFetchExtensionString = caps.fFBFetchExtensionString; fFBFetchExtensionString = caps.fFBFetchExtensionString;
fPreferBindingToReadAndDrawFramebuffer = caps.fPreferBindingToReadAndDrawFramebuffer;
return *this; return *this;
} }
@ -279,6 +282,12 @@ bool GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
this->initFSAASupport(ctxInfo, gli); this->initFSAASupport(ctxInfo, gli);
this->initStencilFormats(ctxInfo); 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 * GrDrawTargetCaps fields
**************************************************************************/ **************************************************************************/

View File

@ -267,6 +267,10 @@ public:
bool fullClearIsFree() const { return fFullClearIsFree; } bool fullClearIsFree() const { return fFullClearIsFree; }
bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; } bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; }
bool preferBindingToReadAndDrawFramebuffer() const {
return fPreferBindingToReadAndDrawFramebuffer;
}
/** /**
* Returns a string containing the caps info. * Returns a string containing the caps info.
@ -389,6 +393,7 @@ private:
bool fDropsTileOnZeroDivide : 1; bool fDropsTileOnZeroDivide : 1;
bool fFBFetchSupport : 1; bool fFBFetchSupport : 1;
bool fFBFetchNeedsCustomOutput : 1; bool fFBFetchNeedsCustomOutput : 1;
bool fPreferBindingToReadAndDrawFramebuffer : 1;
const char* fFBFetchColorName; const char* fFBFetchColorName;
const char* fFBFetchExtensionString; const char* fFBFetchExtensionString;

View File

@ -151,9 +151,6 @@ GrGLGpu::GrGLGpu(const GrGLContext& ctx, GrContext* context)
fLastSuccessfulStencilFmtIdx = 0; fLastSuccessfulStencilFmtIdx = 0;
fHWProgramID = 0; fHWProgramID = 0;
fTempSrcFBOID = 0;
fTempDstFBOID = 0;
fStencilClearFBOID = 0;
if (this->glCaps().pathRenderingSupport()) { if (this->glCaps().pathRenderingSupport()) {
fPathRendering.reset(new GrGLPathRendering(this)); fPathRendering.reset(new GrGLPathRendering(this));
@ -168,14 +165,17 @@ GrGLGpu::~GrGLGpu() {
GL_CALL(UseProgram(0)); GL_CALL(UseProgram(0));
} }
if (0 != fTempSrcFBOID) { if (fTempSrcFBO) {
GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); fTempSrcFBO->release(this->glInterface());
fTempSrcFBO.reset(NULL);
} }
if (0 != fTempDstFBOID) { if (fTempDstFBO) {
GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); fTempDstFBO->release(this->glInterface());
fTempDstFBO.reset(NULL);
} }
if (0 != fStencilClearFBOID) { if (fStencilClearFBO) {
GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); fStencilClearFBO->release(this->glInterface());
fStencilClearFBO.reset(NULL);
} }
delete fProgramCache; delete fProgramCache;
@ -185,9 +185,19 @@ void GrGLGpu::contextAbandoned() {
INHERITED::contextAbandoned(); INHERITED::contextAbandoned();
fProgramCache->abandon(); fProgramCache->abandon();
fHWProgramID = 0; fHWProgramID = 0;
fTempSrcFBOID = 0; if (fTempSrcFBO) {
fTempDstFBOID = 0; fTempSrcFBO->abandon();
fStencilClearFBOID = 0; fTempSrcFBO.reset(NULL);
}
if (fTempDstFBO) {
fTempDstFBO->abandon();
fTempDstFBO.reset(NULL);
}
if (fStencilClearFBO) {
fStencilClearFBO->abandon();
fStencilClearFBO.reset(NULL);
}
if (this->glCaps().pathRenderingSupport()) { if (this->glCaps().pathRenderingSupport()) {
this->glPathRendering()->abandonGpuResources(); this->glPathRendering()->abandonGpuResources();
} }
@ -331,7 +341,9 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
} }
if (resetBits & kRenderTarget_GrGLBackendState) { 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) { if (resetBits & kPathRendering_GrGLBackendState) {
@ -432,9 +444,9 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc) {
GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc) { GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc) {
GrGLRenderTarget::IDDesc idDesc; 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.fMSColorRenderbufferID = 0;
idDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
idDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle; idDesc.fLifeCycle = GrGpuResource::kWrapped_LifeCycle;
GrSurfaceDesc desc; GrSurfaceDesc desc;
@ -814,34 +826,34 @@ static bool renderbuffer_storage_msaa(GrGLContext& ctx,
bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted, GrGLuint texID, bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted, GrGLuint texID,
GrGLRenderTarget::IDDesc* idDesc) { GrGLRenderTarget::IDDesc* idDesc) {
idDesc->fMSColorRenderbufferID = 0; idDesc->fMSColorRenderbufferID = 0;
idDesc->fRTFBOID = 0;
idDesc->fTexFBOID = 0;
idDesc->fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle : idDesc->fLifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle :
GrGpuResource::kUncached_LifeCycle; GrGpuResource::kUncached_LifeCycle;
GrGLenum status; GrGLenum status;
GrGLenum msColorFormat = 0; // suppress warning GrGLenum msColorFormat = 0; // suppress warning
GrGLenum fboTarget = 0; // suppress warning
if (desc.fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) { if (desc.fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
goto FAILED; goto FAILED;
} }
GL_CALL(GenFramebuffers(1, &idDesc->fTexFBOID)); idDesc->fTextureFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface())));
if (!idDesc->fTexFBOID) { if (!idDesc->fTextureFBO->isValid()) {
goto FAILED; goto FAILED;
} }
// If we are using multisampling we will create two FBOS. We render to one and then resolve to // 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 // 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 // extension the texture is multisampled when rendered to and then auto-resolves it when it is
// rendered from. // rendered from.
if (desc.fSampleCnt > 0 && this->glCaps().usesMSAARenderBuffers()) { 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)); GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID));
if (!idDesc->fRTFBOID || if (!idDesc->fMSColorRenderbufferID ||
!idDesc->fMSColorRenderbufferID ||
!this->configToGLFormats(desc.fConfig, !this->configToGLFormats(desc.fConfig,
// ES2 and ES3 require sized internal formats for rb storage. // ES2 and ES3 require sized internal formats for rb storage.
kGLES_GrGLStandard == this->glStandard(), kGLES_GrGLStandard == this->glStandard(),
@ -851,12 +863,10 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted
goto FAILED; goto FAILED;
} }
} else { } else {
idDesc->fRTFBOID = idDesc->fTexFBOID; idDesc->fRenderFBO.reset(SkRef(idDesc->fTextureFBO.get()));
} }
// below here we may bind the FBO if (idDesc->fRenderFBO != idDesc->fTextureFBO) {
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
if (idDesc->fRTFBOID != idDesc->fTexFBOID) {
SkASSERT(desc.fSampleCnt > 0); SkASSERT(desc.fSampleCnt > 0);
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID)); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID));
if (!renderbuffer_storage_msaa(fGLContext, if (!renderbuffer_storage_msaa(fGLContext,
@ -865,12 +875,11 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, bool budgeted
desc.fWidth, desc.fHeight)) { desc.fWidth, desc.fHeight)) {
goto FAILED; goto FAILED;
} }
fStats.incRenderTargetBinds(); fboTarget = this->bindFBO(kChangeAttachments_FBOBinding, idDesc->fRenderFBO);
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fRTFBOID)); GL_CALL(FramebufferRenderbuffer(fboTarget,
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
GR_GL_COLOR_ATTACHMENT0, GR_GL_RENDERBUFFER,
GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID));
idDesc->fMSColorRenderbufferID));
if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) ||
!this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) { !this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) {
GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); 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); fGLContext.caps()->markConfigAsValidColorAttachment(desc.fConfig);
} }
} }
fStats.incRenderTargetBinds(); fboTarget = this->bindFBO(kChangeAttachments_FBOBinding, idDesc->fTextureFBO);
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fTexFBOID));
if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) { if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) {
GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferTexture2DMultisample(fboTarget,
GR_GL_COLOR_ATTACHMENT0, GR_GL_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D, GR_GL_TEXTURE_2D,
texID, 0, desc.fSampleCnt)); texID, 0, desc.fSampleCnt));
} else { } else {
GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferTexture2D(fboTarget,
GR_GL_COLOR_ATTACHMENT0, GR_GL_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D, GR_GL_TEXTURE_2D,
texID, 0)); texID, 0));
} }
if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) || if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) ||
!this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) { !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) { if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
goto FAILED; goto FAILED;
} }
@ -909,11 +917,11 @@ FAILED:
if (idDesc->fMSColorRenderbufferID) { if (idDesc->fMSColorRenderbufferID) {
GL_CALL(DeleteRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); GL_CALL(DeleteRenderbuffers(1, &idDesc->fMSColorRenderbufferID));
} }
if (idDesc->fRTFBOID != idDesc->fTexFBOID) { if (idDesc->fRenderFBO) {
GL_CALL(DeleteFramebuffers(1, &idDesc->fRTFBOID)); idDesc->fRenderFBO->release(this->glInterface());
} }
if (idDesc->fTexFBOID) { if (idDesc->fTextureFBO) {
GL_CALL(DeleteFramebuffers(1, &idDesc->fTexFBOID)); idDesc->fTextureFBO->release(this->glInterface());
} }
return false; 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 // 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 // entire stencil buffer is cleared, even if it is attached to an FBO with a
// smaller color target. // smaller color target.
if (0 == fStencilClearFBOID) { if (!fStencilClearFBO) {
GL_CALL(GenFramebuffers(1, &fStencilClearFBOID)); fStencilClearFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface())));
} }
SkASSERT(fStencilClearFBO->isValid());
GrGLenum fboTarget = this->bindFBO(kClear_FBOBinding, fStencilClearFBO);
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID)); GL_CALL(FramebufferRenderbuffer(fboTarget,
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
fStats.incRenderTargetBinds();
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
GR_GL_STENCIL_ATTACHMENT, GR_GL_STENCIL_ATTACHMENT,
GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
if (sFmt.fPacked) { if (sFmt.fPacked) {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_DEPTH_ATTACHMENT, GR_GL_DEPTH_ATTACHMENT,
GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
} }
@ -1209,23 +1216,23 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width,
GL_CALL(GenRenderbuffers(1, &tempRB)); GL_CALL(GenRenderbuffers(1, &tempRB));
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB)); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB));
GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height)); 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_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, tempRB)); GR_GL_RENDERBUFFER, tempRB));
GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT)); GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_COLOR_ATTACHMENT0, GR_GL_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, 0)); GR_GL_RENDERBUFFER, 0));
GL_CALL(DeleteRenderbuffers(1, &tempRB)); GL_CALL(DeleteRenderbuffers(1, &tempRB));
// Unbind the SB from the FBO so that we don't keep it alive. // 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_STENCIL_ATTACHMENT,
GR_GL_RENDERBUFFER, 0)); GR_GL_RENDERBUFFER, 0));
if (sFmt.fPacked) { if (sFmt.fPacked) {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_DEPTH_ATTACHMENT, GR_GL_DEPTH_ATTACHMENT,
GR_GL_RENDERBUFFER, 0)); GR_GL_RENDERBUFFER, 0));
} }
@ -1245,9 +1252,6 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width,
bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) { bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) {
GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt); GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt);
GrGLuint fbo = glrt->renderFBOID();
if (NULL == sb) { if (NULL == sb) {
if (rt->renderTargetPriv().getStencilBuffer()) { if (rt->renderTargetPriv().getStencilBuffer()) {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
@ -1266,19 +1270,17 @@ bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTar
} else { } else {
GrGLStencilBuffer* glsb = static_cast<GrGLStencilBuffer*>(sb); GrGLStencilBuffer* glsb = static_cast<GrGLStencilBuffer*>(sb);
GrGLuint rb = glsb->renderbufferID(); GrGLuint rb = glsb->renderbufferID();
GrGLenum fboTarget = this->bindFBO(kChangeAttachments_FBOBinding, glrt->renderFBO());
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; GL_CALL(FramebufferRenderbuffer(fboTarget,
fStats.incRenderTargetBinds();
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
GR_GL_STENCIL_ATTACHMENT, GR_GL_STENCIL_ATTACHMENT,
GR_GL_RENDERBUFFER, rb)); GR_GL_RENDERBUFFER, rb));
if (glsb->format().fPacked) { if (glsb->format().fPacked) {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_DEPTH_ATTACHMENT, GR_GL_DEPTH_ATTACHMENT,
GR_GL_RENDERBUFFER, rb)); GR_GL_RENDERBUFFER, rb));
} else { } else {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_DEPTH_ATTACHMENT, GR_GL_DEPTH_ATTACHMENT,
GR_GL_RENDERBUFFER, 0)); GR_GL_RENDERBUFFER, 0));
} }
@ -1287,13 +1289,13 @@ bool GrGLGpu::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTar
if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(), glsb->format())) { if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(), glsb->format())) {
GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
if (status != GR_GL_FRAMEBUFFER_COMPLETE) { if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_STENCIL_ATTACHMENT, GR_GL_STENCIL_ATTACHMENT,
GR_GL_RENDERBUFFER, 0)); GR_GL_RENDERBUFFER, 0));
if (glsb->format().fPacked) { if (glsb->format().fPacked) {
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GL_CALL(FramebufferRenderbuffer(fboTarget,
GR_GL_DEPTH_ATTACHMENT, GR_GL_DEPTH_ATTACHMENT,
GR_GL_RENDERBUFFER, 0)); GR_GL_RENDERBUFFER, 0));
} }
return false; return false;
} else { } else {
@ -1425,20 +1427,23 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
fHWProgramID = programID; fHWProgramID = programID;
} }
if (blendInfo.fWriteColor) {
this->flushBlend(blendInfo);
}
fCurrentProgram->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTracker); fCurrentProgram->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTracker);
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget()); GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
this->flushStencil(pipeline.getStencil()); this->flushStencil(pipeline.getStencil());
this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin()); this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin());
this->flushHWAAState(glRT, pipeline.isHWAntialiasState()); this->flushHWAAState(glRT, pipeline.isHWAntialiasState());
// This must come after textures are flushed because a texture may need // This must come after textures are flushed because a texture may need
// to be msaa-resolved (which will modify bound FBO state). // to be msaa-resolved (which will modify bound FBO and scissor state).
this->flushRenderTarget(glRT, NULL); this->bindFBO(kDraw_FBOBinding, glRT->renderFBO());
this->setViewport(glRT->getViewport());
if (blendInfo.fWriteColor) {
this->flushBlend(blendInfo);
this->markSurfaceContentsDirty(glRT, NULL);
}
return true; return true;
} }
@ -1535,7 +1540,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; GrScissorState scissorState;
if (rect) { if (rect) {
scissorState.set(*rect); scissorState.set(*rect);
@ -1563,40 +1569,36 @@ void GrGLGpu::discard(GrRenderTarget* renderTarget) {
} }
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget); GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget);
if (renderTarget->getUniqueID() != fHWBoundRenderTargetUniqueID) { GrGLenum fboTarget = this->bindFBO(kDiscard_FBOBinding, glRT->renderFBO());
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
fStats.incRenderTargetBinds();
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRT->renderFBOID()));
}
switch (this->glCaps().invalidateFBType()) { switch (this->glCaps().invalidateFBType()) {
case GrGLCaps::kNone_InvalidateFBType: case GrGLCaps::kNone_InvalidateFBType:
SkFAIL("Should never get here."); SkFAIL("Should never get here.");
break; break;
case GrGLCaps::kInvalidate_InvalidateFBType: case GrGLCaps::kInvalidate_InvalidateFBType:
if (0 == glRT->renderFBOID()) { if (glRT->renderFBO()->isDefaultFramebuffer()) {
// When rendering to the default framebuffer the legal values for attachments // When rendering to the default framebuffer the legal values for attachments
// are GL_COLOR, GL_DEPTH, GL_STENCIL, ... rather than the various FBO attachment // are GL_COLOR, GL_DEPTH, GL_STENCIL, ... rather than the various FBO attachment
// types. // types.
static const GrGLenum attachments[] = { GR_GL_COLOR }; 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)); attachments));
} else { } else {
static const GrGLenum attachments[] = { GR_GL_COLOR_ATTACHMENT0 }; 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)); attachments));
} }
break; break;
case GrGLCaps::kDiscard_InvalidateFBType: { case GrGLCaps::kDiscard_InvalidateFBType: {
if (0 == glRT->renderFBOID()) { if (glRT->renderFBO()->isDefaultFramebuffer()) {
// When rendering to the default framebuffer the legal values for attachments // When rendering to the default framebuffer the legal values for attachments
// are GL_COLOR, GL_DEPTH, GL_STENCIL, ... rather than the various FBO attachment // are GL_COLOR, GL_DEPTH, GL_STENCIL, ... rather than the various FBO attachment
// types. See glDiscardFramebuffer() spec. // types. See glDiscardFramebuffer() spec.
static const GrGLenum attachments[] = { GR_GL_COLOR }; 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)); attachments));
} else { } else {
static const GrGLenum attachments[] = { GR_GL_COLOR_ATTACHMENT0 }; 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)); attachments));
} }
break; break;
@ -1611,7 +1613,7 @@ void GrGLGpu::clearStencil(GrRenderTarget* target) {
return; return;
} }
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
this->flushRenderTarget(glRT, &SkIRect::EmptyIRect()); this->bindFBO(kClear_FBOBinding, glRT->renderFBO());
this->disableScissor(); this->disableScissor();
@ -1647,7 +1649,7 @@ void GrGLGpu::onClearStencilClip(GrRenderTarget* target, const SkIRect& rect, bo
value = 0; value = 0;
} }
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
this->flushRenderTarget(glRT, &SkIRect::EmptyIRect()); this->bindFBO(kClear_FBOBinding, glRT->renderFBO());
GrScissorState scissorState; GrScissorState scissorState;
scissorState.set(rect); scissorState.set(rect);
@ -1717,22 +1719,13 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target,
// resolve the render target if necessary // resolve the render target if necessary
GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target); GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
switch (tgt->getResolveType()) { if (tgt->getResolveType() == GrGLRenderTarget::kCantResolve_ResolveType) {
case GrGLRenderTarget::kCantResolve_ResolveType: return false;
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::kCanResolve_ResolveType) {
this->onResolveRenderTarget(tgt);
}
this->bindFBO(kReadPixels_FBOBinding, tgt->textureFBO());
const GrGLIRect& glvp = tgt->getViewport(); const GrGLIRect& glvp = tgt->getViewport();
@ -1797,7 +1790,8 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target,
} }
} }
} else { } else {
SkASSERT(readDst != buffer); SkASSERT(rowBytes != tightRowBytes); SkASSERT(readDst != buffer);
SkASSERT(rowBytes != tightRowBytes);
// copy from readDst to buffer while flipping y // copy from readDst to buffer while flipping y
// const int halfY = height >> 1; // const int halfY = height >> 1;
const char* src = reinterpret_cast<const char*>(readDst); const char* src = reinterpret_cast<const char*>(readDst);
@ -1818,41 +1812,68 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target,
return true; 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 (useGLFramebuffer) {
if (fHWBoundRenderTargetUniqueID != rtID) { SkASSERT(kBlitSrc_FBOBinding != binding);
fStats.incRenderTargetBinds(); fStats.incRenderTargetBinds();
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, target->renderFBOID())); GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo->fboID()));
#ifdef SK_DEBUG fHWFBOBinding[kDraw].fFBO.reset(SkRef(fbo));
// don't do this check in Chromium -- this is causing fHWFBOBinding[kRead].fFBO.reset(SkRef(fbo));
// lots of repeated command buffer flushes when the compositor is return GR_GL_FRAMEBUFFER;
// 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;
}
}
if (NULL == bound || !bound->isEmpty()) {
target->flagAsNeedingResolve(bound);
} }
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;
GrTexture *texture = target->asTexture(); case kReadPixels_FBOBinding:
if (texture) { case kBlitSrc_FBOBinding:
texture->texturePriv().dirtyMipMaps(true); target = GR_GL_READ_FRAMEBUFFER;
hwFBOBinding = &fHWFBOBinding[kRead];
break;
}
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;
}
}
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);
}
} }
} }
@ -1934,8 +1955,8 @@ void GrGLGpu::onStencilPath(const GrPath* path, const StencilPathState& state) {
this->glPathRendering()->setProjectionMatrix(*state.fViewMatrix, size, rt->origin()); this->glPathRendering()->setProjectionMatrix(*state.fViewMatrix, size, rt->origin());
this->flushScissor(*state.fScissor, rt->getViewport(), rt->origin()); this->flushScissor(*state.fScissor, rt->getViewport(), rt->origin());
this->flushHWAAState(rt, state.fUseHWAA); this->flushHWAAState(rt, state.fUseHWAA);
this->flushRenderTarget(rt, NULL); this->bindFBO(kDraw_FBOBinding, rt->renderFBO());
this->setViewport(rt->getViewport());
fPathRendering->stencilPath(path, *state.fStencil); fPathRendering->stencilPath(path, *state.fStencil);
} }
@ -1967,14 +1988,9 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) {
if (rt->needsResolve()) { if (rt->needsResolve()) {
// Some extensions automatically resolves the texture when it is read. // Some extensions automatically resolves the texture when it is read.
if (this->glCaps().usesMSAARenderBuffers()) { if (this->glCaps().usesMSAARenderBuffers()) {
SkASSERT(rt->textureFBOID() != rt->renderFBOID()); SkASSERT(rt->textureFBO() != rt->renderFBO());
fStats.incRenderTargetBinds(); this->bindFBO(kBlitSrc_FBOBinding, rt->renderFBO());
fStats.incRenderTargetBinds(); this->bindFBO(kBlitDst_FBOBinding, rt->textureFBO());
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 GrGLIRect& vp = rt->getViewport();
const SkIRect dirtyRect = rt->getResolveRect(); const SkIRect dirtyRect = rt->getResolveRect();
@ -2528,13 +2544,13 @@ inline bool can_copy_texsubimage(const GrSurface* dst,
const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget()); const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget());
// If dst is multisampled (and uses an extension where there is a separate MSAA renderbuffer) // 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. // 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; return false;
} }
const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget()); const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget());
// If the src is multisampled (and uses an extension where there is a separate MSAA // 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 // renderbuffer) then it is an invalid operation to call CopyTexSubImage
if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) { if (srcRT && srcRT->renderFBO() != srcRT->textureFBO()) {
return false; return false;
} }
if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) && if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
@ -2551,22 +2567,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 // If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is
// relative to is output. // relative to is output.
GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, GrGLGpu::FBOBinding GrGLGpu::bindSurfaceAsFBOForCopy(GrSurface* surface, FBOBinding binding,
TempFBOTarget tempFBOTarget) { GrGLIRect* viewport) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget()); GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
if (NULL == rt) { if (NULL == rt) {
SkASSERT(surface->asTexture()); SkASSERT(surface->asTexture());
GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID(); GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
GrGLuint* tempFBOID; GrGLFBO* tempFBO;
tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID;
if (0 == *tempFBOID) { if (kBlitSrc_FBOBinding == binding) {
GR_GL_CALL(this->glInterface(), GenFramebuffers(1, tempFBOID)); 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(); GrGLenum target = this->bindFBO(binding, tempFBO);
GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, *tempFBOID)); GR_GL_CALL(this->glInterface(), FramebufferTexture2D(target,
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
GR_GL_COLOR_ATTACHMENT0, GR_GL_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D, GR_GL_TEXTURE_2D,
texID, texID,
@ -2575,18 +2600,21 @@ GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLI
viewport->fBottom = 0; viewport->fBottom = 0;
viewport->fWidth = surface->width(); viewport->fWidth = surface->width();
viewport->fHeight = surface->height(); viewport->fHeight = surface->height();
return *tempFBOID; return binding;
} else { } else {
GrGLuint tempFBOID = 0; this->bindFBO(binding, rt->renderFBO());
fStats.incRenderTargetBinds();
GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, rt->renderFBOID()));
*viewport = rt->getViewport(); *viewport = rt->getViewport();
return tempFBOID; return kInvalidFBOBinding;
} }
} }
void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) { void GrGLGpu::unbindSurfaceAsFBOForCopy(FBOBinding binding) {
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, 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_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D, GR_GL_TEXTURE_2D,
0, 0,
@ -2617,7 +2645,7 @@ bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc)
} }
const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget()); 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 // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO blit or
// fail. // fail.
if (this->caps()->isConfigRenderable(src->config(), false)) { if (this->caps()->isConfigRenderable(src->config(), false)) {
@ -2641,14 +2669,13 @@ bool GrGLGpu::copySurface(GrSurface* dst,
const SkIRect& srcRect, const SkIRect& srcRect,
const SkIPoint& dstPoint) { const SkIPoint& dstPoint) {
bool copied = false; bool copied = false;
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
srcRect.width(), srcRect.height());
if (can_copy_texsubimage(dst, src, this)) { if (can_copy_texsubimage(dst, src, this)) {
GrGLuint srcFBO;
GrGLIRect srcVP; 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()); GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
SkASSERT(dstTex); SkASSERT(dstTex);
// We modified the bound FBO
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
GrGLIRect srcGLRect; GrGLIRect srcGLRect;
srcGLRect.setRelativeTo(srcVP, srcGLRect.setRelativeTo(srcVP,
srcRect.fLeft, srcRect.fLeft,
@ -2670,28 +2697,21 @@ bool GrGLGpu::copySurface(GrSurface* dst,
srcGLRect.fLeft, srcGLRect.fBottom, srcGLRect.fLeft, srcGLRect.fBottom,
srcGLRect.fWidth, srcGLRect.fHeight)); srcGLRect.fWidth, srcGLRect.fHeight));
copied = true; copied = true;
if (srcFBO) { this->unbindSurfaceAsFBOForCopy(srcFBOBinding);
this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER);
}
} else if (can_blit_framebuffer(dst, src, this)) { } else if (can_blit_framebuffer(dst, src, this)) {
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
srcRect.width(), srcRect.height());
bool selfOverlap = false; bool selfOverlap = false;
if (dst == src) { if (dst == src) {
selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect); selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect);
} }
if (!selfOverlap) { if (!selfOverlap) {
GrGLuint dstFBO;
GrGLuint srcFBO;
GrGLIRect dstVP; GrGLIRect dstVP;
GrGLIRect srcVP; GrGLIRect srcVP;
dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, FBOBinding dstFBOBinding = this->bindSurfaceAsFBOForCopy(dst, kBlitDst_FBOBinding,
kDst_TempFBOTarget); &dstVP);
srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP, FBOBinding srcFBOBinding = this->bindSurfaceAsFBOForCopy(src, kBlitSrc_FBOBinding,
kSrc_TempFBOTarget); &srcVP);
// We modified the bound FBO
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
GrGLIRect srcGLRect; GrGLIRect srcGLRect;
GrGLIRect dstGLRect; GrGLIRect dstGLRect;
srcGLRect.setRelativeTo(srcVP, srcGLRect.setRelativeTo(srcVP,
@ -2729,15 +2749,14 @@ bool GrGLGpu::copySurface(GrSurface* dst,
dstGLRect.fLeft + dstGLRect.fWidth, dstGLRect.fLeft + dstGLRect.fWidth,
dstGLRect.fBottom + dstGLRect.fHeight, dstGLRect.fBottom + dstGLRect.fHeight,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
if (dstFBO) { this->unbindSurfaceAsFBOForCopy(dstFBOBinding);
this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER); this->unbindSurfaceAsFBOForCopy(srcFBOBinding);
}
if (srcFBO) {
this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER);
}
copied = true; copied = true;
} }
} }
if (copied) {
this->markSurfaceContentsDirty(dst, &dstRect);
}
return copied; return copied;
} }

View File

@ -244,11 +244,28 @@ private:
// ensures that such operations don't negatively interact with tracking bound textures. // ensures that such operations don't negatively interact with tracking bound textures.
void setScratchTextureUnit(); void setScratchTextureUnit();
// bounds is region that may be modified and therefore has to be resolved. // Enumerates the reasons for binding an FBO.
// NULL means whole target. Can be an empty rect. enum FBOBinding {
void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds); kDraw_FBOBinding,
kClear_FBOBinding,
kDiscard_FBOBinding,
kChangeAttachments_FBOBinding,
kReadPixels_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 flushStencil(const GrStencilSettings&);
void flushHWAAState(GrRenderTarget* rt, bool useHWAA); void flushHWAAState(GrRenderTarget* rt, bool useHWAA);
bool configToGLFormats(GrPixelConfig config, bool configToGLFormats(GrPixelConfig config,
@ -279,15 +296,14 @@ private:
bool createRenderTargetObjects(const GrSurfaceDesc&, bool budgeted, GrGLuint texID, bool createRenderTargetObjects(const GrSurfaceDesc&, bool budgeted, GrGLuint texID,
GrGLRenderTarget::IDDesc*); GrGLRenderTarget::IDDesc*);
enum TempFBOTarget { static const FBOBinding kInvalidFBOBinding = static_cast<FBOBinding>(-1);
kSrc_TempFBOTarget,
kDst_TempFBOTarget
};
GrGLuint bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, // Binds a surface as an FBO. A temporary FBO ID may be used if the surface is not already
TempFBOTarget tempFBOTarget); // 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; GrGLContext fGLContext;
@ -307,10 +323,9 @@ private:
kUnknown_TriState kUnknown_TriState
}; };
GrGLuint fTempSrcFBOID; SkAutoTUnref<GrGLFBO> fTempSrcFBO;
GrGLuint fTempDstFBOID; SkAutoTUnref<GrGLFBO> fTempDstFBO;
SkAutoTUnref<GrGLFBO> fStencilClearFBO;
GrGLuint fStencilClearFBOID;
// last scissor / viewport scissor state seen by the GL. // last scissor / viewport scissor state seen by the GL.
struct { struct {
@ -456,9 +471,14 @@ private:
GrPipelineBuilder::DrawFace fHWDrawFace; GrPipelineBuilder::DrawFace fHWDrawFace;
TriState fHWWriteToColor; TriState fHWWriteToColor;
TriState fHWDitherEnabled; TriState fHWDitherEnabled;
uint32_t fHWBoundRenderTargetUniqueID;
SkTArray<uint32_t, true> fHWBoundTextureUniqueIDs; 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 // we record what stencil format worked last time to hopefully exit early

View File

@ -440,7 +440,8 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLBindFragDataLocationIndexed(GrGLuint program,
GrGLenum GR_GL_FUNCTION_TYPE noOpGLCheckFramebufferStatus(GrGLenum target) { 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; return GR_GL_FRAMEBUFFER_COMPLETE;
} }

View File

@ -9,8 +9,20 @@
#include "GrGLGpu.h" #include "GrGLGpu.h"
#define GPUGL static_cast<GrGLGpu*>(this->getGpu()) void GrGLFBO::release(const GrGLInterface* gl) {
#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) 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. // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc) 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) { void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
fRTFBOID = idDesc.fRTFBOID; fRenderFBO.reset(SkRef(idDesc.fRenderFBO.get()));
fTexFBOID = idDesc.fTexFBOID; fTextureFBO.reset(SkSafeRef(idDesc.fTextureFBO.get()));
SkASSERT(fRenderFBO->isValid());
SkASSERT(!fTextureFBO || fTextureFBO->isValid());
fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID; fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID;
fIsWrapped = kWrapped_LifeCycle == idDesc.fLifeCycle; 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. // We own one color value for each MSAA sample.
fColorValuesPerPixel = SkTMax(1, fDesc.fSampleCnt); 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. // If we own the resolve buffer then that is one more sample per pixel.
fColorValuesPerPixel += 1; fColorValuesPerPixel += 1;
} }
@ -56,27 +70,42 @@ size_t GrGLRenderTarget::onGpuMemorySize() const {
void GrGLRenderTarget::onRelease() { void GrGLRenderTarget::onRelease() {
if (!fIsWrapped) { if (!fIsWrapped) {
if (fTexFBOID) { const GrGLInterface* gl = GLGPU->glInterface();
GL_CALL(DeleteFramebuffers(1, &fTexFBOID)); if (fRenderFBO) {
fRenderFBO->release(gl);
fRenderFBO.reset(NULL);
} }
if (fRTFBOID && fRTFBOID != fTexFBOID) { if (fTextureFBO) {
GL_CALL(DeleteFramebuffers(1, &fRTFBOID)); fTextureFBO->release(gl);
fTextureFBO.reset(NULL);
} }
if (fMSColorRenderbufferID) { if (fMSColorRenderbufferID) {
GL_CALL(DeleteRenderbuffers(1, &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(); INHERITED::onRelease();
} }
void GrGLRenderTarget::onAbandon() { void GrGLRenderTarget::onAbandon() {
fRTFBOID = 0; if (fRenderFBO) {
fTexFBOID = 0; fRenderFBO->abandon();
fRenderFBO.reset(NULL);
}
if (fTextureFBO) {
fTextureFBO->abandon();
fTextureFBO.reset(NULL);
}
fMSColorRenderbufferID = 0; fMSColorRenderbufferID = 0;
fIsWrapped = false;
INHERITED::onAbandon(); INHERITED::onAbandon();
} }

View File

@ -15,15 +15,59 @@
class GrGLGpu; 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<GrGLFBO> {
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<uint32_t>(sk_atomic_inc(&gGenID));
}
GrGLuint fID;
bool fIsValid;
typedef SkRefCnt INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
/** GL-specific subclass of GrRenderTarget. */
class GrGLRenderTarget : public GrRenderTarget { class GrGLRenderTarget : public GrRenderTarget {
public: 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 { struct IDDesc {
GrGLuint fRTFBOID; SkAutoTUnref<GrGLFBO> fRenderFBO;
GrGLuint fTexFBOID; SkAutoTUnref<GrGLFBO> fTextureFBO;
GrGLuint fMSColorRenderbufferID; GrGLuint fMSColorRenderbufferID;
GrGpuResource::LifeCycle fLifeCycle; GrGpuResource::LifeCycle fLifeCycle;
}; };
@ -33,21 +77,33 @@ public:
void setViewport(const GrGLIRect& rect) { fViewport = rect; } void setViewport(const GrGLIRect& rect) { fViewport = rect; }
const GrGLIRect& getViewport() const { return fViewport; } const GrGLIRect& getViewport() const { return fViewport; }
// The following two functions return the same ID when a // For multisampled renderbuffer render targets, these will return different GrGLFBO objects. If
// texture/render target is multisampled, and different IDs when // the render target is not texturable, textureFBO() returns NULL. If the render target auto
// it is. // resolves to a texture, the same object is returned.
// FBO ID used to render into
GrGLuint renderFBOID() const { return fRTFBOID; } // FBO that should be rendered into. Always non-NULL unless this resource is destroyed
// FBO ID that has texture ID attached. // (this->wasDestroyed()).
GrGLuint textureFBOID() const { return fTexFBOID; } 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 // override of GrRenderTarget
ResolveType getResolveType() const SK_OVERRIDE { ResolveType getResolveType() const SK_OVERRIDE {
if (!this->isMultisampled() || if (!this->isMultisampled() || this->renderFBO() == this->textureFBO()) {
fRTFBOID == fTexFBOID) {
// catches FBO 0 and non MSAA case // catches FBO 0 and non MSAA case
return kAutoResolves_ResolveType; return kAutoResolves_ResolveType;
} else if (kUnresolvableFBOID == fTexFBOID) { } else if (!this->textureFBO()) {
return kCantResolve_ResolveType; return kCantResolve_ResolveType;
} else { } else {
return kCanResolve_ResolveType; return kCanResolve_ResolveType;
@ -73,23 +129,23 @@ protected:
size_t onGpuMemorySize() const SK_OVERRIDE; size_t onGpuMemorySize() const SK_OVERRIDE;
private: private:
GrGLuint fRTFBOID; SkAutoTUnref<GrGLFBO> fRenderFBO;
GrGLuint fTexFBOID; SkAutoTUnref<GrGLFBO> fTextureFBO;
GrGLuint fMSColorRenderbufferID; GrGLuint fMSColorRenderbufferID;
// We track this separately from GrGpuResource because this may be both a texture and a render // 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. // 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 // 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 // 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) // 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, // 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 // abandon and release zero out the IDs and the cache needs to know the size even after those
// actions. // actions.
uint8_t fColorValuesPerPixel; uint8_t fColorValuesPerPixel;
typedef GrRenderTarget INHERITED; typedef GrRenderTarget INHERITED;
}; };

View File

@ -382,7 +382,8 @@ GrGLvoid GR_GL_FUNCTION_TYPE debugGLReadPixels(GrGLint x,
GrGLenum renderbuffertarget, GrGLenum renderbuffertarget,
GrGLuint renderBufferID) { 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 || GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
GR_GL_DEPTH_ATTACHMENT == attachment || GR_GL_DEPTH_ATTACHMENT == attachment ||
GR_GL_STENCIL_ATTACHMENT == attachment); GR_GL_STENCIL_ATTACHMENT == attachment);
@ -422,7 +423,8 @@ GrGLvoid GR_GL_FUNCTION_TYPE debugGLReadPixels(GrGLint x,
GrGLuint textureID, GrGLuint textureID,
GrGLint level) { 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 || GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
GR_GL_DEPTH_ATTACHMENT == attachment || GR_GL_DEPTH_ATTACHMENT == attachment ||
GR_GL_STENCIL_ATTACHMENT == attachment); GR_GL_STENCIL_ATTACHMENT == attachment);