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.h"
11 #include "sk_tool_utils.h"
12 
13 #include "GrContext.h"
14 #include "GrRenderTargetContextPriv.h"
15 #include "SkGr.h"
16 #include "SkGradientShader.h"
17 #include "effects/GrConstColorProcessor.h"
18 #include "ops/GrDrawOp.h"
19 #include "ops/GrFillRectOp.h"
20 
21 namespace skiagm {
22 /**
23  * This GM directly exercises GrConstColorProcessor.
24  */
25 class ConstColorProcessor : public GM {
26 public:
ConstColorProcessor()27     ConstColorProcessor() {
28         this->setBGColor(0xFFDDDDDD);
29     }
30 
31 protected:
onShortName()32     SkString onShortName() override {
33         return SkString("const_color_processor");
34     }
35 
onISize()36     SkISize onISize() override {
37         return SkISize::Make(kWidth, kHeight);
38     }
39 
onOnceBeforeDraw()40     void onOnceBeforeDraw() override {
41         SkColor colors[] = { 0xFFFF0000, 0x2000FF00, 0xFF0000FF};
42         SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(kRectSize, kRectSize) };
43         fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
44                                                SkShader::kClamp_TileMode);
45     }
46 
onDraw(SkCanvas * canvas)47     void onDraw(SkCanvas* canvas) override {
48         GrRenderTargetContext* renderTargetContext =
49             canvas->internal_private_accessTopLayerRenderTargetContext();
50         if (!renderTargetContext) {
51             skiagm::GM::DrawGpuOnlyMessage(canvas);
52             return;
53         }
54 
55         GrContext* context = canvas->getGrContext();
56         if (!context) {
57             return;
58         }
59 
60         constexpr GrColor kColors[] = {
61             0xFFFFFFFF,
62             0xFFFF00FF,
63             0x80000000,
64             0x00000000,
65         };
66 
67         constexpr SkColor kPaintColors[] = {
68             0xFFFFFFFF,
69             0xFFFF0000,
70             0x80FF0000,
71             0x00000000,
72         };
73 
74         const char* kModeStrs[] {
75             "kIgnore",
76             "kModulateRGBA",
77             "kModulateA",
78         };
79         GR_STATIC_ASSERT(SK_ARRAY_COUNT(kModeStrs) == GrConstColorProcessor::kInputModeCnt);
80 
81         SkScalar y = kPad;
82         SkScalar x = kPad;
83         SkScalar maxW = 0;
84         for (size_t paintType = 0; paintType < SK_ARRAY_COUNT(kPaintColors) + 1; ++paintType) {
85             for (size_t procColor = 0; procColor < SK_ARRAY_COUNT(kColors); ++procColor) {
86                 for (int m = 0; m < GrConstColorProcessor::kInputModeCnt; ++m) {
87                     // translate by x,y for the canvas draws and the test target draws.
88                     canvas->save();
89                     canvas->translate(x, y);
90                     const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y);
91 
92                     // rect to draw
93                     SkRect renderRect = SkRect::MakeXYWH(0, 0, kRectSize, kRectSize);
94 
95                     GrPaint grPaint;
96                     SkPaint skPaint;
97                     if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
98                         skPaint.setShader(fShader);
99                     } else {
100                         skPaint.setColor(kPaintColors[paintType]);
101                     }
102                     SkAssertResult(SkPaintToGrPaint(context, renderTargetContext->colorSpaceInfo(),
103                                                     skPaint, viewMatrix, &grPaint));
104 
105                     GrConstColorProcessor::InputMode mode = (GrConstColorProcessor::InputMode) m;
106                     SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(kColors[procColor]);
107                     auto fp = GrConstColorProcessor::Make(color, mode);
108 
109                     grPaint.addColorFragmentProcessor(std::move(fp));
110                     renderTargetContext->priv().testingOnly_addDrawOp(
111                             GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
112                                                viewMatrix, renderRect));
113 
114                     // Draw labels for the input to the processor and the processor to the right of
115                     // the test rect. The input label appears above the processor label.
116                     SkFont labelFont;
117                     labelFont.setTypeface(sk_tool_utils::create_portable_typeface());
118                     labelFont.setEdging(SkFont::Edging::kAntiAlias);
119                     labelFont.setSize(10.f);
120                     SkPaint labelPaint;
121                     labelPaint.setAntiAlias(true);
122                     SkString inputLabel;
123                     inputLabel.set("Input: ");
124                     if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
125                         inputLabel.append("gradient");
126                     } else {
127                         inputLabel.appendf("0x%08x", kPaintColors[paintType]);
128                     }
129                     SkString procLabel;
130                     procLabel.printf("Proc: [0x%08x, %s]", kColors[procColor], kModeStrs[m]);
131 
132                     SkRect inputLabelBounds;
133                     // get the bounds of the text in order to position it
134                     labelFont.measureText(inputLabel.c_str(), inputLabel.size(),
135                                           kUTF8_SkTextEncoding, &inputLabelBounds);
136                     canvas->drawString(inputLabel, renderRect.fRight + kPad, -inputLabelBounds.fTop,
137                                        labelFont, labelPaint);
138                     // update the bounds to reflect the offset we used to draw it.
139                     inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop);
140 
141                     SkRect procLabelBounds;
142                     labelFont.measureText(procLabel.c_str(), procLabel.size(),
143                                           kUTF8_SkTextEncoding, &procLabelBounds);
144                     canvas->drawString(procLabel, renderRect.fRight + kPad,
145                                        inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop,
146                                        labelFont, labelPaint);
147                     procLabelBounds.offset(renderRect.fRight + kPad,
148                                            inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop);
149 
150                     labelPaint.setStrokeWidth(0);
151                     labelPaint.setStyle(SkPaint::kStroke_Style);
152                     canvas->drawRect(renderRect, labelPaint);
153 
154                     canvas->restore();
155 
156                     // update x and y for the next test case.
157                     SkScalar height = renderRect.height();
158                     SkScalar width = SkTMax(inputLabelBounds.fRight, procLabelBounds.fRight);
159                     maxW = SkTMax(maxW, width);
160                     y += height + kPad;
161                     if (y + height > kHeight) {
162                         y = kPad;
163                         x += maxW + kPad;
164                         maxW = 0;
165                     }
166                 }
167             }
168         }
169     }
170 
171 private:
172     // Use this as a way of generating and input FP
173     sk_sp<SkShader> fShader;
174 
175     static constexpr SkScalar       kPad = 10.f;
176     static constexpr SkScalar       kRectSize = 20.f;
177     static constexpr int            kWidth  = 820;
178     static constexpr int            kHeight = 500;
179 
180     typedef GM INHERITED;
181 };
182 
183 DEF_GM(return new ConstColorProcessor;)
184 }
185