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 "GrProxyProvider.h"
9
10 #include "GrCaps.h"
11 #include "GrRenderTarget.h"
12 #include "GrResourceKey.h"
13 #include "GrResourceProvider.h"
14 #include "GrSurfaceProxy.h"
15 #include "GrSurfaceProxyPriv.h"
16 #include "GrTexture.h"
17 #include "GrTextureProxyCacheAccess.h"
18 #include "GrTextureRenderTargetProxy.h"
19 #include "../private/GrSingleOwner.h"
20 #include "SkAutoPixmapStorage.h"
21 #include "SkBitmap.h"
22 #include "SkGr.h"
23 #include "SkImage.h"
24 #include "SkImage_Base.h"
25 #include "SkImageInfoPriv.h"
26 #include "SkImagePriv.h"
27 #include "SkMipMap.h"
28 #include "SkTraceEvent.h"
29
30 #define ASSERT_SINGLE_OWNER \
31 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
32
GrProxyProvider(GrResourceProvider * resourceProvider,GrResourceCache * resourceCache,sk_sp<const GrCaps> caps,GrSingleOwner * owner)33 GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider,
34 GrResourceCache* resourceCache,
35 sk_sp<const GrCaps> caps,
36 GrSingleOwner* owner)
37 : fResourceProvider(resourceProvider)
38 , fResourceCache(resourceCache)
39 , fAbandoned(false)
40 , fCaps(caps)
41 , fContextUniqueID(resourceCache->contextUniqueID())
42 #ifdef SK_DEBUG
43 , fSingleOwner(owner)
44 #endif
45 {
46 SkASSERT(fResourceProvider);
47 SkASSERT(fResourceCache);
48 SkASSERT(fCaps);
49 SkASSERT(fSingleOwner);
50 }
51
GrProxyProvider(uint32_t contextUniqueID,sk_sp<const GrCaps> caps,GrSingleOwner * owner)52 GrProxyProvider::GrProxyProvider(uint32_t contextUniqueID,
53 sk_sp<const GrCaps> caps,
54 GrSingleOwner* owner)
55 : fResourceProvider(nullptr)
56 , fResourceCache(nullptr)
57 , fAbandoned(false)
58 , fCaps(caps)
59 , fContextUniqueID(contextUniqueID)
60 #ifdef SK_DEBUG
61 , fSingleOwner(owner)
62 #endif
63 {
64 SkASSERT(fContextUniqueID != SK_InvalidUniqueID);
65 SkASSERT(fCaps);
66 SkASSERT(fSingleOwner);
67 }
68
~GrProxyProvider()69 GrProxyProvider::~GrProxyProvider() {
70 if (fResourceCache) {
71 // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since
72 // they need their unique keys to, potentially, find a cached resource when the
73 // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point.
74 SkASSERT(!fUniquelyKeyedProxies.count());
75 }
76 }
77
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)78 bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
79 ASSERT_SINGLE_OWNER
80 SkASSERT(key.isValid());
81 if (this->isAbandoned() || !proxy) {
82 return false;
83 }
84
85 // If there is already a GrResource with this key then the caller has violated the normal
86 // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing
87 // if it already existed in the cache).
88 SkASSERT(!fResourceCache || !fResourceCache->findAndRefUniqueResource(key));
89
90 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key
91
92 proxy->cacheAccess().setUniqueKey(this, key);
93 SkASSERT(proxy->getUniqueKey() == key);
94 fUniquelyKeyedProxies.add(proxy);
95 return true;
96 }
97
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)98 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
99 SkASSERT(surf->getUniqueKey().isValid());
100 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
101 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
102 // multiple proxies can't get the same key
103 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
104 fUniquelyKeyedProxies.add(proxy);
105 }
106
removeUniqueKeyFromProxy(GrTextureProxy * proxy)107 void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) {
108 ASSERT_SINGLE_OWNER
109 SkASSERT(proxy);
110 SkASSERT(proxy->getUniqueKey().isValid());
111
112 if (this->isAbandoned()) {
113 return;
114 }
115
116 this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes);
117 }
118
findProxyByUniqueKey(const GrUniqueKey & key,GrSurfaceOrigin origin)119 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key,
120 GrSurfaceOrigin origin) {
121 ASSERT_SINGLE_OWNER
122
123 if (this->isAbandoned()) {
124 return nullptr;
125 }
126
127 sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
128 if (result) {
129 SkASSERT(result->origin() == origin);
130 }
131 return result;
132 }
133
createWrapped(sk_sp<GrTexture> tex,GrSurfaceOrigin origin)134 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) {
135 #ifdef SK_DEBUG
136 if (tex->getUniqueKey().isValid()) {
137 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin));
138 }
139 #endif
140
141 if (tex->asRenderTarget()) {
142 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin));
143 } else {
144 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin));
145 }
146 }
147
findOrCreateProxyByUniqueKey(const GrUniqueKey & key,GrSurfaceOrigin origin)148 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key,
149 GrSurfaceOrigin origin) {
150 ASSERT_SINGLE_OWNER
151
152 if (this->isAbandoned()) {
153 return nullptr;
154 }
155
156 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin);
157 if (result) {
158 return result;
159 }
160
161 if (!fResourceCache) {
162 return nullptr;
163 }
164
165 GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key);
166 if (!resource) {
167 return nullptr;
168 }
169
170 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
171 SkASSERT(texture);
172
173 result = this->createWrapped(std::move(texture), origin);
174 SkASSERT(result->getUniqueKey() == key);
175 // createWrapped should've added this for us
176 SkASSERT(fUniquelyKeyedProxies.find(key));
177 return result;
178 }
179
createTextureProxy(sk_sp<SkImage> srcImage,GrSurfaceDescFlags descFlags,int sampleCnt,SkBudgeted budgeted,SkBackingFit fit,GrInternalSurfaceFlags surfaceFlags)180 sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage,
181 GrSurfaceDescFlags descFlags,
182 int sampleCnt,
183 SkBudgeted budgeted,
184 SkBackingFit fit,
185 GrInternalSurfaceFlags surfaceFlags) {
186 ASSERT_SINGLE_OWNER
187 SkASSERT(srcImage);
188
189 if (this->isAbandoned()) {
190 return nullptr;
191 }
192
193 SkImageInfo info = as_IB(srcImage)->onImageInfo();
194 GrPixelConfig config = SkImageInfo2GrPixelConfig(info);
195
196 if (kUnknown_GrPixelConfig == config) {
197 return nullptr;
198 }
199
200 GrBackendFormat format = fCaps->getBackendFormatFromColorType(info.colorType());
201 if (!format.isValid()) {
202 return nullptr;
203 }
204
205 if (!this->caps()->isConfigTexturable(config)) {
206 SkBitmap copy8888;
207 if (!copy8888.tryAllocPixels(info.makeColorType(kRGBA_8888_SkColorType)) ||
208 !srcImage->readPixels(copy8888.pixmap(), 0, 0)) {
209 return nullptr;
210 }
211 copy8888.setImmutable();
212 srcImage = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode);
213 config = kRGBA_8888_GrPixelConfig;
214 }
215
216 if (SkToBool(descFlags & kRenderTarget_GrSurfaceFlag)) {
217 sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, config);
218 if (!sampleCnt) {
219 return nullptr;
220 }
221 }
222
223 if (SkToBool(descFlags & kRenderTarget_GrSurfaceFlag)) {
224 if (fCaps->usesMixedSamples() && sampleCnt > 1) {
225 surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;
226 }
227 }
228
229 GrSurfaceDesc desc;
230 desc.fWidth = srcImage->width();
231 desc.fHeight = srcImage->height();
232 desc.fFlags = descFlags;
233 desc.fSampleCnt = sampleCnt;
234 desc.fConfig = config;
235
236 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
237 [desc, budgeted, srcImage, fit, surfaceFlags](GrResourceProvider* resourceProvider) {
238 if (!resourceProvider) {
239 // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref
240 // on srcImage will be released.
241 return sk_sp<GrTexture>();
242 }
243 SkPixmap pixMap;
244 SkAssertResult(srcImage->peekPixels(&pixMap));
245 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() };
246
247 auto resourceProviderFlags = GrResourceProvider::Flags::kNone;
248 if (surfaceFlags & GrInternalSurfaceFlags::kNoPendingIO) {
249 resourceProviderFlags |= GrResourceProvider::Flags::kNoPendingIO;
250 }
251 return resourceProvider->createTexture(desc, budgeted, fit, mipLevel,
252 resourceProviderFlags);
253 },
254 format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, surfaceFlags, fit, budgeted);
255
256 if (!proxy) {
257 return nullptr;
258 }
259
260 if (fResourceProvider) {
261 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
262 // we're better off instantiating the proxy immediately here.
263 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
264 return nullptr;
265 }
266 }
267
268 SkASSERT(proxy->width() == desc.fWidth);
269 SkASSERT(proxy->height() == desc.fHeight);
270 return proxy;
271 }
272
createMipMapProxy(const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,SkBudgeted budgeted)273 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrBackendFormat& format,
274 const GrSurfaceDesc& desc,
275 GrSurfaceOrigin origin,
276 SkBudgeted budgeted) {
277 ASSERT_SINGLE_OWNER
278
279 if (this->isAbandoned()) {
280 return nullptr;
281 }
282
283 return this->createProxy(format, desc, origin, GrMipMapped::kYes, SkBackingFit::kExact,
284 budgeted, GrInternalSurfaceFlags::kNone);
285 }
286
createMipMapProxyFromBitmap(const SkBitmap & bitmap)287 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxyFromBitmap(const SkBitmap& bitmap) {
288 if (!SkImageInfoIsValid(bitmap.info())) {
289 return nullptr;
290 }
291
292 ATRACE_ANDROID_FRAMEWORK("Upload MipMap Texture [%ux%u]", bitmap.width(), bitmap.height());
293
294 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
295 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the
296 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
297 SkCopyPixelsMode copyMode = this->recordingDDL() ? kIfMutable_SkCopyPixelsMode
298 : kNever_SkCopyPixelsMode;
299 sk_sp<SkImage> baseLevel = SkMakeImageFromRasterBitmap(bitmap, copyMode);
300 if (!baseLevel) {
301 return nullptr;
302 }
303
304 // This was never going to have mips anyway
305 if (0 == SkMipMap::ComputeLevelCount(baseLevel->width(), baseLevel->height())) {
306 return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes,
307 SkBackingFit::kExact);
308 }
309
310 const GrBackendFormat format = fCaps->getBackendFormatFromColorType(bitmap.info().colorType());
311 if (!format.isValid()) {
312 return nullptr;
313 }
314
315 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info());
316 if (!this->caps()->isConfigTexturable(desc.fConfig)) {
317 SkBitmap copy8888;
318 if (!copy8888.tryAllocPixels(bitmap.info().makeColorType(kRGBA_8888_SkColorType)) ||
319 !bitmap.readPixels(copy8888.pixmap())) {
320 return nullptr;
321 }
322 copy8888.setImmutable();
323 baseLevel = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode);
324 desc.fConfig = kRGBA_8888_GrPixelConfig;
325 }
326
327 SkPixmap pixmap;
328 SkAssertResult(baseLevel->peekPixels(&pixmap));
329 sk_sp<SkMipMap> mipmaps(SkMipMap::Build(pixmap, nullptr));
330 if (!mipmaps) {
331 return nullptr;
332 }
333
334 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
335 [desc, baseLevel, mipmaps](GrResourceProvider* resourceProvider) {
336 if (!resourceProvider) {
337 return sk_sp<GrTexture>();
338 }
339
340 const int mipLevelCount = mipmaps->countLevels() + 1;
341 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
342
343 SkPixmap pixmap;
344 SkAssertResult(baseLevel->peekPixels(&pixmap));
345
346 // DDL TODO: Instead of copying all this info into GrMipLevels we should just plumb
347 // the use of SkMipMap down through Ganesh.
348 texels[0].fPixels = pixmap.addr();
349 texels[0].fRowBytes = pixmap.rowBytes();
350
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 }
358
359 return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(),
360 mipLevelCount);
361 },
362 format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes, SkBackingFit::kExact,
363 SkBudgeted::kYes);
364
365 if (!proxy) {
366 return nullptr;
367 }
368
369 if (fResourceProvider) {
370 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
371 // we're better off instantiating the proxy immediately here.
372 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
373 return nullptr;
374 }
375 }
376 return proxy;
377 }
378
createProxy(const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted,GrInternalSurfaceFlags surfaceFlags)379 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format,
380 const GrSurfaceDesc& desc,
381 GrSurfaceOrigin origin,
382 GrMipMapped mipMapped,
383 SkBackingFit fit,
384 SkBudgeted budgeted,
385 GrInternalSurfaceFlags surfaceFlags) {
386 if (GrMipMapped::kYes == mipMapped) {
387 // SkMipMap doesn't include the base level in the level count so we have to add 1
388 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
389 if (1 == mipCount) {
390 mipMapped = GrMipMapped::kNo;
391 }
392 }
393
394 if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) {
395 return nullptr;
396 }
397 GrSurfaceDesc copyDesc = desc;
398 if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
399 copyDesc.fSampleCnt =
400 this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig);
401 }
402
403 if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
404 // We know anything we instantiate later from this deferred path will be
405 // both texturable and renderable
406 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*this->caps(), format, copyDesc,
407 origin, mipMapped,
408 fit, budgeted, surfaceFlags));
409 }
410
411 return sk_sp<GrTextureProxy>(new GrTextureProxy(format, copyDesc, origin, mipMapped,
412 fit, budgeted, surfaceFlags));
413 }
414
createProxy(sk_sp<SkData> data,const GrSurfaceDesc & desc)415 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(sk_sp<SkData> data, const GrSurfaceDesc& desc) {
416 if (!this->caps()->isConfigTexturable(desc.fConfig)) {
417 return nullptr;
418 }
419
420 const GrColorType ct = GrPixelConfigToColorType(desc.fConfig);
421 const GrBackendFormat format = fCaps->getBackendFormatFromGrColorType(ct, GrSRGBEncoded::kNo);
422
423 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
424 [desc, data](GrResourceProvider* resourceProvider) {
425 if (!resourceProvider) {
426 return sk_sp<GrTexture>();
427 }
428
429 GrMipLevel texels;
430 texels.fPixels = data->data();
431 texels.fRowBytes = GrBytesPerPixel(desc.fConfig)*desc.fWidth;
432 return resourceProvider->createTexture(desc, SkBudgeted::kYes, &texels, 1);
433 },
434 format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
435 SkBudgeted::kYes);
436
437 if (!proxy) {
438 return nullptr;
439 }
440
441 if (fResourceProvider) {
442 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
443 // we're better off instantiating the proxy immediately here.
444 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
445 return nullptr;
446 }
447 }
448 return proxy;
449 }
450
wrapBackendTexture(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType,ReleaseProc releaseProc,ReleaseContext releaseCtx)451 sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(const GrBackendTexture& backendTex,
452 GrSurfaceOrigin origin,
453 GrWrapOwnership ownership,
454 GrWrapCacheable cacheable,
455 GrIOType ioType,
456 ReleaseProc releaseProc,
457 ReleaseContext releaseCtx) {
458 SkASSERT(ioType != kWrite_GrIOType);
459 if (this->isAbandoned()) {
460 return nullptr;
461 }
462
463 // This is only supported on a direct GrContext.
464 if (!fResourceProvider) {
465 return nullptr;
466 }
467
468 sk_sp<GrTexture> tex =
469 fResourceProvider->wrapBackendTexture(backendTex, ownership, cacheable, ioType);
470 if (!tex) {
471 return nullptr;
472 }
473
474 sk_sp<GrReleaseProcHelper> releaseHelper;
475 if (releaseProc) {
476 releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx));
477 // This gives the texture a ref on the releaseHelper
478 tex->setRelease(releaseHelper);
479 }
480
481 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
482 // Make sure we match how we created the proxy with SkBudgeted::kNo
483 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
484
485 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin));
486 }
487
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)488 sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture(
489 const GrBackendTexture& backendTex, GrSurfaceOrigin origin, int sampleCnt,
490 GrWrapOwnership ownership, GrWrapCacheable cacheable) {
491 if (this->isAbandoned()) {
492 return nullptr;
493 }
494
495 // This is only supported on a direct GrContext.
496 if (!fResourceProvider) {
497 return nullptr;
498 }
499
500 sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config());
501 if (!sampleCnt) {
502 return nullptr;
503 }
504
505 sk_sp<GrTexture> tex = fResourceProvider->wrapRenderableBackendTexture(backendTex, sampleCnt,
506 ownership, cacheable);
507 if (!tex) {
508 return nullptr;
509 }
510
511 SkASSERT(tex->asRenderTarget()); // A GrTextureRenderTarget
512 // Make sure we match how we created the proxy with SkBudgeted::kNo
513 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
514
515 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin));
516 }
517
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin)518 sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget(
519 const GrBackendRenderTarget& backendRT, GrSurfaceOrigin origin) {
520 if (this->isAbandoned()) {
521 return nullptr;
522 }
523
524 // This is only supported on a direct GrContext.
525 if (!fResourceProvider) {
526 return nullptr;
527 }
528
529 sk_sp<GrRenderTarget> rt = fResourceProvider->wrapBackendRenderTarget(backendRT);
530 if (!rt) {
531 return nullptr;
532 }
533 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
534 SkASSERT(!rt->getUniqueKey().isValid());
535 // Make sure we match how we created the proxy with SkBudgeted::kNo
536 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
537
538 return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(rt), origin));
539 }
540
wrapBackendTextureAsRenderTarget(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,int sampleCnt)541 sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendTextureAsRenderTarget(
542 const GrBackendTexture& backendTex, GrSurfaceOrigin origin, int sampleCnt) {
543 if (this->isAbandoned()) {
544 return nullptr;
545 }
546
547 // This is only supported on a direct GrContext.
548 if (!fResourceProvider) {
549 return nullptr;
550 }
551
552 sk_sp<GrRenderTarget> rt =
553 fResourceProvider->wrapBackendTextureAsRenderTarget(backendTex, sampleCnt);
554 if (!rt) {
555 return nullptr;
556 }
557 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
558 SkASSERT(!rt->getUniqueKey().isValid());
559 // This proxy should be unbudgeted because we're just wrapping an external resource
560 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
561
562 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
563 }
564
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)565 sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget(
566 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
567 if (this->isAbandoned()) {
568 return nullptr;
569 }
570
571 // This is only supported on a direct GrContext.
572 if (!fResourceProvider) {
573 return nullptr;
574 }
575
576 sk_sp<GrRenderTarget> rt = fResourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
577 vkInfo);
578
579 if (!rt) {
580 return nullptr;
581 }
582 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
583 SkASSERT(!rt->getUniqueKey().isValid());
584 // This proxy should be unbudgeted because we're just wrapping an external resource
585 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
586
587 // All Vulkan surfaces uses top left origins.
588 return sk_sp<GrRenderTargetProxy>(
589 new GrRenderTargetProxy(std::move(rt),
590 kTopLeft_GrSurfaceOrigin,
591 GrRenderTargetProxy::WrapsVkSecondaryCB::kYes));
592 }
593
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted)594 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
595 const GrBackendFormat& format,
596 const GrSurfaceDesc& desc,
597 GrSurfaceOrigin origin,
598 GrMipMapped mipMapped,
599 SkBackingFit fit,
600 SkBudgeted budgeted) {
601 return this->createLazyProxy(std::move(callback), format, desc, origin, mipMapped,
602 GrInternalSurfaceFlags::kNone, fit, budgeted);
603 }
604
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,GrInternalSurfaceFlags surfaceFlags,SkBackingFit fit,SkBudgeted budgeted)605 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
606 const GrBackendFormat& format,
607 const GrSurfaceDesc& desc,
608 GrSurfaceOrigin origin,
609 GrMipMapped mipMapped,
610 GrInternalSurfaceFlags surfaceFlags,
611 SkBackingFit fit,
612 SkBudgeted budgeted) {
613 // For non-ddl draws always make lazy proxy's single use.
614 LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse
615 : LazyInstantiationType::kMultipleUse;
616 return this->createLazyProxy(std::move(callback), format, desc, origin, mipMapped, surfaceFlags,
617 fit, budgeted, lazyType);
618 }
619
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,GrInternalSurfaceFlags surfaceFlags,SkBackingFit fit,SkBudgeted budgeted,LazyInstantiationType lazyType)620 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
621 const GrBackendFormat& format,
622 const GrSurfaceDesc& desc,
623 GrSurfaceOrigin origin,
624 GrMipMapped mipMapped,
625 GrInternalSurfaceFlags surfaceFlags,
626 SkBackingFit fit,
627 SkBudgeted budgeted,
628 LazyInstantiationType lazyType) {
629 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
630 (desc.fWidth > 0 && desc.fHeight > 0));
631
632 if (desc.fWidth > fCaps->maxTextureSize() || desc.fHeight > fCaps->maxTextureSize()) {
633 return nullptr;
634 }
635
636
637 #ifdef SK_DEBUG
638 if (SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)) {
639 if (SkToBool(surfaceFlags & GrInternalSurfaceFlags::kMixedSampled)) {
640 SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1);
641 }
642 }
643 #endif
644
645 return sk_sp<GrTextureProxy>(
646 SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)
647 ? new GrTextureRenderTargetProxy(std::move(callback), lazyType, format, desc,
648 origin, mipMapped, fit, budgeted, surfaceFlags)
649 : new GrTextureProxy(std::move(callback), lazyType, format, desc, origin,
650 mipMapped, fit, budgeted, surfaceFlags));
651 }
652
createLazyRenderTargetProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrInternalSurfaceFlags surfaceFlags,const TextureInfo * textureInfo,SkBackingFit fit,SkBudgeted budgeted)653 sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy(
654 LazyInstantiateCallback&& callback, const GrBackendFormat& format,
655 const GrSurfaceDesc& desc, GrSurfaceOrigin origin, GrInternalSurfaceFlags surfaceFlags,
656 const TextureInfo* textureInfo, SkBackingFit fit, SkBudgeted budgeted) {
657 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
658 (desc.fWidth > 0 && desc.fHeight > 0));
659
660 if (desc.fWidth > fCaps->maxRenderTargetSize() || desc.fHeight > fCaps->maxRenderTargetSize()) {
661 return nullptr;
662 }
663
664 SkASSERT(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags));
665
666 #ifdef SK_DEBUG
667 if (SkToBool(surfaceFlags & GrInternalSurfaceFlags::kMixedSampled)) {
668 SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1);
669 }
670 #endif
671
672 using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
673 // For non-ddl draws always make lazy proxy's single use.
674 LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse
675 : LazyInstantiationType::kMultipleUse;
676
677 if (textureInfo) {
678 return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(
679 std::move(callback), lazyType, format, desc, origin, textureInfo->fMipMapped,
680 fit, budgeted, surfaceFlags));
681 }
682
683 return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(
684 std::move(callback), lazyType, format, desc, origin, fit, budgeted, surfaceFlags));
685 }
686
MakeFullyLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,Renderable renderable,GrSurfaceOrigin origin,GrPixelConfig config,const GrCaps & caps)687 sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback,
688 const GrBackendFormat& format,
689 Renderable renderable,
690 GrSurfaceOrigin origin,
691 GrPixelConfig config,
692 const GrCaps& caps) {
693 GrSurfaceDesc desc;
694 GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNoPendingIO;
695 if (Renderable::kYes == renderable) {
696 desc.fFlags = kRenderTarget_GrSurfaceFlag;
697 }
698 desc.fWidth = -1;
699 desc.fHeight = -1;
700 desc.fConfig = config;
701 desc.fSampleCnt = 1;
702
703 return sk_sp<GrTextureProxy>(
704 (Renderable::kYes == renderable)
705 ? new GrTextureRenderTargetProxy(
706 std::move(callback), LazyInstantiationType::kSingleUse, format, desc,
707 origin, GrMipMapped::kNo, SkBackingFit::kApprox, SkBudgeted::kYes,
708 surfaceFlags)
709 : new GrTextureProxy(std::move(callback), LazyInstantiationType::kSingleUse,
710 format, desc, origin, GrMipMapped::kNo,
711 SkBackingFit::kApprox, SkBudgeted::kYes, surfaceFlags));
712 }
713
IsFunctionallyExact(GrSurfaceProxy * proxy)714 bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
715 const bool isInstantiated = proxy->isInstantiated();
716 // A proxy is functionally exact if:
717 // it is exact (obvs)
718 // when it is instantiated it will be exact (i.e., power of two dimensions)
719 // it is already instantiated and the proxy covers the entire backing surface
720 return proxy->priv().isExact() ||
721 (!isInstantiated && SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())) ||
722 (isInstantiated && proxy->worstCaseWidth() == proxy->width() &&
723 proxy->worstCaseHeight() == proxy->height());
724 }
725
processInvalidUniqueKey(const GrUniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource)726 void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
727 InvalidateGPUResource invalidateGPUResource) {
728 SkASSERT(key.isValid());
729
730 if (!proxy) {
731 proxy = fUniquelyKeyedProxies.find(key);
732 }
733 SkASSERT(!proxy || proxy->getUniqueKey() == key);
734
735 // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the
736 // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
737 sk_sp<GrGpuResource> invalidGpuResource;
738 if (InvalidateGPUResource::kYes == invalidateGPUResource) {
739 if (proxy && proxy->isInstantiated()) {
740 invalidGpuResource = sk_ref_sp(proxy->peekSurface());
741 }
742 if (!invalidGpuResource && fResourceProvider) {
743 invalidGpuResource = fResourceProvider->findByUniqueKey<GrGpuResource>(key);
744 }
745 SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
746 }
747
748 // Note: this method is called for the whole variety of GrGpuResources so often 'key'
749 // will not be in 'fUniquelyKeyedProxies'.
750 if (proxy) {
751 fUniquelyKeyedProxies.remove(key);
752 proxy->cacheAccess().clearUniqueKey();
753 }
754
755 if (invalidGpuResource) {
756 invalidGpuResource->resourcePriv().removeUniqueKey();
757 }
758 }
759
orphanAllUniqueKeys()760 void GrProxyProvider::orphanAllUniqueKeys() {
761 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
762 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
763 GrTextureProxy& tmp = *iter;
764
765 tmp.fProxyProvider = nullptr;
766 }
767 }
768
removeAllUniqueKeys()769 void GrProxyProvider::removeAllUniqueKeys() {
770 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
771 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
772 GrTextureProxy& tmp = *iter;
773
774 this->processInvalidUniqueKey(tmp.getUniqueKey(), &tmp, InvalidateGPUResource::kNo);
775 }
776 SkASSERT(!fUniquelyKeyedProxies.count());
777 }
778