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