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