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