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