• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gpu/GrConfig.h"
29 #include "include/private/GrTypesPriv.h"
30 #include "include/private/SkColorData.h"
31 #include "src/core/SkCanvasPriv.h"
32 #include "src/core/SkMatrixProvider.h"
33 #include "src/gpu/GrColor.h"
34 #include "src/gpu/GrFragmentProcessor.h"
35 #include "src/gpu/GrPaint.h"
36 #include "src/gpu/SkGr.h"
37 #include "src/gpu/ops/GrOp.h"
38 #include "src/gpu/v1/SurfaceDrawContext_v1.h"
39 #include "tools/ToolUtils.h"
40 #include "tools/gpu/TestOps.h"
41 
42 #include <utility>
43 
44 namespace skiagm {
45 /**
46  * This GM directly exercises Color and ModulateRGBA.
47  */
48 class ColorProcessor : public GpuGM {
49 public:
50     enum class TestMode {
51         kConstColor,
52         kModulateRGBA
53     };
54 
ColorProcessor(TestMode mode)55     ColorProcessor(TestMode mode) : fMode(mode) {
56         this->setBGColor(0xFFDDDDDD);
57     }
58 
59 protected:
onShortName()60     SkString onShortName() override {
61         switch (fMode) {
62             case TestMode::kConstColor:    return SkString("const_color_processor");
63             case TestMode::kModulateRGBA:  return SkString("modulate_rgba");
64         }
65         SkUNREACHABLE;
66     }
67 
onISize()68     SkISize onISize() override {
69         return SkISize::Make(kWidth, kHeight);
70     }
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, SK_ARRAY_COUNT(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 = SkCanvasPriv::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 < SK_ARRAY_COUNT(kPaintColors) + 1; ++paintType) {
104             for (size_t procColor = 0; procColor < SK_ARRAY_COUNT(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 >= SK_ARRAY_COUNT(kPaintColors)) {
115                     GrColorInfo colorInfo;
116                     GrFPArgs args(rContext, SkSimpleMatrixProvider(SkMatrix::I()), &colorInfo);
117                     baseFP = as_SB(fShader)->asFragmentProcessor(args);
118                 } else {
119                     baseFP = GrFragmentProcessor::MakeColor(
120                             SkPMColor4f::FromBytes_RGBA(kPaintColors[paintType]));
121                 }
122 
123                 // Layer a color/modulation FP on top of the base layer, using various colors.
124                 std::unique_ptr<GrFragmentProcessor> colorFP;
125                 switch (fMode) {
126                     case TestMode::kConstColor:
127                         colorFP = GrFragmentProcessor::MakeColor(
128                                 SkPMColor4f::FromBytes_RGBA(kColors[procColor]));
129                         break;
130 
131                     case TestMode::kModulateRGBA:
132                         colorFP = GrFragmentProcessor::ModulateRGBA(
133                                 std::move(baseFP), SkPMColor4f::FromBytes_RGBA(kColors[procColor]));
134                         break;
135                 }
136 
137                 // Render the FP tree.
138                 if (auto op = sk_gpu_test::test_ops::MakeRect(rContext,
139                                                               std::move(colorFP),
140                                                               renderRect.makeOffset(x, y),
141                                                               renderRect,
142                                                               SkMatrix::I())) {
143                     sdc->addDrawOp(std::move(op));
144                 }
145 
146                 // Draw labels for the input to the processor and the processor to the right of
147                 // the test rect. The input label appears above the processor label.
148                 SkFont labelFont;
149                 labelFont.setTypeface(ToolUtils::create_portable_typeface());
150                 labelFont.setEdging(SkFont::Edging::kAntiAlias);
151                 labelFont.setSize(10.f);
152                 SkPaint labelPaint;
153                 labelPaint.setAntiAlias(true);
154                 SkString inputLabel("Input: ");
155                 if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
156                     inputLabel.append("gradient");
157                 } else {
158                     inputLabel.appendf("0x%08x", kPaintColors[paintType]);
159                 }
160                 SkString procLabel;
161                 procLabel.printf("Proc: [0x%08x]", kColors[procColor]);
162 
163                 SkRect inputLabelBounds;
164                 // get the bounds of the text in order to position it
165                 labelFont.measureText(inputLabel.c_str(), inputLabel.size(),
166                                       SkTextEncoding::kUTF8, &inputLabelBounds);
167                 canvas->drawString(inputLabel, renderRect.fRight + kPad, -inputLabelBounds.fTop,
168                                    labelFont, labelPaint);
169                 // update the bounds to reflect the offset we used to draw it.
170                 inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop);
171 
172                 SkRect procLabelBounds;
173                 labelFont.measureText(procLabel.c_str(), procLabel.size(),
174                                       SkTextEncoding::kUTF8, &procLabelBounds);
175                 canvas->drawString(procLabel, renderRect.fRight + kPad,
176                                    inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop,
177                                    labelFont, labelPaint);
178                 procLabelBounds.offset(renderRect.fRight + kPad,
179                                        inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop);
180 
181                 labelPaint.setStrokeWidth(0);
182                 labelPaint.setStyle(SkPaint::kStroke_Style);
183                 canvas->drawRect(renderRect, labelPaint);
184 
185                 canvas->restore();
186 
187                 // update x and y for the next test case.
188                 SkScalar height = renderRect.height();
189                 SkScalar width = std::max(inputLabelBounds.fRight, procLabelBounds.fRight);
190                 maxW = std::max(maxW, width);
191                 y += height + kPad;
192                 if (y + height > kHeight) {
193                     y = kPad;
194                     x += maxW + kPad;
195                     maxW = 0;
196                 }
197             }
198         }
199 
200         return DrawResult::kOk;
201     }
202 
203 private:
204     // Use this as a way of generating an input FP
205     sk_sp<SkShader> fShader;
206     TestMode        fMode;
207 
208     inline static constexpr SkScalar       kPad = 10.f;
209     inline static constexpr SkScalar       kRectSize = 20.f;
210     inline static constexpr int            kWidth  = 820;
211     inline static constexpr int            kHeight = 500;
212 
213     using INHERITED = GM;
214 };
215 
216 DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kConstColor};)
217 DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kModulateRGBA};)
218 
219 }  // namespace skiagm
220