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