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