| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "GrDrawContext.h" |
| #include "GrDrawingManager.h" |
| #include "GrDrawTarget.h" |
| #include "GrPathRenderingDrawContext.h" |
| #include "GrResourceProvider.h" |
| #include "GrSoftwarePathRenderer.h" |
| #include "SkTTopoSort.h" |
| |
| #include "text/GrAtlasTextContext.h" |
| #include "text/GrStencilAndCoverTextContext.h" |
| |
| void GrDrawingManager::cleanup() { |
| for (int i = 0; i < fDrawTargets.count(); ++i) { |
| fDrawTargets[i]->makeClosed(); // no drawTarget should receive a new command after this |
| fDrawTargets[i]->clearRT(); |
| |
| // We shouldn't need to do this, but it turns out some clients still hold onto drawtargets |
| // after a cleanup |
| fDrawTargets[i]->reset(); |
| fDrawTargets[i]->unref(); |
| } |
| |
| fDrawTargets.reset(); |
| |
| delete fPathRendererChain; |
| fPathRendererChain = nullptr; |
| SkSafeSetNull(fSoftwarePathRenderer); |
| } |
| |
| GrDrawingManager::~GrDrawingManager() { |
| this->cleanup(); |
| } |
| |
| void GrDrawingManager::abandon() { |
| fAbandoned = true; |
| this->cleanup(); |
| } |
| |
| void GrDrawingManager::freeGpuResources() { |
| // a path renderer may be holding onto resources |
| delete fPathRendererChain; |
| fPathRendererChain = nullptr; |
| SkSafeSetNull(fSoftwarePathRenderer); |
| } |
| |
| void GrDrawingManager::reset() { |
| for (int i = 0; i < fDrawTargets.count(); ++i) { |
| fDrawTargets[i]->reset(); |
| } |
| fFlushState.reset(); |
| } |
| |
| void GrDrawingManager::flush() { |
| if (fFlushing || this->abandoned()) { |
| return; |
| } |
| fFlushing = true; |
| |
| SkDEBUGCODE(bool result =) |
| SkTTopoSort<GrDrawTarget, GrDrawTarget::TopoSortTraits>(&fDrawTargets); |
| SkASSERT(result); |
| |
| #if 0 |
| for (int i = 0; i < fDrawTargets.count(); ++i) { |
| SkDEBUGCODE(fDrawTargets[i]->dump();) |
| } |
| #endif |
| |
| for (int i = 0; i < fDrawTargets.count(); ++i) { |
| fDrawTargets[i]->prepareBatches(&fFlushState); |
| } |
| |
| // Upload all data to the GPU |
| fFlushState.preIssueDraws(); |
| |
| for (int i = 0; i < fDrawTargets.count(); ++i) { |
| fDrawTargets[i]->drawBatches(&fFlushState); |
| } |
| |
| SkASSERT(fFlushState.lastFlushedToken() == fFlushState.currentToken()); |
| |
| for (int i = 0; i < fDrawTargets.count(); ++i) { |
| fDrawTargets[i]->reset(); |
| #ifdef ENABLE_MDB |
| fDrawTargets[i]->unref(); |
| #endif |
| } |
| |
| #ifndef ENABLE_MDB |
| // When MDB is disabled we keep reusing the same drawTarget |
| if (fDrawTargets.count()) { |
| SkASSERT(fDrawTargets.count() == 1); |
| // Clear out this flag so the topological sort's SkTTopoSort_CheckAllUnmarked check |
| // won't bark |
| fDrawTargets[0]->resetFlag(GrDrawTarget::kWasOutput_Flag); |
| } |
| #else |
| fDrawTargets.reset(); |
| #endif |
| |
| fFlushState.reset(); |
| fFlushing = false; |
| } |
| |
| GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) { |
| SkASSERT(fContext); |
| |
| #ifndef ENABLE_MDB |
| // When MDB is disabled we always just return the single drawTarget |
| if (fDrawTargets.count()) { |
| SkASSERT(fDrawTargets.count() == 1); |
| // In the non-MDB-world the same drawTarget gets reused for multiple render targets. |
| // Update this pointer so all the asserts are happy |
| rt->setLastDrawTarget(fDrawTargets[0]); |
| // DrawingManager gets the creation ref - this ref is for the caller |
| return SkRef(fDrawTargets[0]); |
| } |
| #endif |
| |
| GrDrawTarget* dt = new GrDrawTarget(rt, fContext->getGpu(), fContext->resourceProvider(), |
| fContext->getAuditTrail(), fOptionsForDrawTargets); |
| |
| *fDrawTargets.append() = dt; |
| |
| // DrawingManager gets the creation ref - this ref is for the caller |
| return SkRef(dt); |
| } |
| |
| /* |
| * This method finds a path renderer that can draw the specified path on |
| * the provided target. |
| * Due to its expense, the software path renderer has split out so it can |
| * can be individually allowed/disallowed via the "allowSW" boolean. |
| */ |
| GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args, |
| bool allowSW, |
| GrPathRendererChain::DrawType drawType, |
| GrPathRenderer::StencilSupport* stencilSupport) { |
| |
| if (!fPathRendererChain) { |
| fPathRendererChain = new GrPathRendererChain(fContext); |
| } |
| |
| GrPathRenderer* pr = fPathRendererChain->getPathRenderer(args, drawType, stencilSupport); |
| if (!pr && allowSW) { |
| if (!fSoftwarePathRenderer) { |
| fSoftwarePathRenderer = new GrSoftwarePathRenderer(fContext); |
| } |
| pr = fSoftwarePathRenderer; |
| } |
| |
| return pr; |
| } |
| |
| GrDrawContext* GrDrawingManager::drawContext(GrRenderTarget* rt, |
| const SkSurfaceProps* surfaceProps) { |
| if (this->abandoned()) { |
| return nullptr; |
| } |
| |
| |
| bool useDIF = false; |
| if (surfaceProps) { |
| useDIF = surfaceProps->isUseDeviceIndependentFonts(); |
| } |
| |
| if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() && |
| rt->isStencilBufferMultisampled()) { |
| GrStencilAttachment* sb = fContext->resourceProvider()->attachStencilAttachment(rt); |
| if (sb) { |
| return new GrPathRenderingDrawContext(fContext, this, rt, surfaceProps, |
| fContext->getAuditTrail(), fSingleOwner); |
| } |
| } |
| |
| return new GrDrawContext(fContext, this, rt, surfaceProps, fContext->getAuditTrail(), |
| fSingleOwner); |
| } |