Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/gpu/ganesh/image/SkImage_GaneshYUVA.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2018 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "src/gpu/ganesh/image/SkImage_GaneshYUVA.h"
9
10
#include "include/core/SkAlphaType.h"
11
#include "include/core/SkBitmap.h"
12
#include "include/core/SkColorType.h"
13
#include "include/core/SkImageInfo.h"
14
#include "include/core/SkMatrix.h"
15
#include "include/core/SkPixmap.h"
16
#include "include/core/SkSize.h"
17
#include "include/core/SkSurface.h"
18
#include "include/core/SkYUVAInfo.h"
19
#include "include/core/SkYUVAPixmaps.h"
20
#include "include/gpu/GpuTypes.h"
21
#include "include/gpu/GrBackendSurface.h"  // IWYU pragma: keep
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/GrYUVABackendTextures.h"
27
#include "include/gpu/ganesh/SkImageGanesh.h"
28
#include "include/private/base/SkAssert.h"
29
#include "include/private/base/SkDebug.h"
30
#include "include/private/chromium/SkImageChromium.h"
31
#include "include/private/gpu/ganesh/GrImageContext.h"
32
#include "include/private/gpu/ganesh/GrTypesPriv.h"
33
#include "src/core/SkImageInfoPriv.h"
34
#include "src/core/SkSamplingPriv.h"
35
#include "src/gpu/RefCntedCallback.h"
36
#include "src/gpu/SkBackingFit.h"
37
#include "src/gpu/Swizzle.h"
38
#include "src/gpu/ganesh/GrCaps.h"
39
#include "src/gpu/ganesh/GrColorInfo.h"
40
#include "src/gpu/ganesh/GrColorSpaceXform.h"
41
#include "src/gpu/ganesh/GrDirectContextPriv.h"
42
#include "src/gpu/ganesh/GrFragmentProcessor.h"
43
#include "src/gpu/ganesh/GrImageContextPriv.h"
44
#include "src/gpu/ganesh/GrImageInfo.h"
45
#include "src/gpu/ganesh/GrProxyProvider.h"
46
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
47
#include "src/gpu/ganesh/GrSamplerState.h"
48
#include "src/gpu/ganesh/GrSurfaceProxy.h"
49
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
50
#include "src/gpu/ganesh/GrTextureProxy.h"
51
#include "src/gpu/ganesh/SkGr.h"
52
#include "src/gpu/ganesh/SurfaceFillContext.h"
53
#include "src/gpu/ganesh/effects/GrBicubicEffect.h"
54
#include "src/gpu/ganesh/effects/GrYUVtoRGBEffect.h"
55
#include "src/image/SkImage_Base.h"
56
57
#include <algorithm>
58
#include <utility>
59
60
enum class SkTileMode;
61
struct SkRect;
62
63
static constexpr auto kAssumedColorType = kRGBA_8888_SkColorType;
64
65
SkImage_GaneshYUVA::SkImage_GaneshYUVA(sk_sp<GrImageContext> context,
66
                                       uint32_t uniqueID,
67
                                       GrYUVATextureProxies proxies,
68
                                       sk_sp<SkColorSpace> imageColorSpace)
69
        : INHERITED(std::move(context),
70
                    SkImageInfo::Make(proxies.yuvaInfo().dimensions(),
71
                                      kAssumedColorType,
72
                                      // If an alpha channel is present we always use kPremul. This
73
                                      // is because, although the planar data is always un-premul,
74
                                      // the final interleaved RGBA sample produced in the shader
75
                                      // is premul (and similar if flattened via asView).
76
                                      proxies.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType
77
                                                                    : kOpaque_SkAlphaType,
78
                                      std::move(imageColorSpace)),
79
                    uniqueID)
