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