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