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;
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
**************************************************************************/

View File

@ -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;

View File

@ -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));
}
@ -1209,23 +1216,23 @@ bool GrGLGpu::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width,
GL_CALL(GenRenderbuffers(1, &tempRB));
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB));
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));
}
@ -1245,9 +1252,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,
@ -1266,19 +1270,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));
}
@ -1287,13 +1289,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 {
@ -1425,20 +1427,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;
}
@ -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;
if (rect) {
scissorState.set(*rect);
@ -1563,40 +1569,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;
@ -1611,7 +1613,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();
@ -1647,7 +1649,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);
@ -1717,22 +1719,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();
@ -1797,7 +1790,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);
@ -1818,41 +1812,68 @@ 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;
}
}
if (NULL == bound || !bound->isEmpty()) {
target->flagAsNeedingResolve(bound);
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;
GrTexture *texture = target->asTexture();
if (texture) {
texture->texturePriv().dirtyMipMaps(true);
case kReadPixels_FBOBinding:
case kBlitSrc_FBOBinding:
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->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);
}
@ -1967,14 +1988,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();
@ -2528,13 +2544,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) &&
@ -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
// relative to is output.
GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
TempFBOTarget tempFBOTarget) {
GrGLGpu::FBOBinding GrGLGpu::bindSurfaceAsFBOForCopy(GrSurface* surface, FBOBinding binding,
GrGLIRect* viewport) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
if (NULL == rt) {
SkASSERT(surface->asTexture());
GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
GrGLuint* tempFBOID;
tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID;
GrGLFBO* tempFBO;
if (0 == *tempFBOID) {
GR_GL_CALL(this->glInterface(), GenFramebuffers(1, tempFBOID));
if (kBlitSrc_FBOBinding == binding) {
if (!fTempSrcFBO) {
fTempSrcFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface())));
SkASSERT(fTempSrcFBO->isValid());
}
tempFBO = fTempSrcFBO;
} else {
SkASSERT(kBlitDst_FBOBinding == binding);
if (!fTempDstFBO) {
fTempDstFBO.reset(SkNEW_ARGS(GrGLFBO, (this->glInterface())));
SkASSERT(fTempDstFBO->isValid());
}
tempFBO = fTempDstFBO;
}
fStats.incRenderTargetBinds();
GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, *tempFBOID));
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
GrGLenum target = this->bindFBO(binding, tempFBO);
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(target,
GR_GL_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D,
texID,
@ -2575,18 +2600,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,
@ -2617,7 +2645,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)) {
@ -2641,14 +2669,13 @@ bool GrGLGpu::copySurface(GrSurface* dst,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
bool copied = false;
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
srcRect.width(), srcRect.height());
if (can_copy_texsubimage(dst, src, this)) {
GrGLuint srcFBO;
GrGLIRect srcVP;
srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
FBOBinding srcFBOBinding = this->bindSurfaceAsFBOForCopy(src, kBlitSrc_FBOBinding, &srcVP);
GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
SkASSERT(dstTex);
// We modified the bound FBO
fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
GrGLIRect srcGLRect;
srcGLRect.setRelativeTo(srcVP,
srcRect.fLeft,
@ -2670,28 +2697,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,
@ -2729,15 +2749,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;
}

View File

@ -244,11 +244,28 @@ 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,
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 +296,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 +323,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 +471,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

View File

@ -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;
}

View File

@ -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();
}

View File

@ -15,15 +15,59 @@
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 {
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 {
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;
};

View File

@ -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);