80
0
        , fYUVAProxies(std::move(proxies)) {
81
    // The caller should have checked this, just verifying.
82
0
    SkASSERT(fYUVAProxies.isValid());
83
0
}
Unexecuted instantiation: SkImage_GaneshYUVA::SkImage_GaneshYUVA(sk_sp<GrImageContext>, unsigned int, GrYUVATextureProxies, sk_sp<SkColorSpace>)
Unexecuted instantiation: SkImage_GaneshYUVA::SkImage_GaneshYUVA(sk_sp<GrImageContext>, unsigned int, GrYUVATextureProxies, sk_sp<SkColorSpace>)
84
85
// For onMakeColorTypeAndColorSpace() / onReinterpretColorSpace()
86
SkImage_GaneshYUVA::SkImage_GaneshYUVA(sk_sp<GrImageContext> context,
87
                                       const SkImage_GaneshYUVA* image,
88
                                       sk_sp<SkColorSpace> targetCS,
89
                                       ColorSpaceMode csMode)
90
        : INHERITED(std::move(context),
91
                    image->imageInfo().makeColorSpace(std::move(targetCS)),
92
                    kNeedNewImageUniqueID)
93
        , fYUVAProxies(image->fYUVAProxies)
94
        // If we're *reinterpreting* in a new color space, leave fFromColorSpace null.
95
        // If we're *converting* to a new color space, it must be non-null, so turn null into sRGB.
96
        , fFromColorSpace(csMode == ColorSpaceMode::kReinterpret
97
                                  ? nullptr
98
                                  : (image->colorSpace() ? image->refColorSpace()
99
0
                                                         : SkColorSpace::MakeSRGB())) {}
100
101
0
bool SkImage_GaneshYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
102
0
    if (!context || !fContext->priv().matches(context)) {
103
0
        return false;
104
0
    }
105
0
    if (!context->priv().caps()->mipmapSupport()) {
106
        // We succeed in this case by doing nothing.
107
0
        return true;
108
0
    }
109
0
    int n = fYUVAProxies.yuvaInfo().numPlanes();
110
0
    sk_sp<GrSurfaceProxy> newProxies[4];
111
0
    for (int i = 0; i < n; ++i) {
112
0
        auto* t = fYUVAProxies.proxy(i)->asTextureProxy();
113
0
        if (t->mipmapped() == skgpu::Mipmapped::kNo && (t->width() > 1 || t->height() > 1)) {
114
0
            auto newView = GrCopyBaseMipMapToView(context, fYUVAProxies.makeView(i));
115
0
            if (!newView) {
116
0
                return false;
117
0
            }
118
0
            SkASSERT(newView.swizzle() == fYUVAProxies.makeView(i).swizzle());
119
0
            newProxies[i] = newView.detachProxy();
120
0
        } else {
121
0
            newProxies[i] = fYUVAProxies.refProxy(i);
122
0
        }
123
0
    }
124
0
    fYUVAProxies =
125
0
            GrYUVATextureProxies(fYUVAProxies.yuvaInfo(), newProxies, fYUVAProxies.textureOrigin());
126
0
    SkASSERT(fYUVAProxies.isValid());
127
0
    return true;
