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. 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: 74 SkinningGM(bool deformUsingCPU, bool cache) 75 : fPaint() 76 , fVertices(nullptr) 77 , fDeformUsingCPU(deformUsingCPU) 78 , fCache(cache) 79 {} 80 81 protected: 82 bool runAsBench() const override { 83 return true; 84 } 85 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 97 SkISize onISize() override { 98 return SkISize::Make(2400, 2400); 99 } 100 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 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: 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