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