1 /*
2 * Copyright 2018 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 "src/gpu/ganesh/GrProxyProvider.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkImage.h"
12 #include "include/core/SkTextureCompressionType.h"
13 #include "include/gpu/GrDirectContext.h"
14 #include "include/private/base/SingleOwner.h"
15 #include "include/private/gpu/ganesh/GrImageContext.h"
16 #include "src/core/SkAutoPixmapStorage.h"
17 #include "src/core/SkCompressedDataUtils.h"
18 #include "src/core/SkImageInfoPriv.h"
19 #include "src/core/SkImagePriv.h"
20 #include "src/core/SkMipmap.h"
21 #include "src/core/SkTraceEvent.h"
22 #include "src/gpu/ganesh/GrCaps.h"
23 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
24 #include "src/gpu/ganesh/GrDirectContextPriv.h"
25 #include "src/gpu/ganesh/GrImageContextPriv.h"
26 #include "src/gpu/ganesh/GrRenderTarget.h"
27 #include "src/gpu/ganesh/GrResourceProvider.h"
28 #include "src/gpu/ganesh/GrSurfaceProxy.h"
29 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
30 #include "src/gpu/ganesh/GrTexture.h"
31 #include "src/gpu/ganesh/GrTextureProxyCacheAccess.h"
32 #include "src/gpu/ganesh/GrTextureRenderTargetProxy.h"
33 #include "src/gpu/ganesh/SkGr.h"
34 #include "src/image/SkImage_Base.h"
35
36 #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fImageContext->priv().singleOwner())
37
GrProxyProvider(GrImageContext * imageContext)38 GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {}
39
~GrProxyProvider()40 GrProxyProvider::~GrProxyProvider() {
41 if (this->renderingDirectly()) {
42 // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since
43 // they need their unique keys to, potentially, find a cached resource when the
44 // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point.
45 SkASSERT(!fUniquelyKeyedProxies.count());
46 }
47 }
48
assignUniqueKeyToProxy(const skgpu::UniqueKey & key,GrTextureProxy * proxy)49 bool GrProxyProvider::assignUniqueKeyToProxy(const skgpu::UniqueKey& key, GrTextureProxy* proxy) {
50 ASSERT_SINGLE_OWNER
51 SkASSERT(key.isValid());
52 if (this->isAbandoned() || !proxy) {
53 return false;
54 }
55
56 // Only the proxyProvider that created a proxy should be assigning unique keys to it.
57 SkASSERT(this->isDDLProvider() == proxy->creatingProvider());
58
59 #ifdef SK_DEBUG
60 {
61 auto direct = fImageContext->asDirectContext();
62 if (direct) {
63 GrResourceCache* resourceCache = direct->priv().getResourceCache();
64 // If there is already a GrResource with this key then the caller has violated the
65 // normal usage pattern of uniquely keyed resources (e.g., they have created one w/o
66 // first seeing if it already existed in the cache).
67 SkASSERT(!resourceCache->findAndRefUniqueResource(key));
68 }
69 }
70 #endif
71
72 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key
73
74 proxy->cacheAccess().setUniqueKey(this, key);
75 SkASSERT(proxy->getUniqueKey() == key);
76 fUniquelyKeyedProxies.add(proxy);
77 return true;
78 }
79
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)80 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
81 SkASSERT(surf->getUniqueKey().isValid());
82 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
83 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
84 // multiple proxies can't get the same key
85 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
86 fUniquelyKeyedProxies.add(proxy);
87 }
88
removeUniqueKeyFromProxy(GrTextureProxy * proxy)89 void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) {
90 ASSERT_SINGLE_OWNER
91 SkASSERT(proxy);
92 SkASSERT(proxy->getUniqueKey().isValid());
93
94 if (this->isAbandoned()) {
95 return;
96 }
97
98 this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes);
99 }
100
findProxyByUniqueKey(const skgpu::UniqueKey & key)101 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const skgpu::UniqueKey& key) {
102 ASSERT_SINGLE_OWNER
103
104 if (this->isAbandoned()) {
105 return nullptr;
106 }
107
108 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
109 if (proxy) {
110 return sk_ref_sp(proxy);
111 }
112 return nullptr;
113 }
114
115 ///////////////////////////////////////////////////////////////////////////////
116
117 #if defined(GR_TEST_UTILS)
testingOnly_createInstantiatedProxy(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected)118 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
119 SkISize dimensions,
120 const GrBackendFormat& format,
121 GrRenderable renderable,
122 int renderTargetSampleCnt,
123 SkBackingFit fit,
124 skgpu::Budgeted budgeted,
125 GrProtected isProtected) {
126 ASSERT_SINGLE_OWNER
127 if (this->isAbandoned()) {
128 return nullptr;
129 }
130 auto direct = fImageContext->asDirectContext();
131 if (!direct) {
132 return nullptr;
133 }
134
135 if (this->caps()->isFormatCompressed(format)) {
136 // TODO: Allow this to go to GrResourceProvider::createCompressedTexture() once we no longer
137 // rely on GrColorType to get a swizzle for the proxy.
138 return nullptr;
139 }
140
141 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
142 sk_sp<GrTexture> tex;
143
144 if (SkBackingFit::kApprox == fit) {
145 tex = resourceProvider->createApproxTexture(
146 dimensions,
147 format,
148 format.textureType(),
149 renderable,
150 renderTargetSampleCnt,
151 isProtected,
152 /*label=*/"InstantiatedProxyViaApproxTexture_Test");
153 } else {
154 tex = resourceProvider->createTexture(dimensions,
155 format,
156 format.textureType(),
157 renderable,
158 renderTargetSampleCnt,
159 skgpu::Mipmapped::kNo,
160 budgeted,
161 isProtected,
162 /*label=*/"InstantiatedProxyViaTexture_Test");
163 }
164 if (!tex) {
165 return nullptr;
166 }
167
168 return this->createWrapped(std::move(tex), UseAllocator::kYes);
169 }
170
testingOnly_createInstantiatedProxy(SkISize dimensions,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected)171 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
172 SkISize dimensions,
173 GrColorType colorType,
174 GrRenderable renderable,
175 int renderTargetSampleCnt,
176 SkBackingFit fit,
177 skgpu::Budgeted budgeted,
178 GrProtected isProtected) {
179 ASSERT_SINGLE_OWNER
180 if (this->isAbandoned()) {
181 return nullptr;
182 }
183 auto format = this->caps()->getDefaultBackendFormat(colorType, renderable);
184 return this->testingOnly_createInstantiatedProxy(dimensions,
185 format,
186 renderable,
187 renderTargetSampleCnt,
188 fit,
189 budgeted,
190 isProtected);
191 }
192
testingOnly_createWrapped(sk_sp<GrTexture> tex)193 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createWrapped(sk_sp<GrTexture> tex) {
194 return this->createWrapped(std::move(tex), UseAllocator::kYes);
195 }
196 #endif
197
createWrapped(sk_sp<GrTexture> tex,UseAllocator useAllocator)198 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex,
199 UseAllocator useAllocator) {
200 #ifdef SK_DEBUG
201 if (tex->getUniqueKey().isValid()) {
202 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey()));
203 }
204 #endif
205
206 if (tex->asRenderTarget()) {
207 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(
208 std::move(tex), useAllocator, this->isDDLProvider()));
209 } else {
210 return sk_sp<GrTextureProxy>(
211 new GrTextureProxy(std::move(tex), useAllocator, this->isDDLProvider()));
212 }
213 }
214
findOrCreateProxyByUniqueKey(const skgpu::UniqueKey & key,UseAllocator useAllocator)215 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const skgpu::UniqueKey& key,
216 UseAllocator useAllocator) {
217 ASSERT_SINGLE_OWNER
218
219 if (this->isAbandoned()) {
220 return nullptr;
221 }
222
223 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key);
224 if (result) {
225 return result;
226 }
227
228 auto direct = fImageContext->asDirectContext();
229 if (!direct) {
230 return nullptr;
231 }
232
233 GrResourceCache* resourceCache = direct->priv().getResourceCache();
234
235 GrGpuResource* resource = resourceCache->findAndRefUniqueResource(key);
236 if (!resource) {
237 return nullptr;
238 }
239
240 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
241 SkASSERT(texture);
242
243 result = this->createWrapped(std::move(texture), useAllocator);
244 SkASSERT(result->getUniqueKey() == key);
245 // createWrapped should've added this for us
246 SkASSERT(fUniquelyKeyedProxies.find(key));
247 return result;
248 }
249
findCachedProxyWithColorTypeFallback(const skgpu::UniqueKey & key,GrSurfaceOrigin origin,GrColorType ct,int sampleCnt)250 GrSurfaceProxyView GrProxyProvider::findCachedProxyWithColorTypeFallback(
251 const skgpu::UniqueKey& key,
252 GrSurfaceOrigin origin,
253 GrColorType ct,
254 int sampleCnt) {
255 auto proxy = this->findOrCreateProxyByUniqueKey(key);
256 if (!proxy) {
257 return {};
258 }
259 const GrCaps* caps = fImageContext->priv().caps();
260
261 // Assume that we used a fallback color type if and only if the proxy is renderable.
262 if (proxy->asRenderTargetProxy()) {
263 GrBackendFormat expectedFormat;
264 std::tie(ct, expectedFormat) = caps->getFallbackColorTypeAndFormat(ct, sampleCnt);
265 SkASSERT(expectedFormat == proxy->backendFormat());
266 }
267 skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
268 return {std::move(proxy), origin, swizzle};
269 }
270
createProxyFromBitmap(const SkBitmap & bitmap,skgpu::Mipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted)271 sk_sp<GrTextureProxy> GrProxyProvider::createProxyFromBitmap(const SkBitmap& bitmap,
272 skgpu::Mipmapped mipmapped,
273 SkBackingFit fit,
274 skgpu::Budgeted budgeted) {
275 ASSERT_SINGLE_OWNER
276 SkASSERT(fit == SkBackingFit::kExact || mipmapped == skgpu::Mipmapped::kNo);
277
278 if (this->isAbandoned()) {
279 return nullptr;
280 }
281
282 if (!SkImageInfoIsValid(bitmap.info())) {
283 return nullptr;
284 }
285
286 ATRACE_ANDROID_FRAMEWORK("Upload %sTexture [%dx%d]",
287 skgpu::Mipmapped::kYes == mipmapped ? "MipMap " : "",
288 bitmap.width(),
289 bitmap.height());
290
291 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
292 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the
293 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
294 SkBitmap copyBitmap = bitmap;
295 if (!this->renderingDirectly() && !bitmap.isImmutable()) {
296 copyBitmap.allocPixels();
297 if (!bitmap.readPixels(copyBitmap.pixmap())) {
298 return nullptr;
299 }
300 if (mipmapped == skgpu::Mipmapped::kYes && bitmap.fMips) {
301 copyBitmap.fMips = sk_sp<SkMipmap>(SkMipmap::Build(copyBitmap.pixmap(),
302 /* factoryProc= */ nullptr,
303 /* computeContents= */ false));
304 if (copyBitmap.fMips) {
305 for (int i = 0; i < copyBitmap.fMips->countLevels(); ++i) {
306 SkMipmap::Level src, dst;
307 bitmap.fMips->getLevel(i, &src);
308 copyBitmap.fMips->getLevel(i, &dst);
309 src.fPixmap.readPixels(dst.fPixmap);
310 }
311 }
312 }
313 copyBitmap.setImmutable();
314 }
315
316 sk_sp<GrTextureProxy> proxy;
317 if (mipmapped == skgpu::Mipmapped::kNo ||
318 !SkMipmap::ComputeLevelCount(copyBitmap.dimensions())) {
319 proxy = this->createNonMippedProxyFromBitmap(copyBitmap, fit, budgeted);
320 } else {
321 proxy = this->createMippedProxyFromBitmap(copyBitmap, budgeted);
322 }
323
324 if (!proxy) {
325 return nullptr;
326 }
327
328 auto direct = fImageContext->asDirectContext();
329 if (direct) {
330 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
331
332 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
333 // we're better off instantiating the proxy immediately here.
334 if (!proxy->priv().doLazyInstantiation(resourceProvider)) {
335 return nullptr;
336 }
337 }
338 return proxy;
339 }
340
createNonMippedProxyFromBitmap(const SkBitmap & bitmap,SkBackingFit fit,skgpu::Budgeted budgeted)341 sk_sp<GrTextureProxy> GrProxyProvider::createNonMippedProxyFromBitmap(const SkBitmap& bitmap,
342 SkBackingFit fit,
343 skgpu::Budgeted budgeted) {
344 auto dims = bitmap.dimensions();
345
346 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
347 GrBackendFormat format = this->caps()->getDefaultBackendFormat(colorType, GrRenderable::kNo);
348 if (!format.isValid()) {
349 return nullptr;
350 }
351
352 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
353 [bitmap](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) {
354 SkASSERT(desc.fMipmapped == skgpu::Mipmapped::kNo);
355 GrMipLevel mipLevel = {bitmap.getPixels(), bitmap.rowBytes(), nullptr};
356 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
357 return LazyCallbackResult(resourceProvider->createTexture(desc.fDimensions,
358 desc.fFormat,
359 desc.fTextureType,
360 colorType,
361 desc.fRenderable,
362 desc.fSampleCnt,
363 desc.fBudgeted,
364 desc.fFit,
365 desc.fProtected,
366 mipLevel,
367 desc.fLabel));
368 },
369 format,
370 dims,
371 skgpu::Mipmapped::kNo,
372 GrMipmapStatus::kNotAllocated,
373 GrInternalSurfaceFlags::kNone,
374 fit,
375 budgeted,
376 GrProtected::kNo,
377 UseAllocator::kYes,
378 "ProxyProvider_CreateNonMippedProxyFromBitmap");
379
380 if (!proxy) {
381 return nullptr;
382 }
383 SkASSERT(proxy->dimensions() == bitmap.dimensions());
384 return proxy;
385 }
386
createMippedProxyFromBitmap(const SkBitmap & bitmap,skgpu::Budgeted budgeted)387 sk_sp<GrTextureProxy> GrProxyProvider::createMippedProxyFromBitmap(const SkBitmap& bitmap,
388 skgpu::Budgeted budgeted) {
389 SkASSERT(this->caps()->mipmapSupport());
390
391 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
392 GrBackendFormat format = this->caps()->getDefaultBackendFormat(colorType, GrRenderable::kNo);
393 if (!format.isValid()) {
394 return nullptr;
395 }
396
397 sk_sp<SkMipmap> mipmaps = bitmap.fMips;
398 if (!mipmaps) {
399 mipmaps.reset(SkMipmap::Build(bitmap.pixmap(), /* factoryProc= */ nullptr));
400 if (!mipmaps) {
401 return nullptr;
402 }
403 }
404
405 auto dims = bitmap.dimensions();
406
407 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
408 [bitmap, mipmaps](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) {
409 const int mipLevelCount = mipmaps->countLevels() + 1;
410 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
411 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
412
413 texels[0].fPixels = bitmap.getPixels();
414 texels[0].fRowBytes = bitmap.rowBytes();
415
416 for (int i = 1; i < mipLevelCount; ++i) {
417 SkMipmap::Level generatedMipLevel;
418 mipmaps->getLevel(i - 1, &generatedMipLevel);
419 texels[i].fPixels = generatedMipLevel.fPixmap.addr();
420 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes();
421 SkASSERT(texels[i].fPixels);
422 SkASSERT(generatedMipLevel.fPixmap.colorType() == bitmap.colorType());
423 }
424 return LazyCallbackResult(resourceProvider->createTexture(desc.fDimensions,
425 desc.fFormat,
426 desc.fTextureType,
427 colorType,
428 GrRenderable::kNo,
429 1,
430 desc.fBudgeted,
431 skgpu::Mipmapped::kYes,
432 GrProtected::kNo,
433 texels.get(),
434 desc.fLabel));
435 },
436 format,
437 dims,
438 skgpu::Mipmapped::kYes,
439 GrMipmapStatus::kValid,
440 GrInternalSurfaceFlags::kNone,
441 SkBackingFit::kExact,
442 budgeted,
443 GrProtected::kNo,
444 UseAllocator::kYes,
445 "ProxyProvider_CreateMippedProxyFromBitmap");
446
447 if (!proxy) {
448 return nullptr;
449 }
450
451 SkASSERT(proxy->dimensions() == bitmap.dimensions());
452
453 return proxy;
454 }
455
createProxy(const GrBackendFormat & format,SkISize dimensions,GrRenderable renderable,int renderTargetSampleCnt,skgpu::Mipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,std::string_view label,GrInternalSurfaceFlags surfaceFlags,GrSurfaceProxy::UseAllocator useAllocator)456 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format,
457 SkISize dimensions,
458 GrRenderable renderable,
459 int renderTargetSampleCnt,
460 skgpu::Mipmapped mipmapped,
461 SkBackingFit fit,
462 skgpu::Budgeted budgeted,
463 GrProtected isProtected,
464 std::string_view label,
465 GrInternalSurfaceFlags surfaceFlags,
466 GrSurfaceProxy::UseAllocator useAllocator) {
467 ASSERT_SINGLE_OWNER
468 if (this->isAbandoned()) {
469 return nullptr;
470 }
471
472 const GrCaps* caps = this->caps();
473
474 if (caps->isFormatCompressed(format)) {
475 // Deferred proxies for compressed textures are not supported.
476 return nullptr;
477 }
478
479 if (skgpu::Mipmapped::kYes == mipmapped) {
480 // SkMipmap doesn't include the base level in the level count so we have to add 1
481 int mipCount = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1;
482 if (1 == mipCount) {
483 mipmapped = skgpu::Mipmapped::kNo;
484 }
485 }
486
487 if (!caps->validateSurfaceParams(dimensions,
488 format,
489 renderable,
490 renderTargetSampleCnt,
491 mipmapped,
492 GrTextureType::k2D)) {
493 return nullptr;
494 }
495 GrMipmapStatus mipmapStatus = (skgpu::Mipmapped::kYes == mipmapped)
496 ? GrMipmapStatus::kDirty
497 : GrMipmapStatus::kNotAllocated;
498 if (renderable == GrRenderable::kYes) {
499 renderTargetSampleCnt = caps->getRenderTargetSampleCount(renderTargetSampleCnt, format);
500 SkASSERT(renderTargetSampleCnt);
501 GrInternalSurfaceFlags extraFlags = caps->getExtraSurfaceFlagsForDeferredRT();
502 // We know anything we instantiate later from this deferred path will be
503 // both texturable and renderable
504 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps,
505 format,
506 dimensions,
507 renderTargetSampleCnt,
508 mipmapped,
509 mipmapStatus,
510 fit,
511 budgeted,
512 isProtected,
513 surfaceFlags | extraFlags,
514 useAllocator,
515 this->isDDLProvider(),
516 label));
517 }
518
519 return sk_sp<GrTextureProxy>(new GrTextureProxy(format,
520 dimensions,
521 mipmapped,
522 mipmapStatus,
523 fit,
524 budgeted,
525 isProtected,
526 surfaceFlags,
527 useAllocator,
528 this->isDDLProvider(),
529 label));
530 }
531
createCompressedTextureProxy(SkISize dimensions,skgpu::Budgeted budgeted,skgpu::Mipmapped mipmapped,GrProtected isProtected,SkTextureCompressionType compressionType,sk_sp<SkData> data)532 sk_sp<GrTextureProxy> GrProxyProvider::createCompressedTextureProxy(
533 SkISize dimensions,
534 skgpu::Budgeted budgeted,
535 skgpu::Mipmapped mipmapped,
536 GrProtected isProtected,
537 SkTextureCompressionType compressionType,
538 sk_sp<SkData> data) {
539 ASSERT_SINGLE_OWNER
540 if (this->isAbandoned()) {
541 return nullptr;
542 }
543
544 GrBackendFormat format = this->caps()->getBackendFormatFromCompressionType(compressionType);
545
546 if (!this->caps()->isFormatTexturable(format, GrTextureType::k2D)) {
547 return nullptr;
548 }
549
550 GrMipmapStatus mipmapStatus = (skgpu::Mipmapped::kYes == mipmapped)
551 ? GrMipmapStatus::kValid
552 : GrMipmapStatus::kNotAllocated;
553
554 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
555 [data](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) {
556 return LazyCallbackResult(
557 resourceProvider->createCompressedTexture(desc.fDimensions,
558 desc.fFormat,
559 desc.fBudgeted,
560 desc.fMipmapped,
561 desc.fProtected,
562 data.get(),
563 desc.fLabel));
564 },
565 format,
566 dimensions,
567 mipmapped,
568 mipmapStatus,
569 GrInternalSurfaceFlags::kReadOnly,
570 SkBackingFit::kExact,
571 skgpu::Budgeted::kYes,
572 GrProtected::kNo,
573 UseAllocator::kYes,
574 "ProxyProvider_CreateCompressedTextureProxy");
575
576 if (!proxy) {
577 return nullptr;
578 }
579
580 auto direct = fImageContext->asDirectContext();
581 if (direct) {
582 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
583 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
584 // we're better off instantiating the proxy immediately here.
585 if (!proxy->priv().doLazyInstantiation(resourceProvider)) {
586 return nullptr;
587 }
588 }
589 return proxy;
590 }
591
wrapBackendTexture(const GrBackendTexture & backendTex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType,sk_sp<skgpu::RefCntedCallback> releaseHelper)592 sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(
593 const GrBackendTexture& backendTex,
594 GrWrapOwnership ownership,
595 GrWrapCacheable cacheable,
596 GrIOType ioType,
597 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
598 SkASSERT(ioType != kWrite_GrIOType);
599
600 if (this->isAbandoned()) {
601 return nullptr;
602 }
603
604 // This is only supported on a direct GrContext.
605 auto direct = fImageContext->asDirectContext();
606 if (!direct) {
607 return nullptr;
608 }
609
610 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
611
612 sk_sp<GrTexture> tex =
613 resourceProvider->wrapBackendTexture(backendTex, ownership, cacheable, ioType);
614 if (!tex) {
615 return nullptr;
616 }
617
618 if (releaseHelper) {
619 tex->setRelease(std::move(releaseHelper));
620 }
621
622 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
623 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
624 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
625
626 return sk_sp<GrTextureProxy>(
627 new GrTextureProxy(std::move(tex), UseAllocator::kNo, this->isDDLProvider()));
628 }
629
wrapCompressedBackendTexture(const GrBackendTexture & beTex,GrWrapOwnership ownership,GrWrapCacheable cacheable,sk_sp<skgpu::RefCntedCallback> releaseHelper)630 sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture(
631 const GrBackendTexture& beTex,
632 GrWrapOwnership ownership,
633 GrWrapCacheable cacheable,
634 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
635 if (this->isAbandoned()) {
636 return nullptr;
637 }
638
639 // This is only supported on a direct GrContext.
640 auto direct = fImageContext->asDirectContext();
641 if (!direct) {
642 return nullptr;
643 }
644
645 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
646
647 sk_sp<GrTexture> tex = resourceProvider->wrapCompressedBackendTexture(beTex, ownership,
648 cacheable);
649 if (!tex) {
650 return nullptr;
651 }
652
653 if (releaseHelper) {
654 tex->setRelease(std::move(releaseHelper));
655 }
656
657 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
658 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
659 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
660
661 return sk_sp<GrTextureProxy>(
662 new GrTextureProxy(std::move(tex), UseAllocator::kNo, this->isDDLProvider()));
663 }
664
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable,sk_sp<skgpu::RefCntedCallback> releaseHelper)665 sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture(
666 const GrBackendTexture& backendTex,
667 int sampleCnt,
668 GrWrapOwnership ownership,
669 GrWrapCacheable cacheable,
670 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
671 if (this->isAbandoned()) {
672 return nullptr;
673 }
674
675 // This is only supported on a direct GrContext.
676 auto direct = fImageContext->asDirectContext();
677 if (!direct) {
678 return nullptr;
679 }
680
681 const GrCaps* caps = this->caps();
682
683 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
684
685 sampleCnt = caps->getRenderTargetSampleCount(sampleCnt, backendTex.getBackendFormat());
686 SkASSERT(sampleCnt);
687
688 sk_sp<GrTexture> tex = resourceProvider->wrapRenderableBackendTexture(
689 backendTex, sampleCnt, ownership, cacheable);
690 if (!tex) {
691 return nullptr;
692 }
693
694 if (releaseHelper) {
695 tex->setRelease(std::move(releaseHelper));
696 }
697
698 SkASSERT(tex->asRenderTarget()); // A GrTextureRenderTarget
699 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
700 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
701
702 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(
703 std::move(tex), UseAllocator::kNo, this->isDDLProvider()));
704 }
705
resourceProvider() const706 GrResourceProvider* GrProxyProvider::resourceProvider() const {
707 GrDirectContext* direct = fImageContext->asDirectContext();
708 if (!direct) {
709 return nullptr;
710 }
711
712 return direct->priv().resourceProvider();
713 }
714
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,sk_sp<skgpu::RefCntedCallback> releaseHelper)715 sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget(
716 const GrBackendRenderTarget& backendRT,
717 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
718 if (this->isAbandoned()) {
719 return nullptr;
720 }
721
722 // This is only supported on a direct GrContext.
723 auto direct = fImageContext->asDirectContext();
724 if (!direct) {
725 return nullptr;
726 }
727
728 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
729
730 sk_sp<GrRenderTarget> rt = resourceProvider->wrapBackendRenderTarget(backendRT);
731 if (!rt) {
732 return nullptr;
733 }
734
735 if (releaseHelper) {
736 rt->setRelease(std::move(releaseHelper));
737 }
738
739 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
740 SkASSERT(!rt->getUniqueKey().isValid());
741 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
742 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
743
744 return sk_sp<GrRenderTargetProxy>(
745 new GrRenderTargetProxy(std::move(rt), UseAllocator::kNo, {}));
746 }
747
CreatePromiseProxy(GrContextThreadSafeProxy * threadSafeProxy,LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,skgpu::Mipmapped mipmapped)748 sk_sp<GrTextureProxy> GrProxyProvider::CreatePromiseProxy(GrContextThreadSafeProxy* threadSafeProxy,
749 LazyInstantiateCallback&& callback,
750 const GrBackendFormat& format,
751 SkISize dimensions,
752 skgpu::Mipmapped mipmapped) {
753 if (threadSafeProxy->priv().abandoned()) {
754 return nullptr;
755 }
756 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) ||
757 (dimensions.fWidth > 0 && dimensions.fHeight > 0));
758
759 if (dimensions.fWidth > threadSafeProxy->priv().caps()->maxTextureSize() ||
760 dimensions.fHeight > threadSafeProxy->priv().caps()->maxTextureSize()) {
761 return nullptr;
762 }
763 if (!threadSafeProxy->priv().caps()->isFormatTexturable(format, format.textureType())) {
764 return nullptr;
765 }
766 // Ganesh assumes that, when wrapping a mipmapped backend texture from a client, that its
767 // mipmaps are fully fleshed out.
768 GrMipmapStatus mipmapStatus = (skgpu::Mipmapped::kYes == mipmapped)
769 ? GrMipmapStatus::kValid
770 : GrMipmapStatus::kNotAllocated;
771
772 // We pass kReadOnly here since we should treat content of the client's texture as immutable.
773 // The promise API provides no way for the client to indicate that the texture is protected.
774 auto proxy = sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback),
775 format,
776 dimensions,
777 mipmapped,
778 mipmapStatus,
779 SkBackingFit::kExact,
780 skgpu::Budgeted::kNo,
781 GrProtected::kNo,
782 GrInternalSurfaceFlags::kReadOnly,
783 GrSurfaceProxy::UseAllocator::kYes,
784 GrDDLProvider::kYes,
785 /*label=*/"PromiseProxy"));
786 proxy->priv().setIsPromiseProxy();
787 return proxy;
788 }
789
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,skgpu::Mipmapped mipmapped,GrMipmapStatus mipmapStatus,GrInternalSurfaceFlags surfaceFlags,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrSurfaceProxy::UseAllocator useAllocator,std::string_view label)790 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
791 const GrBackendFormat& format,
792 SkISize dimensions,
793 skgpu::Mipmapped mipmapped,
794 GrMipmapStatus mipmapStatus,
795 GrInternalSurfaceFlags surfaceFlags,
796 SkBackingFit fit,
797 skgpu::Budgeted budgeted,
798 GrProtected isProtected,
799 GrSurfaceProxy::UseAllocator useAllocator,
800 std::string_view label) {
801 ASSERT_SINGLE_OWNER
802 if (this->isAbandoned()) {
803 return nullptr;
804 }
805 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) ||
806 (dimensions.fWidth > 0 && dimensions.fHeight > 0));
807
808 if (!format.isValid() || format.backend() != fImageContext->backend()) {
809 return nullptr;
810 }
811
812 if (dimensions.fWidth > this->caps()->maxTextureSize() ||
813 dimensions.fHeight > this->caps()->maxTextureSize()) {
814 return nullptr;
815 }
816
817 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback),
818 format,
819 dimensions,
820 mipmapped,
821 mipmapStatus,
822 fit,
823 budgeted,
824 isProtected,
825 surfaceFlags,
826 useAllocator,
827 this->isDDLProvider(),
828 label));
829 }
830
createLazyRenderTargetProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,int sampleCnt,GrInternalSurfaceFlags surfaceFlags,const TextureInfo * textureInfo,GrMipmapStatus mipmapStatus,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,bool wrapsVkSecondaryCB,UseAllocator useAllocator)831 sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy(
832 LazyInstantiateCallback&& callback,
833 const GrBackendFormat& format,
834 SkISize dimensions,
835 int sampleCnt,
836 GrInternalSurfaceFlags surfaceFlags,
837 const TextureInfo* textureInfo,
838 GrMipmapStatus mipmapStatus,
839 SkBackingFit fit,
840 skgpu::Budgeted budgeted,
841 GrProtected isProtected,
842 bool wrapsVkSecondaryCB,
843 UseAllocator useAllocator) {
844 ASSERT_SINGLE_OWNER
845 if (this->isAbandoned()) {
846 return nullptr;
847 }
848 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) ||
849 (dimensions.fWidth > 0 && dimensions.fHeight > 0));
850
851 if (dimensions.fWidth > this->caps()->maxRenderTargetSize() ||
852 dimensions.fHeight > this->caps()->maxRenderTargetSize()) {
853 return nullptr;
854 }
855
856 if (textureInfo) {
857 // Wrapped vulkan secondary command buffers don't support texturing since we won't have an
858 // actual VkImage to texture from.
859 SkASSERT(!wrapsVkSecondaryCB);
860 return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(
861 *this->caps(),
862 std::move(callback),
863 format,
864 dimensions,
865 sampleCnt,
866 textureInfo->fMipmapped,
867 mipmapStatus,
868 fit,
869 budgeted,
870 isProtected,
871 surfaceFlags,
872 useAllocator,
873 this->isDDLProvider(),
874 /*label=*/"TextureRenderTarget_LazyRenderTargetProxy"));
875 }
876
877 GrRenderTargetProxy::WrapsVkSecondaryCB vkSCB =
878 wrapsVkSecondaryCB ? GrRenderTargetProxy::WrapsVkSecondaryCB::kYes
879 : GrRenderTargetProxy::WrapsVkSecondaryCB::kNo;
880
881 return sk_sp<GrRenderTargetProxy>(
882 new GrRenderTargetProxy(std::move(callback),
883 format,
884 dimensions,
885 sampleCnt,
886 fit,
887 budgeted,
888 isProtected,
889 surfaceFlags,
890 useAllocator,
891 vkSCB,
892 /*label=*/"RenderTargetProxy_LazyRenderTargetProxy"));
893 }
894
MakeFullyLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrProtected isProtected,const GrCaps & caps,UseAllocator useAllocator)895 sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback,
896 const GrBackendFormat& format,
897 GrRenderable renderable,
898 int renderTargetSampleCnt,
899 GrProtected isProtected,
900 const GrCaps& caps,
901 UseAllocator useAllocator) {
902 if (!format.isValid()) {
903 return nullptr;
904 }
905
906 SkASSERT(renderTargetSampleCnt == 1 || renderable == GrRenderable::kYes);
907 // TODO: If we ever have callers requesting specific surface flags then we shouldn't use the
908 // extra deferred flags here. Instead those callers should all pass in exactly what they want.
909 // However, as of today all uses of this essentially create a deferred proxy in the end.
910 GrInternalSurfaceFlags surfaceFlags = caps.getExtraSurfaceFlagsForDeferredRT();
911
912 // MakeFullyLazyProxy is only called at flush time so we know these texture proxies are
913 // not being created by a DDL provider.
914 static constexpr SkISize kLazyDims = {-1, -1};
915 if (GrRenderable::kYes == renderable) {
916 return sk_sp<GrTextureProxy>(
917 new GrTextureRenderTargetProxy(caps,
918 std::move(callback),
919 format,
920 kLazyDims,
921 renderTargetSampleCnt,
922 skgpu::Mipmapped::kNo,
923 GrMipmapStatus::kNotAllocated,
924 SkBackingFit::kApprox,
925 skgpu::Budgeted::kYes,
926 isProtected,
927 surfaceFlags,
928 useAllocator,
929 GrDDLProvider::kNo,
930 /*label=*/"TextureRenderTarget_FullyLazyProxy"));
931 } else {
932 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback),
933 format,
934 kLazyDims,
935 skgpu::Mipmapped::kNo,
936 GrMipmapStatus::kNotAllocated,
937 SkBackingFit::kApprox,
938 skgpu::Budgeted::kYes,
939 isProtected,
940 surfaceFlags,
941 useAllocator,
942 GrDDLProvider::kNo,
943 /*label=*/"Texture_FullyLazyProxy"));
944 }
945 }
946
processInvalidUniqueKey(const skgpu::UniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource)947 void GrProxyProvider::processInvalidUniqueKey(const skgpu::UniqueKey& key,
948 GrTextureProxy* proxy,
949 InvalidateGPUResource invalidateGPUResource) {
950 this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes);
951 }
952
processInvalidUniqueKeyImpl(const skgpu::UniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource,RemoveTableEntry removeTableEntry)953 void GrProxyProvider::processInvalidUniqueKeyImpl(const skgpu::UniqueKey& key,
954 GrTextureProxy* proxy,
955 InvalidateGPUResource invalidateGPUResource,
956 RemoveTableEntry removeTableEntry) {
957 SkASSERT(key.isValid());
958
959 if (!proxy) {
960 proxy = fUniquelyKeyedProxies.find(key);
961 }
962 SkASSERT(!proxy || proxy->getUniqueKey() == key);
963
964 // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the
965 // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
966 sk_sp<GrGpuResource> invalidGpuResource;
967 if (InvalidateGPUResource::kYes == invalidateGPUResource) {
968 auto direct = fImageContext->asDirectContext();
969 if (direct) {
970 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
971 invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key);
972 }
973 SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
974 }
975
976 // Note: this method is called for the whole variety of GrGpuResources so often 'key'
977 // will not be in 'fUniquelyKeyedProxies'.
978 if (proxy) {
979 if (removeTableEntry == RemoveTableEntry::kYes) {
980 fUniquelyKeyedProxies.remove(key);
981 }
982 proxy->cacheAccess().clearUniqueKey();
983 }
984
985 if (invalidGpuResource) {
986 invalidGpuResource->resourcePriv().removeUniqueKey();
987 }
988 }
989
isDDLProvider() const990 GrDDLProvider GrProxyProvider::isDDLProvider() const {
991 return fImageContext->asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes;
992 }
993
contextID() const994 uint32_t GrProxyProvider::contextID() const {
995 return fImageContext->priv().contextID();
996 }
997
caps() const998 const GrCaps* GrProxyProvider::caps() const {
999 return fImageContext->priv().caps();
1000 }
1001
refCaps() const1002 sk_sp<const GrCaps> GrProxyProvider::refCaps() const {
1003 return fImageContext->priv().refCaps();
1004 }
1005
isAbandoned() const1006 bool GrProxyProvider::isAbandoned() const {
1007 return fImageContext->priv().abandoned();
1008 }
1009
orphanAllUniqueKeys()1010 void GrProxyProvider::orphanAllUniqueKeys() {
1011 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
1012 proxy->fProxyProvider = nullptr;
1013 });
1014 }
1015
removeAllUniqueKeys()1016 void GrProxyProvider::removeAllUniqueKeys() {
1017 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
1018 // It's not safe to remove table entries while iterating with foreach(),
1019 // but since we're going to remove them all anyway, simply save that for the end.
1020 this->processInvalidUniqueKeyImpl(proxy->getUniqueKey(), proxy,
1021 InvalidateGPUResource::kNo,
1022 RemoveTableEntry::kNo);
1023 });
1024 // Removing all those table entries is safe now.
1025 fUniquelyKeyedProxies.reset();
1026 }
1027
renderingDirectly() const1028 bool GrProxyProvider::renderingDirectly() const {
1029 return fImageContext->asDirectContext();
1030 }
1031