xref: /aosp_15_r20/external/skia/gm/constcolorprocessor.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 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/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkFont.h"
14 #include "include/core/SkFontTypes.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSize.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTileMode.h"
25 #include "include/core/SkTypeface.h"
26 #include "include/core/SkTypes.h"
27 #include "include/effects/SkGradientShader.h"
28 #include "include/private/SkColorData.h"
29 #include "include/private/gpu/ganesh/GrTypesPriv.h"
30 #include "src/core/SkCanvasPriv.h"
31 #include "src/gpu/ganesh/GrCanvas.h"
32 #include "src/gpu/ganesh/GrColor.h"
33 #include "src/gpu/ganesh/GrFPArgs.h"
34 #include "src/gpu/ganesh/GrFragmentProcessor.h"
35 #include "src/gpu/ganesh/GrFragmentProcessors.h"
36 #include "src/gpu/ganesh/GrPaint.h"
37 #include "src/gpu/ganesh/SkGr.h"
38 #include "src/gpu/ganesh/SurfaceDrawContext.h"
39 #include "src/gpu/ganesh/ops/GrOp.h"
40 #include "tools/ToolUtils.h"
41 #include "tools/fonts/FontToolUtils.h"
42 #include "tools/gpu/TestOps.h"
43 
44 #include <utility>
45 
46 namespace skiagm {
47 /**
48  * This GM directly exercises Color and ModulateRGBA.
49  */
50 class ColorProcessor : public GpuGM {
51 public:
52     enum class TestMode {
53         kConstColor,
54         kModulateRGBA
55     };
56 
ColorProcessor(TestMode mode)57     ColorProcessor(TestMode mode) : fMode(mode) {
58         this->setBGColor(0xFFDDDDDD);
59     }
60 
61 protected:
getName() const62     SkString getName() const override {
63         switch (fMode) {
64             case TestMode::kConstColor:    return SkString("const_color_processor");
65             case TestMode::kModulateRGBA:  return SkString("modulate_rgba");
66         }
67         SkUNREACHABLE;
68     }
69 
getISize()70     SkISize getISize() override { return SkISize::Make(kWidth, kHeight); }
71 
onOnceBeforeDraw()72     void onOnceBeforeDraw() override {
73         SkColor colors[] = { 0xFFFF0000, 0x2000FF00, 0xFF0000FF};
74         SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(kRectSize, kRectSize) };
75         fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, std::size(colors),
76                                                SkTileMode::kClamp);
77     }
78 
onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)79     DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
80         auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas);
81         if (!sdc) {
82             *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
83             return DrawResult::kSkip;
84         }
85 
86         constexpr GrColor kColors[] = {
87             0xFFFFFFFF,
88             0xFFFF00FF,
89             0x80000000,
90             0x00000000,
91         };
92 
93         constexpr GrColor kPaintColors[] = {
94             0xFFFFFFFF,
95             0xFF0000FF,
96             0x80000080,
97             0x00000000,
98         };
99 
100         SkScalar y = kPad;
101         SkScalar x = kPad;
102         SkScalar maxW = 0;
103         for (size_t paintType = 0; paintType < std::size(kPaintColors) + 1; ++paintType) {
104             for (size_t procColor = 0; procColor < std::size(kColors); ++procColor) {
105                 // translate by x,y for the canvas draws and the test target draws.
106                 canvas->save();
107                 canvas->translate(x, y);
108 
109                 // rect to draw
110                 SkRect renderRect = SkRect::MakeXYWH(0, 0, kRectSize, kRectSize);
111 
112                 // Create a base-layer FP for the const color processor to draw on top of.
113                 std::unique_ptr<GrFragmentProcessor> baseFP;
114                 if (paintType >= std::size(kPaintColors)) {
115                     GrColorInfo colorInfo;
116                     SkSurfaceProps props;
117                     GrFPArgs args(rContext, &colorInfo, props, GrFPArgs::Scope::kDefault);
118                     baseFP = GrFragmentProcessors::Make(fShader.get(), args, SkMatrix::I());
119                 } else {
120                     baseFP = GrFragmentProcessor::MakeColor(
121                             SkPMColor4f::FromBytes_RGBA(kPaintColors[paintType]));
122                 }
123 
124                 // Layer a color/modulation FP on top of the base layer, using various colors.
125                 std::unique_ptr<GrFragmentProcessor> colorFP;
126                 switch (fMode) {
127                     case TestMode::kConstColor:
128                         colorFP = GrFragmentProcessor::MakeColor(
129                                 SkPMColor4f::FromBytes_RGBA(kColors[procColor]));
130                         break;
131 
132                     case TestMode::kModulateRGBA:
133                         colorFP = GrFragmentProcessor::ModulateRGBA(
134                                 std::move(baseFP), SkPMColor4f::FromBytes_RGBA(kColors[procColor]));
135                         break;
136                 }
137 
138                 // Render the FP tree.
139                 if (auto op = sk_gpu_test::test_ops::MakeRect(rContext,
140                                                               std::move(colorFP),
141                                                               renderRect.makeOffset(x, y),
142                                                               renderRect,
143                                                               SkMatrix::I())) {
144                     sdc->addDrawOp(std::move(op));
145                 }
146 
147                 // Draw labels for the input to the processor and the processor to the right of
148                 // the test rect. The input label appears above the processor label.
149                 SkFont labelFont;
150                 labelFont.setTypeface(ToolUtils::DefaultPortableTypeface());
151                 labelFont.setEdging(SkFont::Edging::kAntiAlias);
152                 labelFont.setSize(10.f);
153                 SkPaint labelPaint;
154                 labelPaint.setAntiAlias(true);
155                 SkString inputLabel("Input: ");
156                 if (paintType >= std::size(kPaintColors)) {
157                     inputLabel.append("gradient");
158                 } else {
159                     inputLabel.appendf("0x%08x", kPaintColors[paintType]);
160                 }
161                 SkString procLabel;
162                 procLabel.printf("Proc: [0x%08x]", kColors[procColor]);
163 
164                 SkRect inputLabelBounds;
165                 // get the bounds of the text in order to position it
166                 labelFont.measureText(inputLabel.c_str(), inputLabel.size(),
167                                       SkTextEncoding::kUTF8, &inputLabelBounds);
168                 canvas->drawString(inputLabel, renderRect.fRight + kPad, -inputLabelBounds.fTop,
169                                    labelFont, labelPaint);
170                 // update the bounds to reflect the offset we used to draw it.
171                 inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop);
172 
173                 SkRect procLabelBounds;
174                 labelFont.measureText(procLabel.c_str(), procLabel.size(),
175                                       SkTextEncoding::kUTF8, &procLabelBounds);
176                 canvas->drawString(procLabel, renderRect.fRight + kPad,
177                                    inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop,
178                                    labelFont, labelPaint);
179                 procLabelBounds.offset(renderRect.fRight + kPad,
180                                        inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop);
181 
182                 labelPaint.setStrokeWidth(0);
183                 labelPaint.setStyle(SkPaint::kStroke_Style);
184                 canvas->drawRect(renderRect, labelPaint);
185 
186                 canvas->restore();
187 
188                 // update x and y for the next test case.
189                 SkScalar height = renderRect.height();
190                 SkScalar width = std::max(inputLabelBounds.fRight, procLabelBounds.fRight);
191                 maxW = std::max(maxW, width);
192                 y += height + kPad;
193                 if (y + height > kHeight) {
194                     y = kPad;
195                     x += maxW + kPad;
196                     maxW = 0;
197                 }
198             }
199         }
200 
201         return DrawResult::kOk;
202     }
203 
204 private:
205     // Use this as a way of generating an input FP
206     sk_sp<SkShader> fShader;
207     TestMode        fMode;
208 
209     inline static constexpr SkScalar       kPad = 10.f;
210     inline static constexpr SkScalar       kRectSize = 20.f;
211     inline static constexpr int            kWidth  = 820;
212     inline static constexpr int            kHeight = 500;
213 
214     using INHERITED = GM;
215 };
216 
217 DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kConstColor};)
218 DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kModulateRGBA};)
219 
220 }  // namespace skiagm
221