• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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 "include/core/SkTraceMemoryDump.h"
9 #include "include/gpu/GrBackendSemaphore.h"
10 #include "include/gpu/GrContext.h"
11 #include "include/private/SkDeferredDisplayList.h"
12 #include "include/private/SkImageInfoPriv.h"
13 #include "src/core/SkMakeUnique.h"
14 #include "src/core/SkTaskGroup.h"
15 #include "src/gpu/GrDrawingManager.h"
16 #include "src/gpu/GrGpu.h"
17 #include "src/gpu/GrMemoryPool.h"
18 #include "src/gpu/GrPathRendererChain.h"
19 #include "src/gpu/GrProxyProvider.h"
20 #include "src/gpu/GrRenderTargetProxy.h"
21 #include "src/gpu/GrResourceCache.h"
22 #include "src/gpu/GrResourceProvider.h"
23 #include "src/gpu/GrSemaphore.h"
24 #include "src/gpu/GrShaderUtils.h"
25 #include "src/gpu/GrSoftwarePathRenderer.h"
26 #include "src/gpu/GrTracing.h"
27 #include "src/gpu/SkGr.h"
28 #include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
29 #include "src/gpu/effects/GrSkSLFP.h"
30 #include "src/gpu/text/GrTextBlobCache.h"
31 #include "src/gpu/text/GrTextContext.h"
32 #include "src/image/SkSurface_Gpu.h"
33 #include <atomic>
34 #include <unordered_map>
35 
36 #define ASSERT_OWNED_PROXY(P) \
37     SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this)
38 
39 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
40 #define ASSERT_SINGLE_OWNER \
41     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
42 #define RETURN_IF_ABANDONED if (this->abandoned()) { return; }
43 #define RETURN_FALSE_IF_ABANDONED if (this->abandoned()) { return false; }
44 #define RETURN_NULL_IF_ABANDONED if (this->abandoned()) { return nullptr; }
45 
46 ////////////////////////////////////////////////////////////////////////////////
47 
GrContext(GrBackendApi backend,const GrContextOptions & options,int32_t contextID)48 GrContext::GrContext(GrBackendApi backend, const GrContextOptions& options, int32_t contextID)
49         : INHERITED(backend, options, contextID) {
50     fResourceCache = nullptr;
51     fResourceProvider = nullptr;
52 }
53 
~GrContext()54 GrContext::~GrContext() {
55     ASSERT_SINGLE_OWNER
56 
57     if (this->drawingManager()) {
58         this->drawingManager()->cleanup();
59     }
60     delete fResourceProvider;
61     delete fResourceCache;
62 }
63 
init(sk_sp<const GrCaps> caps,sk_sp<GrSkSLFPFactoryCache> FPFactoryCache)64 bool GrContext::init(sk_sp<const GrCaps> caps, sk_sp<GrSkSLFPFactoryCache> FPFactoryCache) {
65     ASSERT_SINGLE_OWNER
66     SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes
67     SkASSERT(this->proxyProvider());
68 
69     if (!INHERITED::init(std::move(caps), std::move(FPFactoryCache))) {
70         return false;
71     }
72 
73     SkASSERT(this->caps());
74     SkASSERT(this->getGrStrikeCache());
75     SkASSERT(this->getTextBlobCache());
76 
77     if (fGpu) {
78         fResourceCache = new GrResourceCache(this->caps(), this->singleOwner(), this->contextID());
79         fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, this->singleOwner());
80     }
81 
82     if (fResourceCache) {
83         fResourceCache->setProxyProvider(this->proxyProvider());
84     }
85 
86     fDidTestPMConversions = false;
87 
88     // DDL TODO: we need to think through how the task group & persistent cache
89     // get passed on to/shared between all the DDLRecorders created with this context.
90     if (this->options().fExecutor) {
91         fTaskGroup = skstd::make_unique<SkTaskGroup>(*this->options().fExecutor);
92     }
93 
94     fPersistentCache = this->options().fPersistentCache;
95     fShaderErrorHandler = this->options().fShaderErrorHandler;
96     if (!fShaderErrorHandler) {
97         fShaderErrorHandler = GrShaderUtils::DefaultShaderErrorHandler();
98     }
99 
100     return true;
101 }
102 
threadSafeProxy()103 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
104     return fThreadSafeProxy;
105 }
106 
107 //////////////////////////////////////////////////////////////////////////////
108 
abandonContext()109 void GrContext::abandonContext() {
110     if (this->abandoned()) {
111         return;
112     }
113 
114     INHERITED::abandonContext();
115 
116     fResourceProvider->abandon();
117 
118     // Need to cleanup the drawing manager first so all the render targets
119     // will be released/forgotten before they too are abandoned.
120     this->drawingManager()->cleanup();
121 
122     // abandon first to so destructors
123     // don't try to free the resources in the API.
124     fResourceCache->abandonAll();
125 
126     fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
127 }
128 
releaseResourcesAndAbandonContext()129 void GrContext::releaseResourcesAndAbandonContext() {
130     if (this->abandoned()) {
131         return;
132     }
133 
134     INHERITED::abandonContext();
135 
136     fResourceProvider->abandon();
137 
138     // Need to cleanup the drawing manager first so all the render targets
139     // will be released/forgotten before they too are abandoned.
140     this->drawingManager()->cleanup();
141 
142     // Release all resources in the backend 3D API.
143     fResourceCache->releaseAll();
144 
145     fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
146 }
147 
resetGLTextureBindings()148 void GrContext::resetGLTextureBindings() {
149     if (this->abandoned() || this->backend() != GrBackendApi::kOpenGL) {
150         return;
151     }
152     fGpu->resetTextureBindings();
153 }
154 
resetContext(uint32_t state)155 void GrContext::resetContext(uint32_t state) {
156     ASSERT_SINGLE_OWNER
157     fGpu->markContextDirty(state);
158 }
159 
freeGpuResources()160 void GrContext::freeGpuResources() {
161     ASSERT_SINGLE_OWNER
162 
163     // TODO: the glyph cache doesn't hold any GpuResources so this call should not be needed here.
164     // Some slack in the GrTextBlob's implementation requires it though. That could be fixed.
165     this->getGrStrikeCache()->freeAll();
166 
167     this->drawingManager()->freeGpuResources();
168 
169     fResourceCache->purgeAllUnlocked();
170 }
171 
purgeUnlockedResources(bool scratchResourcesOnly)172 void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) {
173     ASSERT_SINGLE_OWNER
174     fResourceCache->purgeUnlockedResources(scratchResourcesOnly);
175     fResourceCache->purgeAsNeeded();
176 
177     // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
178     // place to purge stale blobs
179     this->getTextBlobCache()->purgeStaleBlobs();
180 }
181 
purgeUnlockedResourcesByTag(bool scratchResourcesOnly,const GrGpuResourceTag tag)182 void GrContext::purgeUnlockedResourcesByTag(bool scratchResourcesOnly, const GrGpuResourceTag tag) {
183     ASSERT_SINGLE_OWNER
184     fResourceCache->purgeUnlockedResourcesByTag(scratchResourcesOnly, tag);
185     fResourceCache->purgeAsNeeded();
186 
187     // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
188     // place to purge stale blobs
189     this->getTextBlobCache()->purgeStaleBlobs();
190 }
191 
performDeferredCleanup(std::chrono::milliseconds msNotUsed)192 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
193     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
194 
195     ASSERT_SINGLE_OWNER
196 
197     auto purgeTime = GrStdSteadyClock::now() - msNotUsed;
198 
199     fResourceCache->purgeAsNeeded();
200     fResourceCache->purgeResourcesNotUsedSince(purgeTime);
201 
202     if (auto ccpr = this->drawingManager()->getCoverageCountingPathRenderer()) {
203         ccpr->purgeCacheEntriesOlderThan(this->proxyProvider(), purgeTime);
204     }
205 
206     // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
207     // place to purge stale blobs
208     this->getTextBlobCache()->purgeStaleBlobs();
209 }
210 
purgeUnlockedResources(size_t bytesToPurge,bool preferScratchResources)211 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
212     ASSERT_SINGLE_OWNER
213     fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
214 }
215 
getResourceCacheUsage(int * resourceCount,size_t * resourceBytes) const216 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
217     ASSERT_SINGLE_OWNER
218 
219     if (resourceCount) {
220         *resourceCount = fResourceCache->getBudgetedResourceCount();
221     }
222     if (resourceBytes) {
223         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
224     }
225 }
226 
getResourceCachePurgeableBytes() const227 size_t GrContext::getResourceCachePurgeableBytes() const {
228     ASSERT_SINGLE_OWNER
229     return fResourceCache->getPurgeableBytes();
230 }
231 
ComputeTextureSize(SkColorType type,int width,int height,GrMipMapped mipMapped,bool useNextPow2)232 size_t GrContext::ComputeTextureSize(SkColorType type, int width, int height, GrMipMapped mipMapped,
233                                      bool useNextPow2) {
234     int colorSamplesPerPixel = 1;
235     return GrSurface::ComputeSize(SkColorType2GrPixelConfig(type), width, height,
236                                   colorSamplesPerPixel, mipMapped, useNextPow2);
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 
maxTextureSize() const241 int GrContext::maxTextureSize() const { return this->caps()->maxTextureSize(); }
242 
maxRenderTargetSize() const243 int GrContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); }
244 
colorTypeSupportedAsImage(SkColorType colorType) const245 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
246     GrBackendFormat format =
247             this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType),
248                                                   GrRenderable::kNo);
249     return format.isValid();
250 }
251 
maxSurfaceSampleCountForColorType(SkColorType colorType) const252 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
253     GrBackendFormat format =
254             this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType),
255                                                   GrRenderable::kYes);
256     return this->caps()->maxRenderTargetSampleCount(format);
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 
wait(int numSemaphores,const GrBackendSemaphore waitSemaphores[])261 bool GrContext::wait(int numSemaphores, const GrBackendSemaphore waitSemaphores[]) {
262     if (!fGpu || fGpu->caps()->semaphoreSupport()) {
263         return false;
264     }
265     for (int i = 0; i < numSemaphores; ++i) {
266         sk_sp<GrSemaphore> sema = fResourceProvider->wrapBackendSemaphore(
267                 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
268                 kAdopt_GrWrapOwnership);
269         fGpu->waitSemaphore(std::move(sema));
270     }
271     return true;
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 
flush(const GrFlushInfo & info,const GrPrepareForExternalIORequests & externalRequests)276 GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info,
277                                        const GrPrepareForExternalIORequests& externalRequests) {
278     ASSERT_SINGLE_OWNER
279     if (this->abandoned()) {
280         return GrSemaphoresSubmitted::kNo;
281     }
282 
283     return this->drawingManager()->flush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess,
284                                          info, externalRequests);
285 }
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 
checkAsyncWorkCompletion()289 void GrContext::checkAsyncWorkCompletion() {
290     if (fGpu) {
291         fGpu->checkFinishProcs();
292     }
293 }
294 
295 ////////////////////////////////////////////////////////////////////////////////
296 
storeVkPipelineCacheData()297 void GrContext::storeVkPipelineCacheData() {
298     if (fGpu) {
299         fGpu->storeVkPipelineCacheData();
300     }
301 }
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 
supportsDistanceFieldText() const305 bool GrContext::supportsDistanceFieldText() const {
306     return this->caps()->shaderCaps()->supportsDistanceFieldText();
307 }
308 
309 //////////////////////////////////////////////////////////////////////////////
310 
311 // DDL TODO: remove 'maxResources'
getResourceCacheLimits(int * maxResources,size_t * maxResourceBytes) const312 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
313     ASSERT_SINGLE_OWNER
314     if (maxResources) {
315         *maxResources = fResourceCache->getMaxResourceCount();
316     }
317     if (maxResourceBytes) {
318         *maxResourceBytes = fResourceCache->getMaxResourceBytes();
319     }
320 }
321 
setResourceCacheLimits(int maxResources,size_t maxResourceBytes)322 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
323     ASSERT_SINGLE_OWNER
324     fResourceCache->setLimits(maxResources, maxResourceBytes);
325 }
326 
setCurrentGrResourceTag(const GrGpuResourceTag tag)327 void GrContext::setCurrentGrResourceTag(const GrGpuResourceTag tag) {
328     if (fResourceCache) {
329         fResourceCache->setCurrentGrResourceTag(tag);
330     }
331 }
332 
getCurrentGrResourceTag() const333 GrGpuResourceTag GrContext::getCurrentGrResourceTag() const {
334     if (fResourceCache) {
335         return fResourceCache->getCurrentGrResourceTag();
336     }
337     return {};
338 }
339 
releaseByTag(const GrGpuResourceTag tag)340 void GrContext::releaseByTag(const GrGpuResourceTag tag) {
341     if (fResourceCache) {
342         fResourceCache->releaseByTag(tag);
343     }
344 }
345 
346 //////////////////////////////////////////////////////////////////////////////
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const347 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
348     ASSERT_SINGLE_OWNER
349     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
350     traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache", "size", "bytes",
351                                       this->getTextBlobCache()->usedBytes());
352 }
353 
dumpMemoryStatisticsByTag(SkTraceMemoryDump * traceMemoryDump,GrGpuResourceTag tag) const354 void GrContext::dumpMemoryStatisticsByTag(SkTraceMemoryDump* traceMemoryDump, GrGpuResourceTag tag) const {
355     ASSERT_SINGLE_OWNER
356     fResourceCache->dumpMemoryStatistics(traceMemoryDump, tag);
357     traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache", "size", "bytes",
358         this->getTextBlobCache()->usedBytes());
359 }
360 
361 //////////////////////////////////////////////////////////////////////////////
createBackendTexture(int width,int height,const GrBackendFormat & backendFormat,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)362 GrBackendTexture GrContext::createBackendTexture(int width, int height,
363                                                  const GrBackendFormat& backendFormat,
364                                                  GrMipMapped mipMapped,
365                                                  GrRenderable renderable,
366                                                  GrProtected isProtected) {
367     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
368     if (!this->asDirectContext()) {
369         return GrBackendTexture();
370     }
371 
372     if (this->abandoned()) {
373         return GrBackendTexture();
374     }
375 
376     if (!backendFormat.isValid()) {
377         return GrBackendTexture();
378     }
379 
380     return fGpu->createBackendTexture(width, height, backendFormat,
381                                       mipMapped, renderable,
382                                       nullptr, 0, nullptr, isProtected);
383 }
384 
createBackendTexture(int width,int height,SkColorType skColorType,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)385 GrBackendTexture GrContext::createBackendTexture(int width, int height,
386                                                  SkColorType skColorType,
387                                                  GrMipMapped mipMapped,
388                                                  GrRenderable renderable,
389                                                  GrProtected isProtected) {
390     if (!this->asDirectContext()) {
391         return GrBackendTexture();
392     }
393 
394     if (this->abandoned()) {
395         return GrBackendTexture();
396     }
397 
398     const GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable);
399     if (!format.isValid()) {
400         return GrBackendTexture();
401     }
402 
403     return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected);
404 }
405 
createBackendTexture(const SkSurfaceCharacterization & c)406 GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c) {
407     const GrCaps* caps = this->caps();
408 
409     if (!this->asDirectContext() || !c.isValid()) {
410         return GrBackendTexture();
411     }
412 
413     if (this->abandoned()) {
414         return GrBackendTexture();
415     }
416 
417     if (c.usesGLFBO0()) {
418         // If we are making the surface we will never use FBO0.
419         return GrBackendTexture();
420     }
421 
422     if (c.vulkanSecondaryCBCompatible()) {
423         return {};
424     }
425 
426     const GrBackendFormat format = this->defaultBackendFormat(c.colorType(), GrRenderable::kYes);
427     if (!format.isValid()) {
428         return GrBackendTexture();
429     }
430 
431     if (!SkSurface_Gpu::Valid(caps, format)) {
432         return GrBackendTexture();
433     }
434 
435     GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format,
436                                                          GrMipMapped(c.isMipMapped()),
437                                                          GrRenderable::kYes,
438                                                          c.isProtected());
439     SkASSERT(c.isCompatible(result));
440     return result;
441 }
442 
createBackendTexture(const SkSurfaceCharacterization & c,const SkColor4f & color)443 GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c,
444                                                  const SkColor4f& color) {
445     if (!this->asDirectContext() || !c.isValid()) {
446         return GrBackendTexture();
447     }
448 
449     if (this->abandoned()) {
450         return GrBackendTexture();
451     }
452 
453     if (c.usesGLFBO0()) {
454         // If we are making the surface we will never use FBO0.
455         return GrBackendTexture();
456     }
457 
458     if (c.vulkanSecondaryCBCompatible()) {
459         return {};
460     }
461 
462     const GrBackendFormat format = this->defaultBackendFormat(c.colorType(), GrRenderable::kYes);
463     if (!format.isValid()) {
464         return GrBackendTexture();
465     }
466 
467     if (!SkSurface_Gpu::Valid(this->caps(), format)) {
468         return GrBackendTexture();
469     }
470 
471     GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format, color,
472                                                          GrMipMapped(c.isMipMapped()),
473                                                          GrRenderable::kYes,
474                                                          c.isProtected());
475     SkASSERT(c.isCompatible(result));
476     return result;
477 }
478 
createBackendTexture(int width,int height,const GrBackendFormat & backendFormat,const SkColor4f & color,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)479 GrBackendTexture GrContext::createBackendTexture(int width, int height,
480                                                  const GrBackendFormat& backendFormat,
481                                                  const SkColor4f& color,
482                                                  GrMipMapped mipMapped,
483                                                  GrRenderable renderable,
484                                                  GrProtected isProtected) {
485     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
486     if (!this->asDirectContext()) {
487         return GrBackendTexture();
488     }
489 
490     if (this->abandoned()) {
491         return GrBackendTexture();
492     }
493 
494     if (!backendFormat.isValid()) {
495         return GrBackendTexture();
496     }
497 
498     return fGpu->createBackendTexture(width, height, backendFormat,
499                                       mipMapped, renderable,
500                                       nullptr, 0, &color, isProtected);
501 }
502 
createBackendTexture(int width,int height,SkColorType skColorType,const SkColor4f & color,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)503 GrBackendTexture GrContext::createBackendTexture(int width, int height,
504                                                  SkColorType skColorType,
505                                                  const SkColor4f& color,
506                                                  GrMipMapped mipMapped,
507                                                  GrRenderable renderable,
508                                                  GrProtected isProtected) {
509     if (!this->asDirectContext()) {
510         return GrBackendTexture();
511     }
512 
513     if (this->abandoned()) {
514         return GrBackendTexture();
515     }
516 
517     GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable);
518     if (!format.isValid()) {
519         return GrBackendTexture();
520     }
521 
522     GrColorType grColorType = SkColorTypeToGrColorType(skColorType);
523     SkColor4f swizzledColor = this->caps()->getOutputSwizzle(format, grColorType).applyTo(color);
524 
525     return this->createBackendTexture(width, height, format, swizzledColor, mipMapped, renderable,
526                                       isProtected);
527 }
528 
deleteBackendTexture(GrBackendTexture backendTex)529 void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {
530     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
531     if (this->abandoned() || !backendTex.isValid()) {
532         return;
533     }
534 
535     fGpu->deleteBackendTexture(backendTex);
536 }
537 
538 #ifdef SK_ENABLE_DUMP_GPU
539 #include "src/utils/SkJSONWriter.h"
dump() const540 SkString GrContext::dump() const {
541     SkDynamicMemoryWStream stream;
542     SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
543     writer.beginObject();
544 
545     writer.appendString("backend", GrBackendApiToStr(this->backend()));
546 
547     writer.appendName("caps");
548     this->caps()->dumpJSON(&writer);
549 
550     writer.appendName("gpu");
551     this->fGpu->dumpJSON(&writer);
552 
553     // Flush JSON to the memory stream
554     writer.endObject();
555     writer.flush();
556 
557     // Null terminate the JSON data in the memory stream
558     stream.write8(0);
559 
560     // Allocate a string big enough to hold all the data, then copy out of the stream
561     SkString result(stream.bytesWritten());
562     stream.copyToAndReset(result.writable_str());
563     return result;
564 }
565 #endif
566