1
2/*
3 * Copyright 2015 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9// This test only works with the GPU backend.
10
11#include "gm.h"
12
13#if SK_SUPPORT_GPU
14
15#include "GrContext.h"
16#include "GrTest.h"
17#include "effects/GrConstColorProcessor.h"
18#include "SkGr.h"
19#include "SkGradientShader.h"
20
21namespace skiagm {
22/**
23 * This GM directly exercises GrConstColorProcessor.
24 */
25class ConstColorProcessor : public GM {
26public:
27    ConstColorProcessor() {
28        this->setBGColor(0xFFDDDDDD);
29    }
30
31protected:
32    SkString onShortName() override {
33        return SkString("const_color_processor");
34    }
35
36    SkISize onISize() override {
37        return SkISize::Make(kWidth, kHeight);
38    }
39
40    void onOnceBeforeDraw() override {
41        SkColor colors[] = { 0xFFFF0000, 0x2000FF00, 0xFF0000FF};
42        SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(kRectSize, kRectSize) };
43        fShader.reset(SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
44                       SkShader::kClamp_TileMode));
45    }
46
47    void onDraw(SkCanvas* canvas) override {
48        GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
49        if (NULL == rt) {
50            return;
51        }
52        GrContext* context = rt->getContext();
53        if (NULL == context) {
54            this->drawGpuOnlyMessage(canvas);
55            return;
56        }
57
58        static const GrColor kColors[] = {
59            0xFFFFFFFF,
60            0xFFFF00FF,
61            0x80000000,
62            0x00000000,
63        };
64
65        static const SkColor kPaintColors[] = {
66            0xFFFFFFFF,
67            0xFFFF0000,
68            0x80FF0000,
69            0x00000000,
70        };
71
72        static const char* kModeStrs[] {
73            "kIgnore",
74            "kModulateRGBA",
75            "kModulateA",
76        };
77        GR_STATIC_ASSERT(SK_ARRAY_COUNT(kModeStrs) == GrConstColorProcessor::kInputModeCnt);
78
79        SkScalar y = kPad;
80        SkScalar x = kPad;
81        SkScalar maxW = 0;
82        for (size_t paintType = 0; paintType < SK_ARRAY_COUNT(kPaintColors) + 1; ++paintType) {
83            for (size_t procColor = 0; procColor < SK_ARRAY_COUNT(kColors); ++procColor) {
84                for (int m = 0; m < GrConstColorProcessor::kInputModeCnt; ++m) {
85                    // translate by x,y for the canvas draws and the test target draws.
86                    canvas->save();
87                    canvas->translate(x, y);
88                    const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y);
89
90                    // rect to draw
91                    SkRect renderRect = SkRect::MakeXYWH(0, 0, kRectSize, kRectSize);
92
93                    GrTestTarget tt;
94                    context->getTestTarget(&tt);
95                    if (NULL == tt.target()) {
96                        SkDEBUGFAIL("Couldn't get Gr test target.");
97                        return;
98                    }
99
100                    GrPaint grPaint;
101                    SkPaint skPaint;
102                    if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
103                        skPaint.setShader(fShader);
104                    } else {
105                        skPaint.setColor(kPaintColors[paintType]);
106                    }
107                    SkAssertResult(SkPaint2GrPaint(context, rt, skPaint, viewMatrix, false,
108                                                   &grPaint));
109
110                    GrConstColorProcessor::InputMode mode = (GrConstColorProcessor::InputMode) m;
111                    GrColor color = kColors[procColor];
112                    SkAutoTUnref<GrFragmentProcessor> fp(GrConstColorProcessor::Create(color, mode));
113
114                    GrPipelineBuilder pipelineBuilder;
115                    GrClip clip;
116                    pipelineBuilder.setFromPaint(grPaint, rt, clip);
117                    pipelineBuilder.addColorProcessor(fp);
118
119                    tt.target()->drawSimpleRect(&pipelineBuilder,
120                                                grPaint.getColor(),
121                                                viewMatrix,
122                                                renderRect);
123
124                    // Draw labels for the input to the processor and the processor to the right of
125                    // the test rect. The input label appears above the processor label.
126                    SkPaint labelPaint;
127                    labelPaint.setAntiAlias(true);
128                    labelPaint.setTextSize(10.f);
129                    SkString inputLabel;
130                    inputLabel.set("Input: ");
131                    if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
132                        inputLabel.append("gradient");
133                    } else {
134                        inputLabel.appendf("0x%08x", kPaintColors[paintType]);
135                    }
136                    SkString procLabel;
137                    procLabel.printf("Proc: [0x%08x, %s]", kColors[procColor], kModeStrs[m]);
138
139                    SkRect inputLabelBounds;
140                    // get the bounds of the text in order to position it
141                    labelPaint.measureText(inputLabel.c_str(), inputLabel.size(),
142                                           &inputLabelBounds);
143                    canvas->drawText(inputLabel.c_str(), inputLabel.size(),
144                                     renderRect.fRight + kPad,
145                                     -inputLabelBounds.fTop, labelPaint);
146                    // update the bounds to reflect the offset we used to draw it.
147                    inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop);
148
149                    SkRect procLabelBounds;
150                    labelPaint.measureText(procLabel.c_str(), procLabel.size(),
151                                           &procLabelBounds);
152                    canvas->drawText(procLabel.c_str(), procLabel.size(),
153                                     renderRect.fRight + kPad,
154                                     inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop,
155                                     labelPaint);
156                    procLabelBounds.offset(renderRect.fRight + kPad,
157                                           inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop);
158
159                    labelPaint.setStrokeWidth(0);
160                    labelPaint.setStyle(SkPaint::kStroke_Style);
161                    canvas->drawRect(renderRect, labelPaint);
162
163                    canvas->restore();
164
165                    // update x and y for the next test case.
166                    SkScalar height = renderRect.height();
167                    SkScalar width = SkTMax(inputLabelBounds.fRight, procLabelBounds.fRight);
168                    maxW = SkTMax(maxW, width);
169                    y += height + kPad;
170                    if (y + height > kHeight) {
171                        y = kPad;
172                        x += maxW + kPad;
173                        maxW = 0;
174                    }
175                }
176            }
177        }
178    }
179
180private:
181    // Use this as a way of generating and input FP
182    SkAutoTUnref<SkShader>      fShader;
183
184    static const SkScalar       kPad;
185    static const SkScalar       kRectSize;
186    static const int            kWidth  = 820;
187    static const int            kHeight = 500;
188
189    typedef GM INHERITED;
190};
191
192const SkScalar ConstColorProcessor::kPad = 10.f;
193const SkScalar ConstColorProcessor::kRectSize = 20.f;
194
195DEF_GM( return SkNEW(ConstColorProcessor); )
196}
197
198#endif
199