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