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