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