1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrDrawContext.h"
9 #include "GrDrawingManager.h"
10 #include "GrDrawTarget.h"
11 #include "GrPathRenderingDrawContext.h"
12 #include "GrResourceProvider.h"
13 #include "GrSoftwarePathRenderer.h"
14 #include "SkTTopoSort.h"
15
16 #include "text/GrAtlasTextContext.h"
17 #include "text/GrStencilAndCoverTextContext.h"
18
cleanup()19 void GrDrawingManager::cleanup() {
20 for (int i = 0; i < fDrawTargets.count(); ++i) {
21 fDrawTargets[i]->makeClosed(); // no drawTarget should receive a new command after this
22 fDrawTargets[i]->clearRT();
23
24 // We shouldn't need to do this, but it turns out some clients still hold onto drawtargets
25 // after a cleanup
26 fDrawTargets[i]->reset();
27 fDrawTargets[i]->unref();
28 }
29
30 fDrawTargets.reset();
31
32 delete fPathRendererChain;
33 fPathRendererChain = nullptr;
34 SkSafeSetNull(fSoftwarePathRenderer);
35 }
36
~GrDrawingManager()37 GrDrawingManager::~GrDrawingManager() {
38 this->cleanup();
39 }
40
abandon()41 void GrDrawingManager::abandon() {
42 fAbandoned = true;
43 this->cleanup();
44 }
45
freeGpuResources()46 void GrDrawingManager::freeGpuResources() {
47 // a path renderer may be holding onto resources
48 delete fPathRendererChain;
49 fPathRendererChain = nullptr;
50 SkSafeSetNull(fSoftwarePathRenderer);
51 }
52
reset()53 void GrDrawingManager::reset() {
54 for (int i = 0; i < fDrawTargets.count(); ++i) {
55 fDrawTargets[i]->reset();
56 }
57 fFlushState.reset();
58 }
59
flush()60 void GrDrawingManager::flush() {
61 if (fFlushing || this->abandoned()) {
62 return;
63 }
64 fFlushing = true;
65
66 SkDEBUGCODE(bool result =)
67 SkTTopoSort<GrDrawTarget, GrDrawTarget::TopoSortTraits>(&fDrawTargets);
68 SkASSERT(result);
69
70 #if 0
71 for (int i = 0; i < fDrawTargets.count(); ++i) {
72 SkDEBUGCODE(fDrawTargets[i]->dump();)
73 }
74 #endif
75
76 for (int i = 0; i < fDrawTargets.count(); ++i) {
77 fDrawTargets[i]->prepareBatches(&fFlushState);
78 }
79
80 // Upload all data to the GPU
81 fFlushState.preIssueDraws();
82
83 for (int i = 0; i < fDrawTargets.count(); ++i) {
84 fDrawTargets[i]->drawBatches(&fFlushState);
85 }
86
87 SkASSERT(fFlushState.lastFlushedToken() == fFlushState.currentToken());
88
89 for (int i = 0; i < fDrawTargets.count(); ++i) {
90 fDrawTargets[i]->reset();
91 #ifdef ENABLE_MDB
92 fDrawTargets[i]->unref();
93 #endif
94 }
95
96 #ifndef ENABLE_MDB
97 // When MDB is disabled we keep reusing the same drawTarget
98 if (fDrawTargets.count()) {
99 SkASSERT(fDrawTargets.count() == 1);
100 // Clear out this flag so the topological sort's SkTTopoSort_CheckAllUnmarked check
101 // won't bark
102 fDrawTargets[0]->resetFlag(GrDrawTarget::kWasOutput_Flag);
103 }
104 #else
105 fDrawTargets.reset();
106 #endif
107
108 fFlushState.reset();
109 fFlushing = false;
110 }
111
newDrawTarget(GrRenderTarget * rt)112 GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) {
113 SkASSERT(fContext);
114
115 #ifndef ENABLE_MDB
116 // When MDB is disabled we always just return the single drawTarget
117 if (fDrawTargets.count()) {
118 SkASSERT(fDrawTargets.count() == 1);
119 // In the non-MDB-world the same drawTarget gets reused for multiple render targets.
120 // Update this pointer so all the asserts are happy
121 rt->setLastDrawTarget(fDrawTargets[0]);
122 // DrawingManager gets the creation ref - this ref is for the caller
123 return SkRef(fDrawTargets[0]);
124 }
125 #endif
126
127 GrDrawTarget* dt = new GrDrawTarget(rt, fContext->getGpu(), fContext->resourceProvider(),
128 fContext->getAuditTrail(), fOptionsForDrawTargets);
129
130 *fDrawTargets.append() = dt;
131
132 // DrawingManager gets the creation ref - this ref is for the caller
133 return SkRef(dt);
134 }
135
136 /*
137 * This method finds a path renderer that can draw the specified path on
138 * the provided target.
139 * Due to its expense, the software path renderer has split out so it can
140 * can be individually allowed/disallowed via the "allowSW" boolean.
141 */
getPathRenderer(const GrPathRenderer::CanDrawPathArgs & args,bool allowSW,GrPathRendererChain::DrawType drawType,GrPathRenderer::StencilSupport * stencilSupport)142 GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,
143 bool allowSW,
144 GrPathRendererChain::DrawType drawType,
145 GrPathRenderer::StencilSupport* stencilSupport) {
146
147 if (!fPathRendererChain) {
148 fPathRendererChain = new GrPathRendererChain(fContext);
149 }
150
151 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(args, drawType, stencilSupport);
152 if (!pr && allowSW) {
153 if (!fSoftwarePathRenderer) {
154 fSoftwarePathRenderer = new GrSoftwarePathRenderer(fContext);
155 }
156 pr = fSoftwarePathRenderer;
157 }
158
159 return pr;
160 }
161
drawContext(GrRenderTarget * rt,const SkSurfaceProps * surfaceProps)162 GrDrawContext* GrDrawingManager::drawContext(GrRenderTarget* rt,
163 const SkSurfaceProps* surfaceProps) {
164 if (this->abandoned()) {
165 return nullptr;
166 }
167
168
169 bool useDIF = false;
170 if (surfaceProps) {
171 useDIF = surfaceProps->isUseDeviceIndependentFonts();
172 }
173
174 if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() &&
175 rt->isStencilBufferMultisampled()) {
176 GrStencilAttachment* sb = fContext->resourceProvider()->attachStencilAttachment(rt);
177 if (sb) {
178 return new GrPathRenderingDrawContext(fContext, this, rt, surfaceProps,
179 fContext->getAuditTrail(), fSingleOwner);
180 }
181 }
182
183 return new GrDrawContext(fContext, this, rt, surfaceProps, fContext->getAuditTrail(),
184 fSingleOwner);
185 }
186