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 "GrBackendSemaphore.h"
11 #include "GrContext.h"
12 #include "GrContextPriv.h"
13 #include "GrGpu.h"
14 #include "GrOnFlushResourceProvider.h"
15 #include "GrOpList.h"
16 #include "GrRenderTargetContext.h"
17 #include "GrPathRenderingRenderTargetContext.h"
18 #include "GrRenderTargetProxy.h"
19 #include "GrResourceAllocator.h"
20 #include "GrResourceProvider.h"
21 #include "GrSoftwarePathRenderer.h"
22 #include "GrSurfaceProxyPriv.h"
23 #include "GrTextureContext.h"
24 #include "GrTextureOpList.h"
25 #include "GrTextureProxy.h"
26 #include "GrTextureProxyPriv.h"
27
28 #include "SkDeferredDisplayList.h"
29 #include "SkSurface_Gpu.h"
30 #include "SkTTopoSort.h"
31
32 #include "GrTracing.h"
33 #include "text/GrAtlasTextContext.h"
34 #include "text/GrStencilAndCoverTextContext.h"
35
cleanup()36 void GrDrawingManager::cleanup() {
37 for (int i = 0; i < fOpLists.count(); ++i) {
38 // no opList should receive a new command after this
39 fOpLists[i]->makeClosed(*fContext->caps());
40
41 // We shouldn't need to do this, but it turns out some clients still hold onto opLists
42 // after a cleanup.
43 // MDB TODO: is this still true?
44 if (!fOpLists[i]->unique()) {
45 // TODO: Eventually this should be guaranteed unique.
46 // https://bugs.chromium.org/p/skia/issues/detail?id=7111
47 fOpLists[i]->endFlush();
48 }
49 }
50
51 fOpLists.reset();
52
53 delete fPathRendererChain;
54 fPathRendererChain = nullptr;
55 SkSafeSetNull(fSoftwarePathRenderer);
56
57 fOnFlushCBObjects.reset();
58 }
59
~GrDrawingManager()60 GrDrawingManager::~GrDrawingManager() {
61 this->cleanup();
62 }
63
abandon()64 void GrDrawingManager::abandon() {
65 fAbandoned = true;
66 this->cleanup();
67 }
68
freeGpuResources()69 void GrDrawingManager::freeGpuResources() {
70 for (int i = fOnFlushCBObjects.count() - 1; i >= 0; --i) {
71 if (!fOnFlushCBObjects[i]->retainOnFreeGpuResources()) {
72 // it's safe to just do this because we're iterating in reverse
73 fOnFlushCBObjects.removeShuffle(i);
74 }
75 }
76
77 // a path renderer may be holding onto resources
78 delete fPathRendererChain;
79 fPathRendererChain = nullptr;
80 SkSafeSetNull(fSoftwarePathRenderer);
81 }
82
83 // MDB TODO: make use of the 'proxy' parameter.
internalFlush(GrSurfaceProxy *,GrResourceCache::FlushType type,int numSemaphores,GrBackendSemaphore backendSemaphores[])84 GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*,
85 GrResourceCache::FlushType type,
86 int numSemaphores,
87 GrBackendSemaphore backendSemaphores[]) {
88 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawingManager", "internalFlush", fContext);
89
90 if (fFlushing || this->wasAbandoned()) {
91 return GrSemaphoresSubmitted::kNo;
92 }
93 fFlushing = true;
94
95 for (int i = 0; i < fOpLists.count(); ++i) {
96 // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
97 // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
98 // but need to be flushed anyway. Closing such GrOpLists here will mean new
99 // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
100 fOpLists[i]->makeClosed(*fContext->caps());
101 }
102
103 #ifdef SK_DEBUG
104 // This block checks for any unnecessary splits in the opLists. If two sequential opLists
105 // share the same backing GrSurfaceProxy it means the opList was artificially split.
106 if (fOpLists.count()) {
107 GrRenderTargetOpList* prevOpList = fOpLists[0]->asRenderTargetOpList();
108 for (int i = 1; i < fOpLists.count(); ++i) {
109 GrRenderTargetOpList* curOpList = fOpLists[i]->asRenderTargetOpList();
110
111 if (prevOpList && curOpList) {
112 SkASSERT(prevOpList->fTarget.get() != curOpList->fTarget.get());
113 }
114
115 prevOpList = curOpList;
116 }
117 }
118 #endif
119
120 #ifndef SK_DISABLE_RENDER_TARGET_SORTING
121 SkDEBUGCODE(bool result =)
122 SkTTopoSort<GrOpList, GrOpList::TopoSortTraits>(&fOpLists);
123 SkASSERT(result);
124 #endif
125
126 GrGpu* gpu = fContext->contextPriv().getGpu();
127
128 GrOpFlushState flushState(gpu, fContext->contextPriv().resourceProvider(),
129 &fTokenTracker);
130
131 GrOnFlushResourceProvider onFlushProvider(this);
132 // TODO: AFAICT the only reason fFlushState is on GrDrawingManager rather than on the
133 // stack here is to preserve the flush tokens.
134
135 // Prepare any onFlush op lists (e.g. atlases).
136 if (!fOnFlushCBObjects.empty()) {
137 fFlushingOpListIDs.reset(fOpLists.count());
138 for (int i = 0; i < fOpLists.count(); ++i) {
139 fFlushingOpListIDs[i] = fOpLists[i]->uniqueID();
140 }
141 SkSTArray<4, sk_sp<GrRenderTargetContext>> renderTargetContexts;
142 for (GrOnFlushCallbackObject* onFlushCBObject : fOnFlushCBObjects) {
143 onFlushCBObject->preFlush(&onFlushProvider,
144 fFlushingOpListIDs.begin(), fFlushingOpListIDs.count(),
145 &renderTargetContexts);
146 for (const sk_sp<GrRenderTargetContext>& rtc : renderTargetContexts) {
147 sk_sp<GrRenderTargetOpList> onFlushOpList = sk_ref_sp(rtc->getRTOpList());
148 if (!onFlushOpList) {
149 continue; // Odd - but not a big deal
150 }
151 #ifdef SK_DEBUG
152 // OnFlush callbacks are already invoked during flush, and are therefore expected to
153 // handle resource allocation & usage on their own. (No deferred or lazy proxies!)
154 onFlushOpList->visitProxies_debugOnly([](GrSurfaceProxy* p) {
155 SkASSERT(!p->asTextureProxy() || !p->asTextureProxy()->texPriv().isDeferred());
156 SkASSERT(GrSurfaceProxy::LazyState::kNot == p->lazyInstantiationState());
157 });
158 #endif
159 onFlushOpList->makeClosed(*fContext->caps());
160 onFlushOpList->prepare(&flushState);
161 fOnFlushCBOpLists.push_back(std::move(onFlushOpList));
162 }
163 renderTargetContexts.reset();
164 }
165 }
166
167 #if 0
168 // Enable this to print out verbose GrOp information
169 for (int i = 0; i < fOpLists.count(); ++i) {
170 SkDEBUGCODE(fOpLists[i]->dump();)
171 }
172 #endif
173
174 int startIndex, stopIndex;
175 bool flushed = false;
176
177 {
178 GrResourceAllocator alloc(fContext->contextPriv().resourceProvider());
179 for (int i = 0; i < fOpLists.count(); ++i) {
180 fOpLists[i]->gatherProxyIntervals(&alloc);
181 alloc.markEndOfOpList(i);
182 }
183
184 #ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
185 startIndex = 0;
186 stopIndex = fOpLists.count();
187 #else
188 GrResourceAllocator::AssignError error = GrResourceAllocator::AssignError::kNoError;
189 while (alloc.assign(&startIndex, &stopIndex, &error))
190 #endif
191 {
192 #ifndef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
193 if (GrResourceAllocator::AssignError::kFailedProxyInstantiation == error) {
194 for (int i = startIndex; i < stopIndex; ++i) {
195 fOpLists[i]->purgeOpsWithUninstantiatedProxies();
196 }
197 }
198 #endif
199 if (this->executeOpLists(startIndex, stopIndex, &flushState)) {
200 flushed = true;
201 }
202 }
203 }
204
205 fOpLists.reset();
206
207 GrSemaphoresSubmitted result = gpu->finishFlush(numSemaphores, backendSemaphores);
208
209 // We always have to notify the cache when it requested a flush so it can reset its state.
210 if (flushed || type == GrResourceCache::FlushType::kCacheRequested) {
211 fContext->contextPriv().getResourceCache()->notifyFlushOccurred(type);
212 }
213 for (GrOnFlushCallbackObject* onFlushCBObject : fOnFlushCBObjects) {
214 onFlushCBObject->postFlush(fTokenTracker.nextTokenToFlush(), fFlushingOpListIDs.begin(),
215 fFlushingOpListIDs.count());
216 }
217 fFlushingOpListIDs.reset();
218 fFlushing = false;
219
220 return result;
221 }
222
executeOpLists(int startIndex,int stopIndex,GrOpFlushState * flushState)223 bool GrDrawingManager::executeOpLists(int startIndex, int stopIndex, GrOpFlushState* flushState) {
224 SkASSERT(startIndex <= stopIndex && stopIndex <= fOpLists.count());
225
226 bool anyOpListsExecuted = false;
227
228 for (int i = startIndex; i < stopIndex; ++i) {
229 if (!fOpLists[i]) {
230 continue;
231 }
232
233 #ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
234 if (!fOpLists[i]->instantiate(fContext->contextPriv().resourceProvider())) {
235 SkDebugf("OpList failed to instantiate.\n");
236 fOpLists[i] = nullptr;
237 continue;
238 }
239 #else
240 SkASSERT(fOpLists[i]->isInstantiated());
241 #endif
242
243 // TODO: handle this instantiation via lazy surface proxies?
244 // Instantiate all deferred proxies (being built on worker threads) so we can upload them
245 fOpLists[i]->instantiateDeferredProxies(fContext->contextPriv().resourceProvider());
246 fOpLists[i]->prepare(flushState);
247 }
248
249 // Upload all data to the GPU
250 flushState->preExecuteDraws();
251
252 // Execute the onFlush op lists first, if any.
253 for (sk_sp<GrOpList>& onFlushOpList : fOnFlushCBOpLists) {
254 if (!onFlushOpList->execute(flushState)) {
255 SkDebugf("WARNING: onFlushOpList failed to execute.\n");
256 }
257 SkASSERT(onFlushOpList->unique());
258 onFlushOpList = nullptr;
259 }
260 fOnFlushCBOpLists.reset();
261
262 // Execute the normal op lists.
263 for (int i = startIndex; i < stopIndex; ++i) {
264 if (!fOpLists[i]) {
265 continue;
266 }
267
268 if (fOpLists[i]->execute(flushState)) {
269 anyOpListsExecuted = true;
270 }
271 }
272
273 SkASSERT(!flushState->commandBuffer());
274 SkASSERT(fTokenTracker.nextDrawToken() == fTokenTracker.nextTokenToFlush());
275
276 // We reset the flush state before the OpLists so that the last resources to be freed are those
277 // that are written to in the OpLists. This helps to make sure the most recently used resources
278 // are the last to be purged by the resource cache.
279 flushState->reset();
280
281 for (int i = startIndex; i < stopIndex; ++i) {
282 if (!fOpLists[i]) {
283 continue;
284 }
285 if (!fOpLists[i]->unique()) {
286 // TODO: Eventually this should be guaranteed unique.
287 // https://bugs.chromium.org/p/skia/issues/detail?id=7111
288 fOpLists[i]->endFlush();
289 }
290 fOpLists[i] = nullptr;
291 }
292
293 return anyOpListsExecuted;
294 }
295
prepareSurfaceForExternalIO(GrSurfaceProxy * proxy,int numSemaphores,GrBackendSemaphore backendSemaphores[])296 GrSemaphoresSubmitted GrDrawingManager::prepareSurfaceForExternalIO(
297 GrSurfaceProxy* proxy, int numSemaphores, GrBackendSemaphore backendSemaphores[]) {
298 if (this->wasAbandoned()) {
299 return GrSemaphoresSubmitted::kNo;
300 }
301 SkASSERT(proxy);
302
303 GrSemaphoresSubmitted result = GrSemaphoresSubmitted::kNo;
304 if (proxy->priv().hasPendingIO() || numSemaphores) {
305 result = this->flush(proxy, numSemaphores, backendSemaphores);
306 }
307
308 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
309 return result;
310 }
311
312 GrGpu* gpu = fContext->contextPriv().getGpu();
313 GrSurface* surface = proxy->priv().peekSurface();
314
315 if (gpu && surface->asRenderTarget()) {
316 gpu->resolveRenderTarget(surface->asRenderTarget(), proxy->origin());
317 }
318 return result;
319 }
320
addOnFlushCallbackObject(GrOnFlushCallbackObject * onFlushCBObject)321 void GrDrawingManager::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
322 fOnFlushCBObjects.push_back(onFlushCBObject);
323 }
324
moveOpListsToDDL(SkDeferredDisplayList * ddl)325 void GrDrawingManager::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
326 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
327 for (int i = 0; i < fOpLists.count(); ++i) {
328 // no opList should receive a new command after this
329 fOpLists[i]->makeClosed(*fContext->caps());
330 }
331
332 ddl->fOpLists = std::move(fOpLists);
333 #endif
334 }
335
copyOpListsFromDDL(const SkDeferredDisplayList * ddl,GrRenderTargetProxy * newDest)336 void GrDrawingManager::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
337 GrRenderTargetProxy* newDest) {
338 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
339 // Here we jam the proxy that backs the current replay SkSurface into the LazyProxyData.
340 // The lazy proxy that references it (in the copied opLists) will steal its GrTexture.
341 ddl->fLazyProxyData->fReplayDest = newDest;
342 fOpLists.push_back_n(ddl->fOpLists.count(), ddl->fOpLists.begin());
343 #endif
344 }
345
newRTOpList(GrRenderTargetProxy * rtp,bool managedOpList)346 sk_sp<GrRenderTargetOpList> GrDrawingManager::newRTOpList(GrRenderTargetProxy* rtp,
347 bool managedOpList) {
348 SkASSERT(fContext);
349
350 // This is a temporary fix for the partial-MDB world. In that world we're not reordering
351 // so ops that (in the single opList world) would've just glommed onto the end of the single
352 // opList but referred to a far earlier RT need to appear in their own opList.
353 if (!fOpLists.empty()) {
354 fOpLists.back()->makeClosed(*fContext->caps());
355 }
356
357 auto resourceProvider = fContext->contextPriv().resourceProvider();
358
359 sk_sp<GrRenderTargetOpList> opList(new GrRenderTargetOpList(rtp,
360 resourceProvider,
361 fContext->getAuditTrail()));
362 SkASSERT(rtp->getLastOpList() == opList.get());
363
364 if (managedOpList) {
365 fOpLists.push_back() = opList;
366 }
367
368 return opList;
369 }
370
newTextureOpList(GrTextureProxy * textureProxy)371 sk_sp<GrTextureOpList> GrDrawingManager::newTextureOpList(GrTextureProxy* textureProxy) {
372 SkASSERT(fContext);
373
374 // This is a temporary fix for the partial-MDB world. In that world we're not reordering
375 // so ops that (in the single opList world) would've just glommed onto the end of the single
376 // opList but referred to a far earlier RT need to appear in their own opList.
377 if (!fOpLists.empty()) {
378 fOpLists.back()->makeClosed(*fContext->caps());
379 }
380
381 sk_sp<GrTextureOpList> opList(new GrTextureOpList(fContext->contextPriv().resourceProvider(),
382 textureProxy,
383 fContext->getAuditTrail()));
384
385 SkASSERT(textureProxy->getLastOpList() == opList.get());
386
387 fOpLists.push_back() = opList;
388
389 return opList;
390 }
391
getAtlasTextContext()392 GrAtlasTextContext* GrDrawingManager::getAtlasTextContext() {
393 if (!fAtlasTextContext) {
394 fAtlasTextContext = GrAtlasTextContext::Make(fOptionsForAtlasTextContext);
395 }
396
397 return fAtlasTextContext.get();
398 }
399
400 /*
401 * This method finds a path renderer that can draw the specified path on
402 * the provided target.
403 * Due to its expense, the software path renderer has split out so it can
404 * can be individually allowed/disallowed via the "allowSW" boolean.
405 */
getPathRenderer(const GrPathRenderer::CanDrawPathArgs & args,bool allowSW,GrPathRendererChain::DrawType drawType,GrPathRenderer::StencilSupport * stencilSupport)406 GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,
407 bool allowSW,
408 GrPathRendererChain::DrawType drawType,
409 GrPathRenderer::StencilSupport* stencilSupport) {
410
411 if (!fPathRendererChain) {
412 fPathRendererChain = new GrPathRendererChain(fContext, fOptionsForPathRendererChain);
413 }
414
415 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(args, drawType, stencilSupport);
416 if (!pr && allowSW) {
417 if (!fSoftwarePathRenderer) {
418 fSoftwarePathRenderer =
419 new GrSoftwarePathRenderer(fContext->contextPriv().proxyProvider(),
420 fOptionsForPathRendererChain.fAllowPathMaskCaching);
421 }
422 if (GrPathRenderer::CanDrawPath::kNo != fSoftwarePathRenderer->canDrawPath(args)) {
423 pr = fSoftwarePathRenderer;
424 }
425 }
426
427 return pr;
428 }
429
getCoverageCountingPathRenderer()430 GrCoverageCountingPathRenderer* GrDrawingManager::getCoverageCountingPathRenderer() {
431 if (!fPathRendererChain) {
432 fPathRendererChain = new GrPathRendererChain(fContext, fOptionsForPathRendererChain);
433 }
434 return fPathRendererChain->getCoverageCountingPathRenderer();
435 }
436
makeRenderTargetContext(sk_sp<GrSurfaceProxy> sProxy,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,bool managedOpList)437 sk_sp<GrRenderTargetContext> GrDrawingManager::makeRenderTargetContext(
438 sk_sp<GrSurfaceProxy> sProxy,
439 sk_sp<SkColorSpace> colorSpace,
440 const SkSurfaceProps* surfaceProps,
441 bool managedOpList) {
442 if (this->wasAbandoned() || !sProxy->asRenderTargetProxy()) {
443 return nullptr;
444 }
445
446 // SkSurface catches bad color space usage at creation. This check handles anything that slips
447 // by, including internal usage. We allow a null color space here, for read/write pixels and
448 // other special code paths. If a color space is provided, though, enforce all other rules.
449 if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
450 SkDEBUGFAIL("Invalid config and colorspace combination");
451 return nullptr;
452 }
453
454 sk_sp<GrRenderTargetProxy> rtp(sk_ref_sp(sProxy->asRenderTargetProxy()));
455
456 bool useDIF = false;
457 if (surfaceProps) {
458 useDIF = surfaceProps->isUseDeviceIndependentFonts();
459 }
460
461 if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() &&
462 GrFSAAType::kNone != rtp->fsaaType()) {
463
464 return sk_sp<GrRenderTargetContext>(new GrPathRenderingRenderTargetContext(
465 fContext, this, std::move(rtp),
466 std::move(colorSpace), surfaceProps,
467 fContext->getAuditTrail(), fSingleOwner));
468 }
469
470 return sk_sp<GrRenderTargetContext>(new GrRenderTargetContext(fContext, this, std::move(rtp),
471 std::move(colorSpace),
472 surfaceProps,
473 fContext->getAuditTrail(),
474 fSingleOwner, managedOpList));
475 }
476
makeTextureContext(sk_sp<GrSurfaceProxy> sProxy,sk_sp<SkColorSpace> colorSpace)477 sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy,
478 sk_sp<SkColorSpace> colorSpace) {
479 if (this->wasAbandoned() || !sProxy->asTextureProxy()) {
480 return nullptr;
481 }
482
483 // SkSurface catches bad color space usage at creation. This check handles anything that slips
484 // by, including internal usage. We allow a null color space here, for read/write pixels and
485 // other special code paths. If a color space is provided, though, enforce all other rules.
486 if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
487 SkDEBUGFAIL("Invalid config and colorspace combination");
488 return nullptr;
489 }
490
491 // GrTextureRenderTargets should always be using GrRenderTargetContext
492 SkASSERT(!sProxy->asRenderTargetProxy());
493
494 sk_sp<GrTextureProxy> textureProxy(sk_ref_sp(sProxy->asTextureProxy()));
495
496 return sk_sp<GrTextureContext>(new GrTextureContext(fContext, this, std::move(textureProxy),
497 std::move(colorSpace),
498 fContext->getAuditTrail(),
499 fSingleOwner));
500 }
501