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