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