Improve tracking of bound FBOs in GrGLGpu.
Committed: https://skia.googlesource.com/skia/+/d2ad8eb5801e2c8c0fa544a6a776bb46eedde2a0 Committed: https://skia.googlesource.com/skia/+/b2af2d8b83ca4774c3b3bb1e49bc72605faa9589 Committed: https://skia.googlesource.com/skia/+/0b70b86a7e9fda52ee7ebc1b9897eeaa09b9abef Committed: https://skia.googlesource.com/skia/+/6ba6fa15261be591f33cf0e5df7134e4fc6432ac Review URL: https://codereview.chromium.org/949263002
This commit is contained in:
parent
9d2049db6e
commit
dc963b9264
@ -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
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user