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