xref: /aosp_15_r20/external/skia/src/gpu/ganesh/image/SkImage_GaneshYUVA.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkImageInfo.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkSurface.h"
14 #include "include/core/SkYUVAInfo.h"
15 #include "include/gpu/GpuTypes.h"
16 #include "include/gpu/ganesh/GrBackendSurface.h"  // IWYU pragma: keep
17 #include "include/gpu/ganesh/GrDirectContext.h"
18 #include "include/gpu/ganesh/GrRecordingContext.h"
19 #include "include/gpu/ganesh/GrTypes.h"
20 #include "include/private/base/SkAssert.h"
21 #include "include/private/base/SkDebug.h"
22 #include "include/private/gpu/ganesh/GrImageContext.h"
23 #include "src/core/SkSamplingPriv.h"
24 #include "src/gpu/SkBackingFit.h"
25 #include "src/gpu/Swizzle.h"
26 #include "src/gpu/ganesh/GrCaps.h"
27 #include "src/gpu/ganesh/GrColorInfo.h"
28 #include "src/gpu/ganesh/GrColorSpaceXform.h"
29 #include "src/gpu/ganesh/GrDirectContextPriv.h"
30 #include "src/gpu/ganesh/GrFragmentProcessor.h"
31 #include "src/gpu/ganesh/GrImageContextPriv.h"
32 #include "src/gpu/ganesh/GrImageInfo.h"
33 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
34 #include "src/gpu/ganesh/GrSamplerState.h"
35 #include "src/gpu/ganesh/GrSurfaceProxy.h"
36 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
37 #include "src/gpu/ganesh/GrTextureProxy.h"
38 #include "src/gpu/ganesh/SkGr.h"
39 #include "src/gpu/ganesh/SurfaceFillContext.h"
40 #include "src/gpu/ganesh/effects/GrBicubicEffect.h"
41 #include "src/gpu/ganesh/effects/GrYUVtoRGBEffect.h"
42 #include "src/image/SkImage_Base.h"
43 
44 #include <utility>
45 
46 enum class SkTileMode;
47 struct SkRect;
48 
SkImage_GaneshYUVA(sk_sp<GrImageContext> context,uint32_t uniqueID,GrYUVATextureProxies proxies,sk_sp<SkColorSpace> imageColorSpace)49 SkImage_GaneshYUVA::SkImage_GaneshYUVA(sk_sp<GrImageContext> context,
50                                        uint32_t uniqueID,
51                                        GrYUVATextureProxies proxies,
52                                        sk_sp<SkColorSpace> imageColorSpace)
53         : INHERITED(std::move(context),
54                     SkImageInfo::Make(proxies.yuvaInfo().dimensions(),
55                                       kAssumedColorType,
56                                       // If an alpha channel is present we always use kPremul. This
57                                       // is because, although the planar data is always un-premul,
58                                       // the final interleaved RGBA sample produced in the shader
59                                       // is premul (and similar if flattened via asView).
60                                       proxies.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType
61                                                                     : kOpaque_SkAlphaType,
62                                       std::move(imageColorSpace)),
63                     uniqueID)
64         , fYUVAProxies(std::move(proxies)) {
65     // The caller should have checked this, just verifying.
66     SkASSERT(fYUVAProxies.isValid());
67 }
68 
69 // For onMakeColorTypeAndColorSpace() / onReinterpretColorSpace()
SkImage_GaneshYUVA(sk_sp<GrImageContext> context,const SkImage_GaneshYUVA * image,sk_sp<SkColorSpace> targetCS,ColorSpaceMode csMode)70 SkImage_GaneshYUVA::SkImage_GaneshYUVA(sk_sp<GrImageContext> context,
71                                        const SkImage_GaneshYUVA* image,
72                                        sk_sp<SkColorSpace> targetCS,
73                                        ColorSpaceMode csMode)
74         : INHERITED(std::move(context),
75                     image->imageInfo().makeColorSpace(std::move(targetCS)),
76                     kNeedNewImageUniqueID)
77         , fYUVAProxies(image->fYUVAProxies)
78         // If we're *reinterpreting* in a new color space, leave fFromColorSpace null.
79         // If we're *converting* to a new color space, it must be non-null, so turn null into sRGB.
80         , fFromColorSpace(csMode == ColorSpaceMode::kReinterpret
81                                   ? nullptr
82                                   : (image->colorSpace() ? image->refColorSpace()
83                                                          : SkColorSpace::MakeSRGB())) {}
84 
setupMipmapsForPlanes(GrRecordingContext * context) const85 bool SkImage_GaneshYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
86     if (!context || !fContext->priv().matches(context)) {
87         return false;
88     }
89     if (!context->priv().caps()->mipmapSupport()) {
90         // We succeed in this case by doing nothing.
91         return true;
92     }
93     int n = fYUVAProxies.yuvaInfo().numPlanes();
94     sk_sp<GrSurfaceProxy> newProxies[4];
95     for (int i = 0; i < n; ++i) {
96         auto* t = fYUVAProxies.proxy(i)->asTextureProxy();
97         if (t->mipmapped() == skgpu::Mipmapped::kNo && (t->width() > 1 || t->height() > 1)) {
98             auto newView = GrCopyBaseMipMapToView(context, fYUVAProxies.makeView(i));
99             if (!newView) {
100                 return false;
101             }
102             SkASSERT(newView.swizzle() == fYUVAProxies.makeView(i).swizzle());
103             newProxies[i] = newView.detachProxy();
104         } else {
105             newProxies[i] = fYUVAProxies.refProxy(i);
106         }
107     }
108     fYUVAProxies =
109             GrYUVATextureProxies(fYUVAProxies.yuvaInfo(), newProxies, fYUVAProxies.textureOrigin());
110     SkASSERT(fYUVAProxies.isValid());
111     return true;
112 }
113 
114 //////////////////////////////////////////////////////////////////////////////////////////////////
115 
flush(GrDirectContext * dContext,const GrFlushInfo & info) const116 GrSemaphoresSubmitted SkImage_GaneshYUVA::flush(GrDirectContext* dContext,
117                                                 const GrFlushInfo& info) const {
118     if (!fContext->priv().matches(dContext) || dContext->abandoned()) {
119         if (info.fSubmittedProc) {
120             info.fSubmittedProc(info.fSubmittedContext, false);
121         }
122         if (info.fFinishedProc) {
123             info.fFinishedProc(info.fFinishedContext);
124         }
125         return GrSemaphoresSubmitted::kNo;
126     }
127 
128     GrSurfaceProxy* proxies[SkYUVAInfo::kMaxPlanes] = {};
129     size_t numProxies = fYUVAProxies.numPlanes();
130     for (size_t i = 0; i < numProxies; ++i) {
131         proxies[i] = fYUVAProxies.proxy(i);
132     }
133     return dContext->priv().flushSurfaces(
134             {proxies, numProxies}, SkSurfaces::BackendSurfaceAccess::kNoAccess, info);
135 }
136 
onHasMipmaps() const137 bool SkImage_GaneshYUVA::onHasMipmaps() const {
138     return fYUVAProxies.mipmapped() == skgpu::Mipmapped::kYes;
139 }
140 
onIsProtected() const141 bool SkImage_GaneshYUVA::onIsProtected() const {
142     skgpu::Protected isProtected = fYUVAProxies.proxy(0)->isProtected();
143 
144 #if defined(SK_DEBUG)
145     for (int i = 1; i < fYUVAProxies.numPlanes(); ++i) {
146         SkASSERT(isProtected == fYUVAProxies.proxy(i)->isProtected());
147     }
148 #endif
149 
150     return isProtected == skgpu::Protected::kYes;
151 }
152 
153 
textureSize() const154 size_t SkImage_GaneshYUVA::textureSize() const {
155     size_t size = 0;
156     for (int i = 0; i < fYUVAProxies.numPlanes(); ++i) {
157         size += fYUVAProxies.proxy(i)->gpuMemorySize();
158     }
159     return size;
160 }
161 
onMakeColorTypeAndColorSpace(SkColorType,sk_sp<SkColorSpace> targetCS,GrDirectContext * direct) const162 sk_sp<SkImage> SkImage_GaneshYUVA::onMakeColorTypeAndColorSpace(SkColorType,
163                                                                 sk_sp<SkColorSpace> targetCS,
164                                                                 GrDirectContext* direct) const {
165     // We explicitly ignore color type changes, for now.
166 
167     // we may need a mutex here but for now we expect usage to be in a single thread
168     if (fOnMakeColorSpaceTarget &&
169         SkColorSpace::Equals(targetCS.get(), fOnMakeColorSpaceTarget.get())) {
170         return fOnMakeColorSpaceResult;
171     }
172     sk_sp<SkImage> result = sk_sp<SkImage>(
173             new SkImage_GaneshYUVA(sk_ref_sp(direct), this, targetCS, ColorSpaceMode::kConvert));
174     if (result) {
175         fOnMakeColorSpaceTarget = targetCS;
176         fOnMakeColorSpaceResult = result;
177     }
178     return result;
179 }
180 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const181 sk_sp<SkImage> SkImage_GaneshYUVA::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
182     return sk_sp<SkImage>(
183             new SkImage_GaneshYUVA(fContext, this, std::move(newCS), ColorSpaceMode::kReinterpret));
184 }
185 
asView(GrRecordingContext * rContext,skgpu::Mipmapped mipmapped,GrImageTexGenPolicy) const186 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_GaneshYUVA::asView(GrRecordingContext* rContext,
187                                                                        skgpu::Mipmapped mipmapped,
188                                                                        GrImageTexGenPolicy) const {
189     if (!fContext->priv().matches(rContext)) {
190         return {};
191     }
192     auto sfc = rContext->priv().makeSFC(this->imageInfo(),
193                                         "Image_GpuYUVA_ReinterpretColorSpace",
194                                         SkBackingFit::kExact,
195                                         /*sample count*/ 1,
196                                         mipmapped,
197                                         GrProtected::kNo,
198                                         fYUVAProxies.textureOrigin(),
199                                         skgpu::Budgeted::kYes);
200     if (!sfc) {
201         return {};
202     }
203 
204     const GrCaps& caps = *rContext->priv().caps();
205     auto fp = GrYUVtoRGBEffect::Make(fYUVAProxies, GrSamplerState::Filter::kNearest, caps);
206     if (fFromColorSpace) {
207         fp = GrColorSpaceXformEffect::Make(std::move(fp),
208                                            fFromColorSpace.get(),
209                                            this->alphaType(),
210                                            this->colorSpace(),
211                                            this->alphaType());
212     }
213     sfc->fillWithFP(std::move(fp));
214 
215     return {sfc->readSurfaceView(), sfc->colorInfo().colorType()};
216 }
217 
asFragmentProcessor(GrRecordingContext * context,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const218 std::unique_ptr<GrFragmentProcessor> SkImage_GaneshYUVA::asFragmentProcessor(
219         GrRecordingContext* context,
220         SkSamplingOptions sampling,
221         const SkTileMode tileModes[2],
222         const SkMatrix& m,
223         const SkRect* subset,
224         const SkRect* domain) const {
225     if (!fContext->priv().matches(context)) {
226         return {};
227     }
228     // At least for now we do not attempt aniso filtering on YUVA images.
229     if (sampling.isAniso()) {
230         sampling =
231                 SkSamplingPriv::AnisoFallback(fYUVAProxies.mipmapped() == skgpu::Mipmapped::kYes);
232     }
233 
234     auto wmx = SkTileModeToWrapMode(tileModes[0]);
235     auto wmy = SkTileModeToWrapMode(tileModes[1]);
236     GrSamplerState sampler(wmx, wmy, sampling.filter, sampling.mipmap);
237     if (sampler.mipmapped() == skgpu::Mipmapped::kYes && !this->setupMipmapsForPlanes(context)) {
238         sampler = GrSamplerState(sampler.wrapModeX(),
239                                  sampler.wrapModeY(),
240                                  sampler.filter(),
241                                  GrSamplerState::MipmapMode::kNone);
242     }
243 
244     const auto& yuvM = sampling.useCubic ? SkMatrix::I() : m;
245     auto fp = GrYUVtoRGBEffect::Make(
246             fYUVAProxies, sampler, *context->priv().caps(), yuvM, subset, domain);
247     if (sampling.useCubic) {
248         fp = GrBicubicEffect::Make(std::move(fp),
249                                    this->alphaType(),
250                                    m,
251                                    sampling.cubic,
252                                    GrBicubicEffect::Direction::kXY);
253     }
254     if (fFromColorSpace) {
255         fp = GrColorSpaceXformEffect::Make(std::move(fp),
256                                            fFromColorSpace.get(),
257                                            this->alphaType(),
258                                            this->colorSpace(),
259                                            this->alphaType());
260     }
261     return fp;
262 }
263