1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/YUVUtils.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorPriv.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrYUVABackendTextures.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkImageGanesh.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkCodecImageGenerator.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkYUVAInfoLocation.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkYUVMath.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImage_Base.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/ManagedBackendTexture.h"
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_GRAPHITE
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Image.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/YUVABackendTextures.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkAutoPixmapStorage.h"
33*c8dee2aaSAndroid Build Coastguard Worker #endif
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker namespace {
36*c8dee2aaSAndroid Build Coastguard Worker
convert_yuva_to_rgba(const float mtx[20],uint8_t yuva[4])37*c8dee2aaSAndroid Build Coastguard Worker static SkPMColor convert_yuva_to_rgba(const float mtx[20], uint8_t yuva[4]) {
38*c8dee2aaSAndroid Build Coastguard Worker uint8_t y = yuva[0];
39*c8dee2aaSAndroid Build Coastguard Worker uint8_t u = yuva[1];
40*c8dee2aaSAndroid Build Coastguard Worker uint8_t v = yuva[2];
41*c8dee2aaSAndroid Build Coastguard Worker uint8_t a = yuva[3];
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker uint8_t r = SkTPin(SkScalarRoundToInt(mtx[ 0]*y + mtx[ 1]*u + mtx[ 2]*v + mtx[ 4]*255), 0, 255);
44*c8dee2aaSAndroid Build Coastguard Worker uint8_t g = SkTPin(SkScalarRoundToInt(mtx[ 5]*y + mtx[ 6]*u + mtx[ 7]*v + mtx[ 9]*255), 0, 255);
45*c8dee2aaSAndroid Build Coastguard Worker uint8_t b = SkTPin(SkScalarRoundToInt(mtx[10]*y + mtx[11]*u + mtx[12]*v + mtx[14]*255), 0, 255);
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker return SkPremultiplyARGBInline(a, r, g, b);
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker
look_up(SkPoint normPt,const SkPixmap & pmap,SkColorChannel channel)50*c8dee2aaSAndroid Build Coastguard Worker static uint8_t look_up(SkPoint normPt, const SkPixmap& pmap, SkColorChannel channel) {
51*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(normPt.x() > 0 && normPt.x() < 1.0f);
52*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(normPt.y() > 0 && normPt.y() < 1.0f);
53*c8dee2aaSAndroid Build Coastguard Worker int x = SkScalarFloorToInt(normPt.x() * pmap.width());
54*c8dee2aaSAndroid Build Coastguard Worker int y = SkScalarFloorToInt(normPt.y() * pmap.height());
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Worker auto ii = pmap.info().makeColorType(kRGBA_8888_SkColorType).makeWH(1, 1);
57*c8dee2aaSAndroid Build Coastguard Worker uint32_t pixel;
58*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(pmap.readPixels(ii, &pixel, sizeof(pixel), x, y));
59*c8dee2aaSAndroid Build Coastguard Worker int shift = static_cast<int>(channel) * 8;
60*c8dee2aaSAndroid Build Coastguard Worker return static_cast<uint8_t>((pixel >> shift) & 0xff);
61*c8dee2aaSAndroid Build Coastguard Worker }
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker class Generator : public SkImageGenerator {
64*c8dee2aaSAndroid Build Coastguard Worker public:
Generator(SkYUVAPixmaps pixmaps,sk_sp<SkColorSpace> cs)65*c8dee2aaSAndroid Build Coastguard Worker Generator(SkYUVAPixmaps pixmaps, sk_sp<SkColorSpace> cs)
66*c8dee2aaSAndroid Build Coastguard Worker : SkImageGenerator(SkImageInfo::Make(pixmaps.yuvaInfo().dimensions(),
67*c8dee2aaSAndroid Build Coastguard Worker kN32_SkColorType,
68*c8dee2aaSAndroid Build Coastguard Worker kPremul_SkAlphaType,
69*c8dee2aaSAndroid Build Coastguard Worker std::move(cs)))
70*c8dee2aaSAndroid Build Coastguard Worker , fPixmaps(std::move(pixmaps)) {}
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker protected:
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)73*c8dee2aaSAndroid Build Coastguard Worker bool onGetPixels(const SkImageInfo& info,
74*c8dee2aaSAndroid Build Coastguard Worker void* pixels,
75*c8dee2aaSAndroid Build Coastguard Worker size_t rowBytes,
76*c8dee2aaSAndroid Build Coastguard Worker const Options&) override {
77*c8dee2aaSAndroid Build Coastguard Worker if (kUnknown_SkColorType == fFlattened.colorType()) {
78*c8dee2aaSAndroid Build Coastguard Worker fFlattened.allocPixels(info);
79*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(info == this->getInfo());
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker float mtx[20];
82*c8dee2aaSAndroid Build Coastguard Worker SkColorMatrix_YUV2RGB(fPixmaps.yuvaInfo().yuvColorSpace(), mtx);
83*c8dee2aaSAndroid Build Coastguard Worker SkYUVAInfo::YUVALocations yuvaLocations = fPixmaps.toYUVALocations();
84*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(yuvaLocations));
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker SkMatrix om = fPixmaps.yuvaInfo().originMatrix();
87*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(om.invert(&om));
88*c8dee2aaSAndroid Build Coastguard Worker float normX = 1.f/info.width();
89*c8dee2aaSAndroid Build Coastguard Worker float normY = 1.f/info.height();
90*c8dee2aaSAndroid Build Coastguard Worker if (SkEncodedOriginSwapsWidthHeight(fPixmaps.yuvaInfo().origin())) {
91*c8dee2aaSAndroid Build Coastguard Worker using std::swap;
92*c8dee2aaSAndroid Build Coastguard Worker swap(normX, normY);
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker for (int y = 0; y < info.height(); ++y) {
95*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < info.width(); ++x) {
96*c8dee2aaSAndroid Build Coastguard Worker SkPoint xy1 {(x + 0.5f),
97*c8dee2aaSAndroid Build Coastguard Worker (y + 0.5f)};
98*c8dee2aaSAndroid Build Coastguard Worker xy1 = om.mapPoint(xy1);
99*c8dee2aaSAndroid Build Coastguard Worker xy1.fX *= normX;
100*c8dee2aaSAndroid Build Coastguard Worker xy1.fY *= normY;
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker uint8_t yuva[4] = {0, 0, 0, 255};
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker for (auto c : {SkYUVAInfo::YUVAChannels::kY,
105*c8dee2aaSAndroid Build Coastguard Worker SkYUVAInfo::YUVAChannels::kU,
106*c8dee2aaSAndroid Build Coastguard Worker SkYUVAInfo::YUVAChannels::kV}) {
107*c8dee2aaSAndroid Build Coastguard Worker const auto& pmap = fPixmaps.plane(yuvaLocations[c].fPlane);
108*c8dee2aaSAndroid Build Coastguard Worker yuva[c] = look_up(xy1, pmap, yuvaLocations[c].fChannel);
109*c8dee2aaSAndroid Build Coastguard Worker }
110*c8dee2aaSAndroid Build Coastguard Worker auto [aPlane, aChan] = yuvaLocations[SkYUVAInfo::YUVAChannels::kA];
111*c8dee2aaSAndroid Build Coastguard Worker if (aPlane >= 0) {
112*c8dee2aaSAndroid Build Coastguard Worker const auto& pmap = fPixmaps.plane(aPlane);
113*c8dee2aaSAndroid Build Coastguard Worker yuva[3] = look_up(xy1, pmap, aChan);
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker // Making premul here.
117*c8dee2aaSAndroid Build Coastguard Worker *fFlattened.getAddr32(x, y) = convert_yuva_to_rgba(mtx, yuva);
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker return fFlattened.readPixels(info, pixels, rowBytes, 0, 0);
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker
onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes & types,SkYUVAPixmapInfo * info) const125*c8dee2aaSAndroid Build Coastguard Worker bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& types,
126*c8dee2aaSAndroid Build Coastguard Worker SkYUVAPixmapInfo* info) const override {
127*c8dee2aaSAndroid Build Coastguard Worker *info = fPixmaps.pixmapsInfo();
128*c8dee2aaSAndroid Build Coastguard Worker return info->isValid();
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker
onGetYUVAPlanes(const SkYUVAPixmaps & pixmaps)131*c8dee2aaSAndroid Build Coastguard Worker bool onGetYUVAPlanes(const SkYUVAPixmaps& pixmaps) override {
132*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(pixmaps.yuvaInfo() == fPixmaps.yuvaInfo());
133*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < pixmaps.numPlanes(); ++i) {
134*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPixmaps.plane(i).colorType() == pixmaps.plane(i).colorType());
135*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPixmaps.plane(i).dimensions() == pixmaps.plane(i).dimensions());
136*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPixmaps.plane(i).rowBytes() == pixmaps.plane(i).rowBytes());
137*c8dee2aaSAndroid Build Coastguard Worker fPixmaps.plane(i).readPixels(pixmaps.plane(i));
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker return true;
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker private:
143*c8dee2aaSAndroid Build Coastguard Worker SkYUVAPixmaps fPixmaps;
144*c8dee2aaSAndroid Build Coastguard Worker SkBitmap fFlattened;
145*c8dee2aaSAndroid Build Coastguard Worker };
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker namespace sk_gpu_test {
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker std::tuple<std::array<sk_sp<SkImage>, SkYUVAInfo::kMaxPlanes>, SkYUVAInfo>
MakeYUVAPlanesAsA8(SkImage * src,SkYUVColorSpace cs,SkYUVAInfo::Subsampling ss,GrRecordingContext * rContext)152*c8dee2aaSAndroid Build Coastguard Worker MakeYUVAPlanesAsA8(SkImage* src,
153*c8dee2aaSAndroid Build Coastguard Worker SkYUVColorSpace cs,
154*c8dee2aaSAndroid Build Coastguard Worker SkYUVAInfo::Subsampling ss,
155*c8dee2aaSAndroid Build Coastguard Worker GrRecordingContext* rContext) {
156*c8dee2aaSAndroid Build Coastguard Worker float rgbToYUV[20];
157*c8dee2aaSAndroid Build Coastguard Worker SkColorMatrix_RGB2YUV(cs, rgbToYUV);
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker SkYUVAInfo::PlaneConfig config = src->isOpaque() ? SkYUVAInfo::PlaneConfig::kY_U_V
160*c8dee2aaSAndroid Build Coastguard Worker : SkYUVAInfo::PlaneConfig::kY_U_V_A;
161*c8dee2aaSAndroid Build Coastguard Worker SkISize dims[SkYUVAInfo::kMaxPlanes];
162*c8dee2aaSAndroid Build Coastguard Worker int n = SkYUVAInfo::PlaneDimensions(src->dimensions(),
163*c8dee2aaSAndroid Build Coastguard Worker config,
164*c8dee2aaSAndroid Build Coastguard Worker ss,
165*c8dee2aaSAndroid Build Coastguard Worker kTopLeft_SkEncodedOrigin,
166*c8dee2aaSAndroid Build Coastguard Worker dims);
167*c8dee2aaSAndroid Build Coastguard Worker std::array<sk_sp<SkImage>, 4> planes;
168*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < n; ++i) {
169*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeA8(dims[i]);
170*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSurface> surf;
171*c8dee2aaSAndroid Build Coastguard Worker if (rContext) {
172*c8dee2aaSAndroid Build Coastguard Worker surf = SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kYes, info, 1, nullptr);
173*c8dee2aaSAndroid Build Coastguard Worker } else {
174*c8dee2aaSAndroid Build Coastguard Worker surf = SkSurfaces::Raster(info);
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker if (!surf) {
177*c8dee2aaSAndroid Build Coastguard Worker return {};
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
181*c8dee2aaSAndroid Build Coastguard Worker paint.setBlendMode(SkBlendMode::kSrc);
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker // Make a matrix with the ith row of rgbToYUV copied to the A row since we're drawing to A8.
184*c8dee2aaSAndroid Build Coastguard Worker float m[20] = {};
185*c8dee2aaSAndroid Build Coastguard Worker std::copy_n(rgbToYUV + 5*i, 5, m + 15);
186*c8dee2aaSAndroid Build Coastguard Worker paint.setColorFilter(SkColorFilters::Matrix(m));
187*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->drawImageRect(src,
188*c8dee2aaSAndroid Build Coastguard Worker SkRect::Make(dims[i]),
189*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear),
190*c8dee2aaSAndroid Build Coastguard Worker &paint);
191*c8dee2aaSAndroid Build Coastguard Worker planes[i] = surf->makeImageSnapshot();
192*c8dee2aaSAndroid Build Coastguard Worker if (!planes[i]) {
193*c8dee2aaSAndroid Build Coastguard Worker return {};
194*c8dee2aaSAndroid Build Coastguard Worker }
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker SkYUVAInfo info(src->dimensions(), config, ss, cs);
197*c8dee2aaSAndroid Build Coastguard Worker return {planes, info};
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker
Make(sk_sp<SkData> data,skgpu::Mipmapped mipmapped,sk_sp<SkColorSpace> cs)200*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<LazyYUVImage> LazyYUVImage::Make(sk_sp<SkData> data,
201*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped mipmapped,
202*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> cs) {
203*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<LazyYUVImage> image(new LazyYUVImage());
204*c8dee2aaSAndroid Build Coastguard Worker if (image->reset(std::move(data), mipmapped, std::move(cs))) {
205*c8dee2aaSAndroid Build Coastguard Worker return image;
206*c8dee2aaSAndroid Build Coastguard Worker } else {
207*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker
Make(SkYUVAPixmaps pixmaps,skgpu::Mipmapped mipmapped,sk_sp<SkColorSpace> cs)211*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<LazyYUVImage> LazyYUVImage::Make(SkYUVAPixmaps pixmaps,
212*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped mipmapped,
213*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> cs) {
214*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<LazyYUVImage> image(new LazyYUVImage());
215*c8dee2aaSAndroid Build Coastguard Worker if (image->reset(std::move(pixmaps), mipmapped, std::move(cs))) {
216*c8dee2aaSAndroid Build Coastguard Worker return image;
217*c8dee2aaSAndroid Build Coastguard Worker } else {
218*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker
refImage(GrRecordingContext * rContext,Type type)222*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> LazyYUVImage::refImage(GrRecordingContext* rContext, Type type) {
223*c8dee2aaSAndroid Build Coastguard Worker if (this->ensureYUVImage(rContext, type)) {
224*c8dee2aaSAndroid Build Coastguard Worker size_t idx = static_cast<size_t>(type);
225*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(idx < std::size(fYUVImage));
226*c8dee2aaSAndroid Build Coastguard Worker return fYUVImage[idx];
227*c8dee2aaSAndroid Build Coastguard Worker } else {
228*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker
232*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
refImage(skgpu::graphite::Recorder * recorder,Type type)233*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> LazyYUVImage::refImage(skgpu::graphite::Recorder* recorder, Type type) {
234*c8dee2aaSAndroid Build Coastguard Worker if (this->ensureYUVImage(recorder, type)) {
235*c8dee2aaSAndroid Build Coastguard Worker size_t idx = static_cast<size_t>(type);
236*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(idx < std::size(fYUVImage));
237*c8dee2aaSAndroid Build Coastguard Worker return fYUVImage[idx];
238*c8dee2aaSAndroid Build Coastguard Worker } else {
239*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
240*c8dee2aaSAndroid Build Coastguard Worker }
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker #endif
243*c8dee2aaSAndroid Build Coastguard Worker
reset(sk_sp<SkData> data,skgpu::Mipmapped mipmapped,sk_sp<SkColorSpace> cs)244*c8dee2aaSAndroid Build Coastguard Worker bool LazyYUVImage::reset(sk_sp<SkData> data, skgpu::Mipmapped mipmapped, sk_sp<SkColorSpace> cs) {
245*c8dee2aaSAndroid Build Coastguard Worker fMipmapped = mipmapped;
246*c8dee2aaSAndroid Build Coastguard Worker auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(data);
247*c8dee2aaSAndroid Build Coastguard Worker if (!codec) {
248*c8dee2aaSAndroid Build Coastguard Worker return false;
249*c8dee2aaSAndroid Build Coastguard Worker }
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker SkYUVAPixmapInfo yuvaPixmapInfo;
252*c8dee2aaSAndroid Build Coastguard Worker if (!codec->queryYUVAInfo(SkYUVAPixmapInfo::SupportedDataTypes::All(), &yuvaPixmapInfo)) {
253*c8dee2aaSAndroid Build Coastguard Worker return false;
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker fPixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
256*c8dee2aaSAndroid Build Coastguard Worker if (!fPixmaps.isValid()) {
257*c8dee2aaSAndroid Build Coastguard Worker return false;
258*c8dee2aaSAndroid Build Coastguard Worker }
259*c8dee2aaSAndroid Build Coastguard Worker
260*c8dee2aaSAndroid Build Coastguard Worker if (!codec->getYUVAPlanes(fPixmaps)) {
261*c8dee2aaSAndroid Build Coastguard Worker return false;
262*c8dee2aaSAndroid Build Coastguard Worker }
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker fColorSpace = std::move(cs);
265*c8dee2aaSAndroid Build Coastguard Worker
266*c8dee2aaSAndroid Build Coastguard Worker // The SkPixmap data is fully configured now for MakeFromYUVAPixmaps once we get a GrContext
267*c8dee2aaSAndroid Build Coastguard Worker return true;
268*c8dee2aaSAndroid Build Coastguard Worker }
269*c8dee2aaSAndroid Build Coastguard Worker
reset(SkYUVAPixmaps pixmaps,skgpu::Mipmapped mipmapped,sk_sp<SkColorSpace> cs)270*c8dee2aaSAndroid Build Coastguard Worker bool LazyYUVImage::reset(SkYUVAPixmaps pixmaps,
271*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped mipmapped,
272*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> cs) {
273*c8dee2aaSAndroid Build Coastguard Worker if (!pixmaps.isValid()) {
274*c8dee2aaSAndroid Build Coastguard Worker return false;
275*c8dee2aaSAndroid Build Coastguard Worker }
276*c8dee2aaSAndroid Build Coastguard Worker fMipmapped = mipmapped;
277*c8dee2aaSAndroid Build Coastguard Worker if (pixmaps.ownsStorage()) {
278*c8dee2aaSAndroid Build Coastguard Worker fPixmaps = std::move(pixmaps);
279*c8dee2aaSAndroid Build Coastguard Worker } else {
280*c8dee2aaSAndroid Build Coastguard Worker fPixmaps = SkYUVAPixmaps::MakeCopy(std::move(pixmaps));
281*c8dee2aaSAndroid Build Coastguard Worker }
282*c8dee2aaSAndroid Build Coastguard Worker fColorSpace = std::move(cs);
283*c8dee2aaSAndroid Build Coastguard Worker // The SkPixmap data is fully configured now for MakeFromYUVAPixmaps once we get a GrContext
284*c8dee2aaSAndroid Build Coastguard Worker return true;
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker
ensureYUVImage(GrRecordingContext * rContext,Type type)287*c8dee2aaSAndroid Build Coastguard Worker bool LazyYUVImage::ensureYUVImage(GrRecordingContext* rContext, Type type) {
288*c8dee2aaSAndroid Build Coastguard Worker size_t idx = static_cast<size_t>(type);
289*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(idx < std::size(fYUVImage));
290*c8dee2aaSAndroid Build Coastguard Worker if (fYUVImage[idx] && fYUVImage[idx]->isValid(rContext)) {
291*c8dee2aaSAndroid Build Coastguard Worker return true; // Have already made a YUV image valid for this context.
292*c8dee2aaSAndroid Build Coastguard Worker }
293*c8dee2aaSAndroid Build Coastguard Worker // Try to make a new YUV image for this context.
294*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
295*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromPixmaps:
296*c8dee2aaSAndroid Build Coastguard Worker if (!rContext || rContext->abandoned()) {
297*c8dee2aaSAndroid Build Coastguard Worker return false;
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] = SkImages::TextureFromYUVAPixmaps(rContext,
300*c8dee2aaSAndroid Build Coastguard Worker fPixmaps,
301*c8dee2aaSAndroid Build Coastguard Worker fMipmapped,
302*c8dee2aaSAndroid Build Coastguard Worker /*limit to max tex size*/ false,
303*c8dee2aaSAndroid Build Coastguard Worker fColorSpace);
304*c8dee2aaSAndroid Build Coastguard Worker break;
305*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromGenerator: {
306*c8dee2aaSAndroid Build Coastguard Worker // Make sure the generator has ownership of its backing planes.
307*c8dee2aaSAndroid Build Coastguard Worker auto generator = std::make_unique<Generator>(fPixmaps, fColorSpace);
308*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] = SkImages::DeferredFromGenerator(std::move(generator));
309*c8dee2aaSAndroid Build Coastguard Worker break;
310*c8dee2aaSAndroid Build Coastguard Worker }
311*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromTextures:
312*c8dee2aaSAndroid Build Coastguard Worker if (!rContext || rContext->abandoned()) {
313*c8dee2aaSAndroid Build Coastguard Worker return false;
314*c8dee2aaSAndroid Build Coastguard Worker }
315*c8dee2aaSAndroid Build Coastguard Worker if (auto direct = rContext->asDirectContext()) {
316*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sk_gpu_test::ManagedBackendTexture> mbets[SkYUVAInfo::kMaxPlanes];
317*c8dee2aaSAndroid Build Coastguard Worker GrBackendTexture textures[SkYUVAInfo::kMaxPlanes];
318*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPixmaps.numPlanes(); ++i) {
319*c8dee2aaSAndroid Build Coastguard Worker mbets[i] = sk_gpu_test::ManagedBackendTexture::MakeFromPixmap(
320*c8dee2aaSAndroid Build Coastguard Worker direct,
321*c8dee2aaSAndroid Build Coastguard Worker fPixmaps.plane(i),
322*c8dee2aaSAndroid Build Coastguard Worker fMipmapped,
323*c8dee2aaSAndroid Build Coastguard Worker skgpu::Renderable::kNo,
324*c8dee2aaSAndroid Build Coastguard Worker skgpu::Protected::kNo);
325*c8dee2aaSAndroid Build Coastguard Worker if (mbets[i]) {
326*c8dee2aaSAndroid Build Coastguard Worker textures[i] = mbets[i]->texture();
327*c8dee2aaSAndroid Build Coastguard Worker } else {
328*c8dee2aaSAndroid Build Coastguard Worker return false;
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker }
331*c8dee2aaSAndroid Build Coastguard Worker GrYUVABackendTextures yuvaTextures(fPixmaps.yuvaInfo(),
332*c8dee2aaSAndroid Build Coastguard Worker textures,
333*c8dee2aaSAndroid Build Coastguard Worker kTopLeft_GrSurfaceOrigin);
334*c8dee2aaSAndroid Build Coastguard Worker if (!yuvaTextures.isValid()) {
335*c8dee2aaSAndroid Build Coastguard Worker return false;
336*c8dee2aaSAndroid Build Coastguard Worker }
337*c8dee2aaSAndroid Build Coastguard Worker void* planeRelContext =
338*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::ManagedBackendTexture::MakeYUVAReleaseContext(mbets);
339*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] = SkImages::TextureFromYUVATextures(
340*c8dee2aaSAndroid Build Coastguard Worker direct,
341*c8dee2aaSAndroid Build Coastguard Worker yuvaTextures,
342*c8dee2aaSAndroid Build Coastguard Worker fColorSpace,
343*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::ManagedBackendTexture::ReleaseProc,
344*c8dee2aaSAndroid Build Coastguard Worker planeRelContext);
345*c8dee2aaSAndroid Build Coastguard Worker }
346*c8dee2aaSAndroid Build Coastguard Worker break;
347*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromImages:
348*c8dee2aaSAndroid Build Coastguard Worker // Not supported in Ganesh
349*c8dee2aaSAndroid Build Coastguard Worker return false;
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker return fYUVImage[idx] != nullptr;
352*c8dee2aaSAndroid Build Coastguard Worker }
353*c8dee2aaSAndroid Build Coastguard Worker
354*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
355*c8dee2aaSAndroid Build Coastguard Worker using BackendTexture = skgpu::graphite::BackendTexture;
356*c8dee2aaSAndroid Build Coastguard Worker using Recorder = skgpu::graphite::Recorder;
357*c8dee2aaSAndroid Build Coastguard Worker using YUVABackendTextures = skgpu::graphite::YUVABackendTextures;
358*c8dee2aaSAndroid Build Coastguard Worker
ensureYUVImage(Recorder * recorder,Type type)359*c8dee2aaSAndroid Build Coastguard Worker bool LazyYUVImage::ensureYUVImage(Recorder* recorder, Type type) {
360*c8dee2aaSAndroid Build Coastguard Worker size_t idx = static_cast<size_t>(type);
361*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(idx < std::size(fYUVImage));
362*c8dee2aaSAndroid Build Coastguard Worker if (fYUVImage[idx] && as_IB(fYUVImage[idx])->isGraphiteBacked()) {
363*c8dee2aaSAndroid Build Coastguard Worker return true; // Have already made a YUV image suitable for Graphite.
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker // Try to make a new Graphite YUV image
366*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
367*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromPixmaps:
368*c8dee2aaSAndroid Build Coastguard Worker if (!recorder) {
369*c8dee2aaSAndroid Build Coastguard Worker return false;
370*c8dee2aaSAndroid Build Coastguard Worker }
371*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] =
372*c8dee2aaSAndroid Build Coastguard Worker SkImages::TextureFromYUVAPixmaps(recorder,
373*c8dee2aaSAndroid Build Coastguard Worker fPixmaps,
374*c8dee2aaSAndroid Build Coastguard Worker {fMipmapped == skgpu::Mipmapped::kYes},
375*c8dee2aaSAndroid Build Coastguard Worker /*limitToMaxTextureSize=*/false,
376*c8dee2aaSAndroid Build Coastguard Worker fColorSpace);
377*c8dee2aaSAndroid Build Coastguard Worker break;
378*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromGenerator: {
379*c8dee2aaSAndroid Build Coastguard Worker // Make sure the generator has ownership of its backing planes.
380*c8dee2aaSAndroid Build Coastguard Worker auto generator = std::make_unique<Generator>(fPixmaps, fColorSpace);
381*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] = SkImages::DeferredFromGenerator(std::move(generator));
382*c8dee2aaSAndroid Build Coastguard Worker break;
383*c8dee2aaSAndroid Build Coastguard Worker }
384*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromTextures: {
385*c8dee2aaSAndroid Build Coastguard Worker if (!recorder) {
386*c8dee2aaSAndroid Build Coastguard Worker return false;
387*c8dee2aaSAndroid Build Coastguard Worker }
388*c8dee2aaSAndroid Build Coastguard Worker
389*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sk_gpu_test::ManagedGraphiteTexture> mbets[SkYUVAInfo::kMaxPlanes];
390*c8dee2aaSAndroid Build Coastguard Worker BackendTexture textures[SkYUVAInfo::kMaxPlanes];
391*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPixmaps.numPlanes(); ++i) {
392*c8dee2aaSAndroid Build Coastguard Worker // MakeFromPixmap will handle generating the upper mipmap levels if necessary.
393*c8dee2aaSAndroid Build Coastguard Worker mbets[i] = sk_gpu_test::ManagedGraphiteTexture::MakeFromPixmap(
394*c8dee2aaSAndroid Build Coastguard Worker recorder,
395*c8dee2aaSAndroid Build Coastguard Worker fPixmaps.plane(i),
396*c8dee2aaSAndroid Build Coastguard Worker fMipmapped,
397*c8dee2aaSAndroid Build Coastguard Worker skgpu::Renderable::kNo,
398*c8dee2aaSAndroid Build Coastguard Worker skgpu::Protected::kNo);
399*c8dee2aaSAndroid Build Coastguard Worker if (mbets[i]) {
400*c8dee2aaSAndroid Build Coastguard Worker textures[i] = mbets[i]->texture();
401*c8dee2aaSAndroid Build Coastguard Worker } else {
402*c8dee2aaSAndroid Build Coastguard Worker return false;
403*c8dee2aaSAndroid Build Coastguard Worker }
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker YUVABackendTextures yuvaTextures(recorder,
406*c8dee2aaSAndroid Build Coastguard Worker fPixmaps.yuvaInfo(),
407*c8dee2aaSAndroid Build Coastguard Worker textures);
408*c8dee2aaSAndroid Build Coastguard Worker if (!yuvaTextures.isValid()) {
409*c8dee2aaSAndroid Build Coastguard Worker return false;
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker void* imageRelContext =
412*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::ManagedGraphiteTexture::MakeYUVAReleaseContext(mbets);
413*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] = SkImages::TextureFromYUVATextures(
414*c8dee2aaSAndroid Build Coastguard Worker recorder,
415*c8dee2aaSAndroid Build Coastguard Worker yuvaTextures,
416*c8dee2aaSAndroid Build Coastguard Worker fColorSpace,
417*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::ManagedGraphiteTexture::ImageReleaseProc,
418*c8dee2aaSAndroid Build Coastguard Worker imageRelContext);
419*c8dee2aaSAndroid Build Coastguard Worker break;
420*c8dee2aaSAndroid Build Coastguard Worker }
421*c8dee2aaSAndroid Build Coastguard Worker case Type::kFromImages: {
422*c8dee2aaSAndroid Build Coastguard Worker if (!recorder) {
423*c8dee2aaSAndroid Build Coastguard Worker return false;
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker
426*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> planeImgs[SkYUVAInfo::kMaxPlanes];
427*c8dee2aaSAndroid Build Coastguard Worker
428*c8dee2aaSAndroid Build Coastguard Worker using SkImages::GenerateMipmapsFromBase;
429*c8dee2aaSAndroid Build Coastguard Worker GenerateMipmapsFromBase genMipmaps = GenerateMipmapsFromBase::kNo;
430*c8dee2aaSAndroid Build Coastguard Worker if (fMipmapped == skgpu::Mipmapped::kYes) {
431*c8dee2aaSAndroid Build Coastguard Worker genMipmaps = GenerateMipmapsFromBase::kYes;
432*c8dee2aaSAndroid Build Coastguard Worker }
433*c8dee2aaSAndroid Build Coastguard Worker
434*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPixmaps.numPlanes(); ++i) {
435*c8dee2aaSAndroid Build Coastguard Worker const auto& plane = fPixmaps.plane(i);
436*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ManagedGraphiteTexture> mbet;
437*c8dee2aaSAndroid Build Coastguard Worker if (fMipmapped == skgpu::Mipmapped::kYes) {
438*c8dee2aaSAndroid Build Coastguard Worker mbet = ManagedGraphiteTexture::MakeUnInit(recorder,
439*c8dee2aaSAndroid Build Coastguard Worker plane.info(),
440*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped::kYes,
441*c8dee2aaSAndroid Build Coastguard Worker skgpu::Renderable::kNo);
442*c8dee2aaSAndroid Build Coastguard Worker // We allocate a full mip set because updateBackendTexture requires it. However,
443*c8dee2aaSAndroid Build Coastguard Worker // the non-base levels are cleared to red. We rely on SkImages::WrapTexture
444*c8dee2aaSAndroid Build Coastguard Worker // to actually generate the contents from the base level for each plane on the
445*c8dee2aaSAndroid Build Coastguard Worker // GPU. This exercises the case where the client wants a mipmapped YUV image but
446*c8dee2aaSAndroid Build Coastguard Worker // only provides the base level contents.
447*c8dee2aaSAndroid Build Coastguard Worker int levelCnt = SkMipmap::ComputeLevelCount(plane.dimensions());
448*c8dee2aaSAndroid Build Coastguard Worker skia_private::TArray<SkAutoPixmapStorage> levelStorage(levelCnt);
449*c8dee2aaSAndroid Build Coastguard Worker skia_private::TArray<SkPixmap> levels(levelCnt + 1);
450*c8dee2aaSAndroid Build Coastguard Worker levels.push_back(plane);
451*c8dee2aaSAndroid Build Coastguard Worker for (int l = 0; l < levelCnt; ++l) {
452*c8dee2aaSAndroid Build Coastguard Worker SkISize dims = SkMipmap::ComputeLevelSize(plane.dimensions(), l);
453*c8dee2aaSAndroid Build Coastguard Worker SkAutoPixmapStorage level;
454*c8dee2aaSAndroid Build Coastguard Worker level.alloc(plane.info().makeDimensions(dims));
455*c8dee2aaSAndroid Build Coastguard Worker level.erase(SK_ColorRED);
456*c8dee2aaSAndroid Build Coastguard Worker levels.push_back(level);
457*c8dee2aaSAndroid Build Coastguard Worker levelStorage.push_back(std::move(level));
458*c8dee2aaSAndroid Build Coastguard Worker }
459*c8dee2aaSAndroid Build Coastguard Worker if (!mbet || !recorder->updateBackendTexture(mbet->texture(),
460*c8dee2aaSAndroid Build Coastguard Worker levels.data(),
461*c8dee2aaSAndroid Build Coastguard Worker levels.size())) {
462*c8dee2aaSAndroid Build Coastguard Worker return false;
463*c8dee2aaSAndroid Build Coastguard Worker }
464*c8dee2aaSAndroid Build Coastguard Worker } else {
465*c8dee2aaSAndroid Build Coastguard Worker mbet = ManagedGraphiteTexture::MakeFromPixmap(recorder,
466*c8dee2aaSAndroid Build Coastguard Worker plane,
467*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped::kNo,
468*c8dee2aaSAndroid Build Coastguard Worker skgpu::Renderable::kNo);
469*c8dee2aaSAndroid Build Coastguard Worker if (!mbet) {
470*c8dee2aaSAndroid Build Coastguard Worker return false;
471*c8dee2aaSAndroid Build Coastguard Worker }
472*c8dee2aaSAndroid Build Coastguard Worker }
473*c8dee2aaSAndroid Build Coastguard Worker planeImgs[i] = SkImages::WrapTexture(recorder,
474*c8dee2aaSAndroid Build Coastguard Worker mbet->texture(),
475*c8dee2aaSAndroid Build Coastguard Worker plane.colorType(),
476*c8dee2aaSAndroid Build Coastguard Worker plane.alphaType(),
477*c8dee2aaSAndroid Build Coastguard Worker fColorSpace,
478*c8dee2aaSAndroid Build Coastguard Worker skgpu::Origin::kTopLeft,
479*c8dee2aaSAndroid Build Coastguard Worker genMipmaps,
480*c8dee2aaSAndroid Build Coastguard Worker ManagedGraphiteTexture::ImageReleaseProc,
481*c8dee2aaSAndroid Build Coastguard Worker mbet->releaseContext());
482*c8dee2aaSAndroid Build Coastguard Worker }
483*c8dee2aaSAndroid Build Coastguard Worker
484*c8dee2aaSAndroid Build Coastguard Worker fYUVImage[idx] = SkImages::TextureFromYUVAImages(
485*c8dee2aaSAndroid Build Coastguard Worker recorder,
486*c8dee2aaSAndroid Build Coastguard Worker fPixmaps.yuvaInfo(),
487*c8dee2aaSAndroid Build Coastguard Worker planeImgs,
488*c8dee2aaSAndroid Build Coastguard Worker fColorSpace);
489*c8dee2aaSAndroid Build Coastguard Worker break;
490*c8dee2aaSAndroid Build Coastguard Worker }
491*c8dee2aaSAndroid Build Coastguard Worker }
492*c8dee2aaSAndroid Build Coastguard Worker return fYUVImage[idx] != nullptr;
493*c8dee2aaSAndroid Build Coastguard Worker }
494*c8dee2aaSAndroid Build Coastguard Worker #endif
495*c8dee2aaSAndroid Build Coastguard Worker
496*c8dee2aaSAndroid Build Coastguard Worker } // namespace sk_gpu_test
497