• 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/core/SkYUVAInfo.h"
21 #include "include/core/SkYUVAPixmaps.h"
22 #include "include/gpu/GpuTypes.h"
23 #include "include/gpu/ganesh/GrBackendSurface.h"
24 #include "include/gpu/ganesh/GrContextThreadSafeProxy.h"
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "include/gpu/ganesh/GrExternalTextureGenerator.h"
27 #include "include/gpu/ganesh/GrRecordingContext.h"
28 #include "include/gpu/ganesh/GrTypes.h"
29 #include "include/gpu/ganesh/GrYUVABackendTextures.h"
30 #include "include/private/base/SkAssert.h"
31 #include "include/private/chromium/SkImageChromium.h"
32 #include "include/private/gpu/ganesh/GrImageContext.h"
33 #include "include/private/gpu/ganesh/GrTextureGenerator.h"
34 #include "include/private/gpu/ganesh/GrTypesPriv.h"
35 #include "src/core/SkAutoPixmapStorage.h"
36 #include "src/core/SkImageInfoPriv.h"
37 #include "src/gpu/GpuTypesPriv.h"
38 #include "src/gpu/RefCntedCallback.h"
39 #include "src/gpu/Swizzle.h"
40 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
41 #include "src/gpu/ganesh/GrBackendUtils.h"
42 #include "src/gpu/ganesh/GrCaps.h"
43 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
44 #include "src/gpu/ganesh/GrDirectContextPriv.h"
45 #include "src/gpu/ganesh/GrGpu.h"
46 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
47 #include "src/gpu/ganesh/GrImageContextPriv.h"
48 #include "src/gpu/ganesh/GrProxyProvider.h"
49 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
50 #include "src/gpu/ganesh/GrSemaphore.h"
51 #include "src/gpu/ganesh/GrSurfaceProxy.h"
52 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
53 #include "src/gpu/ganesh/GrTexture.h"
54 #include "src/gpu/ganesh/GrTextureProxy.h"
55 #include "src/gpu/ganesh/GrYUVATextureProxies.h"
56 #include "src/gpu/ganesh/SkGr.h"
57 #include "src/gpu/ganesh/image/GrImageUtils.h"
58 #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
59 #include "src/gpu/ganesh/image/SkImage_GaneshBase.h"
60 #include "src/gpu/ganesh/image/SkImage_GaneshYUVA.h"
61 #include "src/image/SkImage_Base.h"
62 
63 #include <algorithm>
64 #include <memory>
65 #include <tuple>
66 #include <utility>
67 
68 enum SkColorType : int;
69 enum class SkTextureCompressionType;
70 
71 namespace SkImages {
72 
MakeBackendTextureFromImage(GrDirectContext * direct,sk_sp<SkImage> image,GrBackendTexture * backendTexture,BackendTextureReleaseProc * releaseProc)73 bool MakeBackendTextureFromImage(GrDirectContext* direct,
74                                  sk_sp<SkImage> image,
75                                  GrBackendTexture* backendTexture,
76                                  BackendTextureReleaseProc* releaseProc) {
77     if (!image || !backendTexture || !releaseProc) {
78         return false;
79     }
80 
81     auto [view, ct] = skgpu::ganesh::AsView(direct, image, skgpu::Mipmapped::kNo);
82     if (!view) {
83         return false;
84     }
85 
86     // Flush any pending IO on the texture.
87     direct->priv().flushSurface(view.proxy());
88 
89     GrTexture* texture = view.asTextureProxy()->peekTexture();
90     if (!texture) {
91         return false;
92     }
93     // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
94     // image is not unique, or if the texture wraps an external object.
95     if (!image->unique() || !texture->unique() || texture->resourcePriv().refsWrappedObjects()) {
96         // onMakeSubset will always copy the image.
97         image = as_IB(image)->onMakeSubset(direct, image->bounds());
98         if (!image) {
99             return false;
100         }
101         return MakeBackendTextureFromImage(direct, std::move(image), backendTexture, releaseProc);
102     }
103 
104     SkASSERT(!texture->resourcePriv().refsWrappedObjects());
105     SkASSERT(texture->unique());
106     SkASSERT(image->unique());
107 
108     // Take a reference to the GrTexture and release the image.
109     sk_sp<GrTexture> textureRef = sk_ref_sp(texture);
110     view.reset();
111     image = nullptr;
112     SkASSERT(textureRef->unique());
113 
114     // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
115     return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
116 }
117 
GetBackendTextureFromImage(const SkImage * img,GrBackendTexture * outTexture,bool flushPendingGrContextIO,GrSurfaceOrigin * origin)118 bool GetBackendTextureFromImage(const SkImage* img,
119                                 GrBackendTexture* outTexture,
120                                 bool flushPendingGrContextIO,
121                                 GrSurfaceOrigin* origin) {
122     if (!img) {
123         return false;
124     }
125     auto ib = as_IB(img);
126     if (ib->type() != SkImage_Base::Type::kGanesh) {
127         return false;
128     }
129     auto ig = static_cast<const SkImage_Ganesh*>(img);
130     return ig->getExistingBackendTexture(outTexture, flushPendingGrContextIO, origin);
131 }
132 
TextureFromCompressedTexture(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)133 sk_sp<SkImage> TextureFromCompressedTexture(GrRecordingContext* context,
134                                             const GrBackendTexture& backendTexture,
135                                             GrSurfaceOrigin origin,
136                                             SkAlphaType alphaType,
137                                             sk_sp<SkColorSpace> colorSpace,
138                                             TextureReleaseProc textureReleaseProc,
139                                             ReleaseContext releaseContext) {
140     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
141 
142     if (!context) {
143         return nullptr;
144     }
145 
146     const GrCaps* caps = context->priv().caps();
147 
148     if (!SkImage_GaneshBase::ValidateCompressedBackendTexture(caps, backendTexture, alphaType)) {
149         return nullptr;
150     }
151 
152     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
153     sk_sp<GrTextureProxy> proxy =
154             proxyProvider->wrapCompressedBackendTexture(backendTexture,
155                                                         kBorrow_GrWrapOwnership,
156                                                         GrWrapCacheable::kNo,
157                                                         std::move(releaseHelper));
158     if (!proxy) {
159         return nullptr;
160     }
161 
162     SkTextureCompressionType type =
163             GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
164     SkColorType ct = skgpu::CompressionTypeToSkColorType(type);
165 
166     GrSurfaceProxyView view(std::move(proxy), origin, skgpu::Swizzle::RGBA());
167     return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(context),
168                                       kNeedNewImageUniqueID,
169                                       std::move(view),
170                                       SkColorInfo(ct, alphaType, std::move(colorSpace)));
171 }
172 
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)173 static sk_sp<SkImage> new_wrapped_texture_common(GrRecordingContext* rContext,
174                                                  const GrBackendTexture& backendTex,
175                                                  GrColorType colorType,
176                                                  GrSurfaceOrigin origin,
177                                                  SkAlphaType at,
178                                                  sk_sp<SkColorSpace> colorSpace,
179                                                  GrWrapOwnership ownership,
180                                                  sk_sp<skgpu::RefCntedCallback> releaseHelper) {
181     if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
182         return nullptr;
183     }
184 
185     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
186     sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
187             backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper));
188     if (!proxy) {
189         return nullptr;
190     }
191 
192     skgpu::Swizzle swizzle =
193             rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), colorType);
194     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
195     SkColorInfo info(GrColorTypeToSkColorType(colorType), at, std::move(colorSpace));
196     return sk_make_sp<SkImage_Ganesh>(
197             sk_ref_sp(rContext), kNeedNewImageUniqueID, std::move(view), std::move(info));
198 }
199 
BorrowTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)200 sk_sp<SkImage> BorrowTextureFrom(GrRecordingContext* context,
201                                  const GrBackendTexture& backendTexture,
202                                  GrSurfaceOrigin origin,
203                                  SkColorType colorType,
204                                  SkAlphaType alphaType,
205                                  sk_sp<SkColorSpace> colorSpace,
206                                  TextureReleaseProc textureReleaseProc,
207                                  ReleaseContext releaseContext) {
208     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
209 
210     if (!context) {
211         return nullptr;
212     }
213 
214     const GrCaps* caps = context->priv().caps();
215 
216     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
217     if (GrColorType::kUnknown == grColorType) {
218         return nullptr;
219     }
220 
221     if (!SkImage_GaneshBase::ValidateBackendTexture(
222                 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
223         return nullptr;
224     }
225 
226     return new_wrapped_texture_common(context,
227                                       backendTexture,
228                                       grColorType,
229                                       origin,
230                                       alphaType,
231                                       std::move(colorSpace),
232                                       kBorrow_GrWrapOwnership,
233                                       std::move(releaseHelper));
234 }
235 
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType)236 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
237                                 const GrBackendTexture& backendTexture,
238                                 GrSurfaceOrigin textureOrigin,
239                                 SkColorType colorType) {
240     return AdoptTextureFrom(
241             context, backendTexture, textureOrigin, colorType, kPremul_SkAlphaType, nullptr);
242 }
243 
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType,SkAlphaType alphaType)244 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
245                                 const GrBackendTexture& backendTexture,
246                                 GrSurfaceOrigin textureOrigin,
247                                 SkColorType colorType,
248                                 SkAlphaType alphaType) {
249     return AdoptTextureFrom(context, backendTexture, textureOrigin, colorType, alphaType, nullptr);
250 }
251 
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)252 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
253                                 const GrBackendTexture& backendTexture,
254                                 GrSurfaceOrigin origin,
255                                 SkColorType colorType,
256                                 SkAlphaType alphaType,
257                                 sk_sp<SkColorSpace> colorSpace) {
258     auto dContext = GrAsDirectContext(context);
259     if (!dContext) {
260         // We have a DDL context and we don't support adopted textures for them.
261         return nullptr;
262     }
263 
264     const GrCaps* caps = dContext->priv().caps();
265 
266     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
267     if (GrColorType::kUnknown == grColorType) {
268         return nullptr;
269     }
270 
271     if (!SkImage_GaneshBase::ValidateBackendTexture(
272                 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
273         return nullptr;
274     }
275 
276     return new_wrapped_texture_common(dContext,
277                                       backendTexture,
278                                       grColorType,
279                                       origin,
280                                       alphaType,
281                                       std::move(colorSpace),
282                                       kAdopt_GrWrapOwnership,
283                                       nullptr);
284 }
285 
TextureFromCompressedTextureData(GrDirectContext * direct,sk_sp<SkData> data,int width,int height,SkTextureCompressionType type,skgpu::Mipmapped mipmapped,GrProtected isProtected,sk_sp<SkColorSpace> colorSpace)286 sk_sp<SkImage> TextureFromCompressedTextureData(GrDirectContext* direct,
287                                                 sk_sp<SkData> data,
288                                                 int width,
289                                                 int height,
290                                                 SkTextureCompressionType type,
291                                                 skgpu::Mipmapped mipmapped,
292                                                 GrProtected isProtected,
293                                                 sk_sp<SkColorSpace> colorSpace) {
294     if (!direct || !data) {
295         return nullptr;
296     }
297 
298     GrBackendFormat beFormat = direct->compressedBackendFormat(type);
299     if (!beFormat.isValid()) {
300         sk_sp<SkImage> tmp = RasterFromCompressedTextureData(std::move(data), width, height, type);
301         if (!tmp) {
302             return nullptr;
303         }
304         return TextureFromImage(direct, tmp, mipmapped);
305     }
306 
307     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
308     sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
309             {width, height}, skgpu::Budgeted::kYes, mipmapped, isProtected, type, std::move(data));
310     if (!proxy) {
311         return nullptr;
312     }
313     GrSurfaceProxyView view(std::move(proxy));
314 
315     SkColorType colorType = skgpu::CompressionTypeToSkColorType(type);
316 
317     // modify for support astc texture format
318     SkAlphaType alphaType = skgpu::CompressionTypeToSkAlphaType(type);
319 
320     return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(direct),
321                                       kNeedNewImageUniqueID,
322                                       std::move(view),
323                                       SkColorInfo(colorType, alphaType, colorSpace));
324 }
325 
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)326 sk_sp<SkImage> PromiseTextureFrom(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
327                                   const GrBackendFormat& backendFormat,
328                                   SkISize dimensions,
329                                   skgpu::Mipmapped mipmapped,
330                                   GrSurfaceOrigin origin,
331                                   SkColorType colorType,
332                                   SkAlphaType alphaType,
333                                   sk_sp<SkColorSpace> colorSpace,
334                                   PromiseImageTextureFulfillProc textureFulfillProc,
335                                   PromiseImageTextureReleaseProc textureReleaseProc,
336                                   PromiseImageTextureContext textureContext) {
337     // Our contract is that we will always call the release proc even on failure.
338     // We use the helper to convey the context, so we need to ensure make doesn't fail.
339     textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
340     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContext);
341     SkImageInfo info = SkImageInfo::Make(dimensions, colorType, alphaType, colorSpace);
342     if (!SkImageInfoIsValid(info)) {
343         return nullptr;
344     }
345 
346     if (!threadSafeProxy) {
347         return nullptr;
348     }
349 
350     if (dimensions.isEmpty()) {
351         return nullptr;
352     }
353 
354     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
355     if (GrColorType::kUnknown == grColorType) {
356         return nullptr;
357     }
358 
359     if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
360                                                                          backendFormat)) {
361         return nullptr;
362     }
363 
364     auto proxy = SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
365                                                                dimensions,
366                                                                backendFormat,
367                                                                mipmapped,
368                                                                textureFulfillProc,
369                                                                std::move(releaseHelper));
370     if (!proxy) {
371         return nullptr;
372     }
373     skgpu::Swizzle swizzle =
374             threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat, grColorType);
375     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
376     sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
377     return sk_make_sp<SkImage_Ganesh>(std::move(ctx),
378                                       kNeedNewImageUniqueID,
379                                       std::move(view),
380                                       SkColorInfo(colorType, alphaType, std::move(colorSpace)));
381 }
382 
CrossContextTextureFromPixmap(GrDirectContext * dContext,const SkPixmap & originalPixmap,bool buildMips,bool limitToMaxTextureSize)383 sk_sp<SkImage> CrossContextTextureFromPixmap(GrDirectContext* dContext,
384                                              const SkPixmap& originalPixmap,
385                                              bool buildMips,
386                                              bool limitToMaxTextureSize) {
387     // Some backends or drivers don't support (safely) moving resources between contexts
388     if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
389         return RasterFromPixmapCopy(originalPixmap);
390     }
391 
392     // If non-power-of-two mipmapping isn't supported, ignore the client's request
393     if (!dContext->priv().caps()->mipmapSupport()) {
394         buildMips = false;
395     }
396 
397     const SkPixmap* pixmap = &originalPixmap;
398     SkAutoPixmapStorage resized;
399     int maxTextureSize = dContext->priv().caps()->maxTextureSize();
400     int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
401     if (limitToMaxTextureSize && maxDim > maxTextureSize) {
402         float scale = static_cast<float>(maxTextureSize) / maxDim;
403         int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
404         int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
405         SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
406         SkSamplingOptions sampling(SkFilterMode::kLinear);
407         if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
408             return nullptr;
409         }
410         pixmap = &resized;
411     }
412     // Turn the pixmap into a GrTextureProxy
413     SkBitmap bmp;
414     bmp.installPixels(*pixmap);
415     skgpu::Mipmapped mipmapped = buildMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
416     auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
417     if (!view) {
418         return RasterFromPixmapCopy(*pixmap);
419     }
420 
421     sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
422 
423     // Flush any writes or uploads
424     dContext->priv().flushSurface(view.proxy());
425     GrGpu* gpu = dContext->priv().getGpu();
426 
427     std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
428 
429     SkColorType skCT = GrColorTypeToSkColorType(ct);
430     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture),
431                                                     view.origin(),
432                                                     std::move(sema),
433                                                     skCT,
434                                                     pixmap->alphaType(),
435                                                     pixmap->info().refColorSpace());
436     return DeferredFromTextureGenerator(std::move(gen));
437 }
438 
TextureFromImage(GrDirectContext * dContext,const SkImage * img,skgpu::Mipmapped mipmapped,skgpu::Budgeted budgeted)439 sk_sp<SkImage> TextureFromImage(GrDirectContext* dContext,
440                                 const SkImage* img,
441                                 skgpu::Mipmapped mipmapped,
442                                 skgpu::Budgeted budgeted) {
443     if (!dContext || !img) {
444         return nullptr;
445     }
446     auto ib = as_IB(img);
447     if (!dContext->priv().caps()->mipmapSupport() || ib->dimensions().area() <= 1) {
448         mipmapped = skgpu::Mipmapped::kNo;
449     }
450 
451     if (ib->isGaneshBacked()) {
452         if (!ib->context()->priv().matches(dContext)) {
453             return nullptr;
454         }
455 
456         if (mipmapped == skgpu::Mipmapped::kNo || ib->hasMipmaps()) {
457             return sk_ref_sp(const_cast<SkImage_Base*>(ib));
458         }
459     }
460     GrImageTexGenPolicy policy = budgeted == skgpu::Budgeted::kYes
461                                          ? GrImageTexGenPolicy::kNew_Uncached_Budgeted
462                                          : GrImageTexGenPolicy::kNew_Uncached_Unbudgeted;
463     // TODO: Don't flatten YUVA images here. Add mips to the planes instead.
464     auto [view, ct] = skgpu::ganesh::AsView(dContext, ib, mipmapped, policy);
465     if (!view) {
466         return nullptr;
467     }
468     SkASSERT(view.asTextureProxy());
469     SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
470              view.asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes);
471     SkColorInfo colorInfo(GrColorTypeToSkColorType(ct), ib->alphaType(), ib->refColorSpace());
472     return sk_make_sp<SkImage_Ganesh>(
473             sk_ref_sp(dContext), ib->uniqueID(), std::move(view), std::move(colorInfo));
474 }
475 
TextureFromYUVATextures(GrRecordingContext * context,const GrYUVABackendTextures & yuvaTextures)476 sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
477                                        const GrYUVABackendTextures& yuvaTextures) {
478     return TextureFromYUVATextures(context, yuvaTextures, nullptr, nullptr, nullptr);
479 }
480 
TextureFromYUVATextures(GrRecordingContext * context,const GrYUVABackendTextures & yuvaTextures,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)481 sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
482                                        const GrYUVABackendTextures& yuvaTextures,
483                                        sk_sp<SkColorSpace> imageColorSpace,
484                                        TextureReleaseProc textureReleaseProc,
485                                        ReleaseContext releaseContext) {
486     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
487 
488     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
489     int numPlanes = yuvaTextures.yuvaInfo().numPlanes();
490     sk_sp<GrSurfaceProxy> proxies[SkYUVAInfo::kMaxPlanes];
491     for (int plane = 0; plane < numPlanes; ++plane) {
492         proxies[plane] = proxyProvider->wrapBackendTexture(yuvaTextures.texture(plane),
493                                                            kBorrow_GrWrapOwnership,
494                                                            GrWrapCacheable::kNo,
495                                                            kRead_GrIOType,
496                                                            releaseHelper);
497         if (!proxies[plane]) {
498             return {};
499         }
500     }
501     GrYUVATextureProxies yuvaProxies(
502             yuvaTextures.yuvaInfo(), proxies, yuvaTextures.textureOrigin());
503 
504     if (!yuvaProxies.isValid()) {
505         return nullptr;
506     }
507 
508     return sk_make_sp<SkImage_GaneshYUVA>(
509             sk_ref_sp(context), kNeedNewImageUniqueID, yuvaProxies, imageColorSpace);
510 }
511 
TextureFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,skgpu::Mipmapped buildMips,bool limitToMaxTextureSize)512 sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
513                                       const SkYUVAPixmaps& pixmaps,
514                                       skgpu::Mipmapped buildMips,
515                                       bool limitToMaxTextureSize) {
516     return TextureFromYUVAPixmaps(context, pixmaps, buildMips, limitToMaxTextureSize, nullptr);
517 }
518 
TextureFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,skgpu::Mipmapped buildMips,bool limitToMaxTextureSize,sk_sp<SkColorSpace> imageColorSpace)519 sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
520                                       const SkYUVAPixmaps& pixmaps,
521                                       skgpu::Mipmapped buildMips,
522                                       bool limitToMaxTextureSize,
523                                       sk_sp<SkColorSpace> imageColorSpace) {
524     if (!context) {
525         return nullptr;
526     }
527 
528     if (!pixmaps.isValid()) {
529         return nullptr;
530     }
531 
532     if (!context->priv().caps()->mipmapSupport()) {
533         buildMips = skgpu::Mipmapped::kNo;
534     }
535 
536     // Resize the pixmaps if necessary.
537     int numPlanes = pixmaps.numPlanes();
538     int maxTextureSize = context->priv().caps()->maxTextureSize();
539     int maxDim = std::max(pixmaps.yuvaInfo().width(), pixmaps.yuvaInfo().height());
540 
541     SkYUVAPixmaps tempPixmaps;
542     const SkYUVAPixmaps* pixmapsToUpload = &pixmaps;
543     // We assume no plane is larger than the image size (and at least one plane is as big).
544     if (maxDim > maxTextureSize) {
545         if (!limitToMaxTextureSize) {
546             return nullptr;
547         }
548         float scale = static_cast<float>(maxTextureSize) / maxDim;
549         SkISize newDimensions = {
550                 std::min(static_cast<int>(pixmaps.yuvaInfo().width() * scale), maxTextureSize),
551                 std::min(static_cast<int>(pixmaps.yuvaInfo().height() * scale), maxTextureSize)};
552         SkYUVAInfo newInfo = pixmaps.yuvaInfo().makeDimensions(newDimensions);
553         SkYUVAPixmapInfo newPixmapInfo(newInfo, pixmaps.dataType(), /*row bytes*/ nullptr);
554         tempPixmaps = SkYUVAPixmaps::Allocate(newPixmapInfo);
555         SkSamplingOptions sampling(SkFilterMode::kLinear);
556         if (!tempPixmaps.isValid()) {
557             return nullptr;
558         }
559         for (int i = 0; i < numPlanes; ++i) {
560             if (!pixmaps.plane(i).scalePixels(tempPixmaps.plane(i), sampling)) {
561                 return nullptr;
562             }
563         }
564         pixmapsToUpload = &tempPixmaps;
565     }
566 
567     // Convert to texture proxies.
568     GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
569     GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
570     for (int i = 0; i < numPlanes; ++i) {
571         // Turn the pixmap into a GrTextureProxy
572         SkBitmap bmp;
573         bmp.installPixels(pixmapsToUpload->plane(i));
574         std::tie(views[i], std::ignore) = GrMakeUncachedBitmapProxyView(context, bmp, buildMips);
575         if (!views[i]) {
576             return nullptr;
577         }
578         pixmapColorTypes[i] = SkColorTypeToGrColorType(bmp.colorType());
579     }
580 
581     GrYUVATextureProxies yuvaProxies(pixmapsToUpload->yuvaInfo(), views, pixmapColorTypes);
582     SkASSERT(yuvaProxies.isValid());
583     return sk_make_sp<SkImage_GaneshYUVA>(sk_ref_sp(context),
584                                           kNeedNewImageUniqueID,
585                                           std::move(yuvaProxies),
586                                           std::move(imageColorSpace));
587 }
588 
PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,const GrYUVABackendTextureInfo & backendTextureInfo,sk_sp<SkColorSpace> imageColorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureContext textureContexts[])589 sk_sp<SkImage> PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
590                                       const GrYUVABackendTextureInfo& backendTextureInfo,
591                                       sk_sp<SkColorSpace> imageColorSpace,
592                                       PromiseImageTextureFulfillProc textureFulfillProc,
593                                       PromiseImageTextureReleaseProc textureReleaseProc,
594                                       PromiseImageTextureContext textureContexts[]) {
595     if (!backendTextureInfo.isValid()) {
596         return nullptr;
597     }
598 
599     SkISize planeDimensions[SkYUVAInfo::kMaxPlanes];
600     int n = backendTextureInfo.yuvaInfo().planeDimensions(planeDimensions);
601 
602     // Our contract is that we will always call the release proc even on failure.
603     // We use the helper to convey the context, so we need to ensure make doesn't fail.
604     textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
605     sk_sp<skgpu::RefCntedCallback> releaseHelpers[4];
606     for (int i = 0; i < n; ++i) {
607         releaseHelpers[i] = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContexts[i]);
608     }
609 
610     if (!threadSafeProxy) {
611         return nullptr;
612     }
613 
614     SkAlphaType at =
615             backendTextureInfo.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
616     SkImageInfo info = SkImageInfo::Make(
617             backendTextureInfo.yuvaInfo().dimensions(), SkImage_GaneshYUVA::kAssumedColorType, at,
618             imageColorSpace);
619     if (!SkImageInfoIsValid(info)) {
620         return nullptr;
621     }
622 
623     // Make a lazy proxy for each plane
624     sk_sp<GrSurfaceProxy> proxies[4];
625     for (int i = 0; i < n; ++i) {
626         proxies[i] =
627                 SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
628                                                               planeDimensions[i],
629                                                               backendTextureInfo.planeFormat(i),
630                                                               skgpu::Mipmapped::kNo,
631                                                               textureFulfillProc,
632                                                               std::move(releaseHelpers[i]));
633         if (!proxies[i]) {
634             return nullptr;
635         }
636     }
637     GrYUVATextureProxies yuvaTextureProxies(
638             backendTextureInfo.yuvaInfo(), proxies, backendTextureInfo.textureOrigin());
639     SkASSERT(yuvaTextureProxies.isValid());
640     sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
641     return sk_make_sp<SkImage_GaneshYUVA>(std::move(ctx),
642                                           kNeedNewImageUniqueID,
643                                           std::move(yuvaTextureProxies),
644                                           std::move(imageColorSpace));
645 }
646 
647 }  // namespace SkImages
648