xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrBackendTextureImageGenerator.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
8 
9 #include "include/core/SkColorSpace.h"
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkRect.h"
12 #include "include/core/SkSize.h"
13 #include "include/gpu/GpuTypes.h"
14 #include "include/gpu/ganesh/GrDirectContext.h"
15 #include "include/gpu/ganesh/GrRecordingContext.h"
16 #include "include/gpu/ganesh/GrTypes.h"
17 #include "include/private/base/SkAssert.h"
18 #include "include/private/gpu/ganesh/GrTypesPriv.h"
19 #include "src/gpu/RefCntedCallback.h"
20 #include "src/gpu/SkBackingFit.h"
21 #include "src/gpu/Swizzle.h"
22 #include "src/gpu/ganesh/GrCaps.h"
23 #include "src/gpu/ganesh/GrDirectContextPriv.h"
24 #include "src/gpu/ganesh/GrGpu.h"
25 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
26 #include "src/gpu/ganesh/GrProxyProvider.h"
27 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
28 #include "src/gpu/ganesh/GrResourceCache.h"
29 #include "src/gpu/ganesh/GrResourceProvider.h"
30 #include "src/gpu/ganesh/GrResourceProviderPriv.h"
31 #include "src/gpu/ganesh/GrSemaphore.h"
32 #include "src/gpu/ganesh/GrSurface.h"
33 #include "src/gpu/ganesh/GrSurfaceProxy.h"
34 #include "src/gpu/ganesh/GrTexture.h"
35 #include "src/gpu/ganesh/GrTextureProxy.h"
36 #include "src/gpu/ganesh/SkGr.h"
37 
38 #include <functional>
39 #include <utility>
40 
RefHelper(sk_sp<GrTexture> texture,GrDirectContext::DirectContextID owningContextID,std::unique_ptr<GrSemaphore> semaphore)41 GrBackendTextureImageGenerator::RefHelper::RefHelper(
42         sk_sp<GrTexture> texture,
43         GrDirectContext::DirectContextID owningContextID,
44         std::unique_ptr<GrSemaphore> semaphore)
45         : fOriginalTexture(std::move(texture))
46         , fOwningContextID(owningContextID)
47         , fBorrowingContextReleaseProc(nullptr)
48         , fSemaphore(std::move(semaphore)) {}
49 
~RefHelper()50 GrBackendTextureImageGenerator::RefHelper::~RefHelper() {
51     SkASSERT(!fBorrowingContextID.isValid());
52     // Generator has been freed, and no one is borrowing the texture. Notify the original cache
53     // that it can free the last ref, so it happens on the correct thread.
54     GrResourceCache::ReturnResourceFromThread(std::move(fOriginalTexture), fOwningContextID);
55 }
56 
57 std::unique_ptr<GrTextureGenerator>
Make(const sk_sp<GrTexture> & texture,GrSurfaceOrigin origin,std::unique_ptr<GrSemaphore> semaphore,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)58 GrBackendTextureImageGenerator::Make(const sk_sp<GrTexture>& texture,
59                                      GrSurfaceOrigin origin,
60                                      std::unique_ptr<GrSemaphore> semaphore,
61                                      SkColorType colorType,
62                                      SkAlphaType alphaType,
63                                      sk_sp<SkColorSpace> colorSpace) {
64     GrDirectContext* dContext = texture->getContext();
65 
66     if (!dContext->priv().caps()->areColorTypeAndFormatCompatible(
67                 SkColorTypeToGrColorType(colorType), texture->backendFormat())) {
68         return nullptr;
69     }
70 
71     SkColorInfo info(colorType, alphaType, std::move(colorSpace));
72     return std::unique_ptr<GrTextureGenerator>(new GrBackendTextureImageGenerator(
73             info,
74             texture,
75             origin,
76             dContext->directContextID(),
77             std::move(semaphore)));
78 }
79 
GrBackendTextureImageGenerator(const SkColorInfo & info,const sk_sp<GrTexture> & texture,GrSurfaceOrigin origin,GrDirectContext::DirectContextID owningContextID,std::unique_ptr<GrSemaphore> semaphore)80 GrBackendTextureImageGenerator::GrBackendTextureImageGenerator(
81         const SkColorInfo& info,
82         const sk_sp<GrTexture>& texture,
83         GrSurfaceOrigin origin,
84         GrDirectContext::DirectContextID owningContextID,
85         std::unique_ptr<GrSemaphore> semaphore)
86         : INHERITED(SkImageInfo::Make(texture->dimensions(), info))
87         , fRefHelper(new RefHelper(texture, owningContextID, std::move(semaphore)))
88         , fBackendTexture(texture->getBackendTexture())
89         , fSurfaceOrigin(origin) {}
90 
~GrBackendTextureImageGenerator()91 GrBackendTextureImageGenerator::~GrBackendTextureImageGenerator() {
92     fRefHelper->unref();
93 }
94 
onIsProtected() const95 bool GrBackendTextureImageGenerator::onIsProtected() const {
96     return fBackendTexture.isProtected();
97 }
98 
99 ///////////////////////////////////////////////////////////////////////////////////////////////////
100 
ReleaseRefHelper_TextureReleaseProc(void * ctx)101 void GrBackendTextureImageGenerator::ReleaseRefHelper_TextureReleaseProc(void* ctx) {
102     RefHelper* refHelper = static_cast<RefHelper*>(ctx);
103     SkASSERT(refHelper);
104 
105     refHelper->fBorrowingContextReleaseProc = nullptr;
106     refHelper->fBorrowingContextID.makeInvalid();
107     refHelper->unref();
108 }
109 
onGenerateTexture(GrRecordingContext * rContext,const SkImageInfo & info,skgpu::Mipmapped mipmapped,GrImageTexGenPolicy texGenPolicy)110 GrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture(
111         GrRecordingContext* rContext,
112         const SkImageInfo& info,
113         skgpu::Mipmapped mipmapped,
114         GrImageTexGenPolicy texGenPolicy) {
115     SkASSERT(rContext);
116     SkASSERT_RELEASE(info.dimensions() == fBackendTexture.dimensions());
117 
118     // We currently limit GrBackendTextureImageGenerators to direct contexts since
119     // only Flutter uses them and doesn't use recording/DDL contexts. Ideally, the
120     // cross context texture functionality can be subsumed by the thread-safe cache
121     // working with utility contexts.
122     auto dContext = rContext->asDirectContext();
123     if (!dContext) {
124         return {};
125     }
126 
127     if (dContext->backend() != fBackendTexture.backend()) {
128         return {};
129     }
130     if (info.colorType() != this->getInfo().colorType()) {
131         return {};
132     }
133 
134     auto proxyProvider = dContext->priv().proxyProvider();
135 
136     fBorrowingMutex.acquire();
137     sk_sp<skgpu::RefCntedCallback> releaseProcHelper;
138     if (fRefHelper->fBorrowingContextID.isValid()) {
139         if (fRefHelper->fBorrowingContextID != dContext->directContextID()) {
140             fBorrowingMutex.release();
141             rContext->priv().printWarningMessage(
142                     "GrBackendTextureImageGenerator: Trying to use texture on two GrContexts!\n");
143             return {};
144         } else {
145             SkASSERT(fRefHelper->fBorrowingContextReleaseProc);
146             // Ref the release proc to be held by the proxy we make below
147             releaseProcHelper = sk_ref_sp(fRefHelper->fBorrowingContextReleaseProc);
148         }
149     } else {
150         SkASSERT(!fRefHelper->fBorrowingContextReleaseProc);
151         // The ref we add to fRefHelper here will be passed into and owned by the
152         // skgpu::RefCntedCallback.
153         fRefHelper->ref();
154         releaseProcHelper =
155                 skgpu::RefCntedCallback::Make(ReleaseRefHelper_TextureReleaseProc, fRefHelper);
156         fRefHelper->fBorrowingContextReleaseProc = releaseProcHelper.get();
157     }
158     fRefHelper->fBorrowingContextID = dContext->directContextID();
159     if (!fRefHelper->fBorrowedTextureKey.isValid()) {
160         static const auto kDomain = skgpu::UniqueKey::GenerateDomain();
161         skgpu::UniqueKey::Builder builder(&fRefHelper->fBorrowedTextureKey, kDomain, 1);
162         builder[0] = this->uniqueID();
163     }
164     fBorrowingMutex.release();
165 
166     SkASSERT(fRefHelper->fBorrowingContextID == dContext->directContextID());
167 
168     GrBackendFormat backendFormat = fBackendTexture.getBackendFormat();
169     SkASSERT(backendFormat.isValid());
170 
171     GrColorType grColorType = SkColorTypeToGrColorType(info.colorType());
172 
173     skgpu::Mipmapped textureIsMipMapped =
174             fBackendTexture.hasMipmaps() ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
175 
176     // Ganesh assumes that, when wrapping a mipmapped backend texture from a client, that its
177     // mipmaps are fully fleshed out.
178     GrMipmapStatus mipmapStatus = fBackendTexture.hasMipmaps()
179             ? GrMipmapStatus::kValid : GrMipmapStatus::kNotAllocated;
180 
181     skgpu::Swizzle readSwizzle = dContext->priv().caps()->getReadSwizzle(backendFormat,
182                                                                          grColorType);
183 
184     // Must make copies of member variables to capture in the lambda since this image generator may
185     // be deleted before we actually execute the lambda.
186     sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
187             [refHelper = fRefHelper, releaseProcHelper, backendTexture = fBackendTexture](
188                     GrResourceProvider* resourceProvider,
189                     const GrSurfaceProxy::LazySurfaceDesc&) -> GrSurfaceProxy::LazyCallbackResult {
190                 if (refHelper->fSemaphore) {
191                     resourceProvider->priv().gpu()->waitSemaphore(refHelper->fSemaphore.get());
192                 }
193 
194                 // If a client re-draws the same image multiple times, the texture we return
195                 // will be cached and re-used. If they draw a subset, though, we may be
196                 // re-called. In that case, we want to re-use the borrowed texture we've
197                 // previously created.
198                 sk_sp<GrTexture> tex;
199                 SkASSERT(refHelper->fBorrowedTextureKey.isValid());
200                 auto surf = resourceProvider->findByUniqueKey<GrSurface>(
201                         refHelper->fBorrowedTextureKey);
202                 if (surf) {
203                     SkASSERT(surf->asTexture());
204                     tex = sk_ref_sp(surf->asTexture());
205                 } else {
206                     // We just gained access to the texture. If we're on the original
207                     // context, we could use the original texture, but we'd have no way of
208                     // detecting that it's no longer in-use. So we always make a wrapped
209                     // copy, where the release proc informs us that the context is done with
210                     // it. This is unfortunate - we'll have two texture objects referencing
211                     // the same GPU object. However, no client can ever see the original
212                     // texture, so this should be safe. We make the texture uncacheable so
213                     // that the release proc is called ASAP.
214                     tex = resourceProvider->wrapBackendTexture(
215                             backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
216                             kRead_GrIOType);
217                     if (!tex) {
218                         return {};
219                     }
220                     tex->setRelease(releaseProcHelper);
221                     tex->resourcePriv().setUniqueKey(refHelper->fBorrowedTextureKey);
222                 }
223                 // We use keys to avoid re-wrapping the GrBackendTexture in a GrTexture.
224                 // This is unrelated to the whatever SkImage key may be assigned to the
225                 // proxy.
226                 return {std::move(tex), true, GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
227             },
228             backendFormat,
229             fBackendTexture.dimensions(),
230             textureIsMipMapped,
231             mipmapStatus,
232             GrInternalSurfaceFlags::kReadOnly,
233             SkBackingFit::kExact,
234             skgpu::Budgeted::kNo,
235             GrProtected::kNo,
236             GrSurfaceProxy::UseAllocator::kYes,
237             "BackendTextureImageGenerator");
238     if (!proxy) {
239         return {};
240     }
241 
242     if (texGenPolicy == GrImageTexGenPolicy::kDraw &&
243         (mipmapped == skgpu::Mipmapped::kNo || proxy->mipmapped() == skgpu::Mipmapped::kYes)) {
244         // If we have the correct mip support, we're done
245         return GrSurfaceProxyView(std::move(proxy), fSurfaceOrigin, readSwizzle);
246     } else {
247         skgpu::Budgeted budgeted = texGenPolicy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted
248                                            ? skgpu::Budgeted::kNo
249                                            : skgpu::Budgeted::kYes;
250 
251         auto copy = GrSurfaceProxy::Copy(dContext,
252                                          std::move(proxy),
253                                          fSurfaceOrigin,
254                                          mipmapped,
255                                          SkIRect::MakeWH(info.width(), info.height()),
256                                          SkBackingFit::kExact,
257                                          budgeted,
258                                          /*label=*/"BackendTextureImageGenerator_GenerateTexture");
259         return {std::move(copy), fSurfaceOrigin, readSwizzle};
260     }
261 }
262