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