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