1 /* 2 * Copyright 2019 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 #include "bench/Benchmark.h" 8 #include "include/utils/SkRandom.h" 9 #include "src/sksl/SkSLByteCode.h" 10 #include "src/sksl/SkSLCompiler.h" 11 12 // Benchmarks the interpreter with a function that has a color-filter style signature 13 class SkSLInterpreterCFBench : public Benchmark { 14 public: SkSLInterpreterCFBench(SkSL::String name,int pixels,bool striped,const char * src)15 SkSLInterpreterCFBench(SkSL::String name, int pixels, bool striped, const char* src) 16 : fName(SkStringPrintf("sksl_interp_cf_%d_%d_%s", pixels, striped ? 1 : 0, name.c_str())) 17 , fSrc(src) 18 , fCount(pixels) 19 , fStriped(striped) {} 20 21 protected: onGetName()22 const char* onGetName() override { 23 return fName.c_str(); 24 } 25 isSuitableFor(Backend backend)26 bool isSuitableFor(Backend backend) override { 27 return backend == kNonRendering_Backend; 28 } 29 onDelayedSetup()30 void onDelayedSetup() override { 31 SkSL::Compiler compiler; 32 SkSL::Program::Settings settings; 33 auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind, fSrc, settings); 34 SkASSERT(compiler.errorCount() == 0); 35 fByteCode = compiler.toByteCode(*program); 36 SkASSERT(compiler.errorCount() == 0); 37 fMain = fByteCode->getFunction("main"); 38 39 SkRandom rnd; 40 fPixels.resize(fCount * 4); 41 for (float& c : fPixels) { 42 c = rnd.nextF(); 43 } 44 } 45 onDraw(int loops,SkCanvas *)46 void onDraw(int loops, SkCanvas*) override { 47 for (int i = 0; i < loops; i++) { 48 if (fStriped) { 49 float* args[] = { 50 fPixels.data() + 0 * fCount, 51 fPixels.data() + 1 * fCount, 52 fPixels.data() + 2 * fCount, 53 fPixels.data() + 3 * fCount, 54 }; 55 56 SkAssertResult(fByteCode->runStriped(fMain, args, 4, fCount, 57 nullptr, 0, nullptr, 0)); 58 } else { 59 SkAssertResult(fByteCode->run(fMain, fPixels.data(), nullptr, fCount, nullptr, 0)); 60 } 61 } 62 } 63 64 private: 65 SkString fName; 66 SkSL::String fSrc; 67 std::unique_ptr<SkSL::ByteCode> fByteCode; 68 const SkSL::ByteCodeFunction* fMain; 69 70 int fCount; 71 bool fStriped; 72 std::vector<float> fPixels; 73 74 typedef Benchmark INHERITED; 75 }; 76 77 /////////////////////////////////////////////////////////////////////////////// 78 79 const char* kLumaToAlphaSrc = R"( 80 void main(inout float4 color) { 81 color.a = color.r*0.3 + color.g*0.6 + color.b*0.1; 82 color.r = 0; 83 color.g = 0; 84 color.b = 0; 85 } 86 )"; 87 88 const char* kHighContrastFilterSrc = R"( 89 half ucontrast_Stage2; 90 half hue2rgb_Stage2(half p, half q, half t) { 91 if (t < 0) t += 1; 92 if (t > 1) t -= 1; 93 return (t < 1 / 6.) ? p + (q - p) * 6 * t 94 : (t < 1 / 2.) ? q 95 : (t < 2 / 3.) ? p + (q - p) * (2 / 3. - t) * 6 96 : p; 97 } 98 half max(half a, half b) { return a > b ? a : b; } 99 half min(half a, half b) { return a < b ? a : b; } 100 void main(inout half4 color) { 101 ucontrast_Stage2 = 0.2; 102 103 // HighContrastFilter 104 half nonZeroAlpha = max(color.a, 0.0001); 105 color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha); 106 color.rgb = color.rgb * color.rgb; 107 half fmax = max(color.r, max(color.g, color.b)); 108 half fmin = min(color.r, min(color.g, color.b)); 109 half l = (fmax + fmin) / 2; 110 half h; 111 half s; 112 if (fmax == fmin) { 113 h = 0; 114 s = 0; 115 } else { 116 half d = fmax - fmin; 117 s = l > 0.5 ? d / (2 - fmax - fmin) : d / (fmax + fmin); 118 if (color.r >= color.g && color.r >= color.b) { 119 h = (color.g - color.b) / d + (color.g < color.b ? 6 : 0); 120 } else if (color.g >= color.b) { 121 h = (color.b - color.r) / d + 2; 122 } else { 123 h = (color.r - color.g) / d + 4; 124 } 125 } 126 h /= 6; 127 l = 1.0 - l; 128 if (s == 0) { 129 color = half4(l, l, l, 0); 130 } else { 131 half q = l < 0.5 ? l * (1 + s) : l + s - l * s; 132 half p = 2 * l - q; 133 color.r = hue2rgb_Stage2(p, q, h + 1 / 3.); 134 color.g = hue2rgb_Stage2(p, q, h); 135 color.b = hue2rgb_Stage2(p, q, h - 1 / 3.); 136 } 137 if (ucontrast_Stage2 != 0) { 138 half m = (1 + ucontrast_Stage2) / (1 - ucontrast_Stage2); 139 half off = (-0.5 * m + 0.5); 140 color = m * color + off; 141 } 142 // color = saturate(color); 143 color.rgb = sqrt(color.rgb); 144 color.rgb *= color.a; 145 } 146 )"; 147 148 DEF_BENCH(return new SkSLInterpreterCFBench("lumaToAlpha", 256, false, kLumaToAlphaSrc)); 149 DEF_BENCH(return new SkSLInterpreterCFBench("lumaToAlpha", 256, true, kLumaToAlphaSrc)); 150 151 DEF_BENCH(return new SkSLInterpreterCFBench("hcf", 256, false, kHighContrastFilterSrc)); 152 DEF_BENCH(return new SkSLInterpreterCFBench("hcf", 256, true, kHighContrastFilterSrc)); 153 154 class SkSLInterpreterSortBench : public Benchmark { 155 public: SkSLInterpreterSortBench(int groups,int values,const char * src)156 SkSLInterpreterSortBench(int groups, int values, const char* src) 157 : fName(SkStringPrintf("sksl_interp_sort_%dx%d", groups, values)) 158 , fCode(src) 159 , fGroups(groups) 160 , fValues(values) { 161 } 162 163 protected: onGetName()164 const char* onGetName() override { 165 return fName.c_str(); 166 } 167 isSuitableFor(Backend backend)168 bool isSuitableFor(Backend backend) override { 169 return backend == kNonRendering_Backend; 170 } 171 onDelayedSetup()172 void onDelayedSetup() override { 173 SkSL::Compiler compiler; 174 SkSL::Program::Settings settings; 175 auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind, fCode, settings); 176 SkASSERT(compiler.errorCount() == 0); 177 fByteCode = compiler.toByteCode(*program); 178 SkASSERT(compiler.errorCount() == 0); 179 fMain = fByteCode->getFunction("main"); 180 181 fSrc.resize(fGroups * fValues); 182 fDst.resize(fGroups * fValues); 183 184 SkRandom rnd; 185 for (float& x : fSrc) { 186 x = rnd.nextF(); 187 } 188 189 // Trigger one run now to check correctness 190 SkAssertResult(fByteCode->run(fMain, fSrc.data(), fDst.data(), fGroups, nullptr, 0)); 191 for (int i = 0; i < fGroups; ++i) { 192 for (int j = 1; j < fValues; ++j) { 193 SkASSERT(fDst[i * fValues + j] >= fDst[i * fValues + j - 1]); 194 } 195 } 196 } 197 onDraw(int loops,SkCanvas *)198 void onDraw(int loops, SkCanvas*) override { 199 for (int i = 0; i < loops; i++) { 200 SkAssertResult(fByteCode->run(fMain, fSrc.data(), fDst.data(), fGroups, nullptr, 0)); 201 } 202 } 203 204 private: 205 SkString fName; 206 SkSL::String fCode; 207 std::unique_ptr<SkSL::ByteCode> fByteCode; 208 const SkSL::ByteCodeFunction* fMain; 209 210 int fGroups; 211 int fValues; 212 std::vector<float> fSrc; 213 std::vector<float> fDst; 214 215 typedef Benchmark INHERITED; 216 }; 217 218 // Currently, this exceeds the interpreter's stack. Consider it a test case for some eventual 219 // bounds checking. 220 #if 0 221 DEF_BENCH(return new SkSLInterpreterSortBench(1024, 32, R"( 222 float[32] main(float v[32]) { 223 for (int i = 1; i < 32; ++i) { 224 for (int j = i; j > 0 && v[j-1] > v[j]; --j) { 225 float t = v[j]; 226 v[j] = v[j-1]; 227 v[j-1] = t; 228 } 229 } 230 return v; 231 } 232 )")); 233 #endif 234