• 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 
performDeferredCleanup(std::chrono::milliseconds msNotUsed)182 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
183     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
184 
185     ASSERT_SINGLE_OWNER
186 
187     auto purgeTime = GrStdSteadyClock::now() - msNotUsed;
188 
189     fResourceCache->purgeAsNeeded();
190     fResourceCache->purgeResourcesNotUsedSince(purgeTime);
191 
192     if (auto ccpr = this->drawingManager()->getCoverageCountingPathRenderer()) {
193         ccpr->purgeCacheEntriesOlderThan(this->proxyProvider(), purgeTime);
194     }
195 
196     // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
197     // place to purge stale blobs
198     this->getTextBlobCache()->purgeStaleBlobs();
199 }
200 
purgeUnlockedResources(size_t bytesToPurge,bool preferScratchResources)201 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
202     ASSERT_SINGLE_OWNER
203     fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
204 }
205 
getResourceCacheUsage(int * resourceCount,size_t * resourceBytes) const206 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
207     ASSERT_SINGLE_OWNER
208 
209     if (resourceCount) {
210         *resourceCount = fResourceCache->getBudgetedResourceCount();
211     }
212     if (resourceBytes) {
213         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
214     }
215 }
216 
getResourceCachePurgeableBytes() const217 size_t GrContext::getResourceCachePurgeableBytes() const {
218     ASSERT_SINGLE_OWNER
219     return fResourceCache->getPurgeableBytes();
220 }
221 
ComputeTextureSize(SkColorType type,int width,int height,GrMipMapped mipMapped,bool useNextPow2)222 size_t GrContext::ComputeTextureSize(SkColorType type, int width, int height, GrMipMapped mipMapped,
223                                      bool useNextPow2) {
224     int colorSamplesPerPixel = 1;
225     return GrSurface::ComputeSize(SkColorType2GrPixelConfig(type), width, height,
226                                   colorSamplesPerPixel, mipMapped, useNextPow2);
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 
maxTextureSize() const231 int GrContext::maxTextureSize() const { return this->caps()->maxTextureSize(); }
232 
maxRenderTargetSize() const233 int GrContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); }
234 
colorTypeSupportedAsImage(SkColorType colorType) const235 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
236     GrBackendFormat format =
237             this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType),
238                                                   GrRenderable::kNo);
239     return format.isValid();
240 }
241 
maxSurfaceSampleCountForColorType(SkColorType colorType) const242 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
243     GrBackendFormat format =
244             this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType),
245                                                   GrRenderable::kYes);
246     return this->caps()->maxRenderTargetSampleCount(format);
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 
wait(int numSemaphores,const GrBackendSemaphore waitSemaphores[])251 bool GrContext::wait(int numSemaphores, const GrBackendSemaphore waitSemaphores[]) {
252     if (!fGpu || fGpu->caps()->semaphoreSupport()) {
253         return false;
254     }
255     for (int i = 0; i < numSemaphores; ++i) {
256         sk_sp<GrSemaphore> sema = fResourceProvider->wrapBackendSemaphore(
257                 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
258                 kAdopt_GrWrapOwnership);
259         fGpu->waitSemaphore(std::move(sema));
260     }
261     return true;
262 }
263 
264 ////////////////////////////////////////////////////////////////////////////////
265 
flush(const GrFlushInfo & info,const GrPrepareForExternalIORequests & externalRequests)266 GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info,
267                                        const GrPrepareForExternalIORequests& externalRequests) {
268     ASSERT_SINGLE_OWNER
269     if (this->abandoned()) {
270         return GrSemaphoresSubmitted::kNo;
271     }
272 
273     return this->drawingManager()->flush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess,
274                                          info, externalRequests);
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 
checkAsyncWorkCompletion()279 void GrContext::checkAsyncWorkCompletion() {
280     if (fGpu) {
281         fGpu->checkFinishProcs();
282     }
283 }
284 
285 ////////////////////////////////////////////////////////////////////////////////
286 
storeVkPipelineCacheData()287 void GrContext::storeVkPipelineCacheData() {
288     if (fGpu) {
289         fGpu->storeVkPipelineCacheData();
290     }
291 }
292 
293 ////////////////////////////////////////////////////////////////////////////////
294 
supportsDistanceFieldText() const295 bool GrContext::supportsDistanceFieldText() const {
296     return this->caps()->shaderCaps()->supportsDistanceFieldText();
297 }
298 
299 //////////////////////////////////////////////////////////////////////////////
300 
301 // DDL TODO: remove 'maxResources'
getResourceCacheLimits(int * maxResources,size_t * maxResourceBytes) const302 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
303     ASSERT_SINGLE_OWNER
304     if (maxResources) {
305         *maxResources = fResourceCache->getMaxResourceCount();
306     }
307     if (maxResourceBytes) {
308         *maxResourceBytes = fResourceCache->getMaxResourceBytes();
309     }
310 }
311 
setResourceCacheLimits(int maxResources,size_t maxResourceBytes)312 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
313     ASSERT_SINGLE_OWNER
314     fResourceCache->setLimits(maxResources, maxResourceBytes);
315 }
316 
317 //////////////////////////////////////////////////////////////////////////////
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const318 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
319     ASSERT_SINGLE_OWNER
320     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
321     traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache", "size", "bytes",
322                                       this->getTextBlobCache()->usedBytes());
323 }
324 
325 //////////////////////////////////////////////////////////////////////////////
createBackendTexture(int width,int height,const GrBackendFormat & backendFormat,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)326 GrBackendTexture GrContext::createBackendTexture(int width, int height,
327                                                  const GrBackendFormat& backendFormat,
328                                                  GrMipMapped mipMapped,
329                                                  GrRenderable renderable,
330                                                  GrProtected isProtected) {
331     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
332     if (!this->asDirectContext()) {
333         return GrBackendTexture();
334     }
335 
336     if (this->abandoned()) {
337         return GrBackendTexture();
338     }
339 
340     if (!backendFormat.isValid()) {
341         return GrBackendTexture();
342     }
343 
344     return fGpu->createBackendTexture(width, height, backendFormat,
345                                       mipMapped, renderable,
346                                       nullptr, 0, nullptr, isProtected);
347 }
348 
createBackendTexture(int width,int height,SkColorType skColorType,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)349 GrBackendTexture GrContext::createBackendTexture(int width, int height,
350                                                  SkColorType skColorType,
351                                                  GrMipMapped mipMapped,
352                                                  GrRenderable renderable,
353                                                  GrProtected isProtected) {
354     if (!this->asDirectContext()) {
355         return GrBackendTexture();
356     }
357 
358     if (this->abandoned()) {
359         return GrBackendTexture();
360     }
361 
362     const GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable);
363     if (!format.isValid()) {
364         return GrBackendTexture();
365     }
366 
367     return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected);
368 }
369 
createBackendTexture(const SkSurfaceCharacterization & c)370 GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c) {
371     const GrCaps* caps = this->caps();
372 
373     if (!this->asDirectContext() || !c.isValid()) {
374         return GrBackendTexture();
375     }
376 
377     if (this->abandoned()) {
378         return GrBackendTexture();
379     }
380 
381     if (c.usesGLFBO0()) {
382         // If we are making the surface we will never use FBO0.
383         return GrBackendTexture();
384     }
385 
386     if (c.vulkanSecondaryCBCompatible()) {
387         return {};
388     }
389 
390     const GrBackendFormat format = this->defaultBackendFormat(c.colorType(), GrRenderable::kYes);
391     if (!format.isValid()) {
392         return GrBackendTexture();
393     }
394 
395     if (!SkSurface_Gpu::Valid(caps, format)) {
396         return GrBackendTexture();
397     }
398 
399     GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format,
400                                                          GrMipMapped(c.isMipMapped()),
401                                                          GrRenderable::kYes,
402                                                          c.isProtected());
403     SkASSERT(c.isCompatible(result));
404     return result;
405 }
406 
createBackendTexture(const SkSurfaceCharacterization & c,const SkColor4f & color)407 GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c,
408                                                  const SkColor4f& color) {
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(this->caps(), format)) {
432         return GrBackendTexture();
433     }
434 
435     GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format, color,
436                                                          GrMipMapped(c.isMipMapped()),
437                                                          GrRenderable::kYes,
438                                                          c.isProtected());
439     SkASSERT(c.isCompatible(result));
440     return result;
441 }
442 
createBackendTexture(int width,int height,const GrBackendFormat & backendFormat,const SkColor4f & color,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)443 GrBackendTexture GrContext::createBackendTexture(int width, int height,
444                                                  const GrBackendFormat& backendFormat,
445                                                  const SkColor4f& color,
446                                                  GrMipMapped mipMapped,
447                                                  GrRenderable renderable,
448                                                  GrProtected isProtected) {
449     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
450     if (!this->asDirectContext()) {
451         return GrBackendTexture();
452     }
453 
454     if (this->abandoned()) {
455         return GrBackendTexture();
456     }
457 
458     if (!backendFormat.isValid()) {
459         return GrBackendTexture();
460     }
461 
462     return fGpu->createBackendTexture(width, height, backendFormat,
463                                       mipMapped, renderable,
464                                       nullptr, 0, &color, isProtected);
465 }
466 
createBackendTexture(int width,int height,SkColorType skColorType,const SkColor4f & color,GrMipMapped mipMapped,GrRenderable renderable,GrProtected isProtected)467 GrBackendTexture GrContext::createBackendTexture(int width, int height,
468                                                  SkColorType skColorType,
469                                                  const SkColor4f& color,
470                                                  GrMipMapped mipMapped,
471                                                  GrRenderable renderable,
472                                                  GrProtected isProtected) {
473     if (!this->asDirectContext()) {
474         return GrBackendTexture();
475     }
476 
477     if (this->abandoned()) {
478         return GrBackendTexture();
479     }
480 
481     GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable);
482     if (!format.isValid()) {
483         return GrBackendTexture();
484     }
485 
486     GrColorType grColorType = SkColorTypeToGrColorType(skColorType);
487     SkColor4f swizzledColor = this->caps()->getOutputSwizzle(format, grColorType).applyTo(color);
488 
489     return this->createBackendTexture(width, height, format, swizzledColor, mipMapped, renderable,
490                                       isProtected);
491 }
492 
deleteBackendTexture(GrBackendTexture backendTex)493 void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {
494     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
495     if (this->abandoned() || !backendTex.isValid()) {
496         return;
497     }
498 
499     fGpu->deleteBackendTexture(backendTex);
500 }
501 
502 #ifdef SK_ENABLE_DUMP_GPU
503 #include "src/utils/SkJSONWriter.h"
dump() const504 SkString GrContext::dump() const {
505     SkDynamicMemoryWStream stream;
506     SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
507     writer.beginObject();
508 
509     writer.appendString("backend", GrBackendApiToStr(this->backend()));
510 
511     writer.appendName("caps");
512     this->caps()->dumpJSON(&writer);
513 
514     writer.appendName("gpu");
515     this->fGpu->dumpJSON(&writer);
516 
517     // Flush JSON to the memory stream
518     writer.endObject();
519     writer.flush();
520 
521     // Null terminate the JSON data in the memory stream
522     stream.write8(0);
523 
524     // Allocate a string big enough to hold all the data, then copy out of the stream
525     SkString result(stream.bytesWritten());
526     stream.copyToAndReset(result.writable_str());
527     return result;
528 }
529 #endif
530