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 | |
38 | GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {} |
39 | |
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 | |
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 | // 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 | |
80 | void 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 | |
89 | void 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 | |
101 | sk_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 |
118 | sk_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 | |
158 | sk_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 | |
180 | sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createWrapped(sk_sp<GrTexture> tex) { |
181 | return this->createWrapped(std::move(tex), UseAllocator::kYes); |
182 | } |
183 | #endif |
184 | |
185 | sk_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 | |
202 | sk_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 | |
237 | GrSurfaceProxyView 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 | |
256 | sk_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 | |
312 | sk_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 | |
342 | sk_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 | |
393 | sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format, |
394 | SkISize dimensions, |
395 | GrRenderable renderable, |
396 | int renderTargetSampleCnt, |
397 | GrMipmapped mipMapped, |
398 | SkBackingFit fit, |
399 | SkBudgeted budgeted, |
400 | GrProtected isProtected, |
401 | GrInternalSurfaceFlags surfaceFlags, |
402 | GrSurfaceProxy::UseAllocator useAllocator) { |
403 | ASSERT_SINGLE_OWNER |
404 | if (this->isAbandoned()) { |
405 | return nullptr; |
406 | } |
407 | |
408 | const GrCaps* caps = this->caps(); |
409 | |
410 | if (caps->isFormatCompressed(format)) { |
411 | // Deferred proxies for compressed textures are not supported. |
412 | return nullptr; |
413 | } |
414 | |
415 | if (GrMipmapped::kYes == mipMapped) { |
416 | // SkMipmap doesn't include the base level in the level count so we have to add 1 |
417 | int mipCount = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1; |
418 | if (1 == mipCount) { |
419 | mipMapped = GrMipmapped::kNo; |
420 | } |
421 | } |
422 | |
423 | if (!caps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt, |
424 | mipMapped)) { |
425 | return nullptr; |
426 | } |
427 | GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipMapped) |
428 | ? GrMipmapStatus::kDirty |
429 | : GrMipmapStatus::kNotAllocated; |
430 | if (renderable == GrRenderable::kYes) { |
431 | renderTargetSampleCnt = caps->getRenderTargetSampleCount(renderTargetSampleCnt, format); |
432 | SkASSERT(renderTargetSampleCnt); |
433 | // 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 | |
445 | sk_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 | |
488 | sk_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 | |
525 | sk_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 | |
560 | sk_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 | |
601 | sk_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 | |
633 | sk_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 | |
660 | sk_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 | |
696 | sk_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 | |
753 | sk_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 | |
797 | sk_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 | |
828 | void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy, |
829 | InvalidateGPUResource invalidateGPUResource) { |
830 | this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes); |
831 | } |
832 | |
833 | void 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 | |
869 | GrDDLProvider GrProxyProvider::isDDLProvider() const { |
870 | return fImageContext->asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes; |
871 | } |
872 | |
873 | uint32_t GrProxyProvider::contextID() const { |
874 | return fImageContext->priv().contextID(); |
875 | } |
876 | |
877 | const GrCaps* GrProxyProvider::caps() const { |
878 | return fImageContext->priv().caps(); |
879 | } |
880 | |
881 | sk_sp<const GrCaps> GrProxyProvider::refCaps() const { |
882 | return fImageContext->priv().refCaps(); |
883 | } |
884 | |
885 | bool GrProxyProvider::isAbandoned() const { |
886 | return fImageContext->priv().abandoned(); |
887 | } |
888 | |
889 | void GrProxyProvider::orphanAllUniqueKeys() { |
890 | fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){ |
891 | proxy->fProxyProvider = nullptr; |
892 | }); |
893 | } |
894 | |
895 | void 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 | |
907 | bool GrProxyProvider::renderingDirectly() const { |
908 | return fImageContext->asDirectContext(); |
909 | } |
910 | |