128
0
}
Unexecuted instantiation: SkImage_GaneshYUVA::setupMipmapsForPlanes(GrRecordingContext*) const
Unexecuted instantiation: SkImage_GaneshYUVA::setupMipmapsForPlanes(GrRecordingContext*) const
129
130
//////////////////////////////////////////////////////////////////////////////////////////////////
131
132
GrSemaphoresSubmitted SkImage_GaneshYUVA::flush(GrDirectContext* dContext,
133
0
                                                const GrFlushInfo& info) const {
134
0
    if (!fContext->priv().matches(dContext) || dContext->abandoned()) {
135
0
        if (info.fSubmittedProc) {
136
0
            info.fSubmittedProc(info.fSubmittedContext, false);
137
0
        }
138
0
        if (info.fFinishedProc) {
139
0
            info.fFinishedProc(info.fFinishedContext);
140
0
        }
141
0
        return GrSemaphoresSubmitted::kNo;
142
0
    }
143
144
0
    GrSurfaceProxy* proxies[SkYUVAInfo::kMaxPlanes] = {};
145
0
    size_t numProxies = fYUVAProxies.numPlanes();
146
0
    for (size_t i = 0; i < numProxies; ++i) {
147
0
        proxies[i] = fYUVAProxies.proxy(i);
148
0
    }
149
0
    return dContext->priv().flushSurfaces(
150
0
            {proxies, numProxies}, SkSurfaces::BackendSurfaceAccess::kNoAccess, info);
151
0
}
152
153
0
bool SkImage_GaneshYUVA::onHasMipmaps() const {
154
0
    return fYUVAProxies.mipmapped() == skgpu::Mipmapped::kYes;
155
0
}
156
157
0
bool SkImage_GaneshYUVA::onIsProtected() const {
158
0
    skgpu::Protected isProtected = fYUVAProxies.proxy(0)->isProtected();
159
160
#if defined(SK_DEBUG)
161
0
    for (int i = 1; i < fYUVAProxies.numPlanes(); ++i) {
162
0
        SkASSERT(isProtected == fYUVAProxies.proxy(i)->isProtected());
163
0
    }
164
#endif
165
166
0
    return isProtected == skgpu::Protected::kYes;
167
0
}
Unexecuted instantiation: SkImage_GaneshYUVA::onIsProtected() const
Unexecuted instantiation: SkImage_GaneshYUVA::onIsProtected() const
168
169
170
0
size_t SkImage_GaneshYUVA::textureSize() const {
171
0
    size_t size = 0;
172
0
    for (int i = 0; i < fYUVAProxies.numPlanes(); ++i) {
173
0
        size += fYUVAProxies.proxy(i)->gpuMemorySize();
174
0
    }
175
0
    return size;
176
0
}
177
178
sk_sp<SkImage> SkImage_GaneshYUVA::onMakeColorTypeAndColorSpace(SkColorType,
179
                                                                sk_sp<SkColorSpace> targetCS,
180
0
                                                                GrDirectContext* direct) const {
181
    // We explicitly ignore color type changes, for now.
182
183
    // we may need a mutex here but for now we expect usage to be in a single thread
184
0
    if (fOnMakeColorSpaceTarget &&
185
0
        SkColorSpace::Equals(targetCS.get(), fOnMakeColorSpaceTarget.get())) {
186
0
        return fOnMakeColorSpaceResult;
187
0
    }
188
0
    sk_sp<SkImage> result = sk_sp<SkImage>(
189
0
            new SkImage_GaneshYUVA(sk_ref_sp(direct), this, targetCS, ColorSpaceMode::kConvert));
190
0
    if (result) {
191
0
        fOnMakeColorSpaceTarget = targetCS;
192
0
        fOnMakeColorSpaceResult = result;
193
0
    }
194
0
    return result;
195
0
}
196
197
0
sk_sp<SkImage> SkImage_GaneshYUVA::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
198
0
    return sk_sp<SkImage>(
199
0
            new SkImage_GaneshYUVA(fContext, this, std::move(newCS), ColorSpaceMode::kReinterpret));
