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