xref: /aosp_15_r20/external/skia/gm/rendertomipmappedyuvimageplanes.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2024 Google LLC
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 Graphite.
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImageInfoPriv.h"
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkYUVAInfo.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkColorMatrix.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Image.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recorder.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Surface.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkYUVAInfoLocation.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h"
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
27*c8dee2aaSAndroid Build Coastguard Worker class RenderToMipmappedYUVImagePlanes : public GM {
28*c8dee2aaSAndroid Build Coastguard Worker public:
RenderToMipmappedYUVImagePlanes()29*c8dee2aaSAndroid Build Coastguard Worker     RenderToMipmappedYUVImagePlanes() { this->setBGColor(0xFFFFFFFF); }
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const32*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("render_to_mipmapped_yuv_image_planes"); }
33*c8dee2aaSAndroid Build Coastguard Worker 
getISize()34*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {96, 32}; }
35*c8dee2aaSAndroid Build Coastguard Worker 
onGpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext *)36*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override {
37*c8dee2aaSAndroid Build Coastguard Worker         auto* recorder = canvas->recorder();
38*c8dee2aaSAndroid Build Coastguard Worker         if (!recorder) {
39*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = "graphite-only test";
40*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
41*c8dee2aaSAndroid Build Coastguard Worker         }
42*c8dee2aaSAndroid Build Coastguard Worker         if (!fSrcImage) {
43*c8dee2aaSAndroid Build Coastguard Worker             fSrcImage = ToolUtils::GetResourceAsImage("images/mandrill_512.png");
44*c8dee2aaSAndroid Build Coastguard Worker             if (!fSrcImage) {
45*c8dee2aaSAndroid Build Coastguard Worker                 *errorMsg = "Could not load src image.";
46*c8dee2aaSAndroid Build Coastguard Worker                 return DrawResult::kFail;
47*c8dee2aaSAndroid Build Coastguard Worker             }
48*c8dee2aaSAndroid Build Coastguard Worker         }
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
51*c8dee2aaSAndroid Build Coastguard Worker     }
52*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)53*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
54*c8dee2aaSAndroid Build Coastguard Worker         auto* recorder = canvas->recorder();
55*c8dee2aaSAndroid Build Coastguard Worker         if (!recorder) {
56*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = "direct to graphite test";
57*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
58*c8dee2aaSAndroid Build Coastguard Worker         }
59*c8dee2aaSAndroid Build Coastguard Worker         using PlaneConfig = SkYUVAInfo::PlaneConfig;
60*c8dee2aaSAndroid Build Coastguard Worker         using Subsampling = SkYUVAInfo::Subsampling;
61*c8dee2aaSAndroid Build Coastguard Worker         struct TestCase {
62*c8dee2aaSAndroid Build Coastguard Worker             PlaneConfig config;
63*c8dee2aaSAndroid Build Coastguard Worker             Subsampling subsampling;
64*c8dee2aaSAndroid Build Coastguard Worker         };
65*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& tc : {TestCase{PlaneConfig::kY_U_V, Subsampling::k420},
66*c8dee2aaSAndroid Build Coastguard Worker                                TestCase{PlaneConfig::kY_UV,  Subsampling::k422},
67*c8dee2aaSAndroid Build Coastguard Worker                                TestCase{PlaneConfig::kYUV,   Subsampling::k444}}) {
68*c8dee2aaSAndroid Build Coastguard Worker             SkYUVAInfo yuvaInfo(fSrcImage->dimensions(),
69*c8dee2aaSAndroid Build Coastguard Worker                                 tc.config,
70*c8dee2aaSAndroid Build Coastguard Worker                                 tc.subsampling,
71*c8dee2aaSAndroid Build Coastguard Worker                                 kJPEG_Full_SkYUVColorSpace);
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker             float rgbToYuv[20];
74*c8dee2aaSAndroid Build Coastguard Worker             SkColorMatrix::RGBtoYUV(yuvaInfo.yuvColorSpace()).getRowMajor(rgbToYuv);
75*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkImage> planes[SkYUVAInfo::kMaxPlanes];
76*c8dee2aaSAndroid Build Coastguard Worker             SkISize dimensions[SkYUVAInfo::kMaxPlanes];
77*c8dee2aaSAndroid Build Coastguard Worker             int numPlanes = yuvaInfo.planeDimensions(dimensions);
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker             SkColorType colorTypes  [SkYUVAInfo::kMaxPlanes];
80*c8dee2aaSAndroid Build Coastguard Worker             uint32_t    channelFlags[SkYUVAInfo::kMaxPlanes];
81*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < numPlanes; ++i) {
82*c8dee2aaSAndroid Build Coastguard Worker                 switch (yuvaInfo.numChannelsInPlane(i)) {
83*c8dee2aaSAndroid Build Coastguard Worker                     case 1: colorTypes[i] = kAlpha_8_SkColorType;    break;
84*c8dee2aaSAndroid Build Coastguard Worker                     case 2: colorTypes[i] = kR8G8_unorm_SkColorType; break;
85*c8dee2aaSAndroid Build Coastguard Worker                     case 3: colorTypes[i] = kRGB_888x_SkColorType;   break;
86*c8dee2aaSAndroid Build Coastguard Worker                     case 4: colorTypes[i] = kRGBA_8888_SkColorType;  break;
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker                     default: SkUNREACHABLE;
89*c8dee2aaSAndroid Build Coastguard Worker                 }
90*c8dee2aaSAndroid Build Coastguard Worker                 channelFlags[i] = SkColorTypeChannelFlags(colorTypes[i]);
91*c8dee2aaSAndroid Build Coastguard Worker             }
92*c8dee2aaSAndroid Build Coastguard Worker             SkYUVAInfo::YUVALocations locations = yuvaInfo.toYUVALocations(channelFlags);
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < numPlanes; ++i) {
95*c8dee2aaSAndroid Build Coastguard Worker                 auto info = SkImageInfo::Make(dimensions[i], colorTypes[i], kPremul_SkAlphaType);
96*c8dee2aaSAndroid Build Coastguard Worker                 auto surf = SkSurfaces::RenderTarget(recorder, info, skgpu::Mipmapped::kYes);
97*c8dee2aaSAndroid Build Coastguard Worker                 if (!surf) {
98*c8dee2aaSAndroid Build Coastguard Worker                     continue;
99*c8dee2aaSAndroid Build Coastguard Worker                 }
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker                 float matrix[20] {
102*c8dee2aaSAndroid Build Coastguard Worker                     1, 0, 0, 0, 0,
103*c8dee2aaSAndroid Build Coastguard Worker                     0, 1, 0, 0, 0,
104*c8dee2aaSAndroid Build Coastguard Worker                     0, 0, 1, 0, 0,
105*c8dee2aaSAndroid Build Coastguard Worker                     0, 0, 0, 1, 0
106*c8dee2aaSAndroid Build Coastguard Worker                 };
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker                 for (int c = 0; c < SkYUVAInfo::kYUVAChannelCount; ++c) {
109*c8dee2aaSAndroid Build Coastguard Worker                     if (locations[c].fPlane == i) {
110*c8dee2aaSAndroid Build Coastguard Worker                         auto d = static_cast<int>(locations[c].fChannel);
111*c8dee2aaSAndroid Build Coastguard Worker                         std::copy_n(rgbToYuv + 5 * c, 5, matrix + 5 * d);
112*c8dee2aaSAndroid Build Coastguard Worker                     }
113*c8dee2aaSAndroid Build Coastguard Worker                 }
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker                 auto cf = SkColorFilters::Matrix(matrix);
116*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint paint;
117*c8dee2aaSAndroid Build Coastguard Worker                 paint.setColorFilter(SkColorFilters::Matrix(matrix));
118*c8dee2aaSAndroid Build Coastguard Worker                 surf->getCanvas()->drawImageRect(fSrcImage,
119*c8dee2aaSAndroid Build Coastguard Worker                                                  SkRect::Make(surf->imageInfo().dimensions()),
120*c8dee2aaSAndroid Build Coastguard Worker                                                  SkFilterMode::kLinear,
121*c8dee2aaSAndroid Build Coastguard Worker                                                  &paint);
122*c8dee2aaSAndroid Build Coastguard Worker                 planes[i] = SkSurfaces::AsImage(std::move(surf));
123*c8dee2aaSAndroid Build Coastguard Worker             }
124*c8dee2aaSAndroid Build Coastguard Worker             auto yuvaImage = SkImages::TextureFromYUVAImages(recorder,
125*c8dee2aaSAndroid Build Coastguard Worker                                                              yuvaInfo,
126*c8dee2aaSAndroid Build Coastguard Worker                                                              planes,
127*c8dee2aaSAndroid Build Coastguard Worker                                                              /*imageColorSpace=*/nullptr);
128*c8dee2aaSAndroid Build Coastguard Worker             if (yuvaImage) {
129*c8dee2aaSAndroid Build Coastguard Worker                 auto dstRect = SkRect::MakeWH(yuvaImage->width() / 16.f,
130*c8dee2aaSAndroid Build Coastguard Worker                                               yuvaImage->height() / 16.f);
131*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawImageRect(yuvaImage.get(),
132*c8dee2aaSAndroid Build Coastguard Worker                                       dstRect,
133*c8dee2aaSAndroid Build Coastguard Worker                                       SkSamplingOptions(SkFilterMode::kLinear,
134*c8dee2aaSAndroid Build Coastguard Worker                                                         SkMipmapMode::kLinear));
135*c8dee2aaSAndroid Build Coastguard Worker             }
136*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(std::ceil(yuvaInfo.width()/16.f), 0);
137*c8dee2aaSAndroid Build Coastguard Worker         }
138*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
139*c8dee2aaSAndroid Build Coastguard Worker     }
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker private:
142*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> fSrcImage;
143*c8dee2aaSAndroid Build Coastguard Worker };
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new RenderToMipmappedYUVImagePlanes();)
146*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
147*c8dee2aaSAndroid Build Coastguard Worker #endif
148