200
0
}
201
202
std::tuple<GrSurfaceProxyView, GrColorType> SkImage_GaneshYUVA::asView(GrRecordingContext* rContext,
203
                                                                       skgpu::Mipmapped mipmapped,
204
0
                                                                       GrImageTexGenPolicy) const {
205
0
    if (!fContext->priv().matches(rContext)) {
206
0
        return {};
207
0
    }
208
0
    auto sfc = rContext->priv().makeSFC(this->imageInfo(),
209
0
                                        "Image_GpuYUVA_ReinterpretColorSpace",
210
0
                                        SkBackingFit::kExact,
211
0
                                        /*sample count*/ 1,
212
0
                                        mipmapped,
213
0
                                        GrProtected::kNo,
214
0
                                        fYUVAProxies.textureOrigin(),
215
0
                                        skgpu::Budgeted::kYes);
216
0
    if (!sfc) {
217
0
        return {};
218
0
    }
219
220
0
    const GrCaps& caps = *rContext->priv().caps();
221
0
    auto fp = GrYUVtoRGBEffect::Make(fYUVAProxies, GrSamplerState::Filter::kNearest, caps);
222
0
    if (fFromColorSpace) {
223
0
        fp = GrColorSpaceXformEffect::Make(std::move(fp),
224
0
                                           fFromColorSpace.get(),
225
0
                                           this->alphaType(),
226
0
                                           this->colorSpace(),
227
0
                                           this->alphaType());
228
0
    }
229
0
    sfc->fillWithFP(std::move(fp));
230
231
0
    return {sfc->readSurfaceView(), sfc->colorInfo().colorType()};
232
0
}
233
234
std::unique_ptr<GrFragmentProcessor> SkImage_GaneshYUVA::asFragmentProcessor(
235
        GrRecordingContext* context,
236
        SkSamplingOptions sampling,
237
        const SkTileMode tileModes[2],
238
        const SkMatrix& m,
239
        const SkRect* subset,
240
0
        const SkRect* domain) const {
241
0
    if (!fContext->priv().matches(context)) {
242
0
        return {};
243
0
    }
244
    // At least for now we do not attempt aniso filtering on YUVA images.
245
0
    if (sampling.isAniso()) {
246
0
        sampling =
247
0
                SkSamplingPriv::AnisoFallback(fYUVAProxies.mipmapped() == skgpu::Mipmapped::kYes);
248
0
    }
249
250
0
    auto wmx = SkTileModeToWrapMode(tileModes[0]);
251
0
    auto wmy = SkTileModeToWrapMode(tileModes[1]);
252
0
    GrSamplerState sampler(wmx, wmy, sampling.filter, sampling.mipmap);
253
0
    if (sampler.mipmapped() == skgpu::Mipmapped::kYes && !this->setupMipmapsForPlanes(context)) {
254
0
        sampler = GrSamplerState(sampler.wrapModeX(),
255
0
                                 sampler.wrapModeY(),
256
0
                                 sampler.filter(),
257
0
                                 GrSamplerState::MipmapMode::kNone);
258
0
    }
259
260
0
    const auto& yuvM = sampling.useCubic ? SkMatrix::I() : m;
261
0
    auto fp = GrYUVtoRGBEffect::Make(
262
0
            fYUVAProxies, sampler, *context->priv().caps(), yuvM, subset, domain);
263
0
    if (sampling.useCubic) {
264
0
        fp = GrBicubicEffect::Make(std::move(fp),
265
0
                                   this->alphaType(),
266
0
                                   m,
267
0
                                   sampling.cubic,
268
0
                                   GrBicubicEffect::Direction::kXY);
269
0
    }
270
0
    if (fFromColorSpace) {
271
0
        fp = GrColorSpaceXformEffect::Make(std::move(fp),
272
0
                                           fFromColorSpace.get(),
273
0
                                           this->alphaType(),
274
0
                                           this->colorSpace(),
275
0
                                           this->alphaType());
276
0
    }
277
0
    return fp;
278
0
}
279
280
//////////////////////////////////////////////////////////////////////////////////////////////////
281
namespace SkImages {
282
sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
283
0
                                       const GrYUVABackendTextures& yuvaTextures) {
284
0
    return TextureFromYUVATextures(context, yuvaTextures, nullptr, nullptr, nullptr);
285
0
}
286
287
sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
288
                                       const GrYUVABackendTextures& yuvaTextures,
289
                                       sk_sp<SkColorSpace> imageColorSpace,
290
                                       TextureReleaseProc textureReleaseProc,
291
0
                                       ReleaseContext releaseContext) {
292
0
    auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
293
294
0
    GrProxyProvider* proxyProvider = context->priv().proxyProvider();
295
0
    int numPlanes = yuvaTextures.yuvaInfo().numPlanes();
296
0
    sk_sp<GrSurfaceProxy> proxies[SkYUVAInfo::kMaxPlanes];
297
0
    for (int plane = 0; plane < numPlanes; ++plane) {
298
0
        proxies[plane] = proxyProvider->wrapBackendTexture(yuvaTextures.texture(plane),
299
0
                                                           kBorrow_GrWrapOwnership,
300
0
                                                           GrWrapCacheable::kNo,
301
0
                                                           kRead_GrIOType,
302
0
                                                           releaseHelper);
303
0
        if (!proxies[plane]) {
304
0
            return {};
305
0
        }
306
0
    }
307
0
    GrYUVATextureProxies yuvaProxies(
308
0
            yuvaTextures.yuvaInfo(), proxies, yuvaTextures.textureOrigin());
309
310
0
    if (!yuvaProxies.isValid()) {
311
0
        return nullptr;
312
0
    }
313
314
0
    return sk_make_sp<SkImage_GaneshYUVA>(
315
0
            sk_ref_sp(context), kNeedNewImageUniqueID, yuvaProxies, imageColorSpace);
316
0
}
317
318
sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
319
                                      const SkYUVAPixmaps& pixmaps,
