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