Line data Source code
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 "GrDrawingManager.h"
9 :
10 : #include "GrContext.h"
11 : #include "GrRenderTargetContext.h"
12 : #include "GrPathRenderingRenderTargetContext.h"
13 : #include "GrRenderTargetProxy.h"
14 : #include "GrResourceProvider.h"
15 : #include "GrSoftwarePathRenderer.h"
16 : #include "GrSurfacePriv.h"
17 : #include "GrSurfaceProxyPriv.h"
18 : #include "GrTextureContext.h"
19 : #include "GrTextureOpList.h"
20 : #include "SkSurface_Gpu.h"
21 : #include "SkTTopoSort.h"
22 :
23 : #include "text/GrAtlasTextContext.h"
24 : #include "text/GrStencilAndCoverTextContext.h"
25 :
26 0 : void GrDrawingManager::cleanup() {
27 0 : for (int i = 0; i < fOpLists.count(); ++i) {
28 0 : fOpLists[i]->makeClosed(); // no opList should receive a new command after this
29 0 : fOpLists[i]->clearTarget();
30 :
31 : // We shouldn't need to do this, but it turns out some clients still hold onto opLists
32 : // after a cleanup
33 0 : fOpLists[i]->reset();
34 0 : fOpLists[i]->unref();
35 : }
36 :
37 0 : fOpLists.reset();
38 :
39 0 : delete fPathRendererChain;
40 0 : fPathRendererChain = nullptr;
41 0 : SkSafeSetNull(fSoftwarePathRenderer);
42 0 : }
43 :
44 0 : GrDrawingManager::~GrDrawingManager() {
45 0 : this->cleanup();
46 0 : }
47 :
48 0 : void GrDrawingManager::abandon() {
49 0 : fAbandoned = true;
50 0 : for (int i = 0; i < fOpLists.count(); ++i) {
51 0 : fOpLists[i]->abandonGpuResources();
52 : }
53 0 : this->cleanup();
54 0 : }
55 :
56 0 : void GrDrawingManager::freeGpuResources() {
57 : // a path renderer may be holding onto resources
58 0 : delete fPathRendererChain;
59 0 : fPathRendererChain = nullptr;
60 0 : SkSafeSetNull(fSoftwarePathRenderer);
61 0 : for (int i = 0; i < fOpLists.count(); ++i) {
62 0 : fOpLists[i]->freeGpuResources();
63 : }
64 0 : }
65 :
66 0 : void GrDrawingManager::reset() {
67 0 : for (int i = 0; i < fOpLists.count(); ++i) {
68 0 : fOpLists[i]->reset();
69 : }
70 0 : fFlushState.reset();
71 0 : }
72 :
73 : // MDB TODO: make use of the 'proxy' parameter.
74 0 : void GrDrawingManager::internalFlush(GrSurfaceProxy*, GrResourceCache::FlushType type) {
75 0 : if (fFlushing || this->wasAbandoned()) {
76 0 : return;
77 : }
78 0 : fFlushing = true;
79 0 : bool flushed = false;
80 :
81 0 : for (int i = 0; i < fOpLists.count(); ++i) {
82 : // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
83 : // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
84 : // but need to be flushed anyway. Closing such GrOpLists here will mean new
85 : // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
86 0 : fOpLists[i]->makeClosed();
87 : }
88 :
89 : SkDEBUGCODE(bool result =)
90 0 : SkTTopoSort<GrOpList, GrOpList::TopoSortTraits>(&fOpLists);
91 0 : SkASSERT(result);
92 :
93 0 : GrPreFlushResourceProvider preFlushProvider(this);
94 :
95 0 : if (fPreFlushCBObjects.count()) {
96 : // MDB TODO: pre-MDB '1' is the correct pre-allocated size. Post-MDB it will need
97 : // to be larger.
98 0 : SkAutoSTArray<1, uint32_t> opListIds(fOpLists.count());
99 0 : for (int i = 0; i < fOpLists.count(); ++i) {
100 0 : opListIds[i] = fOpLists[i]->uniqueID();
101 : }
102 :
103 0 : SkSTArray<1, sk_sp<GrRenderTargetContext>> renderTargetContexts;
104 0 : for (int i = 0; i < fPreFlushCBObjects.count(); ++i) {
105 0 : fPreFlushCBObjects[i]->preFlush(&preFlushProvider,
106 0 : opListIds.get(), opListIds.count(),
107 0 : &renderTargetContexts);
108 0 : if (!renderTargetContexts.count()) {
109 0 : continue; // This is fine. No atlases of this type are required for this flush
110 : }
111 :
112 0 : for (int j = 0; j < renderTargetContexts.count(); ++j) {
113 0 : GrRenderTargetOpList* opList = renderTargetContexts[j]->getOpList();
114 0 : if (!opList) {
115 0 : continue; // Odd - but not a big deal
116 : }
117 0 : SkDEBUGCODE(opList->validateTargetsSingleRenderTarget());
118 0 : opList->prepareOps(&fFlushState);
119 0 : if (!opList->executeOps(&fFlushState)) {
120 0 : continue; // This is bad
121 : }
122 : }
123 0 : renderTargetContexts.reset();
124 : }
125 : }
126 :
127 0 : for (int i = 0; i < fOpLists.count(); ++i) {
128 0 : fOpLists[i]->prepareOps(&fFlushState);
129 : }
130 :
131 : #if 0
132 : // Enable this to print out verbose GrOp information
133 : for (int i = 0; i < fOpLists.count(); ++i) {
134 : SkDEBUGCODE(fOpLists[i]->dump();)
135 : }
136 : #endif
137 :
138 : // Upload all data to the GPU
139 0 : fFlushState.preIssueDraws();
140 :
141 0 : for (int i = 0; i < fOpLists.count(); ++i) {
142 0 : if (fOpLists[i]->executeOps(&fFlushState)) {
143 0 : flushed = true;
144 : }
145 : }
146 :
147 0 : SkASSERT(fFlushState.nextDrawToken() == fFlushState.nextTokenToFlush());
148 :
149 0 : for (int i = 0; i < fOpLists.count(); ++i) {
150 0 : fOpLists[i]->reset();
151 : #ifdef ENABLE_MDB
152 : fOpLists[i]->unref();
153 : #endif
154 : }
155 :
156 : #ifndef ENABLE_MDB
157 : // When MDB is disabled we keep reusing the same GrOpList
158 0 : if (fOpLists.count()) {
159 0 : SkASSERT(fOpLists.count() == 1);
160 : // Clear out this flag so the topological sort's SkTTopoSort_CheckAllUnmarked check
161 : // won't bark
162 0 : fOpLists[0]->resetFlag(GrOpList::kWasOutput_Flag);
163 : }
164 : #else
165 : fOpLists.reset();
166 : #endif
167 :
168 0 : fFlushState.reset();
169 : // We always have to notify the cache when it requested a flush so it can reset its state.
170 0 : if (flushed || type == GrResourceCache::FlushType::kCacheRequested) {
171 0 : fContext->getResourceCache()->notifyFlushOccurred(type);
172 : }
173 0 : fFlushing = false;
174 : }
175 :
176 0 : void GrDrawingManager::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
177 0 : if (this->wasAbandoned()) {
178 0 : return;
179 : }
180 0 : SkASSERT(proxy);
181 :
182 0 : if (proxy->priv().hasPendingIO()) {
183 0 : this->flush(proxy);
184 : }
185 :
186 0 : GrSurface* surface = proxy->instantiate(fContext->resourceProvider());
187 0 : if (!surface) {
188 0 : return;
189 : }
190 :
191 0 : if (fContext->getGpu() && surface->asRenderTarget()) {
192 0 : fContext->getGpu()->resolveRenderTarget(surface->asRenderTarget());
193 : }
194 : }
195 :
196 0 : void GrDrawingManager::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) {
197 0 : fPreFlushCBObjects.push_back(preFlushCBObject);
198 0 : }
199 :
200 0 : GrRenderTargetOpList* GrDrawingManager::newOpList(GrRenderTargetProxy* rtp) {
201 0 : SkASSERT(fContext);
202 :
203 : #ifndef ENABLE_MDB
204 : // When MDB is disabled we always just return the single GrOpList
205 0 : if (fOpLists.count()) {
206 0 : SkASSERT(fOpLists.count() == 1);
207 : // In the non-MDB-world the same GrOpList gets reused for multiple render targets.
208 : // Update this pointer so all the asserts are happy
209 0 : rtp->setLastOpList(fOpLists[0]);
210 : // DrawingManager gets the creation ref - this ref is for the caller
211 :
212 : // TODO: although this is true right now it isn't cool
213 0 : return SkRef((GrRenderTargetOpList*) fOpLists[0]);
214 : }
215 : #endif
216 :
217 : GrRenderTargetOpList* opList = new GrRenderTargetOpList(rtp,
218 0 : fContext->getGpu(),
219 0 : fContext->resourceProvider(),
220 0 : fContext->getAuditTrail(),
221 0 : fOptionsForOpLists);
222 :
223 0 : *fOpLists.append() = opList;
224 :
225 : // DrawingManager gets the creation ref - this ref is for the caller
226 0 : return SkRef(opList);
227 : }
228 :
229 0 : GrTextureOpList* GrDrawingManager::newOpList(GrTextureProxy* textureProxy) {
230 0 : SkASSERT(fContext);
231 :
232 0 : GrTextureOpList* opList = new GrTextureOpList(textureProxy, fContext->getGpu(),
233 0 : fContext->getAuditTrail());
234 :
235 : #ifndef ENABLE_MDB
236 : // When MDB is disabled we still create a new GrOpList, but don't store or ref it - we rely
237 : // on the caller to immediately execute and free it.
238 0 : return opList;
239 : #else
240 : *fOpLists.append() = opList;
241 :
242 : // Drawing manager gets the creation ref - this ref is for the caller
243 : return SkRef(opList);
244 : #endif
245 : }
246 :
247 0 : GrAtlasTextContext* GrDrawingManager::getAtlasTextContext() {
248 0 : if (!fAtlasTextContext) {
249 0 : fAtlasTextContext.reset(GrAtlasTextContext::Create());
250 : }
251 :
252 0 : return fAtlasTextContext.get();
253 : }
254 :
255 : /*
256 : * This method finds a path renderer that can draw the specified path on
257 : * the provided target.
258 : * Due to its expense, the software path renderer has split out so it can
259 : * can be individually allowed/disallowed via the "allowSW" boolean.
260 : */
261 0 : GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,
262 : bool allowSW,
263 : GrPathRendererChain::DrawType drawType,
264 : GrPathRenderer::StencilSupport* stencilSupport) {
265 :
266 0 : if (!fPathRendererChain) {
267 0 : fPathRendererChain = new GrPathRendererChain(fContext, fOptionsForPathRendererChain);
268 : }
269 :
270 0 : GrPathRenderer* pr = fPathRendererChain->getPathRenderer(args, drawType, stencilSupport);
271 0 : if (!pr && allowSW) {
272 0 : if (!fSoftwarePathRenderer) {
273 0 : fSoftwarePathRenderer =
274 0 : new GrSoftwarePathRenderer(fContext->resourceProvider(),
275 0 : fOptionsForPathRendererChain.fAllowPathMaskCaching);
276 : }
277 0 : if (fSoftwarePathRenderer->canDrawPath(args)) {
278 0 : pr = fSoftwarePathRenderer;
279 : }
280 : }
281 :
282 0 : return pr;
283 : }
284 :
285 0 : sk_sp<GrRenderTargetContext> GrDrawingManager::makeRenderTargetContext(
286 : sk_sp<GrSurfaceProxy> sProxy,
287 : sk_sp<SkColorSpace> colorSpace,
288 : const SkSurfaceProps* surfaceProps) {
289 0 : if (this->wasAbandoned() || !sProxy->asRenderTargetProxy()) {
290 0 : return nullptr;
291 : }
292 :
293 : // SkSurface catches bad color space usage at creation. This check handles anything that slips
294 : // by, including internal usage. We allow a null color space here, for read/write pixels and
295 : // other special code paths. If a color space is provided, though, enforce all other rules.
296 0 : if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
297 0 : SkDEBUGFAIL("Invalid config and colorspace combination");
298 0 : return nullptr;
299 : }
300 :
301 0 : sk_sp<GrRenderTargetProxy> rtp(sk_ref_sp(sProxy->asRenderTargetProxy()));
302 :
303 0 : bool useDIF = false;
304 0 : if (surfaceProps) {
305 0 : useDIF = surfaceProps->isUseDeviceIndependentFonts();
306 : }
307 :
308 0 : if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() &&
309 0 : rtp->isStencilBufferMultisampled()) {
310 : // TODO: defer stencil buffer attachment for PathRenderingDrawContext
311 0 : sk_sp<GrRenderTarget> rt(sk_ref_sp(rtp->instantiate(fContext->resourceProvider())));
312 0 : if (!rt) {
313 0 : return nullptr;
314 : }
315 0 : GrStencilAttachment* sb = fContext->resourceProvider()->attachStencilAttachment(rt.get());
316 0 : if (sb) {
317 : return sk_sp<GrRenderTargetContext>(new GrPathRenderingRenderTargetContext(
318 0 : fContext, this, std::move(rtp),
319 0 : std::move(colorSpace), surfaceProps,
320 0 : fContext->getAuditTrail(), fSingleOwner));
321 : }
322 : }
323 :
324 0 : return sk_sp<GrRenderTargetContext>(new GrRenderTargetContext(fContext, this, std::move(rtp),
325 0 : std::move(colorSpace),
326 : surfaceProps,
327 0 : fContext->getAuditTrail(),
328 0 : fSingleOwner));
329 : }
330 :
331 0 : sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy,
332 : sk_sp<SkColorSpace> colorSpace) {
333 0 : if (this->wasAbandoned() || !sProxy->asTextureProxy()) {
334 0 : return nullptr;
335 : }
336 :
337 : // SkSurface catches bad color space usage at creation. This check handles anything that slips
338 : // by, including internal usage. We allow a null color space here, for read/write pixels and
339 : // other special code paths. If a color space is provided, though, enforce all other rules.
340 0 : if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
341 0 : SkDEBUGFAIL("Invalid config and colorspace combination");
342 0 : return nullptr;
343 : }
344 :
345 : // GrTextureRenderTargets should always be using GrRenderTargetContext
346 0 : SkASSERT(!sProxy->asRenderTargetProxy());
347 :
348 0 : sk_sp<GrTextureProxy> textureProxy(sk_ref_sp(sProxy->asTextureProxy()));
349 :
350 0 : return sk_sp<GrTextureContext>(new GrTextureContext(fContext, this, std::move(textureProxy),
351 0 : std::move(colorSpace),
352 0 : fContext->getAuditTrail(),
353 0 : fSingleOwner));
354 : }
|