dcshader.cpp revision 96fcdcc219d2a0d3579719b84b28bede76efba64
1
2/*
3 * Copyright 2014 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#include "gm.h"
10#if SK_SUPPORT_GPU
11#include "GrFragmentProcessor.h"
12#include "GrCoordTransform.h"
13#include "gl/GrGLProcessor.h"
14#include "gl/builders/GrGLProgramBuilder.h"
15#include "Resources.h"
16#include "SkReadBuffer.h"
17#include "SkShader.h"
18#include "SkStream.h"
19#include "SkTypeface.h"
20#include "SkWriteBuffer.h"
21
22namespace skiagm {
23
24///////////////////////////////////////////////////////////////////////////////
25
26class DCShader : public SkShader {
27public:
28    DCShader(const SkMatrix& matrix) : fDeviceMatrix(matrix) {}
29
30    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DCShader);
31
32    void flatten(SkWriteBuffer& buf) const override {
33        buf.writeMatrix(fDeviceMatrix);
34    }
35
36    bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM,
37                             const SkMatrix* localMatrix, GrColor* color, GrProcessorDataManager*,
38                             GrFragmentProcessor** fp) const override;
39
40#ifndef SK_IGNORE_TO_STRING
41    void toString(SkString* str) const override {
42        str->appendf("DCShader: ()");
43    }
44#endif
45
46private:
47    const SkMatrix fDeviceMatrix;
48};
49
50SkFlattenable* DCShader::CreateProc(SkReadBuffer& buf) {
51    SkMatrix matrix;
52    buf.readMatrix(&matrix);
53    return new DCShader(matrix);
54}
55
56class DCFP : public GrFragmentProcessor {
57public:
58    DCFP(GrProcessorDataManager*, const SkMatrix& m) : fDeviceTransform(kDevice_GrCoordSet, m) {
59        this->addCoordTransform(&fDeviceTransform);
60        this->initClassID<DCFP>();
61    }
62
63    GrGLFragmentProcessor* onCreateGLInstance() const override {
64        class DCGLFP : public GrGLFragmentProcessor {
65            void emitCode(EmitArgs& args) override {
66                GrGLFragmentBuilder* fpb = args.fBuilder->getFragmentShaderBuilder();
67                fpb->codeAppendf("vec2 c = %s;", fpb->ensureFSCoords2D(args.fCoords, 0).c_str());
68                fpb->codeAppend("vec2 r = mod(c, vec2(20.0));");
69                fpb->codeAppend("vec4 color = vec4(0.5*sin(c.x / 15.0) + 0.5,"
70                                                    "0.5*cos((c.x + c.y) / 15.0) + 0.5,"
71                                                    "(r.x + r.y) / 20.0,"
72                                                    "distance(r, vec2(15.0)) / 20.0 + 0.2);");
73                fpb->codeAppendf("color.rgb *= color.a;"
74                                    "%s = color * %s;",
75                                    args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str());
76            }
77            void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override {}
78        };
79        return new DCGLFP;
80    }
81
82    const char* name() const override { return "DCFP"; }
83
84    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
85        inout->mulByUnknownFourComponents();
86    }
87
88private:
89    void onGetGLProcessorKey(const GrGLSLCaps& caps,
90                             GrProcessorKeyBuilder* b) const override {}
91
92    bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
93
94    GrCoordTransform fDeviceTransform;
95};
96
97bool DCShader::asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM,
98                                   const SkMatrix* localMatrix, GrColor* color,
99                                   GrProcessorDataManager* procDataManager,
100                                   GrFragmentProcessor** fp) const {
101    *fp = new DCFP(procDataManager, fDeviceMatrix);
102    *color = GrColorPackA4(paint.getAlpha());
103    return true;
104}
105
106class DCShaderGM : public GM {
107public:
108    DCShaderGM() {
109        this->setBGColor(sk_tool_utils::color_to_565(0xFFAABBCC));
110    }
111
112    ~DCShaderGM() override {
113        for (int i = 0; i < fPrims.count(); ++i) {
114            delete fPrims[i];
115        }
116    }
117
118protected:
119
120    SkString onShortName() override {
121        return SkString("dcshader");
122    }
123
124    SkISize onISize() override { return SkISize::Make(1000, 900); }
125
126    void onOnceBeforeDraw() override {
127        struct Rect : public Prim {
128            SkRect draw(SkCanvas* canvas, const SkPaint& paint) override {
129                SkRect rect = SkRect::MakeXYWH(0, 0, 50, 50);
130                canvas->drawRect(rect, paint);
131                return rect;
132            }
133        };
134
135        struct Circle : public Prim {
136            SkRect draw(SkCanvas* canvas, const SkPaint& paint) override {
137                static const SkScalar radius = 25;
138                canvas->drawCircle(radius, radius, radius, paint);
139                return SkRect::MakeXYWH(0, 0, 2 * radius, 2 * radius);
140            }
141        };
142
143        struct RRect : public Prim {
144            SkRect draw(SkCanvas* canvas, const SkPaint& paint) override {
145                SkRRect rrect;
146                rrect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 10, 10);
147                canvas->drawRRect(rrect, paint);
148                return rrect.getBounds();
149            }
150        };
151
152        struct DRRect : public Prim {
153            SkRect draw(SkCanvas* canvas, const SkPaint& paint) override {
154                SkRRect outerRRect;
155                outerRRect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 5, 5);
156                SkRRect innerRRect;
157                innerRRect.setRectXY(SkRect::MakeXYWH(5, 8, 35, 30), 8, 3);
158                canvas->drawDRRect(outerRRect, innerRRect, paint);
159                return outerRRect.getBounds();
160            }
161        };
162        struct Path : public Prim {
163            SkRect draw(SkCanvas* canvas, const SkPaint& paint) override {
164                SkPath path;
165                path.addCircle(15, 15, 10);
166                path.addOval(SkRect::MakeXYWH(2, 2, 22, 37));
167                path.setFillType(SkPath::kEvenOdd_FillType);
168                canvas->drawPath(path, paint);
169                return path.getBounds();
170            }
171        };
172
173        struct Points : public Prim {
174            Points(SkCanvas::PointMode mode) : fMode(mode) {}
175
176            SkRect draw(SkCanvas* canvas, const SkPaint& paint) override {
177                SkRandom random;
178                SkPoint points[500];
179                SkRect bounds = SkRect::MakeWH(50, 50);
180                int count = SkToInt(SK_ARRAY_COUNT(points));
181                if (SkCanvas::kPoints_PointMode != fMode) {
182                    count = SkTMin(count, 10);
183                }
184                for (int p = 0; p < count; ++p) {
185                    points[p].fX = random.nextUScalar1() * bounds.width();
186                    points[p].fY = random.nextUScalar1() * bounds.width();
187                }
188                canvas->drawPoints(fMode, count, points, paint);
189                return bounds;
190            }
191            SkCanvas::PointMode fMode;
192        };
193
194        struct Text : public Prim {
195            SkRect draw(SkCanvas* canvas, const SkPaint& origPaint) override {
196                SkPaint paint = origPaint;
197                paint.setTextSize(30.f);
198                this->setFont(&paint);
199                const char* text = this->text();
200                static const SkVector offset = SkVector::Make(10, 10);
201                canvas->drawText(text, strlen(text), offset.fX, offset.fY, paint);
202                SkRect bounds;
203                paint.measureText(text, strlen(text), &bounds);
204                bounds.offset(offset);
205                return bounds;
206            }
207
208            virtual void setFont(SkPaint* paint) {
209                sk_tool_utils::set_portable_typeface(paint);
210            }
211
212            virtual const char* text() const { return "Hello, Skia!"; }
213        };
214
215        fPrims.push_back(new Rect);
216        fPrims.push_back(new Circle);
217        fPrims.push_back(new RRect);
218        fPrims.push_back(new DRRect);
219        fPrims.push_back(new Path);
220        fPrims.push_back(new Points(SkCanvas::kPoints_PointMode));
221        fPrims.push_back(new Points(SkCanvas::kLines_PointMode));
222        fPrims.push_back(new Points(SkCanvas::kPolygon_PointMode));
223        fPrims.push_back(new Text);
224    }
225
226    void onDraw(SkCanvas* canvas) override {
227        // This GM exists to test a specific feature of the GPU backend. It does not work with the
228        // sw rasterizer, tile modes, etc.
229        if (nullptr == canvas->getGrContext()) {
230            this->drawGpuOnlyMessage(canvas);
231            return;
232        }
233        SkPaint paint;
234        SkTArray<SkMatrix> devMats;
235        devMats.push_back().reset();
236        devMats.push_back().setRotate(45, 500, 500);
237        devMats.push_back().setRotate(-30, 200, 200);
238        devMats.back().setPerspX(-SK_Scalar1 / 2000);
239        devMats.back().setPerspY(SK_Scalar1 / 1000);
240
241
242        SkTArray<SkMatrix> viewMats;
243        viewMats.push_back().setScale(0.75f, 0.75f);
244        viewMats.push_back().setRotate(45, 50, 50);
245        viewMats.back().postScale(0.5f, 1.1f);
246
247        canvas->translate(10, 20);
248        canvas->save();
249        SkScalar tx = 0, maxTy = 0;
250        static const SkScalar kW = 900;
251
252        for (int aa = 0; aa < 2; ++aa) {
253            for (int i = 0; i < fPrims.count(); ++i) {
254                for (int j = 0; j < devMats.count(); ++j) {
255                    for (int k = 0; k < viewMats.count(); ++k) {
256                        paint.setShader(new DCShader(devMats[j]))->unref();
257                        paint.setAntiAlias(SkToBool(aa));
258                        canvas->save();
259                        canvas->concat(viewMats[k]);
260                        SkRect bounds = fPrims[i]->draw(canvas, paint);
261                        canvas->restore();
262                        viewMats[k].mapRect(&bounds);
263                        // add margins
264                        bounds.fRight += 20;
265                        bounds.fBottom += 20;
266                        canvas->translate(bounds.fRight, 0);
267                        tx += bounds.fRight;
268                        maxTy = SkTMax(bounds.fBottom, maxTy);
269                        if (tx > kW) {
270                            tx = 0;
271                            canvas->restore();
272                            canvas->translate(0, maxTy);
273                            canvas->save();
274                            maxTy = 0;
275                        }
276                    }
277                }
278            }
279        }
280        canvas->restore();
281    }
282
283private:
284    struct Prim {
285        virtual ~Prim() {}
286        virtual SkRect draw(SkCanvas*, const SkPaint&) = 0;
287    };
288
289    SkTArray<Prim*> fPrims;
290
291    typedef GM INHERITED;
292};
293
294DEF_GM(return new DCShaderGM;)
295}
296#endif
297