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/GrResourceKey.h"
15 #include "include/private/GrSingleOwner.h"
16 #include "include/private/SkImageInfoPriv.h"
17 #include "src/core/SkAutoPixmapStorage.h"
18 #include "src/core/SkCompressedDataUtils.h"
19 #include "src/core/SkImagePriv.h"
20 #include "src/core/SkMipmap.h"
21 #include "src/core/SkTraceEvent.h"
22 #include "src/gpu/GrCaps.h"
23 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
24 #include "src/gpu/GrDirectContextPriv.h"
25 #include "src/gpu/GrImageContextPriv.h"
26 #include "src/gpu/GrRenderTarget.h"
27 #include "src/gpu/GrResourceProvider.h"
28 #include "src/gpu/GrSurfaceProxy.h"
29 #include "src/gpu/GrSurfaceProxyPriv.h"
30 #include "src/gpu/GrTexture.h"
31 #include "src/gpu/GrTextureProxyCacheAccess.h"
32 #include "src/gpu/GrTextureRenderTargetProxy.h"
33 #include "src/gpu/SkGr.h"
34 #include "src/image/SkImage_Base.h"
35
36 #ifdef SK_VULKAN
37 #include "include/gpu/vk/GrVkTypes.h"
38 #endif
39
40 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fImageContext->priv().singleOwner())
41
GrProxyProvider(GrImageContext * imageContext)42 GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {}
43
~GrProxyProvider()44 GrProxyProvider::~GrProxyProvider() {
45 if (this->renderingDirectly()) {
46 // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since
47 // they need their unique keys to, potentially, find a cached resource when the
48 // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point.
49 SkASSERT(!fUniquelyKeyedProxies.count());
50 }
51 }
52
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)53 bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
54 ASSERT_SINGLE_OWNER
55 SkASSERT(key.isValid());
56 if (this->isAbandoned() || !proxy) {
57 return false;
58 }
59
60 // Only the proxyProvider that created a proxy should be assigning unique keys to it.
61 SkASSERT(this->isDDLProvider() == proxy->creatingProvider());
62
63 #ifdef SK_DEBUG
64 {
65 auto direct = fImageContext->asDirectContext();
66 if (direct) {
67 GrResourceCache* resourceCache = direct->priv().getResourceCache();
68 // If there is already a GrResource with this key then the caller has violated the
69 // normal usage pattern of uniquely keyed resources (e.g., they have created one w/o
70 // first seeing if it already existed in the cache).
71 SkASSERT(!resourceCache->findAndRefUniqueResource(key));
72 }
73 }
74 #endif
75
76 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key
77
78 proxy->cacheAccess().setUniqueKey(this, key);
79 SkASSERT(proxy->getUniqueKey() == key);
80 fUniquelyKeyedProxies.add(proxy);
81 return true;
82 }
83
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)84 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
85 SkASSERT(surf->getUniqueKey().isValid());
86 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
87 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
88 // multiple proxies can't get the same key
89 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
90 fUniquelyKeyedProxies.add(proxy);
91 }
92
removeUniqueKeyFromProxy(GrTextureProxy * proxy)93 void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) {
94 ASSERT_SINGLE_OWNER
95 SkASSERT(proxy);
96 SkASSERT(proxy->getUniqueKey().isValid());
97
98 if (this->isAbandoned()) {
99 return;
100 }
101
102 this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes);
103 }
104
findProxyByUniqueKey(const GrUniqueKey & key)105 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key) {
106 ASSERT_SINGLE_OWNER
107
108 if (this->isAbandoned()) {
109 return nullptr;
110 }
111
112 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
113 if (proxy) {
114 return sk_ref_sp(proxy);
115 }
116 return nullptr;
117 }
118
119 ///////////////////////////////////////////////////////////////////////////////
120
121 #if GR_TEST_UTILS
testingOnly_createInstantiatedProxy(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected)122 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
123 SkISize dimensions,
124 const GrBackendFormat& format,
125 GrRenderable renderable,
126 int renderTargetSampleCnt,
127 SkBackingFit fit,
128 SkBudgeted budgeted,
129 GrProtected isProtected) {
130 ASSERT_SINGLE_OWNER
131 if (this->isAbandoned()) {
132 return nullptr;
133 }
134 auto direct = fImageContext->asDirectContext();
135 if (!direct) {
136 return nullptr;
137 }
138
139 if (this->caps()->isFormatCompressed(format)) {
140 // TODO: Allow this to go to GrResourceProvider::createCompressedTexture() once we no longer
141 // rely on GrColorType to get a swizzle for the proxy.
142 return nullptr;
143 }
144
145 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
146 sk_sp<GrTexture> tex;
147
148 if (SkBackingFit::kApprox == fit) {
149 tex = resourceProvider->createApproxTexture(dimensions,
150 format,
151 format.textureType(),
152 renderable,
153 renderTargetSampleCnt,
154 isProtected);
155 } else {
156 tex = resourceProvider->createTexture(dimensions,
157 format,
158 format.textureType(),
159 renderable,
160 renderTargetSampleCnt,
161 GrMipmapped::kNo,
162 budgeted,
163 isProtected);
164 }
165 if (!tex) {
166 return nullptr;
167 }
168
169 return this->createWrapped(std::move(tex), UseAllocator::kYes);
170 }
171
testingOnly_createInstantiatedProxy(SkISize dimensions,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected)172 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
173 SkISize dimensions,
174 GrColorType colorType,
175 GrRenderable renderable,
176 int renderTargetSampleCnt,
177 SkBackingFit fit,
178 SkBudgeted budgeted,
179 GrProtected isProtected) {
180 ASSERT_SINGLE_OWNER
181 if (this->isAbandoned()) {
182 return nullptr;
183 }
184 auto format = this->caps()->getDefaultBackendFormat(colorType, renderable);
185 return this->testingOnly_createInstantiatedProxy(dimensions,
186 format,
187 renderable,
188 renderTargetSampleCnt,
189 fit,
190 budgeted,
191 isProtected);
192 }
193
testingOnly_createWrapped(sk_sp<GrTexture> tex)194 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createWrapped(sk_sp<GrTexture> tex) {
195 return this->createWrapped(std::move(tex), UseAllocator::kYes);
196 }
197 #endif
198
createWrapped(sk_sp<GrTexture> tex,UseAllocator useAllocator)199 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex,
200 UseAllocator useAllocator) {
201 #ifdef SK_DEBUG
202 if (tex->getUniqueKey().isValid()) {
203 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey()));
204 }
205 #endif
206
207 if (tex->asRenderTarget()) {
208 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), useAllocator,
209 this->isDDLProvider()));
210 } else {
211 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), useAllocator,
212 this->isDDLProvider()));
213 }
214 }
215
findOrCreateProxyByUniqueKey(const GrUniqueKey & key,UseAllocator useAllocator)216 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key,
217 UseAllocator useAllocator) {
218 ASSERT_SINGLE_OWNER
219
220 if (this->isAbandoned()) {
221 return nullptr;
222 }
223
224 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key);
225 if (result) {
226 return result;
227 }
228
229 auto direct = fImageContext->asDirectContext();
230 if (!direct) {
231 return nullptr;
232 }
233
234 GrResourceCache* resourceCache = direct->priv().getResourceCache();
235
236 GrGpuResource* resource = resourceCache->findAndRefUniqueResource(key);
237 if (!resource) {
238 return nullptr;
239 }
240
241 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
242 SkASSERT(texture);
243
244 result = this->createWrapped(std::move(texture), useAllocator);
245 SkASSERT(result->getUniqueKey() == key);
246 // createWrapped should've added this for us
247 SkASSERT(fUniquelyKeyedProxies.find(key));
248 return result;
249 }
250
findCachedProxyWithColorTypeFallback(const GrUniqueKey & key,GrSurfaceOrigin origin,GrColorType ct,int sampleCnt)251 GrSurfaceProxyView GrProxyProvider::findCachedProxyWithColorTypeFallback(const GrUniqueKey& 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 GrSwizzle 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 GrUniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource)865 void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
866 InvalidateGPUResource invalidateGPUResource) {
867 this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes);
868 }
869
processInvalidUniqueKeyImpl(const GrUniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource,RemoveTableEntry removeTableEntry)870 void GrProxyProvider::processInvalidUniqueKeyImpl(const GrUniqueKey& key, GrTextureProxy* proxy,
871 InvalidateGPUResource invalidateGPUResource,
872 RemoveTableEntry removeTableEntry) {
873 SkASSERT(key.isValid());
874
875 if (!proxy) {
876 proxy = fUniquelyKeyedProxies.find(key);
877 }
878 SkASSERT(!proxy || proxy->getUniqueKey() == key);
879
880 // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the
881 // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
882 sk_sp<GrGpuResource> invalidGpuResource;
883 if (InvalidateGPUResource::kYes == invalidateGPUResource) {
884 auto direct = fImageContext->asDirectContext();
885 if (direct) {
886 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
887 invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key);
888 }
889 SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
890 }
891
892 // Note: this method is called for the whole variety of GrGpuResources so often 'key'
893 // will not be in 'fUniquelyKeyedProxies'.
894 if (proxy) {
895 if (removeTableEntry == RemoveTableEntry::kYes) {
896 fUniquelyKeyedProxies.remove(key);
897 }
898 proxy->cacheAccess().clearUniqueKey();
899 }
900
901 if (invalidGpuResource) {
902 invalidGpuResource->resourcePriv().removeUniqueKey();
903 }
904 }
905
isDDLProvider() const906 GrDDLProvider GrProxyProvider::isDDLProvider() const {
907 return fImageContext->asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes;
908 }
909
contextID() const910 uint32_t GrProxyProvider::contextID() const {
911 return fImageContext->priv().contextID();
912 }
913
caps() const914 const GrCaps* GrProxyProvider::caps() const {
915 return fImageContext->priv().caps();
916 }
917
refCaps() const918 sk_sp<const GrCaps> GrProxyProvider::refCaps() const {
919 return fImageContext->priv().refCaps();
920 }
921
isAbandoned() const922 bool GrProxyProvider::isAbandoned() const {
923 return fImageContext->priv().abandoned();
924 }
925
orphanAllUniqueKeys()926 void GrProxyProvider::orphanAllUniqueKeys() {
927 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
928 proxy->fProxyProvider = nullptr;
929 });
930 }
931
removeAllUniqueKeys()932 void GrProxyProvider::removeAllUniqueKeys() {
933 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
934 // It's not safe to remove table entries while iterating with foreach(),
935 // but since we're going to remove them all anyway, simply save that for the end.
936 this->processInvalidUniqueKeyImpl(proxy->getUniqueKey(), proxy,
937 InvalidateGPUResource::kNo,
938 RemoveTableEntry::kNo);
939 });
940 // Removing all those table entries is safe now.
941 fUniquelyKeyedProxies.reset();
942 }
943
renderingDirectly() const944 bool GrProxyProvider::renderingDirectly() const {
945 return fImageContext->asDirectContext();
946 }
947