• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
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/SkBlender.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkCustomMesh.h"
12 #include "include/core/SkSurface.h"
13 #include "include/effects/SkGradientShader.h"
14 #include "src/core/SkCanvasPriv.h"
15 
16 #include <memory>
17 
18 namespace skiagm {
19 class CustomMeshGM : public skiagm::GM {
20 public:
CustomMeshGM()21     CustomMeshGM() {}
22 
23 protected:
24     using Attribute = SkCustomMeshSpecification::Attribute;
25     using Varying   = SkCustomMeshSpecification::Varying;
26 
onISize()27     SkISize onISize() override { return {435, 1180}; }
28 
onOnceBeforeDraw()29     void onOnceBeforeDraw() override {
30         {
31             static const Attribute kAttributes[]{
32                     {Attribute::Type::kFloat4,       8, SkString{"xuyv"}},
33                     {Attribute::Type::kUByte4_unorm, 4, SkString{"brag"}},
34             };
35             static const Varying kVaryings[]{
36                     {Varying::Type::kHalf4,  SkString{"color"}},
37                     {Varying::Type::kFloat2, SkString{"uv"}   },
38             };
39             static constexpr char kVS[] = R"(
40                     half4 unswizzle_color(half4 color) { return color.garb; }
41 
42                     float2 main(in Attributes attributes, out Varyings varyings) {
43                         varyings.color = unswizzle_color(attributes.brag);
44                         varyings.uv    = attributes.xuyv.yw;
45                         return attributes.xuyv.xz;
46                     }
47             )";
48             static constexpr char kFS[] = R"(
49                     float2 main(in Varyings varyings, out float4 color) {
50                         color = varyings.color;
51                         return varyings.uv;
52                     }
53             )";
54             auto [spec, error] = SkCustomMeshSpecification::Make(
55                     SkMakeSpan(kAttributes, SK_ARRAY_COUNT(kAttributes)),
56                     sizeof(ColorVertex),
57                     SkMakeSpan(kVaryings, SK_ARRAY_COUNT(kVaryings)),
58                     SkString(kVS),
59                     SkString(kFS));
60             if (!spec) {
61                 SkDebugf("%s\n", error.c_str());
62             }
63             fSpecWithColor = std::move(spec);
64         }
65         {
66             static const Attribute kAttributes[]{
67                     {Attribute::Type::kFloat4, 0, SkString{"xuyv"}},
68             };
69             static const Varying kVaryings[]{
70                     {Varying::Type::kFloat2, SkString{"vux2"}},
71             };
72             static constexpr char kVS[] = R"(
73                     float2 main(in Attributes a, out Varyings v) {
74                         v.vux2 = 2*a.xuyv.wy;
75                         return a.xuyv.xz;
76                     }
77             )";
78             static constexpr char kFS[] = R"(
79                     float2 helper(in float2 vux2) { return vux2.yx/2; }
80                     float2 main(in Varyings varyings) {
81                         return helper(varyings.vux2);
82                     }
83             )";
84             auto [spec, error] = SkCustomMeshSpecification::Make(
85                     SkMakeSpan(kAttributes, SK_ARRAY_COUNT(kAttributes)),
86                     sizeof(NoColorVertex),
87                     SkMakeSpan(kVaryings, SK_ARRAY_COUNT(kVaryings)),
88                     SkString(kVS),
89                     SkString(kFS));
90             if (!spec) {
91                 SkDebugf("%s\n", error.c_str());
92             }
93             fSpecWithNoColor = std::move(spec);
94         }
95 
96         static constexpr SkColor kColors[] = {SK_ColorTRANSPARENT, SK_ColorWHITE};
97         fShader = SkGradientShader::MakeRadial({10, 10},
98                                                3,
99                                                kColors,
100                                                nullptr,
101                                                2,
102                                                SkTileMode::kMirror);
103     }
104 
onShortName()105     SkString onShortName() override { return SkString("custommesh"); }
106 
onDraw(SkCanvas * canvas,SkString *)107     DrawResult onDraw(SkCanvas* canvas, SkString*) override {
108         int i = 0;
109         for (const sk_sp<SkBlender>& blender : {SkBlender::Mode(SkBlendMode::kDst),
110                                                 SkBlender::Mode(SkBlendMode::kSrc),
111                                                 SkBlender::Mode(SkBlendMode::kSaturation)}) {
112             canvas->save();
113             for (uint8_t alpha  : {0xFF , 0x40})
114             for (bool    colors : {false, true})
115             for (bool    shader : {false, true}) {
116                 SkCustomMesh cm;
117                 cm.spec   = colors ? fSpecWithColor : fSpecWithNoColor;
118                 cm.bounds = kRect;
119                 // Rather than pile onto the combinatorics we draw every other test case indexed.
120                 if ((i & 1) == 0) {
121                     cm.vb     = colors ? static_cast<const void*>(kColorQuad)
122                                        : static_cast<const void*>(kNoColorQuad);
123                     cm.vcount = 4;
124                     cm.mode   = SkCustomMesh::Mode::kTriangleStrip;
125                 } else {
126                     cm.vb      = colors ? static_cast<const void*>(kColorIndexedQuad)
127                                         : static_cast<const void*>(kNoColorIndexedQuad);
128                     cm.vcount  = 6;
129                     cm.icount  = 6;
130                     cm.indices = kIndices;
131                     cm.mode   = SkCustomMesh::Mode::kTriangles;
132                 }
133 
134                 SkPaint paint;
135                 paint.setColor(SK_ColorGREEN);
136                 paint.setShader(shader ? fShader : nullptr);
137                 paint.setAlpha(alpha);
138 
139                 SkCanvasPriv::DrawCustomMesh(canvas, std::move(cm), blender, paint);
140 
141                 canvas->translate(0, 150);
142                 ++i;
143             }
144             canvas->restore();
145             canvas->translate(150, 0);
146         }
147         return DrawResult::kOk;
148     }
149 
150 private:
151     struct ColorVertex {
152         uint32_t pad;
153         uint32_t brag;
154         float    xuyv[4];
155     };
156 
157     struct NoColorVertex {
158         float xuyv[4];
159     };
160 
161     static constexpr auto kRect = SkRect::MakeLTRB(20, 20, 120, 120);
162     static constexpr auto kUV   = SkRect::MakeLTRB( 0,  0,  20,  20);
163 
164     static constexpr ColorVertex kColorQuad[] {
165             {0, 0x00FFFF00, {kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
166             {0, 0x00FFFFFF, {kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
167             {0, 0xFFFF00FF, {kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
168             {0, 0xFFFFFF00, {kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
169     };
170 
171     static constexpr NoColorVertex kNoColorQuad[]{
172             {{kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
173             {{kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
174             {{kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
175             {{kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
176     };
177 
178     // The indexed quads draw the same as the non-indexed. They just have unused vertices that the
179     // index buffer skips over draw with triangles instead of a triangle strip.
180     static constexpr ColorVertex kColorIndexedQuad[] {
181             {0, 0x00FFFF00, {kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
182             {0, 0x00000000, {        100.f,        0.f,        100.f,    5.f         }}, // unused
183             {0, 0x00FFFFFF, {kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
184             {0, 0x00000000, {        200.f,        10.f,        200.f,   10.f        }}, // unused
185             {0, 0xFFFF00FF, {kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
186             {0, 0xFFFFFF00, {kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
187     };
188 
189     static constexpr NoColorVertex kNoColorIndexedQuad[]{
190             {{kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
191             {{        100.f,        0.f,        100.f,    5.f         }}, // unused
192             {{kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
193             {{        200.f,        10.f,        200.f,   10.f        }}, // unused
194             {{kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
195             {{kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
196     };
197 
198     static constexpr uint16_t kIndices[]{0, 2, 4, 2, 5, 4};
199 
200     sk_sp<SkShader> fShader;
201 
202     sk_sp<SkCustomMeshSpecification> fSpecWithColor;
203     sk_sp<SkCustomMeshSpecification> fSpecWithNoColor;
204 };
205 
206 constexpr SkRect CustomMeshGM::kRect;
207 constexpr SkRect CustomMeshGM::kUV;
208 
209 constexpr CustomMeshGM::ColorVertex   CustomMeshGM::kColorQuad[];
210 constexpr CustomMeshGM::NoColorVertex CustomMeshGM::kNoColorQuad[];
211 constexpr CustomMeshGM::ColorVertex   CustomMeshGM::kColorIndexedQuad[];
212 constexpr CustomMeshGM::NoColorVertex CustomMeshGM::kNoColorIndexedQuad[];
213 
214 constexpr uint16_t CustomMeshGM::kIndices[];
215 
216 DEF_GM( return new CustomMeshGM; )
217 
218 class CustomMeshColorSpaceGM : public skiagm::GM {
219 public:
CustomMeshColorSpaceGM()220     CustomMeshColorSpaceGM() {}
221 
222 protected:
223     using Attribute = SkCustomMeshSpecification::Attribute;
224     using Varying   = SkCustomMeshSpecification::Varying;
225 
onISize()226     SkISize onISize() override { return {468, 258}; }
227 
onOnceBeforeDraw()228     void onOnceBeforeDraw() override {
229         static const Attribute kAttributes[]{
230                 {Attribute::Type::kFloat2, 0, SkString{"pos"}  },
231                 {Attribute::Type::kFloat4, 8, SkString{"color"}},
232         };
233         static const Varying kVaryings[]{
234                 {Varying::Type::kHalf4,  SkString{"color"}},
235         };
236         static constexpr char kPremulVS[] = R"(
237                 float2 main(in Attributes attributes, out Varyings varyings) {
238                     varyings.color = half4(attributes.color.a*attributes.color.rgb,
239                                            attributes.color.a);
240                     return attributes.pos;
241                 }
242         )";
243         static constexpr char kUnpremulVS[] = R"(
244                 float2 main(in Attributes attributes, out Varyings varyings) {
245                     varyings.color = attributes.color;
246                     return attributes.pos;
247                 }
248         )";
249         static constexpr char kFS[] = R"(
250                 void main(in Varyings varyings, out half4 color) {
251                     color = varyings.color;
252                 }
253         )";
254         for (bool unpremul : {false, true}) {
255             auto at = unpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
256             auto vs = unpremul ? kUnpremulVS : kPremulVS;
257             for (bool spin : {false, true}) {
258                 auto cs = SkColorSpace::MakeSRGB();
259                 if (spin) {
260                     cs = cs->makeColorSpin();
261                 }
262 
263                 auto [spec, error] = SkCustomMeshSpecification::Make(
264                         SkMakeSpan(kAttributes, SK_ARRAY_COUNT(kAttributes)),
265                         sizeof(Vertex),
266                         SkMakeSpan(kVaryings, SK_ARRAY_COUNT(kVaryings)),
267                         SkString(vs),
268                         SkString(kFS),
269                         std::move(cs),
270                         at);
271                 if (!spec) {
272                     SkDebugf("%s\n", error.c_str());
273                 }
274                 fSpecs[SpecIndex(unpremul, spin)] = std::move(spec);
275             }
276         }
277         SkPoint pts[]    = {{kRect.fLeft, 0}, {kRect.centerX(), 0}};
278         SkColor colors[] = {SK_ColorWHITE,    SK_ColorTRANSPARENT};
279         fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
280     }
281 
onShortName()282     SkString onShortName() override { return SkString("custommesh_cs"); }
283 
onDraw(SkCanvas * canvas,SkString * error)284     DrawResult onDraw(SkCanvas* canvas, SkString* error) override {
285         // Force an intermediate surface if the canvas is in "legacy" mode
286         SkCanvas* c = canvas;
287         sk_sp<SkSurface> surface;
288         if (!c->imageInfo().colorSpace()) {
289             SkImageInfo info = canvas->imageInfo().makeColorSpace(SkColorSpace::MakeSRGB());
290             surface = canvas->makeSurface(info);
291             if (!surface) {
292                 // This GM won't work on configs that use a recording canvas.
293                 return DrawResult::kSkip;
294             }
295             c = surface->getCanvas();
296             c->clear(SK_ColorWHITE);
297         }
298         for (bool useShader : {false, true})
299         for (bool unpremul  : {false, true}) {
300             c->save();
301             for (bool spin : {false, true}) {
302                 SkCustomMesh cm;
303                 cm.spec   = fSpecs[SpecIndex(unpremul, spin)];
304                 cm.bounds = kRect;
305                 cm.vb     = kQuad;
306                 cm.vcount = 4;
307                 cm.mode   = SkCustomMesh::Mode::kTriangleStrip;
308 
309                 SkPaint paint;
310                 paint.setShader(useShader ? fShader : nullptr);
311                 SkBlendMode mode = useShader ? SkBlendMode::kModulate : SkBlendMode::kDst;
312                 SkCanvasPriv::DrawCustomMesh(c,
313                                              std::move(cm),
314                                              SkBlender::Mode(mode),
315                                              paint);
316 
317                 c->translate(0, kRect.height() + 10);
318             }
319             c->restore();
320             c->translate(kRect.width() + 10, 0);
321             c->save();
322         }
323         if (surface) {
324             surface->draw(canvas, 0, 0);
325         }
326         return DrawResult::kOk;
327     }
328 
329 private:
330     struct Vertex {
331         SkPoint   pos;
332         SkColor4f color;
333     };
334 
SpecIndex(bool spin,bool unpremul)335     static int SpecIndex(bool spin, bool unpremul) {
336         return static_cast<int>(spin) + 2*static_cast<int>(unpremul);
337     }
338 
339     static constexpr auto kRect = SkRect::MakeLTRB(20, 20, 120, 120);
340 
341     static constexpr Vertex kQuad[] {
342             {{kRect.left() , kRect.top()   }, {1, 0, 0, 1}},
343             {{kRect.right(), kRect.top()   }, {0, 1, 0, 0}},
344             {{kRect.left() , kRect.bottom()}, {1, 1, 0, 0}},
345             {{kRect.right(), kRect.bottom()}, {0, 0, 1, 1}},
346     };
347 
348     sk_sp<SkCustomMeshSpecification> fSpecs[4];
349 
350     sk_sp<SkShader> fShader;
351 };
352 
353 constexpr SkRect CustomMeshColorSpaceGM::kRect;
354 
355 constexpr CustomMeshColorSpaceGM::Vertex CustomMeshColorSpaceGM::kQuad[];
356 
357 DEF_GM( return new CustomMeshColorSpaceGM; )
358 
359 }  // namespace skiagm
360