320
                                      skgpu::Mipmapped buildMips,
321
0
                                      bool limitToMaxTextureSize) {
322
0
    return TextureFromYUVAPixmaps(context, pixmaps, buildMips, limitToMaxTextureSize, nullptr);
323
0
}
324
325
sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
326
                                      const SkYUVAPixmaps& pixmaps,
327
                                      skgpu::Mipmapped buildMips,
328
                                      bool limitToMaxTextureSize,
329
0
                                      sk_sp<SkColorSpace> imageColorSpace) {
330
0
    if (!context) {
331
0
        return nullptr;
332
0
    }
333
334
0
    if (!pixmaps.isValid()) {
335
0
        return nullptr;
336
0
    }
337
338
0
    if (!context->priv().caps()->mipmapSupport()) {
339
0
        buildMips = skgpu::Mipmapped::kNo;
340
0
    }
341
342
    // Resize the pixmaps if necessary.
343
0
    int numPlanes = pixmaps.numPlanes();
344
0
    int maxTextureSize = context->priv().caps()->maxTextureSize();
345
0
    int maxDim = std::max(pixmaps.yuvaInfo().width(), pixmaps.yuvaInfo().height());
346
347
0
    SkYUVAPixmaps tempPixmaps;
348
0
    const SkYUVAPixmaps* pixmapsToUpload = &pixmaps;
349
    // We assume no plane is larger than the image size (and at least one plane is as big).
350
0
    if (maxDim > maxTextureSize) {
351
0
        if (!limitToMaxTextureSize) {
352
0
            return nullptr;
353
0
        }
354
0
        float scale = static_cast<float>(maxTextureSize) / maxDim;
355
0
        SkISize newDimensions = {
356
0
                std::min(static_cast<int>(pixmaps.yuvaInfo().width() * scale), maxTextureSize),
357
0
                std::min(static_cast<int>(pixmaps.yuvaInfo().height() * scale), maxTextureSize)};
358
0
        SkYUVAInfo newInfo = pixmaps.yuvaInfo().makeDimensions(newDimensions);
359
0
        SkYUVAPixmapInfo newPixmapInfo(newInfo, pixmaps.dataType(), /*row bytes*/ nullptr);
360
0
        tempPixmaps = SkYUVAPixmaps::Allocate(newPixmapInfo);
361
0
        SkSamplingOptions sampling(SkFilterMode::kLinear);
362
0
        if (!tempPixmaps.isValid()) {
363
0
            return nullptr;
364
0
        }
365
0
        for (int i = 0; i < numPlanes; ++i) {
366
0
            if (!pixmaps.plane(i).scalePixels(tempPixmaps.plane(i), sampling)) {
367
0
                return nullptr;
368
0
            }
369
0
        }
370
0
        pixmapsToUpload = &tempPixmaps;
371
0
    }
372
373
    // Convert to texture proxies.
374
0
    GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
375
0
    GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
376
0
    for (int i = 0; i < numPlanes; ++i) {
377
        // Turn the pixmap into a GrTextureProxy
378
0
        SkBitmap bmp;
379
0
        bmp.installPixels(pixmapsToUpload->plane(i));
380
0
        std::tie(views[i], std::ignore) = GrMakeUncachedBitmapProxyView(context, bmp, buildMips);
381
0
        if (!views[i]) {
382
0
            return nullptr;
383
0
        }
384
0
        pixmapColorTypes[i] = SkColorTypeToGrColorType(bmp.colorType());
385
0
    }
386
387
0
    GrYUVATextureProxies yuvaProxies(pixmapsToUpload->yuvaInfo(), views, pixmapColorTypes);
388
0
    SkASSERT(yuvaProxies.isValid());
389
0
    return sk_make_sp<SkImage_GaneshYUVA>(sk_ref_sp(context),
390
0
                                          kNeedNewImageUniqueID,
391
0
                                          std::move(yuvaProxies),
392
0
                                          std::move(imageColorSpace));
393
0
}
Unexecuted instantiation: SkImages::TextureFromYUVAPixmaps(GrRecordingContext*, SkYUVAPixmaps const&, skgpu::Mipmapped, bool, sk_sp<SkColorSpace>)
Unexecuted instantiation: SkImages::TextureFromYUVAPixmaps(GrRecordingContext*, SkYUVAPixmaps const&, skgpu::Mipmapped, bool, sk_sp<SkColorSpace>)
394
395
sk_sp<SkImage> PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
396
                                      const GrYUVABackendTextureInfo& backendTextureInfo,
