blob: 713dcfecb512c8b855f7d9b49687d09fcb6ac34c [file] [log] [blame]
Brian Salomon8f46ecc2020-11-17 13:28:45 -05001/*
2 * Copyright 2014 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// This test only works with the GPU backend.
9
10#include "gm/gm.h"
11#include "include/core/SkBitmap.h"
12#include "include/core/SkColor.h"
13#include "include/core/SkImageInfo.h"
14#include "include/core/SkMatrix.h"
15#include "include/core/SkRect.h"
16#include "include/core/SkScalar.h"
17#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
Brian Salomon0857bef2021-01-13 15:54:04 -050019#include "include/core/SkYUVAInfo.h"
20#include "include/core/SkYUVAPixmaps.h"
Robert Phillips7a0d3c32021-07-21 15:39:51 -040021#include "src/core/SkCanvasPriv.h"
Kevin Lubickacdc1082023-06-09 11:05:24 -040022#include "src/gpu/ganesh/GrCanvas.h"
Jim Van Verth7a978312022-12-01 14:46:28 -050023#include "src/gpu/ganesh/GrRecordingContextPriv.h"
Greg Daniel719239c2022-04-07 11:20:24 -040024#include "src/gpu/ganesh/GrSamplerState.h"
25#include "src/gpu/ganesh/GrTextureProxy.h"
26#include "src/gpu/ganesh/GrYUVATextureProxies.h"
27#include "src/gpu/ganesh/SkGr.h"
Robert Phillipsc1b94082022-08-09 17:16:19 -040028#include "src/gpu/ganesh/SurfaceDrawContext.h"
Greg Daniel719239c2022-04-07 11:20:24 -040029#include "src/gpu/ganesh/effects/GrYUVtoRGBEffect.h"
Brian Salomon8f46ecc2020-11-17 13:28:45 -050030
31#include <memory>
32#include <utility>
33
34class SkCanvas;
35
Brian Salomon8f46ecc2020-11-17 13:28:45 -050036namespace skiagm {
37
38//////////////////////////////////////////////////////////////////////////////
39
40// This GM tests subsetting YUV multiplanar images where the U and V
41// planes have different resolution from Y. See skbug:8959
42
43class YUVtoRGBSubsetEffect : public GpuGM {
44public:
45 YUVtoRGBSubsetEffect() {
46 this->setBGColor(0xFFFFFFFF);
47 }
48
49protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +000050 SkString getName() const override { return SkString("yuv_to_rgb_subset_effect"); }
Brian Salomon8f46ecc2020-11-17 13:28:45 -050051
Leandro Lovisolo8f023882023-08-15 21:13:52 +000052 SkISize getISize() override { return {1310, 540}; }
Brian Salomon8f46ecc2020-11-17 13:28:45 -050053
Brian Salomon0857bef2021-01-13 15:54:04 -050054 void makePixmaps() {
55 SkYUVAInfo yuvaInfo = SkYUVAInfo({8, 8},
56 SkYUVAInfo::PlaneConfig::kY_U_V,
57 SkYUVAInfo::Subsampling::k420,
58 kJPEG_Full_SkYUVColorSpace);
59 SkColorType colorTypes[] = {kAlpha_8_SkColorType,
60 kAlpha_8_SkColorType,
61 kAlpha_8_SkColorType};
62 SkYUVAPixmapInfo pmapInfo(yuvaInfo, colorTypes, nullptr);
63 fPixmaps = SkYUVAPixmaps::Allocate(pmapInfo);
Brian Salomon8f46ecc2020-11-17 13:28:45 -050064
65 unsigned char innerY[16] = {149, 160, 130, 105,
66 160, 130, 105, 149,
67 130, 105, 149, 160,
68 105, 149, 160, 130};
69 unsigned char innerU[4] = {43, 75, 145, 200};
70 unsigned char innerV[4] = {88, 180, 200, 43};
71 int outerYUV[] = {128, 128, 128};
Brian Salomon0857bef2021-01-13 15:54:04 -050072 SkBitmap bitmaps[3];
Brian Salomon8f46ecc2020-11-17 13:28:45 -050073 for (int i = 0; i < 3; ++i) {
Brian Salomon0857bef2021-01-13 15:54:04 -050074 bitmaps[i].installPixels(fPixmaps.plane(i));
75 bitmaps[i].eraseColor(SkColorSetARGB(outerYUV[i], 0, 0, 0));
Brian Salomon8f46ecc2020-11-17 13:28:45 -050076 }
77 SkPixmap innerYPM(SkImageInfo::MakeA8(4, 4), innerY, 4);
78 SkPixmap innerUPM(SkImageInfo::MakeA8(2, 2), innerU, 2);
79 SkPixmap innerVPM(SkImageInfo::MakeA8(2, 2), innerV, 2);
Brian Salomon0857bef2021-01-13 15:54:04 -050080 bitmaps[0].writePixels(innerYPM, 2, 2);
81 bitmaps[1].writePixels(innerUPM, 1, 1);
82 bitmaps[2].writePixels(innerVPM, 1, 1);
Brian Salomon8f46ecc2020-11-17 13:28:45 -050083 }
84
Brian Salomonc759bbf2023-12-05 11:11:27 -050085 DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override {
Jim Van Vertha8624432023-02-13 16:48:09 -050086 auto context = GrAsDirectContext(canvas->recordingContext());
Brian Salomon0857bef2021-01-13 15:54:04 -050087 if (!context) {
88 return DrawResult::kSkip;
89 }
90 if (!fPixmaps.isValid()) {
91 this->makePixmaps();
92 }
93 GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
94 GrColorType colorTypes[SkYUVAInfo::kMaxPlanes];
95 for (int i = 0; i < fPixmaps.numPlanes(); ++i) {
96 SkBitmap bitmap;
97 bitmap.installPixels(fPixmaps.plane(i));
98 bitmap.setImmutable();
Kevin Lubickdf73d162023-09-11 11:56:53 -040099 views[i] = std::get<0>(GrMakeCachedBitmapProxyView(
100 context, bitmap, /*label=*/"DrawResult_GpuSetup", skgpu::Mipmapped::kNo));
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500101 if (!views[i]) {
102 *errorMsg = "Failed to create proxy";
Brian Salomon0857bef2021-01-13 15:54:04 -0500103 return context->abandoned() ? DrawResult::kSkip : DrawResult::kFail;
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500104 }
Brian Salomon0857bef2021-01-13 15:54:04 -0500105 colorTypes[i] = SkColorTypeToGrColorType(bitmap.colorType());
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500106 }
Brian Salomon0857bef2021-01-13 15:54:04 -0500107 fProxies = GrYUVATextureProxies(fPixmaps.yuvaInfo(), views, colorTypes);
108 if (!fProxies.isValid()) {
109 *errorMsg = "Failed to create GrYUVATextureProxies";
110 return DrawResult::kFail;
111 }
112 return DrawResult::kOk;
113 }
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500114
Brian Salomon0857bef2021-01-13 15:54:04 -0500115 void onGpuTeardown() override { fProxies = {}; }
116
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400117 DrawResult onDraw(GrRecordingContext* rContext,
Brian Salomon0857bef2021-01-13 15:54:04 -0500118 SkCanvas* canvas,
119 SkString* errorMsg) override {
Kevin Lubickacdc1082023-06-09 11:05:24 -0400120 auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400121 if (!sdc) {
122 *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
123 return DrawResult::kSkip;
124 }
125
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500126 static const GrSamplerState::Filter kFilters[] = {GrSamplerState::Filter::kNearest,
127 GrSamplerState::Filter::kLinear};
128 static const SkRect kColorRect = SkRect::MakeLTRB(2.f, 2.f, 6.f, 6.f);
129
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500130 // Outset to visualize wrap modes.
Brian Salomon0857bef2021-01-13 15:54:04 -0500131 SkRect rect = SkRect::Make(fProxies.yuvaInfo().dimensions());
132 rect = rect.makeOutset(fProxies.yuvaInfo().width()/2.f, fProxies.yuvaInfo().height()/2.f);
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500133
134 SkScalar y = kTestPad;
135 // Rows are filter modes.
Herb Derbyc37b3862022-06-21 09:49:17 -0400136 for (uint32_t i = 0; i < std::size(kFilters); ++i) {
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500137 SkScalar x = kTestPad;
138 // Columns are non-subsetted followed by subsetted with each WrapMode in a row
139 for (uint32_t j = 0; j < GrSamplerState::kWrapModeCount + 1; ++j) {
140 SkMatrix ctm = SkMatrix::Translate(x, y);
141 ctm.postScale(10.f, 10.f);
142
143 const SkRect* subset = j > 0 ? &kColorRect : nullptr;
144
Brian Salomonb4baeba2022-03-07 08:12:59 -0500145 auto wm = GrSamplerState::WrapMode::kClamp;
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500146 if (j > 0) {
Brian Salomonb4baeba2022-03-07 08:12:59 -0500147 wm = static_cast<GrSamplerState::WrapMode>(j - 1);
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500148 }
Brian Salomonb4baeba2022-03-07 08:12:59 -0500149 GrSamplerState samplerState(wm, kFilters[i]);
150
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400151 const auto& caps = *rContext->priv().caps();
Brian Salomon0857bef2021-01-13 15:54:04 -0500152 std::unique_ptr<GrFragmentProcessor> fp =
153 GrYUVtoRGBEffect::Make(fProxies, samplerState, caps, SkMatrix::I(), subset);
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500154 if (fp) {
155 GrPaint grPaint;
156 grPaint.setColorFragmentProcessor(std::move(fp));
Robert Phillips7a0d3c32021-07-21 15:39:51 -0400157 sdc->drawRect(nullptr, std::move(grPaint), GrAA::kYes, ctm, rect);
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500158 }
159 x += rect.width() + kTestPad;
160 }
161
162 y += rect.height() + kTestPad;
163 }
164
165 return DrawResult::kOk;
Brian Salomon0857bef2021-01-13 15:54:04 -0500166 }
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500167
168private:
Brian Salomon0857bef2021-01-13 15:54:04 -0500169 SkYUVAPixmaps fPixmaps;
170 GrYUVATextureProxies fProxies;
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500171
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400172 inline static constexpr SkScalar kTestPad = 10.f;
Brian Salomon8f46ecc2020-11-17 13:28:45 -0500173
174 using INHERITED = GM;
175};
176
177DEF_GM(return new YUVtoRGBSubsetEffect;)
178} // namespace skiagm