1 /*
2  * Copyright 2018 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.h"
9 #include "SkCanvas.h"
10 #include "SkVertices.h"
11 #include "SkPoint.h"
12 
13 #include <iostream>
14 #include <vector>
15 
16 using namespace skiagm;
17 
18 static const int kCellSize = 60;
19 static const int kColumnSize = 36;
20 
21 static const int kBoneCount = 7;
22 static const SkVertices::Bone kBones[] = {
23     {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }},   // SkMatrix::I()
24     {{ 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f }},  // SkMatrix::MakeTrans(10, 0)
25     {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f }},  // SkMatrix::MakeTrans(0, 10)
26     {{ 1.0f, 0.0f, 0.0f, 1.0f, -10.0f, 0.0f }}, // SkMatrix::MakeTrans(-10, 0)
27     {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -10.0f }}, // SkMatrix::MakeTrans(0, -10)
28     {{ 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f }},   // SkMatrix::MakeScale(0.5)
29     {{ 1.5f, 0.0f, 0.0f, 1.5f, 0.0f, 0.0f }},   // SkMatrix::MakeScale(1.5)
30 };
31 
32 static const int kVertexCount = 4;
33 static const SkPoint kPositions[] = {
34     { 0, 0 },
35     { 0, 30 },
36     { 30, 30 },
37     { 30, 0 },
38 };
39 static const SkColor kColors[] = {
40     0xFFFF0000,
41     0xFF00FF00,
42     0xFF0000FF,
43     0xFFFFFF00,
44 };
45 static const SkVertices::BoneIndices kBoneIndices[] = {
46     {{ 1, 0, 0, 0 }},
47     {{ 2, 1, 0, 0 }},
48     {{ 3, 2, 1, 0 }},
49     {{ 4, 3, 2, 1 }},
50 };
51 static const SkVertices::BoneWeights kBoneWeights[] = {
52     {{ 1.0f,  0.0f,  0.0f,  0.0f  }},
53     {{ 0.5f,  0.5f,  0.0f,  0.0f  }},
54     {{ 0.34f, 0.33f, 0.33f, 0.0f  }},
55     {{ 0.25f, 0.25f, 0.25f, 0.25f }},
56 };
57 
58 static const int kIndexCount = 6;
59 static const uint16_t kIndices[] = {
60     0, 1, 2,
61     2, 3, 0,
62 };
63 
64 // Swap two SkVertices::Bone pointers in place.
swap(const SkVertices::Bone ** x,const SkVertices::Bone ** y)65 static void swap(const SkVertices::Bone** x, const SkVertices::Bone** y) {
66     const SkVertices::Bone* temp = *x;
67     *x = *y;
68     *y = temp;
69 }
70 
71 class SkinningGM : public GM {
72 
73 public:
SkinningGM(bool deformUsingCPU,bool cache)74     SkinningGM(bool deformUsingCPU, bool cache)
75             : fPaint()
76             , fVertices(nullptr)
77             , fDeformUsingCPU(deformUsingCPU)
78             , fCache(cache)
79     {}
80 
81 protected:
runAsBench() const82     bool runAsBench() const override {
83         return true;
84     }
85 
onShortName()86     SkString onShortName() override {
87         SkString name("skinning");
88         if (fDeformUsingCPU) {
89             name.append("_cpu");
90         }
91         if (fCache) {
92             name.append("_cached");
93         }
94         return name;
95     }
96 
onISize()97     SkISize onISize() override {
98         return SkISize::Make(2400, 2400);
99     }
100 
onOnceBeforeDraw()101     void onOnceBeforeDraw() override {
102         fVertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
103                                          kVertexCount,
104                                          kPositions,
105                                          nullptr,
106                                          kColors,
107                                          kBoneIndices,
108                                          kBoneWeights,
109                                          kIndexCount,
110                                          kIndices,
111                                          !fCache);
112     }
113 
onDraw(SkCanvas * canvas)114     void onDraw(SkCanvas* canvas) override {
115         // Set the initial position.
116         int xpos = kCellSize;
117         int ypos = kCellSize;
118 
119         // Create the mutable set of bones.
120         const SkVertices::Bone* bones[kBoneCount];
121         for (int i = 0; i < kBoneCount; i ++) {
122             bones[i] = &kBones[i];
123         }
124 
125         // Draw the vertices.
126         drawPermutations(canvas, xpos, ypos, bones, 1);
127     }
128 
129 private:
drawPermutations(SkCanvas * canvas,int & xpos,int & ypos,const SkVertices::Bone ** bones,int start)130     void drawPermutations(SkCanvas* canvas,
131                           int& xpos,
132                           int& ypos,
133                           const SkVertices::Bone** bones,
134                           int start) {
135         if (start == kBoneCount) {
136             // Reached the end of the permutations, so draw.
137             canvas->save();
138 
139             // Copy the bones.
140             SkVertices::Bone copiedBones[kBoneCount];
141             for (int i = 0; i < kBoneCount; i ++) {
142                 copiedBones[i] = *bones[i];
143             }
144 
145             // Set the position.
146             canvas->translate(xpos, ypos);
147 
148             // Draw the vertices.
149             if (fDeformUsingCPU) {
150                 // Apply the bones.
151                 sk_sp<SkVertices> vertices = fVertices->applyBones(copiedBones,
152                                                                    kBoneCount);
153 
154                 // Deform with CPU.
155                 canvas->drawVertices(vertices.get(),
156                                      SkBlendMode::kSrc,
157                                      fPaint);
158             } else {
159                 // Deform with GPU.
160                 canvas->drawVertices(fVertices.get(),
161                                      copiedBones,
162                                      kBoneCount,
163                                      SkBlendMode::kSrc,
164                                      fPaint);
165             }
166 
167             canvas->restore();
168 
169             // Get a new position to draw the vertices.
170             xpos += kCellSize;
171             if (xpos > kCellSize * kColumnSize) {
172                 xpos = kCellSize;
173                 ypos += kCellSize;
174             }
175 
176             return;
177         }
178 
179         // Find all possible permutations within the given range.
180         for (int i = start; i < kBoneCount; i ++) {
181             // Swap the start and i-th elements.
182             swap(bones + start, bones + i);
183 
184             // Find permutations of the sub array.
185             drawPermutations(canvas, xpos, ypos, bones, start + 1);
186 
187             // Swap the elements back.
188             swap(bones + i, bones + start);
189         }
190     }
191 
192 private:
193     SkPaint fPaint;
194     sk_sp<SkVertices> fVertices;
195     bool fDeformUsingCPU;
196     bool fCache;
197 
198     typedef GM INHERITED;
199 };
200 
201 /////////////////////////////////////////////////////////////////////////////////////
202 
203 DEF_GM(return new SkinningGM(true, true);)
204 DEF_GM(return new SkinningGM(false, true);)
205 DEF_GM(return new SkinningGM(true, false);)
206 DEF_GM(return new SkinningGM(false, false);)
207