• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrGpu.h"
12 #include "GrOnFlushResourceProvider.h"
13 #include "GrRenderTargetContext.h"
14 #include "GrPathRenderingRenderTargetContext.h"
15 #include "GrRenderTargetProxy.h"
16 #include "GrResourceProvider.h"
17 #include "GrSoftwarePathRenderer.h"
18 #include "GrSurfacePriv.h"
19 #include "GrSurfaceProxyPriv.h"
20 #include "GrTextureContext.h"
21 #include "GrTextureOpList.h"
22 #include "SkSurface_Gpu.h"
23 #include "SkTTopoSort.h"
24 
25 #include "GrTracing.h"
26 #include "text/GrAtlasTextContext.h"
27 #include "text/GrStencilAndCoverTextContext.h"
28 
cleanup()29 void GrDrawingManager::cleanup() {
30     for (int i = 0; i < fOpLists.count(); ++i) {
31         // no opList should receive a new command after this
32         fOpLists[i]->makeClosed(*fContext->caps());
33 
34         // We shouldn't need to do this, but it turns out some clients still hold onto opLists
35         // after a cleanup.
36         // MDB TODO: is this still true?
37         fOpLists[i]->reset();
38     }
39 
40     fOpLists.reset();
41 
42     delete fPathRendererChain;
43     fPathRendererChain = nullptr;
44     SkSafeSetNull(fSoftwarePathRenderer);
45 }
46 
~GrDrawingManager()47 GrDrawingManager::~GrDrawingManager() {
48     this->cleanup();
49 }
50 
abandon()51 void GrDrawingManager::abandon() {
52     fAbandoned = true;
53     for (int i = 0; i < fOpLists.count(); ++i) {
54         fOpLists[i]->abandonGpuResources();
55     }
56     this->cleanup();
57 }
58 
freeGpuResources()59 void GrDrawingManager::freeGpuResources() {
60     // a path renderer may be holding onto resources
61     delete fPathRendererChain;
62     fPathRendererChain = nullptr;
63     SkSafeSetNull(fSoftwarePathRenderer);
64     for (int i = 0; i < fOpLists.count(); ++i) {
65         fOpLists[i]->freeGpuResources();
66     }
67 }
68 
reset()69 void GrDrawingManager::reset() {
70     for (int i = 0; i < fOpLists.count(); ++i) {
71         fOpLists[i]->reset();
72     }
73     fFlushState.reset();
74 }
75 
instancingAllocator()76 gr_instanced::OpAllocator* GrDrawingManager::instancingAllocator() {
77     if (fInstancingAllocator) {
78         return fInstancingAllocator.get();
79     }
80 
81     fInstancingAllocator = fContext->getGpu()->createInstancedRenderingAllocator();
82     return fInstancingAllocator.get();
83 }
84 
85 // MDB TODO: make use of the 'proxy' parameter.
internalFlush(GrSurfaceProxy *,GrResourceCache::FlushType type)86 void GrDrawingManager::internalFlush(GrSurfaceProxy*, GrResourceCache::FlushType type) {
87     GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawingManager", "internalFlush", fContext);
88 
89     if (fFlushing || this->wasAbandoned()) {
90         return;
91     }
92     fFlushing = true;
93     bool flushed = false;
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 #ifdef ENABLE_MDB
121     SkDEBUGCODE(bool result =)
122                         SkTTopoSort<GrOpList, GrOpList::TopoSortTraits>(&fOpLists);
123     SkASSERT(result);
124 #endif
125 
126     GrOnFlushResourceProvider onFlushProvider(this);
127 
128     if (!fOnFlushCBObjects.empty()) {
129         // MDB TODO: pre-MDB '1' is the correct pre-allocated size. Post-MDB it will need
130         // to be larger.
131         SkAutoSTArray<1, uint32_t> opListIds(fOpLists.count());
132         for (int i = 0; i < fOpLists.count(); ++i) {
133             opListIds[i] = fOpLists[i]->uniqueID();
134         }
135 
136         SkSTArray<1, sk_sp<GrRenderTargetContext>> renderTargetContexts;
137         for (GrOnFlushCallbackObject* onFlushCBObject : fOnFlushCBObjects) {
138             onFlushCBObject->preFlush(&onFlushProvider,
139                                       opListIds.get(), opListIds.count(),
140                                       &renderTargetContexts);
141             if (!renderTargetContexts.count()) {
142                 continue;       // This is fine. No atlases of this type are required for this flush
143             }
144 
145             for (int j = 0; j < renderTargetContexts.count(); ++j) {
146                 GrOpList* opList = renderTargetContexts[j]->getOpList();
147                 if (!opList) {
148                     continue;   // Odd - but not a big deal
149                 }
150                 opList->makeClosed(*fContext->caps());
151                 opList->prepareOps(&fFlushState);
152                 if (!opList->executeOps(&fFlushState)) {
153                     continue;         // This is bad
154                 }
155             }
156             renderTargetContexts.reset();
157         }
158     }
159 
160 #if 0
161     // Enable this to print out verbose GrOp information
162     for (int i = 0; i < fOpLists.count(); ++i) {
163         SkDEBUGCODE(fOpLists[i]->dump();)
164     }
165 #endif
166 
167     for (int i = 0; i < fOpLists.count(); ++i) {
168         if (!fOpLists[i]->instantiate(fContext->resourceProvider())) {
169             fOpLists[i] = nullptr;
170             continue;
171         }
172 
173         fOpLists[i]->prepareOps(&fFlushState);
174     }
175 
176     // Upload all data to the GPU
177     fFlushState.preIssueDraws();
178 
179     for (int i = 0; i < fOpLists.count(); ++i) {
180         if (!fOpLists[i]) {
181             continue;
182         }
183 
184         if (fOpLists[i]->executeOps(&fFlushState)) {
185             flushed = true;
186         }
187         fOpLists[i]->reset();
188     }
189     fOpLists.reset();
190 
191     SkASSERT(fFlushState.nextDrawToken() == fFlushState.nextTokenToFlush());
192 
193     fContext->getGpu()->finishFlush();
194 
195     fFlushState.reset();
196     // We always have to notify the cache when it requested a flush so it can reset its state.
197     if (flushed || type == GrResourceCache::FlushType::kCacheRequested) {
198         fContext->getResourceCache()->notifyFlushOccurred(type);
199     }
200     for (GrOnFlushCallbackObject* onFlushCBObject : fOnFlushCBObjects) {
201         onFlushCBObject->postFlush();
202     }
203     fFlushing = false;
204 }
205 
prepareSurfaceForExternalIO(GrSurfaceProxy * proxy)206 void GrDrawingManager::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
207     if (this->wasAbandoned()) {
208         return;
209     }
210     SkASSERT(proxy);
211 
212     if (proxy->priv().hasPendingIO()) {
213         this->flush(proxy);
214     }
215 
216     if (!proxy->instantiate(fContext->resourceProvider())) {
217         return;
218     }
219 
220     GrSurface* surface = proxy->priv().peekSurface();
221 
222     if (fContext->getGpu() && surface->asRenderTarget()) {
223         fContext->getGpu()->resolveRenderTarget(surface->asRenderTarget());
224     }
225 }
226 
addOnFlushCallbackObject(GrOnFlushCallbackObject * onFlushCBObject)227 void GrDrawingManager::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
228     fOnFlushCBObjects.push_back(onFlushCBObject);
229 }
230 
newRTOpList(GrRenderTargetProxy * rtp,bool managedOpList)231 sk_sp<GrRenderTargetOpList> GrDrawingManager::newRTOpList(GrRenderTargetProxy* rtp,
232                                                           bool managedOpList) {
233     SkASSERT(fContext);
234 
235     // This is  a temporary fix for the partial-MDB world. In that world we're not reordering
236     // so ops that (in the single opList world) would've just glommed onto the end of the single
237     // opList but referred to a far earlier RT need to appear in their own opList.
238     if (!fOpLists.empty()) {
239         fOpLists.back()->makeClosed(*fContext->caps());
240     }
241 
242     sk_sp<GrRenderTargetOpList> opList(new GrRenderTargetOpList(rtp,
243                                                                 fContext->getGpu(),
244                                                                 fContext->getAuditTrail()));
245     SkASSERT(rtp->getLastOpList() == opList.get());
246 
247     if (managedOpList) {
248         fOpLists.push_back() = opList;
249     }
250 
251     return opList;
252 }
253 
newTextureOpList(GrTextureProxy * textureProxy)254 sk_sp<GrTextureOpList> GrDrawingManager::newTextureOpList(GrTextureProxy* textureProxy) {
255     SkASSERT(fContext);
256 
257     // This is  a temporary fix for the partial-MDB world. In that world we're not reordering
258     // so ops that (in the single opList world) would've just glommed onto the end of the single
259     // opList but referred to a far earlier RT need to appear in their own opList.
260     if (!fOpLists.empty()) {
261         fOpLists.back()->makeClosed(*fContext->caps());
262     }
263 
264     sk_sp<GrTextureOpList> opList(new GrTextureOpList(fContext->resourceProvider(),
265                                                       textureProxy,
266                                                       fContext->getAuditTrail()));
267 
268     SkASSERT(textureProxy->getLastOpList() == opList.get());
269 
270     fOpLists.push_back() = opList;
271 
272     return opList;
273 }
274 
getAtlasTextContext()275 GrAtlasTextContext* GrDrawingManager::getAtlasTextContext() {
276     if (!fAtlasTextContext) {
277         fAtlasTextContext.reset(GrAtlasTextContext::Create());
278     }
279 
280     return fAtlasTextContext.get();
281 }
282 
283 /*
284  * This method finds a path renderer that can draw the specified path on
285  * the provided target.
286  * Due to its expense, the software path renderer has split out so it can
287  * can be individually allowed/disallowed via the "allowSW" boolean.
288  */
getPathRenderer(const GrPathRenderer::CanDrawPathArgs & args,bool allowSW,GrPathRendererChain::DrawType drawType,GrPathRenderer::StencilSupport * stencilSupport)289 GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,
290                                                   bool allowSW,
291                                                   GrPathRendererChain::DrawType drawType,
292                                                   GrPathRenderer::StencilSupport* stencilSupport) {
293 
294     if (!fPathRendererChain) {
295         fPathRendererChain = new GrPathRendererChain(fContext, fOptionsForPathRendererChain);
296     }
297 
298     GrPathRenderer* pr = fPathRendererChain->getPathRenderer(args, drawType, stencilSupport);
299     if (!pr && allowSW) {
300         if (!fSoftwarePathRenderer) {
301             fSoftwarePathRenderer =
302                     new GrSoftwarePathRenderer(fContext->resourceProvider(),
303                                                fOptionsForPathRendererChain.fAllowPathMaskCaching);
304         }
305         if (fSoftwarePathRenderer->canDrawPath(args)) {
306             pr = fSoftwarePathRenderer;
307         }
308     }
309 
310     return pr;
311 }
312 
makeRenderTargetContext(sk_sp<GrSurfaceProxy> sProxy,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,bool managedOpList)313 sk_sp<GrRenderTargetContext> GrDrawingManager::makeRenderTargetContext(
314                                                             sk_sp<GrSurfaceProxy> sProxy,
315                                                             sk_sp<SkColorSpace> colorSpace,
316                                                             const SkSurfaceProps* surfaceProps,
317                                                             bool managedOpList) {
318     if (this->wasAbandoned() || !sProxy->asRenderTargetProxy()) {
319         return nullptr;
320     }
321 
322     // SkSurface catches bad color space usage at creation. This check handles anything that slips
323     // by, including internal usage. We allow a null color space here, for read/write pixels and
324     // other special code paths. If a color space is provided, though, enforce all other rules.
325     if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
326         SkDEBUGFAIL("Invalid config and colorspace combination");
327         return nullptr;
328     }
329 
330     sk_sp<GrRenderTargetProxy> rtp(sk_ref_sp(sProxy->asRenderTargetProxy()));
331 
332     bool useDIF = false;
333     if (surfaceProps) {
334         useDIF = surfaceProps->isUseDeviceIndependentFonts();
335     }
336 
337     if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() &&
338         GrFSAAType::kNone != rtp->fsaaType()) {
339         // TODO: defer stencil buffer attachment for PathRenderingDrawContext
340         if (!rtp->instantiate(fContext->resourceProvider())) {
341             return nullptr;
342         }
343         GrRenderTarget* rt = rtp->priv().peekRenderTarget();
344 
345         GrStencilAttachment* sb = fContext->resourceProvider()->attachStencilAttachment(rt);
346         if (sb) {
347             return sk_sp<GrRenderTargetContext>(new GrPathRenderingRenderTargetContext(
348                                                         fContext, this, std::move(rtp),
349                                                         std::move(colorSpace), surfaceProps,
350                                                         fContext->getAuditTrail(), fSingleOwner));
351         }
352     }
353 
354     return sk_sp<GrRenderTargetContext>(new GrRenderTargetContext(fContext, this, std::move(rtp),
355                                                                   std::move(colorSpace),
356                                                                   surfaceProps,
357                                                                   fContext->getAuditTrail(),
358                                                                   fSingleOwner, managedOpList));
359 }
360 
makeTextureContext(sk_sp<GrSurfaceProxy> sProxy,sk_sp<SkColorSpace> colorSpace)361 sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy,
362                                                              sk_sp<SkColorSpace> colorSpace) {
363     if (this->wasAbandoned() || !sProxy->asTextureProxy()) {
364         return nullptr;
365     }
366 
367     // SkSurface catches bad color space usage at creation. This check handles anything that slips
368     // by, including internal usage. We allow a null color space here, for read/write pixels and
369     // other special code paths. If a color space is provided, though, enforce all other rules.
370     if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
371         SkDEBUGFAIL("Invalid config and colorspace combination");
372         return nullptr;
373     }
374 
375     // GrTextureRenderTargets should always be using GrRenderTargetContext
376     SkASSERT(!sProxy->asRenderTargetProxy());
377 
378     sk_sp<GrTextureProxy> textureProxy(sk_ref_sp(sProxy->asTextureProxy()));
379 
380     return sk_sp<GrTextureContext>(new GrTextureContext(fContext, this, std::move(textureProxy),
381                                                         std::move(colorSpace),
382                                                         fContext->getAuditTrail(),
383                                                         fSingleOwner));
384 }
385