xref: /aosp_15_r20/external/skia/gm/yuvtorgbsubset.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2014 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 // This test only works with the GPU backend.
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkYUVAInfo.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkYUVAPixmaps.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCanvasPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SkGr.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/YUVUtils.h"
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
28*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker class SkCanvas;
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker // This GM tests subsetting YUV multiplanar images where the U and V
37*c8dee2aaSAndroid Build Coastguard Worker // planes have different resolution from Y. See skbug:8959
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker class YUVtoRGBSubsetEffect : public GM {
40*c8dee2aaSAndroid Build Coastguard Worker public:
YUVtoRGBSubsetEffect()41*c8dee2aaSAndroid Build Coastguard Worker     YUVtoRGBSubsetEffect() {
42*c8dee2aaSAndroid Build Coastguard Worker         this->setBGColor(0xFFFFFFFF);
43*c8dee2aaSAndroid Build Coastguard Worker     }
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const46*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("yuv_to_rgb_subset_effect"); }
47*c8dee2aaSAndroid Build Coastguard Worker 
getISize()48*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {1310, 540}; }
49*c8dee2aaSAndroid Build Coastguard Worker 
makePixmaps()50*c8dee2aaSAndroid Build Coastguard Worker     void makePixmaps() {
51*c8dee2aaSAndroid Build Coastguard Worker         SkYUVAInfo yuvaInfo = SkYUVAInfo({8, 8},
52*c8dee2aaSAndroid Build Coastguard Worker                                          SkYUVAInfo::PlaneConfig::kY_U_V,
53*c8dee2aaSAndroid Build Coastguard Worker                                          SkYUVAInfo::Subsampling::k420,
54*c8dee2aaSAndroid Build Coastguard Worker                                          kJPEG_Full_SkYUVColorSpace);
55*c8dee2aaSAndroid Build Coastguard Worker         SkColorType colorTypes[] = {kAlpha_8_SkColorType,
56*c8dee2aaSAndroid Build Coastguard Worker                                     kAlpha_8_SkColorType,
57*c8dee2aaSAndroid Build Coastguard Worker                                     kAlpha_8_SkColorType};
58*c8dee2aaSAndroid Build Coastguard Worker         SkYUVAPixmapInfo pmapInfo(yuvaInfo, colorTypes, nullptr);
59*c8dee2aaSAndroid Build Coastguard Worker         fPixmaps = SkYUVAPixmaps::Allocate(pmapInfo);
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker         unsigned char innerY[16] = {149, 160, 130, 105,
62*c8dee2aaSAndroid Build Coastguard Worker                                     160, 130, 105, 149,
63*c8dee2aaSAndroid Build Coastguard Worker                                     130, 105, 149, 160,
64*c8dee2aaSAndroid Build Coastguard Worker                                     105, 149, 160, 130};
65*c8dee2aaSAndroid Build Coastguard Worker         unsigned char innerU[4] = {43, 75, 145, 200};
66*c8dee2aaSAndroid Build Coastguard Worker         unsigned char innerV[4] = {88, 180, 200, 43};
67*c8dee2aaSAndroid Build Coastguard Worker         int outerYUV[] = {128, 128, 128};
68*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap bitmaps[3];
69*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < 3; ++i) {
70*c8dee2aaSAndroid Build Coastguard Worker             bitmaps[i].installPixels(fPixmaps.plane(i));
71*c8dee2aaSAndroid Build Coastguard Worker             bitmaps[i].eraseColor(SkColorSetARGB(outerYUV[i], 0, 0, 0));
72*c8dee2aaSAndroid Build Coastguard Worker         }
73*c8dee2aaSAndroid Build Coastguard Worker         SkPixmap innerYPM(SkImageInfo::MakeA8(4, 4), innerY, 4);
74*c8dee2aaSAndroid Build Coastguard Worker         SkPixmap innerUPM(SkImageInfo::MakeA8(2, 2), innerU, 2);
75*c8dee2aaSAndroid Build Coastguard Worker         SkPixmap innerVPM(SkImageInfo::MakeA8(2, 2), innerV, 2);
76*c8dee2aaSAndroid Build Coastguard Worker         bitmaps[0].writePixels(innerYPM, 2, 2);
77*c8dee2aaSAndroid Build Coastguard Worker         bitmaps[1].writePixels(innerUPM, 1, 1);
78*c8dee2aaSAndroid Build Coastguard Worker         bitmaps[2].writePixels(innerVPM, 1, 1);
79*c8dee2aaSAndroid Build Coastguard Worker     }
80*c8dee2aaSAndroid Build Coastguard Worker 
onGpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext *)81*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override {
82*c8dee2aaSAndroid Build Coastguard Worker         auto context = GrAsDirectContext(canvas->recordingContext());
83*c8dee2aaSAndroid Build Coastguard Worker         skgpu::graphite::Recorder* recorder = nullptr;
84*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
85*c8dee2aaSAndroid Build Coastguard Worker         recorder = canvas->recorder();
86*c8dee2aaSAndroid Build Coastguard Worker #endif
87*c8dee2aaSAndroid Build Coastguard Worker         if (!context && !recorder) {
88*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
89*c8dee2aaSAndroid Build Coastguard Worker         }
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker         if (!fPixmaps.isValid()) {
92*c8dee2aaSAndroid Build Coastguard Worker             this->makePixmaps();
93*c8dee2aaSAndroid Build Coastguard Worker         }
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         auto lazyYUV = sk_gpu_test::LazyYUVImage::Make(fPixmaps);
96*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
97*c8dee2aaSAndroid Build Coastguard Worker         if (recorder) {
98*c8dee2aaSAndroid Build Coastguard Worker             fYUVImage = lazyYUV->refImage(recorder, sk_gpu_test::LazyYUVImage::Type::kFromPixmaps);
99*c8dee2aaSAndroid Build Coastguard Worker         } else
100*c8dee2aaSAndroid Build Coastguard Worker #endif
101*c8dee2aaSAndroid Build Coastguard Worker         {
102*c8dee2aaSAndroid Build Coastguard Worker             fYUVImage = lazyYUV->refImage(context, sk_gpu_test::LazyYUVImage::Type::kFromPixmaps);
103*c8dee2aaSAndroid Build Coastguard Worker         }
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
106*c8dee2aaSAndroid Build Coastguard Worker     }
107*c8dee2aaSAndroid Build Coastguard Worker 
onGpuTeardown()108*c8dee2aaSAndroid Build Coastguard Worker     void onGpuTeardown() override { fYUVImage.reset(); }
109*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)110*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas,
111*c8dee2aaSAndroid Build Coastguard Worker                       SkString* errorMsg) override {
112*c8dee2aaSAndroid Build Coastguard Worker         auto context = GrAsDirectContext(canvas->recordingContext());
113*c8dee2aaSAndroid Build Coastguard Worker         skgpu::graphite::Recorder* recorder = nullptr;
114*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
115*c8dee2aaSAndroid Build Coastguard Worker         recorder = canvas->recorder();
116*c8dee2aaSAndroid Build Coastguard Worker #endif
117*c8dee2aaSAndroid Build Coastguard Worker         if (!context && !recorder) {
118*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
119*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
120*c8dee2aaSAndroid Build Coastguard Worker         }
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker         if (!fYUVImage) {
123*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = "No valid YUV image generated -- skipping";
124*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
125*c8dee2aaSAndroid Build Coastguard Worker         }
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker         static const SkFilterMode kFilters[] = {SkFilterMode::kNearest,
128*c8dee2aaSAndroid Build Coastguard Worker                                                 SkFilterMode::kLinear};
129*c8dee2aaSAndroid Build Coastguard Worker         static const SkIRect kColorRect = SkIRect::MakeLTRB(2, 2, 6, 6);
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker         // Outset to visualize wrap modes.
132*c8dee2aaSAndroid Build Coastguard Worker         SkRect rect = SkRect::Make(fYUVImage->dimensions());
133*c8dee2aaSAndroid Build Coastguard Worker         rect = rect.makeOutset(fYUVImage->width()/2.f, fYUVImage->height()/2.f);
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker         SkScalar y = kTestPad;
136*c8dee2aaSAndroid Build Coastguard Worker         // Rows are filter modes.
137*c8dee2aaSAndroid Build Coastguard Worker         for (uint32_t i = 0; i < std::size(kFilters); ++i) {
138*c8dee2aaSAndroid Build Coastguard Worker             SkScalar x = kTestPad;
139*c8dee2aaSAndroid Build Coastguard Worker             // Columns are non-subsetted followed by subsetted with each TileMode in a row
140*c8dee2aaSAndroid Build Coastguard Worker             for (uint32_t j = 0; j < kSkTileModeCount + 1; ++j) {
141*c8dee2aaSAndroid Build Coastguard Worker                 SkMatrix ctm = SkMatrix::Translate(x, y);
142*c8dee2aaSAndroid Build Coastguard Worker                 ctm.postScale(10.f, 10.f);
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker                 const SkIRect* subset = j > 0 ? &kColorRect : nullptr;
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker                 auto tm = SkTileMode::kClamp;
147*c8dee2aaSAndroid Build Coastguard Worker                 if (j > 0) {
148*c8dee2aaSAndroid Build Coastguard Worker                     tm = static_cast<SkTileMode>(j - 1);
149*c8dee2aaSAndroid Build Coastguard Worker                 }
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker                 canvas->save();
152*c8dee2aaSAndroid Build Coastguard Worker                 canvas->concat(ctm);
153*c8dee2aaSAndroid Build Coastguard Worker                 SkSamplingOptions sampling(kFilters[i]);
154*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint paint;
155*c8dee2aaSAndroid Build Coastguard Worker                 // Draw black rectangle in background so rendering with Decal tilemode matches
156*c8dee2aaSAndroid Build Coastguard Worker                 // the previously used ClampToBorder wrapmode.
157*c8dee2aaSAndroid Build Coastguard Worker                 paint.setColor(SK_ColorBLACK);
158*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawRect(rect, paint);
159*c8dee2aaSAndroid Build Coastguard Worker                 if (subset) {
160*c8dee2aaSAndroid Build Coastguard Worker                     sk_sp<SkImage> subsetImg;
161*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
162*c8dee2aaSAndroid Build Coastguard Worker                     if (recorder) {
163*c8dee2aaSAndroid Build Coastguard Worker                         subsetImg = fYUVImage->makeSubset(recorder, *subset, {false});
164*c8dee2aaSAndroid Build Coastguard Worker                     } else
165*c8dee2aaSAndroid Build Coastguard Worker #endif
166*c8dee2aaSAndroid Build Coastguard Worker                     {
167*c8dee2aaSAndroid Build Coastguard Worker                         subsetImg = fYUVImage->makeSubset(context, *subset);
168*c8dee2aaSAndroid Build Coastguard Worker                     }
169*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(subsetImg);
170*c8dee2aaSAndroid Build Coastguard Worker                     paint.setShader(subsetImg->makeShader(tm, tm,
171*c8dee2aaSAndroid Build Coastguard Worker                                                           sampling, SkMatrix::Translate(2, 2)));
172*c8dee2aaSAndroid Build Coastguard Worker                 } else {
173*c8dee2aaSAndroid Build Coastguard Worker                     paint.setShader(fYUVImage->makeShader(tm, tm,
174*c8dee2aaSAndroid Build Coastguard Worker                                                           sampling, SkMatrix::I()));
175*c8dee2aaSAndroid Build Coastguard Worker                 }
176*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawRect(rect, paint);
177*c8dee2aaSAndroid Build Coastguard Worker                 canvas->restore();
178*c8dee2aaSAndroid Build Coastguard Worker                 x += rect.width() + kTestPad;
179*c8dee2aaSAndroid Build Coastguard Worker             }
180*c8dee2aaSAndroid Build Coastguard Worker 
181*c8dee2aaSAndroid Build Coastguard Worker             y += rect.height() + kTestPad;
182*c8dee2aaSAndroid Build Coastguard Worker         }
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
185*c8dee2aaSAndroid Build Coastguard Worker     }
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker private:
188*c8dee2aaSAndroid Build Coastguard Worker     SkYUVAPixmaps fPixmaps;
189*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> fYUVImage;
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr SkScalar kTestPad = 10.f;
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GM;
194*c8dee2aaSAndroid Build Coastguard Worker };
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new YUVtoRGBSubsetEffect;)
197*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
198