• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google LLC
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/gpu/ganesh/SkImageGanesh.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPixmap.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkSamplingOptions.h"
19 #include "include/core/SkSize.h"
20 #include "include/gpu/GpuTypes.h"
21 #include "include/gpu/GrBackendSurface.h"
22 #include "include/gpu/GrContextThreadSafeProxy.h"
23 #include "include/gpu/GrDirectContext.h"
24 #include "include/gpu/GrRecordingContext.h"
25 #include "include/gpu/GrTypes.h"
26 #include "include/gpu/ganesh/GrExternalTextureGenerator.h"
27 #include "include/private/base/SkAssert.h"
28 #include "include/private/chromium/SkImageChromium.h"
29 #include "include/private/gpu/ganesh/GrImageContext.h"
30 #include "include/private/gpu/ganesh/GrTextureGenerator.h"
31 #include "include/private/gpu/ganesh/GrTypesPriv.h"
32 #include "src/core/SkAutoPixmapStorage.h"
33 #include "src/core/SkImageInfoPriv.h"
34 #include "src/gpu/GpuTypesPriv.h"
35 #include "src/gpu/RefCntedCallback.h"
36 #include "src/gpu/Swizzle.h"
37 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
38 #include "src/gpu/ganesh/GrBackendUtils.h"
39 #include "src/gpu/ganesh/GrCaps.h"
40 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
41 #include "src/gpu/ganesh/GrDirectContextPriv.h"
42 #include "src/gpu/ganesh/GrGpu.h"
43 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
44 #include "src/gpu/ganesh/GrImageContextPriv.h"
45 #include "src/gpu/ganesh/GrProxyProvider.h"
46 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
47 #include "src/gpu/ganesh/GrSemaphore.h"
48 #include "src/gpu/ganesh/GrSurfaceProxy.h"
49 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
50 #include "src/gpu/ganesh/GrTexture.h"
51 #include "src/gpu/ganesh/GrTextureProxy.h"
52 #include "src/gpu/ganesh/SkGr.h"
53 #include "src/gpu/ganesh/image/GrImageUtils.h"
54 #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
55 #include "src/gpu/ganesh/image/SkImage_GaneshBase.h"
56 #include "src/image/SkImage_Base.h"
57 
58 #include <algorithm>
59 #include <memory>
60 #include <utility>
61 
62 enum SkColorType : int;
63 enum class SkTextureCompressionType;
64 
65 namespace SkImages {
66 
MakeBackendTextureFromImage(GrDirectContext * direct,sk_sp<SkImage> image,GrBackendTexture * backendTexture,BackendTextureReleaseProc * releaseProc)67 bool MakeBackendTextureFromImage(GrDirectContext* direct,
68                                  sk_sp<SkImage> image,
69                                  GrBackendTexture* backendTexture,
70                                  BackendTextureReleaseProc* releaseProc) {
71     if (!image || !backendTexture || !releaseProc) {
72         return false;
73     }
74 
75     auto [view, ct] = skgpu::ganesh::AsView(direct, image, skgpu::Mipmapped::kNo);
76     if (!view) {
77         return false;
78     }
79 
80     // Flush any pending IO on the texture.
81     direct->priv().flushSurface(view.proxy());
82 
83     GrTexture* texture = view.asTextureProxy()->peekTexture();
84     if (!texture) {
85         return false;
86     }
87     // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
88     // image is not unique, or if the texture wraps an external object.
89     if (!image->unique() || !texture->unique() || texture->resourcePriv().refsWrappedObjects()) {
90         // onMakeSubset will always copy the image.
91         image = as_IB(image)->onMakeSubset(direct, image->bounds());
92         if (!image) {
93             return false;
94         }
95         return MakeBackendTextureFromImage(direct, std::move(image), backendTexture, releaseProc);
96     }
97 
98     SkASSERT(!texture->resourcePriv().refsWrappedObjects());
99     SkASSERT(texture->unique());
100     SkASSERT(image->unique());
101 
102     // Take a reference to the GrTexture and release the image.
103     sk_sp<GrTexture> textureRef = sk_ref_sp(texture);
104     view.reset();
105     image = nullptr;
106     SkASSERT(textureRef->unique());
107 
108     // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
109     return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
110 }
111 
GetBackendTextureFromImage(const SkImage * img,GrBackendTexture * outTexture,bool flushPendingGrContextIO,GrSurfaceOrigin * origin)112 bool GetBackendTextureFromImage(const SkImage* img,
113                                 GrBackendTexture* outTexture,
114                                 bool flushPendingGrContextIO,
115                                 GrSurfaceOrigin* origin) {
116     if (!img) {
117         return false;
118     }
119     auto ib = as_IB(img);
120     if (ib->type() != SkImage_Base::Type::kGanesh) {
121         return false;
122     }
123     auto ig = static_cast<const SkImage_Ganesh*>(img);
124     return ig->getExistingBackendTexture(outTexture, flushPendingGrContextIO, origin);
125 }
126 
TextureFromCompressedTexture(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)127 sk_sp<SkImage> TextureFromCompressedTexture(GrRecordingContext* context,
128                                             const GrBackendTexture& backendTexture,
129                                             GrSurfaceOrigin origin,
130                                             SkAlphaType alphaType,
131                                             sk_sp<SkColorSpace> colorSpace,
132                                             TextureReleaseProc textureReleaseProc,
133                                             ReleaseContext releaseContext) {
134     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
135 
136     if (!context) {
137         return nullptr;
138     }
139 
140     const GrCaps* caps = context->priv().caps();
141 
142     if (!SkImage_GaneshBase::ValidateCompressedBackendTexture(caps, backendTexture, alphaType)) {
143         return nullptr;
144     }
145 
146     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
147     sk_sp<GrTextureProxy> proxy =
148             proxyProvider->wrapCompressedBackendTexture(backendTexture,
149                                                         kBorrow_GrWrapOwnership,
150                                                         GrWrapCacheable::kNo,
151                                                         std::move(releaseHelper));
152     if (!proxy) {
153         return nullptr;
154     }
155 
156     SkTextureCompressionType type =
157             GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
158     SkColorType ct = skgpu::CompressionTypeToSkColorType(type);
159 
160     GrSurfaceProxyView view(std::move(proxy), origin, skgpu::Swizzle::RGBA());
161     return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(context),
162                                       kNeedNewImageUniqueID,
163                                       std::move(view),
164                                       SkColorInfo(ct, alphaType, std::move(colorSpace)));
165 }
166 
new_wrapped_texture_common(GrRecordingContext * rContext,const GrBackendTexture & backendTex,GrColorType colorType,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,GrWrapOwnership ownership,sk_sp<skgpu::RefCntedCallback> releaseHelper)167 static sk_sp<SkImage> new_wrapped_texture_common(GrRecordingContext* rContext,
168                                                  const GrBackendTexture& backendTex,
169                                                  GrColorType colorType,
170                                                  GrSurfaceOrigin origin,
171                                                  SkAlphaType at,
172                                                  sk_sp<SkColorSpace> colorSpace,
173                                                  GrWrapOwnership ownership,
174                                                  sk_sp<skgpu::RefCntedCallback> releaseHelper) {
175     if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
176         return nullptr;
177     }
178 
179     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
180     sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
181             backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper));
182     if (!proxy) {
183         return nullptr;
184     }
185 
186     skgpu::Swizzle swizzle =
187             rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), colorType);
188     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
189     SkColorInfo info(GrColorTypeToSkColorType(colorType), at, std::move(colorSpace));
190     return sk_make_sp<SkImage_Ganesh>(
191             sk_ref_sp(rContext), kNeedNewImageUniqueID, std::move(view), std::move(info));
192 }
193 
BorrowTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)194 sk_sp<SkImage> BorrowTextureFrom(GrRecordingContext* context,
195                                  const GrBackendTexture& backendTexture,
196                                  GrSurfaceOrigin origin,
197                                  SkColorType colorType,
198                                  SkAlphaType alphaType,
199                                  sk_sp<SkColorSpace> colorSpace,
200                                  TextureReleaseProc textureReleaseProc,
201                                  ReleaseContext releaseContext) {
202     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
203 
204     if (!context) {
205         return nullptr;
206     }
207 
208     const GrCaps* caps = context->priv().caps();
209 
210     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
211     if (GrColorType::kUnknown == grColorType) {
212         return nullptr;
213     }
214 
215     if (!SkImage_GaneshBase::ValidateBackendTexture(
216                 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
217         return nullptr;
218     }
219 
220     return new_wrapped_texture_common(context,
221                                       backendTexture,
222                                       grColorType,
223                                       origin,
224                                       alphaType,
225                                       std::move(colorSpace),
226                                       kBorrow_GrWrapOwnership,
227                                       std::move(releaseHelper));
228 }
229 
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType)230 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
231                                 const GrBackendTexture& backendTexture,
232                                 GrSurfaceOrigin textureOrigin,
233                                 SkColorType colorType) {
234     return AdoptTextureFrom(
235             context, backendTexture, textureOrigin, colorType, kPremul_SkAlphaType, nullptr);
236 }
237 
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType,SkAlphaType alphaType)238 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
239                                 const GrBackendTexture& backendTexture,
240                                 GrSurfaceOrigin textureOrigin,
241                                 SkColorType colorType,
242                                 SkAlphaType alphaType) {
243     return AdoptTextureFrom(context, backendTexture, textureOrigin, colorType, alphaType, nullptr);
244 }
245 
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)246 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
247                                 const GrBackendTexture& backendTexture,
248                                 GrSurfaceOrigin origin,
249                                 SkColorType colorType,
250                                 SkAlphaType alphaType,
251                                 sk_sp<SkColorSpace> colorSpace) {
252     auto dContext = GrAsDirectContext(context);
253     if (!dContext) {
254         // We have a DDL context and we don't support adopted textures for them.
255         return nullptr;
256     }
257 
258     const GrCaps* caps = dContext->priv().caps();
259 
260     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
261     if (GrColorType::kUnknown == grColorType) {
262         return nullptr;
263     }
264 
265     if (!SkImage_GaneshBase::ValidateBackendTexture(
266                 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
267         return nullptr;
268     }
269 
270     return new_wrapped_texture_common(dContext,
271                                       backendTexture,
272                                       grColorType,
273                                       origin,
274                                       alphaType,
275                                       std::move(colorSpace),
276                                       kAdopt_GrWrapOwnership,
277                                       nullptr);
278 }
279 
TextureFromCompressedTextureData(GrDirectContext * direct,sk_sp<SkData> data,int width,int height,SkTextureCompressionType type,skgpu::Mipmapped mipmapped,GrProtected isProtected)280 sk_sp<SkImage> TextureFromCompressedTextureData(GrDirectContext* direct,
281                                                 sk_sp<SkData> data,
282                                                 int width,
283                                                 int height,
284                                                 SkTextureCompressionType type,
285                                                 skgpu::Mipmapped mipmapped,
286                                                 GrProtected isProtected) {
287     if (!direct || !data) {
288         return nullptr;
289     }
290 
291     GrBackendFormat beFormat = direct->compressedBackendFormat(type);
292     if (!beFormat.isValid()) {
293         sk_sp<SkImage> tmp = RasterFromCompressedTextureData(std::move(data), width, height, type);
294         if (!tmp) {
295             return nullptr;
296         }
297         return TextureFromImage(direct, tmp, mipmapped);
298     }
299 
300     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
301     sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
302             {width, height}, skgpu::Budgeted::kYes, mipmapped, isProtected, type, std::move(data));
303     if (!proxy) {
304         return nullptr;
305     }
306     GrSurfaceProxyView view(std::move(proxy));
307 
308     SkColorType colorType = skgpu::CompressionTypeToSkColorType(type);
309 
310     return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(direct),
311                                       kNeedNewImageUniqueID,
312                                       std::move(view),
313                                       SkColorInfo(colorType, kOpaque_SkAlphaType, nullptr));
314 }
315 
PromiseTextureFrom(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,const GrBackendFormat & backendFormat,SkISize dimensions,skgpu::Mipmapped mipmapped,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureContext textureContext)316 sk_sp<SkImage> PromiseTextureFrom(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
317                                   const GrBackendFormat& backendFormat,
318                                   SkISize dimensions,
319                                   skgpu::Mipmapped mipmapped,
320                                   GrSurfaceOrigin origin,
321                                   SkColorType colorType,
322                                   SkAlphaType alphaType,
323                                   sk_sp<SkColorSpace> colorSpace,
324                                   PromiseImageTextureFulfillProc textureFulfillProc,
325                                   PromiseImageTextureReleaseProc textureReleaseProc,
326                                   PromiseImageTextureContext textureContext) {
327     // Our contract is that we will always call the release proc even on failure.
328     // We use the helper to convey the context, so we need to ensure make doesn't fail.
329     textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
330     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContext);
331     SkImageInfo info = SkImageInfo::Make(dimensions, colorType, alphaType, colorSpace);
332     if (!SkImageInfoIsValid(info)) {
333         return nullptr;
334     }
335 
336     if (!threadSafeProxy) {
337         return nullptr;
338     }
339 
340     if (dimensions.isEmpty()) {
341         return nullptr;
342     }
343 
344     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
345     if (GrColorType::kUnknown == grColorType) {
346         return nullptr;
347     }
348 
349     if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
350                                                                          backendFormat)) {
351         return nullptr;
352     }
353 
354     auto proxy = SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
355                                                                dimensions,
356                                                                backendFormat,
357                                                                mipmapped,
358                                                                textureFulfillProc,
359                                                                std::move(releaseHelper));
360     if (!proxy) {
361         return nullptr;
362     }
363     skgpu::Swizzle swizzle =
364             threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat, grColorType);
365     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
366     sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
367     return sk_make_sp<SkImage_Ganesh>(std::move(ctx),
368                                       kNeedNewImageUniqueID,
369                                       std::move(view),
370                                       SkColorInfo(colorType, alphaType, std::move(colorSpace)));
371 }
372 
CrossContextTextureFromPixmap(GrDirectContext * dContext,const SkPixmap & originalPixmap,bool buildMips,bool limitToMaxTextureSize)373 sk_sp<SkImage> CrossContextTextureFromPixmap(GrDirectContext* dContext,
374                                              const SkPixmap& originalPixmap,
375                                              bool buildMips,
376                                              bool limitToMaxTextureSize) {
377     // Some backends or drivers don't support (safely) moving resources between contexts
378     if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
379         return RasterFromPixmapCopy(originalPixmap);
380     }
381 
382     // If non-power-of-two mipmapping isn't supported, ignore the client's request
383     if (!dContext->priv().caps()->mipmapSupport()) {
384         buildMips = false;
385     }
386 
387     const SkPixmap* pixmap = &originalPixmap;
388     SkAutoPixmapStorage resized;
389     int maxTextureSize = dContext->priv().caps()->maxTextureSize();
390     int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
391     if (limitToMaxTextureSize && maxDim > maxTextureSize) {
392         float scale = static_cast<float>(maxTextureSize) / maxDim;
393         int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
394         int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
395         SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
396         SkSamplingOptions sampling(SkFilterMode::kLinear);
397         if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
398             return nullptr;
399         }
400         pixmap = &resized;
401     }
402     // Turn the pixmap into a GrTextureProxy
403     SkBitmap bmp;
404     bmp.installPixels(*pixmap);
405     skgpu::Mipmapped mipmapped = buildMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
406     auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
407     if (!view) {
408         return RasterFromPixmapCopy(*pixmap);
409     }
410 
411     sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
412 
413     // Flush any writes or uploads
414     dContext->priv().flushSurface(view.proxy());
415     GrGpu* gpu = dContext->priv().getGpu();
416 
417     std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
418 
419     SkColorType skCT = GrColorTypeToSkColorType(ct);
420     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture),
421                                                     view.origin(),
422                                                     std::move(sema),
423                                                     skCT,
424                                                     pixmap->alphaType(),
425                                                     pixmap->info().refColorSpace());
426     return DeferredFromTextureGenerator(std::move(gen));
427 }
428 
TextureFromImage(GrDirectContext * dContext,const SkImage * img,skgpu::Mipmapped mipmapped,skgpu::Budgeted budgeted)429 sk_sp<SkImage> TextureFromImage(GrDirectContext* dContext,
430                                 const SkImage* img,
431                                 skgpu::Mipmapped mipmapped,
432                                 skgpu::Budgeted budgeted) {
433     if (!dContext || !img) {
434         return nullptr;
435     }
436     auto ib = as_IB(img);
437     if (!dContext->priv().caps()->mipmapSupport() || ib->dimensions().area() <= 1) {
438         mipmapped = skgpu::Mipmapped::kNo;
439     }
440 
441     if (ib->isGaneshBacked()) {
442         if (!ib->context()->priv().matches(dContext)) {
443             return nullptr;
444         }
445 
446         if (mipmapped == skgpu::Mipmapped::kNo || ib->hasMipmaps()) {
447             return sk_ref_sp(const_cast<SkImage_Base*>(ib));
448         }
449     }
450     GrImageTexGenPolicy policy = budgeted == skgpu::Budgeted::kYes
451                                          ? GrImageTexGenPolicy::kNew_Uncached_Budgeted
452                                          : GrImageTexGenPolicy::kNew_Uncached_Unbudgeted;
453     // TODO: Don't flatten YUVA images here. Add mips to the planes instead.
454     auto [view, ct] = skgpu::ganesh::AsView(dContext, ib, mipmapped, policy);
455     if (!view) {
456         return nullptr;
457     }
458     SkASSERT(view.asTextureProxy());
459     SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
460              view.asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes);
461     SkColorInfo colorInfo(GrColorTypeToSkColorType(ct), ib->alphaType(), ib->refColorSpace());
462     return sk_make_sp<SkImage_Ganesh>(
463             sk_ref_sp(dContext), ib->uniqueID(), std::move(view), std::move(colorInfo));
464 }
465 
466 }  // namespace SkImages
467