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/GrDirectContext.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/GrSDFTOptions.h" |
34 | #include "src/gpu/text/GrStrikeCache.h" |
35 | #include "src/gpu/text/GrTextBlobCache.h" |
36 | #include "src/image/SkImage_GpuBase.h" |
37 | #include "src/image/SkSurface_Gpu.h" |
38 | #include <atomic> |
39 | #include <memory> |
40 | |
41 | #define ASSERT_OWNED_PROXY(P) \ |
42 | SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this) |
43 | |
44 | #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) |
45 | #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(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(sk_sp<GrContextThreadSafeProxy> proxy) : INHERITED(std::move(proxy)) { |
53 | fResourceCache = nullptr; |
54 | fResourceProvider = nullptr; |
55 | } |
56 | |
57 | GrContext::~GrContext() { |
58 | ASSERT_SINGLE_OWNER |
59 | |
60 | this->destroyDrawingManager(); |
61 | fMappedBufferManager.reset(); |
62 | delete fResourceProvider; |
63 | delete fResourceCache; |
64 | } |
65 | |
66 | bool GrContext::init() { |
67 | ASSERT_SINGLE_OWNER |
68 | SkASSERT(this->proxyProvider()); |
69 | |
70 | if (!INHERITED::init()) { |
71 | return false; |
72 | } |
73 | |
74 | SkASSERT(this->getTextBlobCache()); |
75 | |
76 | if (fGpu) { |
77 | fStrikeCache = std::make_unique<GrStrikeCache>(); |
78 | fResourceCache = new GrResourceCache(this->caps(), this->singleOwner(), this->contextID()); |
79 | fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, this->singleOwner()); |
80 | fMappedBufferManager = std::make_unique<GrClientMappedBufferManager>(this->contextID()); |
81 | } |
82 | |
83 | if (fResourceCache) { |
84 | fResourceCache->setProxyProvider(this->proxyProvider()); |
85 | } |
86 | |
87 | fDidTestPMConversions = false; |
88 | |
89 | // DDL TODO: we need to think through how the task group & persistent cache |
90 | // get passed on to/shared between all the DDLRecorders created with this context. |
91 | if (this->options().fExecutor) { |
92 | fTaskGroup = std::make_unique<SkTaskGroup>(*this->options().fExecutor); |
93 | } |
94 | |
95 | fPersistentCache = this->options().fPersistentCache; |
96 | fShaderErrorHandler = this->options().fShaderErrorHandler; |
97 | if (!fShaderErrorHandler) { |
98 | fShaderErrorHandler = GrShaderUtils::DefaultShaderErrorHandler(); |
99 | } |
100 | |
101 | return true; |
102 | } |
103 | |
104 | sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { |
105 | return INHERITED::threadSafeProxy(); |
106 | } |
107 | |
108 | ////////////////////////////////////////////////////////////////////////////// |
109 | |
110 | void GrContext::abandonContext() { |
111 | if (INHERITED::abandoned()) { |
112 | return; |
113 | } |
114 | |
115 | INHERITED::abandonContext(); |
116 | |
117 | fStrikeCache->freeAll(); |
118 | |
119 | fMappedBufferManager->abandon(); |
120 | |
121 | fResourceProvider->abandon(); |
122 | |
123 | // abandon first to so destructors |
124 | // don't try to free the resources in the API. |
125 | fResourceCache->abandonAll(); |
126 | |
127 | fGpu->disconnect(GrGpu::DisconnectType::kAbandon); |
128 | |
129 | fMappedBufferManager.reset(); |
130 | } |
131 | |
132 | void GrContext::releaseResourcesAndAbandonContext() { |
133 | if (INHERITED::abandoned()) { |
134 | return; |
135 | } |
136 | |
137 | INHERITED::abandonContext(); |
138 | |
139 | fMappedBufferManager.reset(); |
140 | |
141 | fResourceProvider->abandon(); |
142 | |
143 | // Release all resources in the backend 3D API. |
144 | fResourceCache->releaseAll(); |
145 | |
146 | fGpu->disconnect(GrGpu::DisconnectType::kCleanup); |
147 | } |
148 | |
149 | bool GrContext::abandoned() { |
150 | if (INHERITED::abandoned()) { |
151 | return true; |
152 | } |
153 | |
154 | if (fGpu && fGpu->isDeviceLost()) { |
155 | this->abandonContext(); |
156 | return true; |
157 | } |
158 | return false; |
159 | } |
160 | |
161 | bool GrContext::oomed() { return fGpu ? fGpu->checkAndResetOOMed() : false; } |
162 | |
163 | void GrContext::resetGLTextureBindings() { |
164 | if (this->abandoned() || this->backend() != GrBackendApi::kOpenGL) { |
165 | return; |
166 | } |
167 | fGpu->resetTextureBindings(); |
168 | } |
169 | |
170 | void GrContext::resetContext(uint32_t state) { |
171 | ASSERT_SINGLE_OWNER |
172 | fGpu->markContextDirty(state); |
173 | } |
174 | |
175 | void GrContext::freeGpuResources() { |
176 | ASSERT_SINGLE_OWNER |
177 | |
178 | if (this->abandoned()) { |
179 | return; |
180 | } |
181 | |
182 | // TODO: the glyph cache doesn't hold any GpuResources so this call should not be needed here. |
183 | // Some slack in the GrTextBlob's implementation requires it though. That could be fixed. |
184 | fStrikeCache->freeAll(); |
185 | |
186 | this->drawingManager()->freeGpuResources(); |
187 | |
188 | fResourceCache->purgeAllUnlocked(); |
189 | } |
190 | |
191 | void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) { |
192 | ASSERT_SINGLE_OWNER |
193 | |
194 | if (this->abandoned()) { |
195 | return; |
196 | } |
197 | |
198 | fResourceCache->purgeUnlockedResources(scratchResourcesOnly); |
199 | fResourceCache->purgeAsNeeded(); |
200 | |
201 | // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient |
202 | // place to purge stale blobs |
203 | this->getTextBlobCache()->purgeStaleBlobs(); |
204 | } |
205 | |
206 | void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) { |
207 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
208 | |
209 | ASSERT_SINGLE_OWNER |
210 | |
211 | if (this->abandoned()) { |
212 | return; |
213 | } |
214 | |
215 | fMappedBufferManager->process(); |
216 | auto purgeTime = GrStdSteadyClock::now() - msNotUsed; |
217 | |
218 | fResourceCache->purgeAsNeeded(); |
219 | fResourceCache->purgeResourcesNotUsedSince(purgeTime); |
220 | |
221 | if (auto ccpr = this->drawingManager()->getCoverageCountingPathRenderer()) { |
222 | ccpr->purgeCacheEntriesOlderThan(this->proxyProvider(), purgeTime); |
223 | } |
224 | |
225 | // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient |
226 | // place to purge stale blobs |
227 | this->getTextBlobCache()->purgeStaleBlobs(); |
228 | } |
229 | |
230 | void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) { |
231 | ASSERT_SINGLE_OWNER |
232 | |
233 | if (this->abandoned()) { |
234 | return; |
235 | } |
236 | |
237 | fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources); |
238 | } |
239 | |
240 | void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { |
241 | ASSERT_SINGLE_OWNER |
242 | |
243 | if (resourceCount) { |
244 | *resourceCount = fResourceCache->getBudgetedResourceCount(); |
245 | } |
246 | if (resourceBytes) { |
247 | *resourceBytes = fResourceCache->getBudgetedResourceBytes(); |
248 | } |
249 | } |
250 | |
251 | size_t GrContext::getResourceCachePurgeableBytes() const { |
252 | ASSERT_SINGLE_OWNER |
253 | return fResourceCache->getPurgeableBytes(); |
254 | } |
255 | |
256 | size_t GrContext::ComputeImageSize(sk_sp<SkImage> image, GrMipmapped mipMapped, bool useNextPow2) { |
257 | if (!image->isTextureBacked()) { |
258 | return 0; |
259 | } |
260 | SkImage_GpuBase* gpuImage = static_cast<SkImage_GpuBase*>(as_IB(image.get())); |
261 | GrTextureProxy* proxy = gpuImage->peekProxy(); |
262 | if (!proxy) { |
263 | return 0; |
264 | } |
265 | |
266 | const GrCaps& caps = *gpuImage->context()->priv().caps(); |
267 | int colorSamplesPerPixel = 1; |
268 | return GrSurface::ComputeSize(caps, proxy->backendFormat(), image->dimensions(), |
269 | colorSamplesPerPixel, mipMapped, useNextPow2); |
270 | } |
271 | |
272 | //////////////////////////////////////////////////////////////////////////////// |
273 | |
274 | int GrContext::maxTextureSize() const { return this->caps()->maxTextureSize(); } |
275 | |
276 | int GrContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); } |
277 | |
278 | bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const { |
279 | GrBackendFormat format = |
280 | this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType), |
281 | GrRenderable::kNo); |
282 | return format.isValid(); |
283 | } |
284 | |
285 | //////////////////////////////////////////////////////////////////////////////// |
286 | |
287 | bool GrContext::wait(int numSemaphores, const GrBackendSemaphore waitSemaphores[], |
288 | bool deleteSemaphoresAfterWait) { |
289 | if (!fGpu || fGpu->caps()->semaphoreSupport()) { |
290 | return false; |
291 | } |
292 | GrWrapOwnership ownership = |
293 | deleteSemaphoresAfterWait ? kAdopt_GrWrapOwnership : kBorrow_GrWrapOwnership; |
294 | for (int i = 0; i < numSemaphores; ++i) { |
295 | std::unique_ptr<GrSemaphore> sema = fResourceProvider->wrapBackendSemaphore( |
296 | waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait, ownership); |
297 | // If we failed to wrap the semaphore it means the client didn't give us a valid semaphore |
298 | // to begin with. Therefore, it is fine to not wait on it. |
299 | if (sema) { |
300 | fGpu->waitSemaphore(sema.get()); |
301 | } |
302 | } |
303 | return true; |
304 | } |
305 | |
306 | //////////////////////////////////////////////////////////////////////////////// |
307 | |
308 | GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info) { |
309 | ASSERT_SINGLE_OWNER |
310 | if (this->abandoned()) { |
311 | if (info.fFinishedProc) { |
312 | info.fFinishedProc(info.fFinishedContext); |
313 | } |
314 | if (info.fSubmittedProc) { |
315 | info.fSubmittedProc(info.fSubmittedContext, false); |
316 | } |
317 | return GrSemaphoresSubmitted::kNo; |
318 | } |
319 | |
320 | bool flushed = this->drawingManager()->flush( |
321 | nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, info, nullptr); |
322 | |
323 | if (!flushed || (!this->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) { |
324 | return GrSemaphoresSubmitted::kNo; |
325 | } |
326 | return GrSemaphoresSubmitted::kYes; |
327 | } |
328 | |
329 | bool GrContext::submit(bool syncCpu) { |
330 | ASSERT_SINGLE_OWNER |
331 | if (this->abandoned()) { |
332 | return false; |
333 | } |
334 | |
335 | if (!fGpu) { |
336 | return false; |
337 | } |
338 | |
339 | return fGpu->submitToGpu(syncCpu); |
340 | } |
341 | |
342 | //////////////////////////////////////////////////////////////////////////////// |
343 | |
344 | void GrContext::checkAsyncWorkCompletion() { |
345 | if (fGpu) { |
346 | fGpu->checkFinishProcs(); |
347 | } |
348 | } |
349 | |
350 | //////////////////////////////////////////////////////////////////////////////// |
351 | |
352 | void GrContext::storeVkPipelineCacheData() { |
353 | if (fGpu) { |
354 | fGpu->storeVkPipelineCacheData(); |
355 | } |
356 | } |
357 | |
358 | //////////////////////////////////////////////////////////////////////////////// |
359 | |
360 | bool GrContext::supportsDistanceFieldText() const { |
361 | return this->caps()->shaderCaps()->supportsDistanceFieldText(); |
362 | } |
363 | |
364 | ////////////////////////////////////////////////////////////////////////////// |
365 | |
366 | void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const { |
367 | ASSERT_SINGLE_OWNER |
368 | if (maxResources) { |
369 | *maxResources = -1; |
370 | } |
371 | if (maxResourceBytes) { |
372 | *maxResourceBytes = this->getResourceCacheLimit(); |
373 | } |
374 | } |
375 | |
376 | size_t GrContext::getResourceCacheLimit() const { |
377 | ASSERT_SINGLE_OWNER |
378 | return fResourceCache->getMaxResourceBytes(); |
379 | } |
380 | |
381 | void GrContext::setResourceCacheLimits(int unused, size_t maxResourceBytes) { |
382 | ASSERT_SINGLE_OWNER |
383 | this->setResourceCacheLimit(maxResourceBytes); |
384 | } |
385 | |
386 | void GrContext::setResourceCacheLimit(size_t maxResourceBytes) { |
387 | ASSERT_SINGLE_OWNER |
388 | fResourceCache->setLimit(maxResourceBytes); |
389 | } |
390 | |
391 | ////////////////////////////////////////////////////////////////////////////// |
392 | void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { |
393 | ASSERT_SINGLE_OWNER |
394 | fResourceCache->dumpMemoryStatistics(traceMemoryDump); |
395 | traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache" , "size" , "bytes" , |
396 | this->getTextBlobCache()->usedBytes()); |
397 | } |
398 | |
399 | ////////////////////////////////////////////////////////////////////////////// |
400 | GrBackendTexture GrContext::createBackendTexture(int width, int height, |
401 | const GrBackendFormat& backendFormat, |
402 | GrMipmapped mipMapped, |
403 | GrRenderable renderable, |
404 | GrProtected isProtected) { |
405 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
406 | if (!this->asDirectContext()) { |
407 | return GrBackendTexture(); |
408 | } |
409 | |
410 | if (this->abandoned()) { |
411 | return GrBackendTexture(); |
412 | } |
413 | |
414 | return fGpu->createBackendTexture({width, height}, backendFormat, renderable, |
415 | mipMapped, isProtected); |
416 | } |
417 | |
418 | GrBackendTexture GrContext::createBackendTexture(int width, int height, |
419 | SkColorType skColorType, |
420 | GrMipmapped mipMapped, |
421 | GrRenderable renderable, |
422 | GrProtected isProtected) { |
423 | if (!this->asDirectContext()) { |
424 | return GrBackendTexture(); |
425 | } |
426 | |
427 | if (this->abandoned()) { |
428 | return GrBackendTexture(); |
429 | } |
430 | |
431 | const GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); |
432 | |
433 | return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected); |
434 | } |
435 | |
436 | GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c) { |
437 | if (!this->asDirectContext() || !c.isValid()) { |
438 | return GrBackendTexture(); |
439 | } |
440 | |
441 | if (this->abandoned()) { |
442 | return GrBackendTexture(); |
443 | } |
444 | |
445 | if (c.usesGLFBO0()) { |
446 | // If we are making the surface we will never use FBO0. |
447 | return GrBackendTexture(); |
448 | } |
449 | |
450 | if (c.vulkanSecondaryCBCompatible()) { |
451 | return {}; |
452 | } |
453 | |
454 | const GrBackendFormat format = this->defaultBackendFormat(c.colorType(), GrRenderable::kYes); |
455 | if (!format.isValid()) { |
456 | return GrBackendTexture(); |
457 | } |
458 | |
459 | GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format, |
460 | GrMipmapped(c.isMipMapped()), |
461 | GrRenderable::kYes, |
462 | c.isProtected()); |
463 | SkASSERT(c.isCompatible(result)); |
464 | return result; |
465 | } |
466 | |
467 | static GrBackendTexture create_and_update_backend_texture( |
468 | GrDirectContext* context, |
469 | SkISize dimensions, |
470 | const GrBackendFormat& backendFormat, |
471 | GrMipmapped mipMapped, |
472 | GrRenderable renderable, |
473 | GrProtected isProtected, |
474 | sk_sp<GrRefCntedCallback> finishedCallback, |
475 | const GrGpu::BackendTextureData* data) { |
476 | GrGpu* gpu = context->priv().getGpu(); |
477 | |
478 | GrBackendTexture beTex = gpu->createBackendTexture(dimensions, backendFormat, renderable, |
479 | mipMapped, isProtected); |
480 | if (!beTex.isValid()) { |
481 | return {}; |
482 | } |
483 | |
484 | if (!context->priv().getGpu()->updateBackendTexture(beTex, std::move(finishedCallback), data)) { |
485 | context->deleteBackendTexture(beTex); |
486 | return {}; |
487 | } |
488 | return beTex; |
489 | } |
490 | |
491 | |
492 | GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c, |
493 | const SkColor4f& color, |
494 | GrGpuFinishedProc finishedProc, |
495 | GrGpuFinishedContext finishedContext) { |
496 | sk_sp<GrRefCntedCallback> finishedCallback; |
497 | if (finishedProc) { |
498 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
499 | } |
500 | |
501 | if (!this->asDirectContext() || !c.isValid()) { |
502 | return {}; |
503 | } |
504 | |
505 | if (this->abandoned()) { |
506 | return {}; |
507 | } |
508 | |
509 | if (c.usesGLFBO0()) { |
510 | // If we are making the surface we will never use FBO0. |
511 | return {}; |
512 | } |
513 | |
514 | if (c.vulkanSecondaryCBCompatible()) { |
515 | return {}; |
516 | } |
517 | |
518 | const GrBackendFormat format = this->defaultBackendFormat(c.colorType(), GrRenderable::kYes); |
519 | if (!format.isValid()) { |
520 | return {}; |
521 | } |
522 | |
523 | GrGpu::BackendTextureData data(color); |
524 | GrBackendTexture result = create_and_update_backend_texture( |
525 | this->asDirectContext(), {c.width(), c.height()}, format, GrMipmapped(c.isMipMapped()), |
526 | GrRenderable::kYes, c.isProtected(), std::move(finishedCallback), &data); |
527 | |
528 | SkASSERT(c.isCompatible(result)); |
529 | return result; |
530 | } |
531 | |
532 | GrBackendTexture GrContext::createBackendTexture(int width, int height, |
533 | const GrBackendFormat& backendFormat, |
534 | const SkColor4f& color, |
535 | GrMipmapped mipMapped, |
536 | GrRenderable renderable, |
537 | GrProtected isProtected, |
538 | GrGpuFinishedProc finishedProc, |
539 | GrGpuFinishedContext finishedContext) { |
540 | sk_sp<GrRefCntedCallback> finishedCallback; |
541 | if (finishedProc) { |
542 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
543 | } |
544 | |
545 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
546 | if (!this->asDirectContext()) { |
547 | return {}; |
548 | } |
549 | |
550 | if (this->abandoned()) { |
551 | return {}; |
552 | } |
553 | |
554 | GrGpu::BackendTextureData data(color); |
555 | return create_and_update_backend_texture(this->asDirectContext(), {width, height}, |
556 | backendFormat, mipMapped, renderable, isProtected, |
557 | std::move(finishedCallback), &data); |
558 | } |
559 | |
560 | GrBackendTexture GrContext::createBackendTexture(int width, int height, |
561 | SkColorType skColorType, |
562 | const SkColor4f& color, |
563 | GrMipmapped mipMapped, |
564 | GrRenderable renderable, |
565 | GrProtected isProtected, |
566 | GrGpuFinishedProc finishedProc, |
567 | GrGpuFinishedContext finishedContext) { |
568 | sk_sp<GrRefCntedCallback> finishedCallback; |
569 | if (finishedProc) { |
570 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
571 | } |
572 | |
573 | if (!this->asDirectContext()) { |
574 | return {}; |
575 | } |
576 | |
577 | if (this->abandoned()) { |
578 | return {}; |
579 | } |
580 | |
581 | GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); |
582 | if (!format.isValid()) { |
583 | return {}; |
584 | } |
585 | |
586 | GrColorType grColorType = SkColorTypeToGrColorType(skColorType); |
587 | SkColor4f swizzledColor = this->caps()->getWriteSwizzle(format, grColorType).applyTo(color); |
588 | |
589 | GrGpu::BackendTextureData data(swizzledColor); |
590 | return create_and_update_backend_texture(this->asDirectContext(), {width, height}, format, |
591 | mipMapped, renderable, isProtected, |
592 | std::move(finishedCallback), &data); |
593 | } |
594 | |
595 | GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int numProvidedLevels, |
596 | GrRenderable renderable, GrProtected isProtected, |
597 | GrGpuFinishedProc finishedProc, |
598 | GrGpuFinishedContext finishedContext) { |
599 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
600 | |
601 | sk_sp<GrRefCntedCallback> finishedCallback; |
602 | if (finishedProc) { |
603 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
604 | } |
605 | |
606 | if (!this->asDirectContext()) { |
607 | return {}; |
608 | } |
609 | |
610 | if (this->abandoned()) { |
611 | return {}; |
612 | } |
613 | |
614 | if (!srcData || numProvidedLevels <= 0) { |
615 | return {}; |
616 | } |
617 | |
618 | int baseWidth = srcData[0].width(); |
619 | int baseHeight = srcData[0].height(); |
620 | SkColorType colorType = srcData[0].colorType(); |
621 | |
622 | GrMipmapped mipMapped = GrMipmapped::kNo; |
623 | int numExpectedLevels = 1; |
624 | if (numProvidedLevels > 1) { |
625 | numExpectedLevels = SkMipmap::ComputeLevelCount(baseWidth, baseHeight) + 1; |
626 | mipMapped = GrMipmapped::kYes; |
627 | } |
628 | |
629 | if (numProvidedLevels != numExpectedLevels) { |
630 | return {}; |
631 | } |
632 | |
633 | GrBackendFormat backendFormat = this->defaultBackendFormat(colorType, renderable); |
634 | |
635 | GrGpu::BackendTextureData data(srcData); |
636 | return create_and_update_backend_texture(this->asDirectContext(), {baseWidth, baseHeight}, |
637 | backendFormat, mipMapped, renderable, isProtected, |
638 | std::move(finishedCallback), &data); |
639 | } |
640 | |
641 | bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, |
642 | const SkColor4f& color, |
643 | GrGpuFinishedProc finishedProc, |
644 | GrGpuFinishedContext finishedContext) { |
645 | sk_sp<GrRefCntedCallback> finishedCallback; |
646 | if (finishedProc) { |
647 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
648 | } |
649 | |
650 | if (!this->asDirectContext()) { |
651 | return false; |
652 | } |
653 | |
654 | if (this->abandoned()) { |
655 | return false; |
656 | } |
657 | |
658 | GrGpu::BackendTextureData data(color); |
659 | return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data); |
660 | } |
661 | |
662 | bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, |
663 | SkColorType skColorType, |
664 | const SkColor4f& color, |
665 | GrGpuFinishedProc finishedProc, |
666 | GrGpuFinishedContext finishedContext) { |
667 | sk_sp<GrRefCntedCallback> finishedCallback; |
668 | if (finishedProc) { |
669 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
670 | } |
671 | |
672 | if (!this->asDirectContext()) { |
673 | return false; |
674 | } |
675 | |
676 | if (this->abandoned()) { |
677 | return false; |
678 | } |
679 | |
680 | GrBackendFormat format = backendTexture.getBackendFormat(); |
681 | GrColorType grColorType = SkColorTypeAndFormatToGrColorType(this->caps(), skColorType, format); |
682 | |
683 | if (!this->caps()->areColorTypeAndFormatCompatible(grColorType, format)) { |
684 | return false; |
685 | } |
686 | |
687 | GrSwizzle swizzle = this->caps()->getWriteSwizzle(format, grColorType); |
688 | GrGpu::BackendTextureData data(swizzle.applyTo(color)); |
689 | |
690 | return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data); |
691 | } |
692 | |
693 | bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, |
694 | const SkPixmap srcData[], |
695 | int numLevels, |
696 | GrGpuFinishedProc finishedProc, |
697 | GrGpuFinishedContext finishedContext) { |
698 | sk_sp<GrRefCntedCallback> finishedCallback; |
699 | if (finishedProc) { |
700 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
701 | } |
702 | |
703 | if (!this->asDirectContext()) { |
704 | return false; |
705 | } |
706 | |
707 | if (this->abandoned()) { |
708 | return false; |
709 | } |
710 | |
711 | if (!srcData || numLevels <= 0) { |
712 | return false; |
713 | } |
714 | |
715 | int numExpectedLevels = 1; |
716 | if (backendTexture.hasMipmaps()) { |
717 | numExpectedLevels = SkMipmap::ComputeLevelCount(backendTexture.width(), |
718 | backendTexture.height()) + 1; |
719 | } |
720 | if (numLevels != numExpectedLevels) { |
721 | return false; |
722 | } |
723 | |
724 | GrGpu::BackendTextureData data(srcData); |
725 | return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data); |
726 | } |
727 | |
728 | ////////////////////////////////////////////////////////////////////////////// |
729 | |
730 | static GrBackendTexture create_and_update_compressed_backend_texture( |
731 | GrDirectContext* context, |
732 | SkISize dimensions, |
733 | const GrBackendFormat& backendFormat, |
734 | GrMipmapped mipMapped, |
735 | GrProtected isProtected, |
736 | sk_sp<GrRefCntedCallback> finishedCallback, |
737 | const GrGpu::BackendTextureData* data) { |
738 | GrGpu* gpu = context->priv().getGpu(); |
739 | |
740 | GrBackendTexture beTex = gpu->createCompressedBackendTexture(dimensions, backendFormat, |
741 | mipMapped, isProtected); |
742 | if (!beTex.isValid()) { |
743 | return {}; |
744 | } |
745 | |
746 | if (!context->priv().getGpu()->updateCompressedBackendTexture( |
747 | beTex, std::move(finishedCallback), data)) { |
748 | context->deleteBackendTexture(beTex); |
749 | return {}; |
750 | } |
751 | return beTex; |
752 | } |
753 | |
754 | GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height, |
755 | const GrBackendFormat& backendFormat, |
756 | const SkColor4f& color, |
757 | GrMipmapped mipMapped, |
758 | GrProtected isProtected, |
759 | GrGpuFinishedProc finishedProc, |
760 | GrGpuFinishedContext finishedContext) { |
761 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
762 | sk_sp<GrRefCntedCallback> finishedCallback; |
763 | if (finishedProc) { |
764 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
765 | } |
766 | |
767 | if (!this->asDirectContext()) { |
768 | return {}; |
769 | } |
770 | |
771 | if (this->abandoned()) { |
772 | return {}; |
773 | } |
774 | |
775 | GrGpu::BackendTextureData data(color); |
776 | return create_and_update_compressed_backend_texture(this->asDirectContext(), {width, height}, |
777 | backendFormat, mipMapped, isProtected, |
778 | std::move(finishedCallback), &data); |
779 | } |
780 | |
781 | GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height, |
782 | SkImage::CompressionType compression, |
783 | const SkColor4f& color, |
784 | GrMipmapped mipMapped, |
785 | GrProtected isProtected, |
786 | GrGpuFinishedProc finishedProc, |
787 | GrGpuFinishedContext finishedContext) { |
788 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
789 | GrBackendFormat format = this->compressedBackendFormat(compression); |
790 | return this->createCompressedBackendTexture(width, height, format, color, |
791 | mipMapped, isProtected, finishedProc, |
792 | finishedContext); |
793 | } |
794 | |
795 | GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height, |
796 | const GrBackendFormat& backendFormat, |
797 | const void* compressedData, |
798 | size_t dataSize, |
799 | GrMipmapped mipMapped, |
800 | GrProtected isProtected, |
801 | GrGpuFinishedProc finishedProc, |
802 | GrGpuFinishedContext finishedContext) { |
803 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
804 | sk_sp<GrRefCntedCallback> finishedCallback; |
805 | if (finishedProc) { |
806 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
807 | } |
808 | |
809 | if (!this->asDirectContext()) { |
810 | return {}; |
811 | } |
812 | |
813 | if (this->abandoned()) { |
814 | return {}; |
815 | } |
816 | |
817 | GrGpu::BackendTextureData data(compressedData, dataSize); |
818 | return create_and_update_compressed_backend_texture(this->asDirectContext(), {width, height}, |
819 | backendFormat, mipMapped, isProtected, |
820 | std::move(finishedCallback), &data); |
821 | } |
822 | |
823 | GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height, |
824 | SkImage::CompressionType compression, |
825 | const void* data, size_t dataSize, |
826 | GrMipmapped mipMapped, |
827 | GrProtected isProtected, |
828 | GrGpuFinishedProc finishedProc, |
829 | GrGpuFinishedContext finishedContext) { |
830 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
831 | GrBackendFormat format = this->compressedBackendFormat(compression); |
832 | return this->createCompressedBackendTexture(width, height, format, data, dataSize, mipMapped, |
833 | isProtected, finishedProc, finishedContext); |
834 | } |
835 | |
836 | bool GrContext::setBackendTextureState(const GrBackendTexture& backendTexture, |
837 | const GrBackendSurfaceMutableState& state, |
838 | GrGpuFinishedProc finishedProc, |
839 | GrGpuFinishedContext finishedContext) { |
840 | sk_sp<GrRefCntedCallback> callback; |
841 | if (finishedProc) { |
842 | callback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
843 | } |
844 | |
845 | if (!this->asDirectContext()) { |
846 | return false; |
847 | } |
848 | |
849 | if (this->abandoned()) { |
850 | return false; |
851 | } |
852 | |
853 | return fGpu->setBackendTextureState(backendTexture, state, std::move(callback)); |
854 | } |
855 | |
856 | bool GrContext::updateCompressedBackendTexture(const GrBackendTexture& backendTexture, |
857 | const SkColor4f& color, |
858 | GrGpuFinishedProc finishedProc, |
859 | GrGpuFinishedContext finishedContext) { |
860 | sk_sp<GrRefCntedCallback> finishedCallback; |
861 | if (finishedProc) { |
862 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
863 | } |
864 | |
865 | if (!this->asDirectContext()) { |
866 | return false; |
867 | } |
868 | |
869 | if (this->abandoned()) { |
870 | return false; |
871 | } |
872 | |
873 | GrGpu::BackendTextureData data(color); |
874 | return fGpu->updateCompressedBackendTexture(backendTexture, std::move(finishedCallback), &data); |
875 | } |
876 | |
877 | bool GrContext::updateCompressedBackendTexture(const GrBackendTexture& backendTexture, |
878 | const void* compressedData, |
879 | size_t dataSize, |
880 | GrGpuFinishedProc finishedProc, |
881 | GrGpuFinishedContext finishedContext) { |
882 | sk_sp<GrRefCntedCallback> finishedCallback; |
883 | if (finishedProc) { |
884 | finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
885 | } |
886 | |
887 | if (!this->asDirectContext()) { |
888 | return false; |
889 | } |
890 | |
891 | if (this->abandoned()) { |
892 | return false; |
893 | } |
894 | |
895 | if (!compressedData) { |
896 | return false; |
897 | } |
898 | |
899 | GrGpu::BackendTextureData data(compressedData, dataSize); |
900 | |
901 | return fGpu->updateCompressedBackendTexture(backendTexture, std::move(finishedCallback), &data); |
902 | } |
903 | |
904 | ////////////////////////////////////////////////////////////////////////////// |
905 | |
906 | bool GrContext::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget, |
907 | const GrBackendSurfaceMutableState& state, |
908 | GrGpuFinishedProc finishedProc, |
909 | GrGpuFinishedContext finishedContext) { |
910 | sk_sp<GrRefCntedCallback> callback; |
911 | if (finishedProc) { |
912 | callback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); |
913 | } |
914 | |
915 | if (!this->asDirectContext()) { |
916 | return false; |
917 | } |
918 | |
919 | if (this->abandoned()) { |
920 | return false; |
921 | } |
922 | |
923 | return fGpu->setBackendRenderTargetState(backendRenderTarget, state, std::move(callback)); |
924 | } |
925 | |
926 | void GrContext::deleteBackendTexture(GrBackendTexture backendTex) { |
927 | TRACE_EVENT0("skia.gpu" , TRACE_FUNC); |
928 | // For the Vulkan backend we still must destroy the backend texture when the context is |
929 | // abandoned. |
930 | if ((this->abandoned() && this->backend() != GrBackendApi::kVulkan) || !backendTex.isValid()) { |
931 | return; |
932 | } |
933 | |
934 | fGpu->deleteBackendTexture(backendTex); |
935 | } |
936 | |
937 | ////////////////////////////////////////////////////////////////////////////// |
938 | |
939 | bool GrContext::precompileShader(const SkData& key, const SkData& data) { |
940 | return fGpu->precompileShader(key, data); |
941 | } |
942 | |
943 | #ifdef SK_ENABLE_DUMP_GPU |
944 | #include "include/core/SkString.h" |
945 | #include "src/utils/SkJSONWriter.h" |
946 | SkString GrContext::dump() const { |
947 | SkDynamicMemoryWStream stream; |
948 | SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty); |
949 | writer.beginObject(); |
950 | |
951 | writer.appendString("backend" , GrBackendApiToStr(this->backend())); |
952 | |
953 | writer.appendName("caps" ); |
954 | this->caps()->dumpJSON(&writer); |
955 | |
956 | writer.appendName("gpu" ); |
957 | this->fGpu->dumpJSON(&writer); |
958 | |
959 | writer.appendName("context" ); |
960 | this->dumpJSON(&writer); |
961 | |
962 | // Flush JSON to the memory stream |
963 | writer.endObject(); |
964 | writer.flush(); |
965 | |
966 | // Null terminate the JSON data in the memory stream |
967 | stream.write8(0); |
968 | |
969 | // Allocate a string big enough to hold all the data, then copy out of the stream |
970 | SkString result(stream.bytesWritten()); |
971 | stream.copyToAndReset(result.writable_str()); |
972 | return result; |
973 | } |
974 | #endif |
975 | |