diff options
author | egdaniel <egdaniel@google.com> | 2015-09-14 12:56:10 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-09-14 12:56:10 -0700 |
commit | ec00d94199fad7723b5987b86c1abef8ddafe2d8 (patch) | |
tree | 4161bb293ffe433cbe0fd41a4ad0263b36eedffd | |
parent | 37497dc9de9cf8df4f9dd972b50cbd35b9da6682 (diff) |
Move some of the adding stencil attachment logic of Gpu and into Render Target.
The new flow of calls for attaching a Stencil looks like:
Client
rt->attachStencilAttachment()
gpu->getStencilAttachment()
glgpu->createStencilAttachment()
glrt->completeStencilAttachment() //actually attaches
BUG=skia:
Review URL: https://codereview.chromium.org/1333383002
-rw-r--r-- | include/gpu/GrRenderTarget.h | 14 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrDrawContext.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.cpp | 4 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 45 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 21 | ||||
-rw-r--r-- | src/gpu/GrRenderTarget.cpp | 23 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetPriv.h | 9 | ||||
-rw-r--r-- | src/gpu/GrResourceProvider.cpp | 52 | ||||
-rw-r--r-- | src/gpu/GrResourceProvider.h | 8 | ||||
-rw-r--r-- | src/gpu/GrTest.cpp | 10 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 139 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLRenderTarget.cpp | 82 | ||||
-rw-r--r-- | src/gpu/gl/GrGLRenderTarget.h | 13 | ||||
-rw-r--r-- | tests/ResourceCacheTest.cpp | 39 |
16 files changed, 241 insertions, 242 deletions
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h index 8983d53a25..2309dbd876 100644 --- a/include/gpu/GrRenderTarget.h +++ b/include/gpu/GrRenderTarget.h @@ -144,15 +144,18 @@ public: */ virtual GrBackendObject getRenderTargetHandle() const = 0; + // Checked when this object is asked to attach a stencil buffer. + virtual bool canAttemptStencilAttachment() const = 0; + // Provides access to functions that aren't part of the public API. GrRenderTargetPriv renderTargetPriv(); const GrRenderTargetPriv renderTargetPriv() const; protected: GrRenderTarget(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc, - SampleConfig sampleConfig) + SampleConfig sampleConfig, GrStencilAttachment* stencil = nullptr) : INHERITED(gpu, lifeCycle, desc) - , fStencilAttachment(NULL) + , fStencilAttachment(stencil) , fSampleConfig(sampleConfig) { fResolveRect.setLargestInverted(); } @@ -162,8 +165,11 @@ protected: void onRelease() override; private: - // Checked when this object is asked to attach a stencil buffer. - virtual bool canAttemptStencilAttachment() const = 0; + // Allows the backends to perform any additional work that is required for attaching a + // GrStencilAttachment. When this is called, the GrStencilAttachment has already been put onto + // the GrRenderTarget. This function must return false if any failures occur when completing the + // stencil attachment. + virtual bool completeStencilAttachment() = 0; friend class GrRenderTargetPriv; diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 0f32839a7e..0ab1600b7d 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -717,7 +717,8 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, SkASSERT(kNone_ClipMaskType == fCurrClipMaskType); SkASSERT(rt); - GrStencilAttachment* stencilAttachment = rt->renderTargetPriv().attachStencilAttachment(); + GrStencilAttachment* stencilAttachment = + fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); if (nullptr == stencilAttachment) { return false; } @@ -977,7 +978,8 @@ void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipel int stencilBits = 0; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); - GrStencilAttachment* stencilAttachment = rt->renderTargetPriv().attachStencilAttachment(); + GrStencilAttachment* stencilAttachment = + fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); if (stencilAttachment) { stencilBits = stencilAttachment->bits(); } diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index 3d3be749d0..94fcee0313 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -63,7 +63,8 @@ GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget, if (fContext->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isStencilBufferMultisampled() && fSurfaceProps.isUseDeviceIndependentFonts()) { - GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment(); + GrStencilAttachment* sb = + fContext->resourceProvider()->attachStencilAttachment(renderTarget); if (sb) { return GrStencilAndCoverTextContext::Create(fContext, surfaceProps); } diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 076b626a1a..3d5f4288f4 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -215,7 +215,7 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder, // set stencil settings for path GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); - GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment(); + GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt); this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); GrBatch* batch = GrStencilPathBatch::Create(viewMatrix, @@ -270,7 +270,7 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder, // Ensure the render target has a stencil buffer and get the stencil settings. GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); - GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment(); + GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt); this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); batch->setStencilSettings(stencilSettings); diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index e1b8ed5c85..96728f3ba8 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -16,6 +16,7 @@ #include "GrPathRendering.h" #include "GrPipeline.h" #include "GrResourceCache.h" +#include "GrResourceProvider.h" #include "GrRenderTargetPriv.h" #include "GrStencilAttachment.h" #include "GrSurfacePriv.h" @@ -134,48 +135,6 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, bool budgeted, return tex; } -bool GrGpu::attachStencilAttachmentToRenderTarget(GrRenderTarget* rt) { - SkASSERT(nullptr == rt->renderTargetPriv().getStencilAttachment()); - GrUniqueKey sbKey; - - int width = rt->width(); - int height = rt->height(); -#if 0 - if (this->caps()->oversizedStencilSupport()) { - width = SkNextPow2(width); - height = SkNextPow2(height); - } -#endif - - GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, - rt->numStencilSamples(), &sbKey); - SkAutoTUnref<GrStencilAttachment> sb(static_cast<GrStencilAttachment*>( - this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey))); - if (sb) { - if (this->attachStencilAttachmentToRenderTarget(sb, rt)) { - rt->renderTargetPriv().didAttachStencilAttachment(sb); - return true; - } - return false; - } - if (this->createStencilAttachmentForRenderTarget(rt, width, height)) { - // Right now we're clearing the stencil buffer here after it is - // attached to an RT for the first time. When we start matching - // stencil buffers with smaller color targets this will no longer - // be correct because it won't be guaranteed to clear the entire - // sb. - // We used to clear down in the GL subclass using a special purpose - // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported - // FBO status. - this->clearStencil(rt); - GrStencilAttachment* sb = rt->renderTargetPriv().getStencilAttachment(); - sb->resourcePriv().setUniqueKey(sbKey); - return true; - } else { - return false; - } -} - GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwnership ownership) { this->handleDirtyContext(); GrTexture* tex = this->onWrapBackendTexture(desc, ownership); @@ -184,7 +143,7 @@ GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwn } // TODO: defer this and attach dynamically GrRenderTarget* tgt = tex->asRenderTarget(); - if (tgt && !this->attachStencilAttachmentToRenderTarget(tgt)) { + if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) { tex->unref(); return nullptr; } else { diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 73a5264bbc..d8e5681de1 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -369,8 +369,14 @@ public: virtual bool isTestingOnlyBackendTexture(GrBackendObject id) const = 0; virtual void deleteTestingOnlyBackendTexture(GrBackendObject id) const = 0; - // Given a rt, find or create a stencil buffer and attach it - bool attachStencilAttachmentToRenderTarget(GrRenderTarget* target); + // width and height may be larger than rt (if underlying API allows it). + // Returns nullptr if compatible sb could not be created, otherwise the caller owns the ref on + // the GrStencilAttachment. + virtual GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, + int width, + int height) = 0; + // clears target's entire stencil buffer to 0 + virtual void clearStencil(GrRenderTarget* target) = 0; // This is only to be used in GL-specific tests. virtual const GrGLContext* glContextForTesting() const { return nullptr; } @@ -466,17 +472,6 @@ private: const SkIRect& srcRect, const SkIPoint& dstPoint) = 0; - // width and height may be larger than rt (if underlying API allows it). - // Should attach the SB to the RT. Returns false if compatible sb could - // not be created. - virtual bool createStencilAttachmentForRenderTarget(GrRenderTarget*, int width, int height) = 0; - - // attaches an existing SB to an existing RT. - virtual bool attachStencilAttachmentToRenderTarget(GrStencilAttachment*, GrRenderTarget*) = 0; - - // clears target's entire stencil buffer to 0 - virtual void clearStencil(GrRenderTarget* target) = 0; - void resetContext() { this->onResetContext(fResetBits); fResetBits = 0; diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp index 5cb34e849a..c16738e795 100644 --- a/src/gpu/GrRenderTarget.cpp +++ b/src/gpu/GrRenderTarget.cpp @@ -55,29 +55,24 @@ void GrRenderTarget::overrideResolveRect(const SkIRect rect) { } void GrRenderTarget::onRelease() { - this->renderTargetPriv().didAttachStencilAttachment(nullptr); + SkSafeSetNull(fStencilAttachment); INHERITED::onRelease(); } void GrRenderTarget::onAbandon() { - this->renderTargetPriv().didAttachStencilAttachment(nullptr); + SkSafeSetNull(fStencilAttachment); INHERITED::onAbandon(); } /////////////////////////////////////////////////////////////////////////////// -void GrRenderTargetPriv::didAttachStencilAttachment(GrStencilAttachment* stencilAttachment) { - SkRefCnt_SafeAssign(fRenderTarget->fStencilAttachment, stencilAttachment); -} - -GrStencilAttachment* GrRenderTargetPriv::attachStencilAttachment() const { - if (fRenderTarget->fStencilAttachment) { - return fRenderTarget->fStencilAttachment; - } - if (!fRenderTarget->wasDestroyed() && fRenderTarget->canAttemptStencilAttachment()) { - fRenderTarget->getGpu()->attachStencilAttachmentToRenderTarget(fRenderTarget); - } - return fRenderTarget->fStencilAttachment; +bool GrRenderTargetPriv::attachStencilAttachment(GrStencilAttachment* stencil) { + fRenderTarget->fStencilAttachment = stencil; + if (!fRenderTarget->completeStencilAttachment()) { + SkSafeSetNull(fRenderTarget->fStencilAttachment); + return false; + } + return true; } diff --git a/src/gpu/GrRenderTargetPriv.h b/src/gpu/GrRenderTargetPriv.h index 59262f4b11..f4931db1db 100644 --- a/src/gpu/GrRenderTargetPriv.h +++ b/src/gpu/GrRenderTargetPriv.h @@ -21,12 +21,11 @@ public: GrStencilAttachment* getStencilAttachment() const { return fRenderTarget->fStencilAttachment; } /** - * If this render target already has a stencil buffer, return it. Otherwise attempt to attach - * one. + * Attaches the GrStencilAttachment onto the render target. If stencil is a nullptr then the + * currently attached GrStencilAttachment will be removed if one was previously attached. This + * function returns false if there were any failure in attaching the GrStencilAttachment. */ - GrStencilAttachment* attachStencilAttachment() const; - - void didAttachStencilAttachment(GrStencilAttachment*); + bool attachStencilAttachment(GrStencilAttachment* stencil); private: explicit GrRenderTargetPriv(GrRenderTarget* renderTarget) : fRenderTarget(renderTarget) {} diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp index d3ab8ccfa1..bd9cc9ac6b 100644 --- a/src/gpu/GrResourceProvider.cpp +++ b/src/gpu/GrResourceProvider.cpp @@ -10,8 +10,11 @@ #include "GrGpu.h" #include "GrIndexBuffer.h" #include "GrPathRendering.h" +#include "GrRenderTarget.h" +#include "GrRenderTargetPriv.h" #include "GrResourceCache.h" #include "GrResourceKey.h" +#include "GrStencilAttachment.h" #include "GrVertexBuffer.h" GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); @@ -163,3 +166,52 @@ GrBatchAtlas* GrResourceProvider::createAtlas(GrPixelConfig config, } return new GrBatchAtlas(texture, numPlotsX, numPlotsY); } + +GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) { + SkASSERT(rt); + if (rt->renderTargetPriv().getStencilAttachment()) { + return rt->renderTargetPriv().getStencilAttachment(); + } + + if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) { + GrUniqueKey sbKey; + + int width = rt->width(); + int height = rt->height(); +#if 0 + if (this->caps()->oversizedStencilSupport()) { + width = SkNextPow2(width); + height = SkNextPow2(height); + } +#endif + bool newStencil = false; + GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, + rt->numStencilSamples(), &sbKey); + GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>( + this->findAndRefResourceByUniqueKey(sbKey)); + if (!stencil) { + // Need to try and create a new stencil + stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height); + if (stencil) { + stencil->resourcePriv().setUniqueKey(sbKey); + newStencil = true; + } + } + if (rt->renderTargetPriv().attachStencilAttachment(stencil)) { + if (newStencil) { + // Right now we're clearing the stencil attachment here after it is + // attached to an RT for the first time. When we start matching + // stencil buffers with smaller color targets this will no longer + // be correct because it won't be guaranteed to clear the entire + // sb. + // We used to clear down in the GL subclass using a special purpose + // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported + // FBO status. + this->gpu()->clearStencil(rt); + } + } + } + return rt->renderTargetPriv().getStencilAttachment(); +} + + diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h index 72efab1cef..33a9f3bd12 100644 --- a/src/gpu/GrResourceProvider.h +++ b/src/gpu/GrResourceProvider.h @@ -16,6 +16,8 @@ class GrBatchAtlas; class GrIndexBuffer; class GrPath; +class GrRenderTarget; +class GrStencilAttachment; class GrStrokeInfo; class GrVertexBuffer; class SkDescriptor; @@ -134,6 +136,12 @@ public: GrBatchAtlas* createAtlas(GrPixelConfig, int width, int height, int numPlotsX, int numPlotsY, GrBatchAtlas::EvictionFunc func, void* data); + /** + * If passed in render target already has a stencil buffer, return it. Otherwise attempt to + * attach one. + */ + GrStencilAttachment* attachStencilAttachment(GrRenderTarget* rt); + private: const GrIndexBuffer* createInstancedIndexBuffer(const uint16_t* pattern, int patternSize, diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp index 4e697ff655..8d6208de79 100644 --- a/src/gpu/GrTest.cpp +++ b/src/gpu/GrTest.cpp @@ -255,12 +255,10 @@ private: void onResolveRenderTarget(GrRenderTarget* target) override { return; } - bool createStencilAttachmentForRenderTarget(GrRenderTarget*, int width, int height) override { - return false; - } - - bool attachStencilAttachmentToRenderTarget(GrStencilAttachment*, GrRenderTarget*) override { - return false; + GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, + int width, + int height) override { + return nullptr; } void clearStencil(GrRenderTarget* target) override {} diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index e10b951d32..c07f704d21 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -495,20 +495,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount()); desc.fOrigin = resolve_origin(wrapDesc.fOrigin, true); - GrRenderTarget* tgt = new GrGLRenderTarget(this, desc, idDesc); - if (wrapDesc.fStencilBits) { - GrGLStencilAttachment::IDDesc sbDesc; - GrGLStencilAttachment::Format format; - format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat; - format.fPacked = false; - format.fStencilBits = wrapDesc.fStencilBits; - format.fTotalBits = wrapDesc.fStencilBits; - GrGLStencilAttachment* sb = new GrGLStencilAttachment( - this, sbDesc, desc.fWidth, desc.fHeight, desc.fSampleCnt, format); - tgt->renderTargetPriv().didAttachStencilAttachment(sb); - sb->unref(); - } - return tgt; + return GrGLRenderTarget::CreateWrapped(this, desc, idDesc, wrapDesc.fStencilBits); } //////////////////////////////////////////////////////////////////////////////// @@ -1241,7 +1228,7 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { // Create Framebuffer GrGLuint fb; GL_CALL(GenFramebuffers(1, &fb)); - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, @@ -1304,7 +1291,9 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { return fPixelConfigToStencilIndex[config]; } -bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int width, int height) { +GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt, + int width, + int height) { // All internally created RTs are also textures. We don't create // SBs for a client's standalone RT (that is a RT that isn't also a texture). SkASSERT(rt->asTexture()); @@ -1316,14 +1305,14 @@ bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int wid int sIdx = this->getCompatibleStencilIndex(rt->config()); if (sIdx == kUnsupportedStencilIndex) { - return false; + return nullptr; } if (!sbDesc.fRenderbufferID) { GL_CALL(GenRenderbuffers(1, &sbDesc.fRenderbufferID)); } if (!sbDesc.fRenderbufferID) { - return false; + return nullptr; } GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[sIdx]; @@ -1346,113 +1335,13 @@ bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int wid // whatever sizes GL gives us. In that case we query for the size. GrGLStencilAttachment::Format format = sFmt; get_stencil_rb_sizes(this->glInterface(), &format); - SkAutoTUnref<GrGLStencilAttachment> sb( - new GrGLStencilAttachment(this, sbDesc, width, height, samples, format)); - SkAssertResult(this->attachStencilAttachmentToRenderTarget(sb, rt)); - rt->renderTargetPriv().didAttachStencilAttachment(sb); - // This work around is currently breaking on windows 7 hd2000 bot when we bind a color buffer -#if 0 - // 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)); - } - - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID)); - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; - fStats.incRenderTargetBinds(); - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_STENCIL_ATTACHMENT, - GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); - if (sFmt.fPacked) { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID)); - } - - GL_CALL(ClearStencil(0)); - // Many GL implementations seem to have trouble with clearing an FBO with only - // a stencil buffer. - GrGLuint tempRB; - GL_CALL(GenRenderbuffers(1, &tempRB)); - GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB)); - if (samples > 0) { - renderbuffer_storage_msaa(fGLContext, samples, GR_GL_RGBA8, width, height); - } else { - GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height)); - } - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_COLOR_ATTACHMENT0, - GR_GL_RENDERBUFFER, tempRB)); - - GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT)); - - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - 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, - GR_GL_STENCIL_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); - if (sFmt.fPacked) { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); - } -#endif - return true; -} - -bool GrGLGpu::attachStencilAttachmentToRenderTarget(GrStencilAttachment* sb, GrRenderTarget* rt) { - GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt); - - GrGLuint fbo = glrt->renderFBOID(); - - if (nullptr == sb) { - if (rt->renderTargetPriv().getStencilAttachment()) { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_STENCIL_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); -#ifdef SK_DEBUG - GrGLenum status; - GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); - SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); -#endif - } - return true; - } else { - GrGLStencilAttachment* glsb = static_cast<GrGLStencilAttachment*>(sb); - GrGLuint rb = glsb->renderbufferID(); - - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; - fStats.incRenderTargetBinds(); - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo)); - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_STENCIL_ATTACHMENT, - GR_GL_RENDERBUFFER, rb)); - if (glsb->format().fPacked) { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, rb)); - } else { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); - } - -#ifdef SK_DEBUG - GrGLenum status; - GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); - SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); -#endif - return true; - } + GrGLStencilAttachment* stencil = new GrGLStencilAttachment(this, + sbDesc, + width, + height, + samples, + format); + return stencil; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index fecede06c7..833f1ff7ec 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -99,6 +99,16 @@ public: return &this->glContext(); } + void clearStencil(GrRenderTarget*) override; + + void invalidateBoundRenderTarget() { + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + } + + GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget* rt, + int width, + int height) override; + GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h, GrPixelConfig config) const override; bool isTestingOnlyBackendTexture(GrBackendObject id) const override; @@ -122,9 +132,6 @@ private: GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override; GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&, GrWrapOwnership) override; - bool createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int width, int height) override; - bool attachStencilAttachmentToRenderTarget(GrStencilAttachment* sb, - GrRenderTarget* rt) override; // Given a GrPixelConfig return the index into the stencil format array on GrGLCaps to a // compatible stencil format. int getCompatibleStencilIndex(GrPixelConfig config); @@ -154,8 +161,6 @@ private: const SkIRect& srcRect, const SkIPoint& dstPoint) override; - void clearStencil(GrRenderTarget*) override; - // binds texture unit in GL void setTextureUnit(int unitIdx); diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp index cb9d310010..dfb4e88ee3 100644 --- a/src/gpu/gl/GrGLRenderTarget.cpp +++ b/src/gpu/gl/GrGLRenderTarget.cpp @@ -7,15 +7,20 @@ #include "GrGLRenderTarget.h" +#include "GrRenderTargetPriv.h" #include "GrGLGpu.h" +#include "GrGLUtil.h" #define GPUGL static_cast<GrGLGpu*>(this->getGpu()) #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) // Because this class is virtually derived from GrSurface we must explicitly call its constructor. -GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc) +GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, + const GrSurfaceDesc& desc, + const IDDesc& idDesc, + GrGLStencilAttachment* stencil) : GrSurface(gpu, idDesc.fLifeCycle, desc) - , INHERITED(gpu, idDesc.fLifeCycle, desc, idDesc.fSampleConfig) { + , INHERITED(gpu, idDesc.fLifeCycle, desc, idDesc.fSampleConfig, stencil) { this->init(desc, idDesc); this->registerWithCache(); } @@ -56,10 +61,77 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { SkASSERT(fGpuMemorySize <= WorseCaseSize(desc)); } +GrGLRenderTarget* GrGLRenderTarget::CreateWrapped(GrGLGpu* gpu, + const GrSurfaceDesc& desc, + const IDDesc& idDesc, + int stencilBits) { + GrGLStencilAttachment* sb = nullptr; + if (stencilBits) { + GrGLStencilAttachment::IDDesc sbDesc; + GrGLStencilAttachment::Format format; + format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat; + format.fPacked = false; + format.fStencilBits = stencilBits; + format.fTotalBits = stencilBits; + // Owndership of sb is passed to the GrRenderTarget so doesn't need to be deleted + sb = new GrGLStencilAttachment(gpu, sbDesc, desc.fWidth, desc.fHeight, + desc.fSampleCnt, format); + } + return (new GrGLRenderTarget(gpu, desc, idDesc, sb)); +} + size_t GrGLRenderTarget::onGpuMemorySize() const { return fGpuMemorySize; } +bool GrGLRenderTarget::completeStencilAttachment() { + GrGLGpu* gpu = this->getGLGpu(); + const GrGLInterface* interface = gpu->glInterface(); + GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); + if (nullptr == stencil) { + if (this->renderTargetPriv().getStencilAttachment()) { + GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_STENCIL_ATTACHMENT, + GR_GL_RENDERBUFFER, 0)); + GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_DEPTH_ATTACHMENT, + GR_GL_RENDERBUFFER, 0)); +#ifdef SK_DEBUG + GrGLenum status; + GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); + SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); +#endif + } + return true; + } else { + const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil); + GrGLuint rb = glStencil->renderbufferID(); + + gpu->invalidateBoundRenderTarget(); + gpu->stats()->incRenderTargetBinds(); + GR_GL_CALL(interface, BindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID())); + GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_STENCIL_ATTACHMENT, + GR_GL_RENDERBUFFER, rb)); + if (glStencil->format().fPacked) { + GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_DEPTH_ATTACHMENT, + GR_GL_RENDERBUFFER, rb)); + } else { + GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_DEPTH_ATTACHMENT, + GR_GL_RENDERBUFFER, 0)); + } + +#ifdef SK_DEBUG + GrGLenum status; + GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); + SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); +#endif + return true; + } +} + void GrGLRenderTarget::onRelease() { if (kBorrowed_LifeCycle != fRTLifecycle) { if (fTexFBOID) { @@ -84,3 +156,9 @@ void GrGLRenderTarget::onAbandon() { fMSColorRenderbufferID = 0; INHERITED::onAbandon(); } + +GrGLGpu* GrGLRenderTarget::getGLGpu() const { + SkASSERT(!this->wasDestroyed()); + return static_cast<GrGLGpu*>(this->getGpu()); +} + diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h index 1e6dc7f767..0539a08d81 100644 --- a/src/gpu/gl/GrGLRenderTarget.h +++ b/src/gpu/gl/GrGLRenderTarget.h @@ -14,6 +14,7 @@ #include "SkScalar.h" class GrGLGpu; +class GrGLStencilAttachment; class GrGLRenderTarget : public GrRenderTarget { public: @@ -29,7 +30,10 @@ public: GrRenderTarget::SampleConfig fSampleConfig; }; - GrGLRenderTarget(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&); + static GrGLRenderTarget* CreateWrapped(GrGLGpu*, + const GrSurfaceDesc&, + const IDDesc&, + int stencilBits); void setViewport(const GrGLIRect& rect) { fViewport = rect; } const GrGLIRect& getViewport() const { return fViewport; } @@ -78,6 +82,13 @@ protected: size_t onGpuMemorySize() const override; private: + // This ctor is used only for creating wrapped render targets and is only called for the static + // create function CreateWrapped(...). + GrGLRenderTarget(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&, GrGLStencilAttachment*); + + GrGLGpu* getGLGpu() const; + bool completeStencilAttachment() override; + GrGLuint fRTFBOID; GrGLuint fTexFBOID; GrGLuint fMSColorRenderbufferID; diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp index d76da31920..6370b92490 100644 --- a/tests/ResourceCacheTest.cpp +++ b/tests/ResourceCacheTest.cpp @@ -78,33 +78,34 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex smallDesc.fSampleCnt = 0; GrTextureProvider* cache = context->textureProvider(); + GrResourceProvider* resourceProvider = context->resourceProvider(); // Test that two budgeted RTs with the same desc share a stencil buffer. SkAutoTUnref<GrTexture> smallRT0(cache->createTexture(smallDesc, true)); if (smallRT0 && smallRT0->asRenderTarget()) { - smallRT0->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()); } SkAutoTUnref<GrTexture> smallRT1(cache->createTexture(smallDesc, true)); if (smallRT1 && smallRT1->asRenderTarget()) { - smallRT1->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(smallRT1->asRenderTarget()); } REPORTER_ASSERT(reporter, smallRT0 && smallRT1 && smallRT0->asRenderTarget() && smallRT1->asRenderTarget() && - smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() == - smallRT1->asRenderTarget()->renderTargetPriv().getStencilAttachment()); + resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) == + resourceProvider->attachStencilAttachment(smallRT1->asRenderTarget())); // An unbudgeted RT with the same desc should also share. SkAutoTUnref<GrTexture> smallRT2(cache->createTexture(smallDesc, false)); if (smallRT2 && smallRT2->asRenderTarget()) { - smallRT2->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(smallRT2->asRenderTarget()); } REPORTER_ASSERT(reporter, smallRT0 && smallRT2 && smallRT0->asRenderTarget() && smallRT2->asRenderTarget() && - smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() == - smallRT2->asRenderTarget()->renderTargetPriv().getStencilAttachment()); + resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) == + resourceProvider->attachStencilAttachment(smallRT2->asRenderTarget())); // An RT with a much larger size should not share. GrSurfaceDesc bigDesc; @@ -115,13 +116,13 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex bigDesc.fSampleCnt = 0; SkAutoTUnref<GrTexture> bigRT(cache->createTexture(bigDesc, false)); if (bigRT && bigRT->asRenderTarget()) { - bigRT->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(bigRT->asRenderTarget()); } REPORTER_ASSERT(reporter, smallRT0 && bigRT && smallRT0->asRenderTarget() && bigRT->asRenderTarget() && - smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() != - bigRT->asRenderTarget()->renderTargetPriv().getStencilAttachment()); + resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) != + resourceProvider->attachStencilAttachment(bigRT->asRenderTarget())); if (context->caps()->maxSampleCount() >= 4) { // An RT with a different sample count should not share. @@ -129,7 +130,7 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex smallMSAADesc.fSampleCnt = 4; SkAutoTUnref<GrTexture> smallMSAART0(cache->createTexture(smallMSAADesc, false)); if (smallMSAART0 && smallMSAART0->asRenderTarget()) { - smallMSAART0->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()); } #ifdef SK_BUILD_FOR_ANDROID if (!smallMSAART0) { @@ -140,19 +141,19 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex REPORTER_ASSERT(reporter, smallRT0 && smallMSAART0 && smallRT0->asRenderTarget() && smallMSAART0->asRenderTarget() && - smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() != - smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment()); + resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) != + resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget())); // A second MSAA RT should share with the first MSAA RT. SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, false)); if (smallMSAART1 && smallMSAART1->asRenderTarget()) { - smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget()); } REPORTER_ASSERT(reporter, smallMSAART0 && smallMSAART1 && smallMSAART0->asRenderTarget() && smallMSAART1->asRenderTarget() && - smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment() == - smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilAttachment()); + resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()) == + resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget())); // But not one with a larger sample count should not. (Also check that the request for 4 // samples didn't get rounded up to >= 8 or else they could share.). if (context->caps()->maxSampleCount() >= 8 && @@ -162,14 +163,14 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex smallMSAART1.reset(cache->createTexture(smallMSAADesc, false)); SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, false)); if (smallMSAART1 && smallMSAART1->asRenderTarget()) { - smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); + resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget()); } REPORTER_ASSERT(reporter, smallMSAART0 && smallMSAART1 && smallMSAART0->asRenderTarget() && smallMSAART1->asRenderTarget() && - smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment() != - smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilAttachment()); + resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()) != + resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget())); } } } |