397
                                      sk_sp<SkColorSpace> imageColorSpace,
398
                                      PromiseImageTextureFulfillProc textureFulfillProc,
399
                                      PromiseImageTextureReleaseProc textureReleaseProc,
400
0
                                      PromiseImageTextureContext textureContexts[]) {
401
0
    if (!backendTextureInfo.isValid()) {
402
0
        return nullptr;
403
0
    }
404
405
0
    SkISize planeDimensions[SkYUVAInfo::kMaxPlanes];
406
0
    int n = backendTextureInfo.yuvaInfo().planeDimensions(planeDimensions);
407
408
    // Our contract is that we will always call the release proc even on failure.
409
    // We use the helper to convey the context, so we need to ensure make doesn't fail.
410
0
    textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
411
0
    sk_sp<skgpu::RefCntedCallback> releaseHelpers[4];
412
0
    for (int i = 0; i < n; ++i) {
413
0
        releaseHelpers[i] = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContexts[i]);
414
0
    }
415
416
0
    if (!threadSafeProxy) {
417
0
        return nullptr;
418
0
    }
419
420
0
    SkAlphaType at =
421
0
            backendTextureInfo.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
422
0
    SkImageInfo info = SkImageInfo::Make(
423
0
            backendTextureInfo.yuvaInfo().dimensions(), kAssumedColorType, at, imageColorSpace);
424
0
    if (!SkImageInfoIsValid(info)) {
425
0
        return nullptr;
426
0
    }
427
428
    // Make a lazy proxy for each plane
429
0
    sk_sp<GrSurfaceProxy> proxies[4];
430
0
    for (int i = 0; i < n; ++i) {
431
0
        proxies[i] =
432
0
                SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
433
0
                                                              planeDimensions[i],
434
0
                                                              backendTextureInfo.planeFormat(i),
435
0
                                                              skgpu::Mipmapped::kNo,
436
0
                                                              textureFulfillProc,
437
0
                                                              std::move(releaseHelpers[i]));
438
0
        if (!proxies[i]) {
439
0
            return nullptr;
440
0
        }
441
0
    }
442
0
    GrYUVATextureProxies yuvaTextureProxies(
443
0
            backendTextureInfo.yuvaInfo(), proxies, backendTextureInfo.textureOrigin());
444
0
    SkASSERT(yuvaTextureProxies.isValid());
445
0
    sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
446
0
    return sk_make_sp<SkImage_GaneshYUVA>(std::move(ctx),
447
0
                                          kNeedNewImageUniqueID,
448
0
                                          std::move(yuvaTextureProxies),
449
0
                                          std::move(imageColorSpace));
450
0
}
Unexecuted instantiation: SkImages::PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy>, GrYUVABackendTextureInfo const&, sk_sp<SkColorSpace>, sk_sp<GrPromiseImageTexture> (*)(void*), void (*)(void*), void**)
Unexecuted instantiation: SkImages::PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy>, GrYUVABackendTextureInfo const&, sk_sp<SkColorSpace>, sk_sp<GrPromiseImageTexture> (*)(void*), void (*)(void*), void**)
451
}  // namespace SkImages