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