• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 #include "gm/gm.h"
9 #include "include/core/SkBlendMode.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorFilter.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPoint.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkScalar.h"
18 #include "include/core/SkShader.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkString.h"
21 #include "include/core/SkTileMode.h"
22 #include "include/core/SkTypes.h"
23 #include "include/core/SkVertices.h"
24 #include "include/effects/SkGradientShader.h"
25 #include "include/effects/SkRuntimeEffect.h"
26 #include "include/private/SkTDArray.h"
27 #include "include/utils/SkRandom.h"
28 #include "src/core/SkVerticesPriv.h"
29 #include "src/shaders/SkLocalMatrixShader.h"
30 #include "src/utils/SkPatchUtils.h"
31 #include "tools/Resources.h"
32 #include "tools/ToolUtils.h"
33 
34 #include <initializer_list>
35 #include <utility>
36 
37 static constexpr SkScalar kShaderSize = 40;
make_shader1(SkScalar shaderScale)38 static sk_sp<SkShader> make_shader1(SkScalar shaderScale) {
39     const SkColor colors[] = {
40         SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE,
41         SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorYELLOW,
42     };
43     const SkPoint pts[] = {{kShaderSize / 4, 0}, {3 * kShaderSize / 4, kShaderSize}};
44     const SkMatrix localMatrix = SkMatrix::Scale(shaderScale, shaderScale);
45 
46     sk_sp<SkShader> grad = SkGradientShader::MakeLinear(pts, colors, nullptr,
47                                                         SK_ARRAY_COUNT(colors),
48                                                         SkTileMode::kMirror, 0,
49                                                         &localMatrix);
50     // Throw in a couple of local matrix wrappers for good measure.
51     return shaderScale == 1
52         ? grad
53         : sk_make_sp<SkLocalMatrixShader>(
54               sk_make_sp<SkLocalMatrixShader>(std::move(grad), SkMatrix::Translate(-10, 0)),
55               SkMatrix::Translate(10, 0));
56 }
57 
make_shader2()58 static sk_sp<SkShader> make_shader2() {
59     return SkShaders::Color(SK_ColorBLUE);
60 }
61 
make_color_filter()62 static sk_sp<SkColorFilter> make_color_filter() {
63     return SkColorFilters::Blend(0xFFAABBCC, SkBlendMode::kDarken);
64 }
65 
66 static constexpr SkScalar kMeshSize = 30;
67 
68 // start with the center of a 3x3 grid of vertices.
69 static constexpr uint16_t kMeshFan[] = {
70         4,
71         0, 1, 2, 5, 8, 7, 6, 3, 0
72 };
73 
74 static const int kMeshIndexCnt = (int)SK_ARRAY_COUNT(kMeshFan);
75 static const int kMeshVertexCnt = 9;
76 
fill_mesh(SkPoint pts[kMeshVertexCnt],SkPoint texs[kMeshVertexCnt],SkColor colors[kMeshVertexCnt],SkScalar shaderScale)77 static void fill_mesh(SkPoint pts[kMeshVertexCnt], SkPoint texs[kMeshVertexCnt],
78                       SkColor colors[kMeshVertexCnt], SkScalar shaderScale) {
79     pts[0].set(0, 0);
80     pts[1].set(kMeshSize / 2, 3);
81     pts[2].set(kMeshSize, 0);
82     pts[3].set(3, kMeshSize / 2);
83     pts[4].set(kMeshSize / 2, kMeshSize / 2);
84     pts[5].set(kMeshSize - 3, kMeshSize / 2);
85     pts[6].set(0, kMeshSize);
86     pts[7].set(kMeshSize / 2, kMeshSize - 3);
87     pts[8].set(kMeshSize, kMeshSize);
88 
89     const auto shaderSize = kShaderSize * shaderScale;
90     texs[0].set(0, 0);
91     texs[1].set(shaderSize / 2, 0);
92     texs[2].set(shaderSize, 0);
93     texs[3].set(0, shaderSize / 2);
94     texs[4].set(shaderSize / 2, shaderSize / 2);
95     texs[5].set(shaderSize, shaderSize / 2);
96     texs[6].set(0, shaderSize);
97     texs[7].set(shaderSize / 2, shaderSize);
98     texs[8].set(shaderSize, shaderSize);
99 
100     SkRandom rand;
101     for (size_t i = 0; i < kMeshVertexCnt; ++i) {
102         colors[i] = rand.nextU() | 0xFF000000;
103     }
104 }
105 
106 class VerticesGM : public skiagm::GM {
107     SkPoint                 fPts[kMeshVertexCnt];
108     SkPoint                 fTexs[kMeshVertexCnt];
109     SkColor                 fColors[kMeshVertexCnt];
110     sk_sp<SkShader>         fShader1;
111     sk_sp<SkShader>         fShader2;
112     sk_sp<SkColorFilter>    fColorFilter;
113     SkScalar                fShaderScale;
114 
115 public:
VerticesGM(SkScalar shaderScale)116     VerticesGM(SkScalar shaderScale) : fShaderScale(shaderScale) {}
117 
118 protected:
119 
onOnceBeforeDraw()120     void onOnceBeforeDraw() override {
121         fill_mesh(fPts, fTexs, fColors, fShaderScale);
122         fShader1 = make_shader1(fShaderScale);
123         fShader2 = make_shader2();
124         fColorFilter = make_color_filter();
125     }
126 
onShortName()127     SkString onShortName() override {
128         SkString name("vertices");
129         if (fShaderScale != 1) {
130             name.append("_scaled_shader");
131         }
132         return name;
133     }
134 
onISize()135     SkISize onISize() override {
136         return SkISize::Make(975, 1175);
137     }
138 
onDraw(SkCanvas * canvas)139     void onDraw(SkCanvas* canvas) override {
140         const SkBlendMode modes[] = {
141             SkBlendMode::kClear,
142             SkBlendMode::kSrc,
143             SkBlendMode::kDst,
144             SkBlendMode::kSrcOver,
145             SkBlendMode::kDstOver,
146             SkBlendMode::kSrcIn,
147             SkBlendMode::kDstIn,
148             SkBlendMode::kSrcOut,
149             SkBlendMode::kDstOut,
150             SkBlendMode::kSrcATop,
151             SkBlendMode::kDstATop,
152             SkBlendMode::kXor,
153             SkBlendMode::kPlus,
154             SkBlendMode::kModulate,
155             SkBlendMode::kScreen,
156             SkBlendMode::kOverlay,
157             SkBlendMode::kDarken,
158             SkBlendMode::kLighten,
159             SkBlendMode::kColorDodge,
160             SkBlendMode::kColorBurn,
161             SkBlendMode::kHardLight,
162             SkBlendMode::kSoftLight,
163             SkBlendMode::kDifference,
164             SkBlendMode::kExclusion,
165             SkBlendMode::kMultiply,
166             SkBlendMode::kHue,
167             SkBlendMode::kSaturation,
168             SkBlendMode::kColor,
169             SkBlendMode::kLuminosity,
170         };
171 
172         SkPaint paint;
173 
174         canvas->translate(4, 4);
175         int x = 0;
176         for (auto mode : modes) {
177             canvas->save();
178             for (float alpha : {1.0f, 0.5f}) {
179                 for (const auto& cf : {sk_sp<SkColorFilter>(nullptr), fColorFilter}) {
180                     for (const auto& shader : {fShader1, fShader2}) {
181                         static constexpr struct {
182                             bool fHasColors;
183                             bool fHasTexs;
184                         } kAttrs[] = {{true, false}, {false, true}, {true, true}};
185                         for (auto attrs : kAttrs) {
186                             paint.setShader(shader);
187                             paint.setColorFilter(cf);
188                             paint.setAlphaf(alpha);
189 
190                             const SkColor* colors = attrs.fHasColors ? fColors : nullptr;
191                             const SkPoint* texs = attrs.fHasTexs ? fTexs : nullptr;
192                             auto v = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
193                                                           kMeshVertexCnt, fPts, texs, colors,
194                                                           kMeshIndexCnt, kMeshFan);
195                             canvas->drawVertices(v, mode, paint);
196                             canvas->translate(40, 0);
197                             ++x;
198                         }
199                     }
200                 }
201             }
202             canvas->restore();
203             canvas->translate(0, 40);
204         }
205     }
206 
207 private:
208     using INHERITED = skiagm::GM;
209 };
210 
211 /////////////////////////////////////////////////////////////////////////////////////
212 
213 DEF_GM(return new VerticesGM(1);)
214 DEF_GM(return new VerticesGM(1 / kShaderSize);)
215 
draw_batching(SkCanvas * canvas)216 static void draw_batching(SkCanvas* canvas) {
217     // Triangle fans can't batch so we convert to regular triangles,
218     static constexpr int kNumTris = kMeshIndexCnt - 2;
219     SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, kMeshVertexCnt, 3 * kNumTris,
220                                 SkVertices::kHasColors_BuilderFlag |
221                                 SkVertices::kHasTexCoords_BuilderFlag);
222 
223     SkPoint* pts = builder.positions();
224     SkPoint* texs = builder.texCoords();
225     SkColor* colors = builder.colors();
226     fill_mesh(pts, texs, colors, 1);
227 
228     SkTDArray<SkMatrix> matrices;
229     matrices.push()->reset();
230     matrices.push()->setTranslate(0, 40);
231     matrices.push()
232             ->setRotate(45, kMeshSize / 2, kMeshSize / 2)
233             .postScale(1.2f, .8f, kMeshSize / 2, kMeshSize / 2)
234             .postTranslate(0, 80);
235 
236     auto shader = make_shader1(1);
237 
238     uint16_t* indices = builder.indices();
239     for (size_t i = 0; i < kNumTris; ++i) {
240         indices[3 * i] = kMeshFan[0];
241         indices[3 * i + 1] = kMeshFan[i + 1];
242         indices[3 * i + 2] = kMeshFan[i + 2];
243 
244     }
245 
246     canvas->save();
247     canvas->translate(10, 10);
248     for (bool useShader : {false, true}) {
249         for (bool useTex : {false, true}) {
250             for (const auto& m : matrices) {
251                 canvas->save();
252                 canvas->concat(m);
253                 SkPaint paint;
254                 paint.setShader(useShader ? shader : nullptr);
255 
256                 const SkPoint* t = useTex ? texs : nullptr;
257                 auto v = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, kMeshVertexCnt,
258                                               pts, t, colors, kNumTris * 3, indices);
259                 canvas->drawVertices(v, SkBlendMode::kModulate, paint);
260                 canvas->restore();
261             }
262             canvas->translate(0, 120);
263         }
264     }
265     canvas->restore();
266 }
267 
268 // This test exists to exercise batching in the gpu backend.
269 DEF_SIMPLE_GM(vertices_batching, canvas, 100, 500) {
270     draw_batching(canvas);
271     canvas->translate(50, 0);
272     draw_batching(canvas);
273 }
274 
275 // Test case for skbug.com/10069. We need to draw the vertices twice (with different matrices) to
276 // trigger the bug.
277 DEF_SIMPLE_GM(vertices_perspective, canvas, 256, 256) {
278     SkPaint paint;
279     paint.setShader(ToolUtils::create_checkerboard_shader(SK_ColorBLACK, SK_ColorWHITE, 32));
280 
281     SkRect r = SkRect::MakeWH(128, 128);
282 
283     SkPoint pos[4];
284     r.toQuad(pos);
285     auto verts = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, pos, pos, nullptr);
286 
287     SkMatrix persp;
288     persp.setPerspY(SK_Scalar1 / 100);
289 
290     canvas->save();
291     canvas->concat(persp);
292     canvas->drawRect(r, paint);
293     canvas->restore();
294 
295     canvas->save();
296     canvas->translate(r.width(), 0);
297     canvas->concat(persp);
298     canvas->drawRect(r, paint);
299     canvas->restore();
300 
301     canvas->save();
302     canvas->translate(0, r.height());
303     canvas->concat(persp);
304     canvas->drawVertices(verts, paint);
305     canvas->restore();
306 
307     canvas->save();
308     canvas->translate(r.width(), r.height());
309     canvas->concat(persp);
310     canvas->drawVertices(verts, paint);
311     canvas->restore();
312 }
313