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