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