xref: /aosp_15_r20/external/skia/src/gpu/ganesh/image/SkImage_GaneshFactories.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/GrRecordingContext.h"
27 #include "include/gpu/ganesh/GrTypes.h"
28 #include "include/gpu/ganesh/GrYUVABackendTextures.h"
29 #include "include/gpu/ganesh/GrExternalTextureGenerator.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)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     if (!direct || !data) {
294         return nullptr;
295     }
296 
297     GrBackendFormat beFormat = direct->compressedBackendFormat(type);
298     if (!beFormat.isValid()) {
299         sk_sp<SkImage> tmp = RasterFromCompressedTextureData(std::move(data), width, height, type);
300         if (!tmp) {
301             return nullptr;
302         }
303         return TextureFromImage(direct, tmp, mipmapped);
304     }
305 
306     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
307     sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
308             {width, height}, skgpu::Budgeted::kYes, mipmapped, isProtected, type, std::move(data));
309     if (!proxy) {
310         return nullptr;
311     }
312     GrSurfaceProxyView view(std::move(proxy));
313 
314     SkColorType colorType = skgpu::CompressionTypeToSkColorType(type);
315 
316     return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(direct),
317                                       kNeedNewImageUniqueID,
318                                       std::move(view),
319                                       SkColorInfo(colorType, kOpaque_SkAlphaType, nullptr));
320 }
321 
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)322 sk_sp<SkImage> PromiseTextureFrom(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
323                                   const GrBackendFormat& backendFormat,
324                                   SkISize dimensions,
325                                   skgpu::Mipmapped mipmapped,
326                                   GrSurfaceOrigin origin,
327                                   SkColorType colorType,
328                                   SkAlphaType alphaType,
329                                   sk_sp<SkColorSpace> colorSpace,
330                                   PromiseImageTextureFulfillProc textureFulfillProc,
331                                   PromiseImageTextureReleaseProc textureReleaseProc,
332                                   PromiseImageTextureContext textureContext) {
333     // Our contract is that we will always call the release proc even on failure.
334     // We use the helper to convey the context, so we need to ensure make doesn't fail.
335     textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
336     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContext);
337     SkImageInfo info = SkImageInfo::Make(dimensions, colorType, alphaType, colorSpace);
338     if (!SkImageInfoIsValid(info)) {
339         return nullptr;
340     }
341 
342     if (!threadSafeProxy) {
343         return nullptr;
344     }
345 
346     if (dimensions.isEmpty()) {
347         return nullptr;
348     }
349 
350     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
351     if (GrColorType::kUnknown == grColorType) {
352         return nullptr;
353     }
354 
355     if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
356                                                                          backendFormat)) {
357         return nullptr;
358     }
359 
360     auto proxy = SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
361                                                                dimensions,
362                                                                backendFormat,
363                                                                mipmapped,
364                                                                textureFulfillProc,
365                                                                std::move(releaseHelper));
366     if (!proxy) {
367         return nullptr;
368     }
369     skgpu::Swizzle swizzle =
370             threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat, grColorType);
371     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
372     sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
373     return sk_make_sp<SkImage_Ganesh>(std::move(ctx),
374                                       kNeedNewImageUniqueID,
375                                       std::move(view),
376                                       SkColorInfo(colorType, alphaType, std::move(colorSpace)));
377 }
378 
CrossContextTextureFromPixmap(GrDirectContext * dContext,const SkPixmap & originalPixmap,bool buildMips,bool limitToMaxTextureSize)379 sk_sp<SkImage> CrossContextTextureFromPixmap(GrDirectContext* dContext,
380                                              const SkPixmap& originalPixmap,
381                                              bool buildMips,
382                                              bool limitToMaxTextureSize) {
383     // Some backends or drivers don't support (safely) moving resources between contexts
384     if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
385         return RasterFromPixmapCopy(originalPixmap);
386     }
387 
388     // If non-power-of-two mipmapping isn't supported, ignore the client's request
389     if (!dContext->priv().caps()->mipmapSupport()) {
390         buildMips = false;
391     }
392 
393     const SkPixmap* pixmap = &originalPixmap;
394     SkAutoPixmapStorage resized;
395     int maxTextureSize = dContext->priv().caps()->maxTextureSize();
396     int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
397     if (limitToMaxTextureSize && maxDim > maxTextureSize) {
398         float scale = static_cast<float>(maxTextureSize) / maxDim;
399         int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
400         int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
401         SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
402         SkSamplingOptions sampling(SkFilterMode::kLinear);
403         if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
404             return nullptr;
405         }
406         pixmap = &resized;
407     }
408     // Turn the pixmap into a GrTextureProxy
409     SkBitmap bmp;
410     bmp.installPixels(*pixmap);
411     skgpu::Mipmapped mipmapped = buildMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
412     auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
413     if (!view) {
414         return RasterFromPixmapCopy(*pixmap);
415     }
416 
417     sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
418 
419     // Flush any writes or uploads
420     dContext->priv().flushSurface(view.proxy());
421     GrGpu* gpu = dContext->priv().getGpu();
422 
423     std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
424 
425     SkColorType skCT = GrColorTypeToSkColorType(ct);
426     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture),
427                                                     view.origin(),
428                                                     std::move(sema),
429                                                     skCT,
430                                                     pixmap->alphaType(),
431                                                     pixmap->info().refColorSpace());
432     return DeferredFromTextureGenerator(std::move(gen));
433 }
434 
TextureFromImage(GrDirectContext * dContext,const SkImage * img,skgpu::Mipmapped mipmapped,skgpu::Budgeted budgeted)435 sk_sp<SkImage> TextureFromImage(GrDirectContext* dContext,
436                                 const SkImage* img,
437                                 skgpu::Mipmapped mipmapped,
438                                 skgpu::Budgeted budgeted) {
439     if (!dContext || !img) {
440         return nullptr;
441     }
442     auto ib = as_IB(img);
443     if (!dContext->priv().caps()->mipmapSupport() || ib->dimensions().area() <= 1) {
444         mipmapped = skgpu::Mipmapped::kNo;
445     }
446 
447     if (ib->isGaneshBacked()) {
448         if (!ib->context()->priv().matches(dContext)) {
449             return nullptr;
450         }
451 
452         if (mipmapped == skgpu::Mipmapped::kNo || ib->hasMipmaps()) {
453             return sk_ref_sp(const_cast<SkImage_Base*>(ib));
454         }
455     }
456     GrImageTexGenPolicy policy = budgeted == skgpu::Budgeted::kYes
457                                          ? GrImageTexGenPolicy::kNew_Uncached_Budgeted
458                                          : GrImageTexGenPolicy::kNew_Uncached_Unbudgeted;
459     // TODO: Don't flatten YUVA images here. Add mips to the planes instead.
460     auto [view, ct] = skgpu::ganesh::AsView(dContext, ib, mipmapped, policy);
461     if (!view) {
462         return nullptr;
463     }
464     SkASSERT(view.asTextureProxy());
465     SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
466              view.asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes);
467     SkColorInfo colorInfo(GrColorTypeToSkColorType(ct), ib->alphaType(), ib->refColorSpace());
468     return sk_make_sp<SkImage_Ganesh>(
469             sk_ref_sp(dContext), ib->uniqueID(), std::move(view), std::move(colorInfo));
470 }
471 
TextureFromYUVATextures(GrRecordingContext * context,const GrYUVABackendTextures & yuvaTextures)472 sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
473                                        const GrYUVABackendTextures& yuvaTextures) {
474     return TextureFromYUVATextures(context, yuvaTextures, nullptr, nullptr, nullptr);
475 }
476 
TextureFromYUVATextures(GrRecordingContext * context,const GrYUVABackendTextures & yuvaTextures,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)477 sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
478                                        const GrYUVABackendTextures& yuvaTextures,
479                                        sk_sp<SkColorSpace> imageColorSpace,
480                                        TextureReleaseProc textureReleaseProc,
481                                        ReleaseContext releaseContext) {
482     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
483 
484     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
485     int numPlanes = yuvaTextures.yuvaInfo().numPlanes();
486     sk_sp<GrSurfaceProxy> proxies[SkYUVAInfo::kMaxPlanes];
487     for (int plane = 0; plane < numPlanes; ++plane) {
488         proxies[plane] = proxyProvider->wrapBackendTexture(yuvaTextures.texture(plane),
489                                                            kBorrow_GrWrapOwnership,
490                                                            GrWrapCacheable::kNo,
491                                                            kRead_GrIOType,
492                                                            releaseHelper);
493         if (!proxies[plane]) {
494             return {};
495         }
496     }
497     GrYUVATextureProxies yuvaProxies(
498             yuvaTextures.yuvaInfo(), proxies, yuvaTextures.textureOrigin());
499 
500     if (!yuvaProxies.isValid()) {
501         return nullptr;
502     }
503 
504     return sk_make_sp<SkImage_GaneshYUVA>(
505             sk_ref_sp(context), kNeedNewImageUniqueID, yuvaProxies, imageColorSpace);
506 }
507 
TextureFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,skgpu::Mipmapped buildMips,bool limitToMaxTextureSize)508 sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
509                                       const SkYUVAPixmaps& pixmaps,
510                                       skgpu::Mipmapped buildMips,
511                                       bool limitToMaxTextureSize) {
512     return TextureFromYUVAPixmaps(context, pixmaps, buildMips, limitToMaxTextureSize, nullptr);
513 }
514 
TextureFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,skgpu::Mipmapped buildMips,bool limitToMaxTextureSize,sk_sp<SkColorSpace> imageColorSpace)515 sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
516                                       const SkYUVAPixmaps& pixmaps,
517                                       skgpu::Mipmapped buildMips,
518                                       bool limitToMaxTextureSize,
519                                       sk_sp<SkColorSpace> imageColorSpace) {
520     if (!context) {
521         return nullptr;
522     }
523 
524     if (!pixmaps.isValid()) {
525         return nullptr;
526     }
527 
528     if (!context->priv().caps()->mipmapSupport()) {
529         buildMips = skgpu::Mipmapped::kNo;
530     }
531 
532     // Resize the pixmaps if necessary.
533     int numPlanes = pixmaps.numPlanes();
534     int maxTextureSize = context->priv().caps()->maxTextureSize();
535     int maxDim = std::max(pixmaps.yuvaInfo().width(), pixmaps.yuvaInfo().height());
536 
537     SkYUVAPixmaps tempPixmaps;
538     const SkYUVAPixmaps* pixmapsToUpload = &pixmaps;
539     // We assume no plane is larger than the image size (and at least one plane is as big).
540     if (maxDim > maxTextureSize) {
541         if (!limitToMaxTextureSize) {
542             return nullptr;
543         }
544         float scale = static_cast<float>(maxTextureSize) / maxDim;
545         SkISize newDimensions = {
546                 std::min(static_cast<int>(pixmaps.yuvaInfo().width() * scale), maxTextureSize),
547                 std::min(static_cast<int>(pixmaps.yuvaInfo().height() * scale), maxTextureSize)};
548         SkYUVAInfo newInfo = pixmaps.yuvaInfo().makeDimensions(newDimensions);
549         SkYUVAPixmapInfo newPixmapInfo(newInfo, pixmaps.dataType(), /*row bytes*/ nullptr);
550         tempPixmaps = SkYUVAPixmaps::Allocate(newPixmapInfo);
551         SkSamplingOptions sampling(SkFilterMode::kLinear);
552         if (!tempPixmaps.isValid()) {
553             return nullptr;
554         }
555         for (int i = 0; i < numPlanes; ++i) {
556             if (!pixmaps.plane(i).scalePixels(tempPixmaps.plane(i), sampling)) {
557                 return nullptr;
558             }
559         }
560         pixmapsToUpload = &tempPixmaps;
561     }
562 
563     // Convert to texture proxies.
564     GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
565     GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
566     for (int i = 0; i < numPlanes; ++i) {
567         // Turn the pixmap into a GrTextureProxy
568         SkBitmap bmp;
569         bmp.installPixels(pixmapsToUpload->plane(i));
570         std::tie(views[i], std::ignore) = GrMakeUncachedBitmapProxyView(context, bmp, buildMips);
571         if (!views[i]) {
572             return nullptr;
573         }
574         pixmapColorTypes[i] = SkColorTypeToGrColorType(bmp.colorType());
575     }
576 
577     GrYUVATextureProxies yuvaProxies(pixmapsToUpload->yuvaInfo(), views, pixmapColorTypes);
578     SkASSERT(yuvaProxies.isValid());
579     return sk_make_sp<SkImage_GaneshYUVA>(sk_ref_sp(context),
580                                           kNeedNewImageUniqueID,
581                                           std::move(yuvaProxies),
582                                           std::move(imageColorSpace));
583 }
584 
PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,const GrYUVABackendTextureInfo & backendTextureInfo,sk_sp<SkColorSpace> imageColorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureContext textureContexts[])585 sk_sp<SkImage> PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
586                                       const GrYUVABackendTextureInfo& backendTextureInfo,
587                                       sk_sp<SkColorSpace> imageColorSpace,
588                                       PromiseImageTextureFulfillProc textureFulfillProc,
589                                       PromiseImageTextureReleaseProc textureReleaseProc,
590                                       PromiseImageTextureContext textureContexts[]) {
591     if (!backendTextureInfo.isValid()) {
592         return nullptr;
593     }
594 
595     SkISize planeDimensions[SkYUVAInfo::kMaxPlanes];
596     int n = backendTextureInfo.yuvaInfo().planeDimensions(planeDimensions);
597 
598     // Our contract is that we will always call the release proc even on failure.
599     // We use the helper to convey the context, so we need to ensure make doesn't fail.
600     textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
601     sk_sp<skgpu::RefCntedCallback> releaseHelpers[4];
602     for (int i = 0; i < n; ++i) {
603         releaseHelpers[i] = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContexts[i]);
604     }
605 
606     if (!threadSafeProxy) {
607         return nullptr;
608     }
609 
610     SkAlphaType at =
611             backendTextureInfo.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
612     SkImageInfo info = SkImageInfo::Make(
613             backendTextureInfo.yuvaInfo().dimensions(), SkImage_GaneshYUVA::kAssumedColorType, at,
614             imageColorSpace);
615     if (!SkImageInfoIsValid(info)) {
616         return nullptr;
617     }
618 
619     // Make a lazy proxy for each plane
620     sk_sp<GrSurfaceProxy> proxies[4];
621     for (int i = 0; i < n; ++i) {
622         proxies[i] =
623                 SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
624                                                               planeDimensions[i],
625                                                               backendTextureInfo.planeFormat(i),
626                                                               skgpu::Mipmapped::kNo,
627                                                               textureFulfillProc,
628                                                               std::move(releaseHelpers[i]));
629         if (!proxies[i]) {
630             return nullptr;
631         }
632     }
633     GrYUVATextureProxies yuvaTextureProxies(
634             backendTextureInfo.yuvaInfo(), proxies, backendTextureInfo.textureOrigin());
635     SkASSERT(yuvaTextureProxies.isValid());
636     sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
637     return sk_make_sp<SkImage_GaneshYUVA>(std::move(ctx),
638                                           kNeedNewImageUniqueID,
639                                           std::move(yuvaTextureProxies),
640                                           std::move(imageColorSpace));
641 }
642 
643 }  // namespace SkImages
644