1/* 2 * Copyright 2015 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 "Benchmark.h" 9#include "SkPMFloat.h" 10 11// Used to prevent the compiler from optimizing away the whole loop. 12volatile uint32_t blackhole = 0; 13 14// Not a great random number generator, but it's very fast. 15// The code we're measuring is quite fast, so low overhead is essential. 16static uint32_t lcg_rand(uint32_t* seed) { 17 *seed *= 1664525; 18 *seed += 1013904223; 19 return *seed; 20} 21 22// I'm having better luck getting these to constant-propagate away as template parameters. 23template <bool kClamp, bool kWide> 24struct PMFloatGetSetBench : public Benchmark { 25 PMFloatGetSetBench() {} 26 27 const char* onGetName() override { 28 switch (kClamp << 1 | kWide) { 29 case 0: return "SkPMFloat_get_1x"; 30 case 1: return "SkPMFloat_get_4x"; 31 case 2: return "SkPMFloat_clamp_1x"; 32 case 3: return "SkPMFloat_clamp_4x"; 33 } 34 SkFAIL("unreachable"); 35 return "oh bother"; 36 } 37 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } 38 39 void onDraw(const int loops, SkCanvas* canvas) override { 40 // Unlike blackhole, junk can and probably will be a register. 41 uint32_t junk = 0; 42 uint32_t seed = 0; 43 for (int i = 0; i < loops; i++) { 44 SkPMColor colors[4]; 45 #ifdef SK_DEBUG 46 for (int i = 0; i < 4; i++) { 47 // Our SkASSERTs will remind us that it's technically required that we premultiply. 48 colors[i] = SkPreMultiplyColor(lcg_rand(&seed)); 49 } 50 #else 51 // But it's a lot faster not to, and this code won't really mind the non-PM colors. 52 (void)lcg_rand(&seed); 53 colors[0] = seed + 0; 54 colors[1] = seed + 1; 55 colors[2] = seed + 2; 56 colors[3] = seed + 3; 57 #endif 58 59 SkPMFloat fa,fb,fc,fd; 60 if (kWide) { 61 SkPMFloat::From4PMColors(colors, &fa, &fb, &fc, &fd); 62 } else { 63 fa = SkPMFloat::FromPMColor(colors[0]); 64 fb = SkPMFloat::FromPMColor(colors[1]); 65 fc = SkPMFloat::FromPMColor(colors[2]); 66 fd = SkPMFloat::FromPMColor(colors[3]); 67 } 68 69 SkPMColor back[4]; 70 switch (kClamp << 1 | kWide) { 71 case 0: { 72 back[0] = fa.round(); 73 back[1] = fb.round(); 74 back[2] = fc.round(); 75 back[3] = fd.round(); 76 } break; 77 case 1: SkPMFloat::RoundTo4PMColors(fa, fb, fc, fd, back); break; 78 case 2: { 79 back[0] = fa.roundClamp(); 80 back[1] = fb.roundClamp(); 81 back[2] = fc.roundClamp(); 82 back[3] = fd.roundClamp(); 83 } break; 84 case 3: SkPMFloat::RoundClampTo4PMColors(fa, fb, fc, fd, back); break; 85 } 86 for (int i = 0; i < 4; i++) { 87 junk ^= back[i]; 88 } 89 } 90 blackhole ^= junk; 91 } 92}; 93 94// Extra () help DEF_BENCH not get confused by the comma inside the <>. 95DEF_BENCH(return (new PMFloatGetSetBench< true, true>);) 96DEF_BENCH(return (new PMFloatGetSetBench<false, true>);) 97DEF_BENCH(return (new PMFloatGetSetBench< true, false>);) 98DEF_BENCH(return (new PMFloatGetSetBench<false, false>);) 99 100struct PMFloatGradientBench : public Benchmark { 101 const char* onGetName() override { return "PMFloat_gradient"; } 102 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } 103 104 SkPMColor fDevice[100]; 105 void onDraw(const int loops, SkCanvas*) override { 106 Sk4f c0 = SkPMFloat::FromARGB(255, 255, 0, 0), 107 c1 = SkPMFloat::FromARGB(255, 0, 0, 255), 108 dc = c1 - c0, 109 fx(0.1f), 110 dx(0.002f), 111 dcdx(dc*dx), 112 dcdx4(dcdx+dcdx+dcdx+dcdx); 113 114 for (int n = 0; n < loops; n++) { 115 Sk4f a = c0 + dc*fx + Sk4f(0.5f), // The +0.5f lets us call trunc() instead of get(). 116 b = a + dcdx, 117 c = b + dcdx, 118 d = c + dcdx; 119 for (size_t i = 0; i < SK_ARRAY_COUNT(fDevice); i += 4) { 120 fDevice[i+0] = SkPMFloat(a).trunc(); 121 fDevice[i+1] = SkPMFloat(b).trunc(); 122 fDevice[i+2] = SkPMFloat(c).trunc(); 123 fDevice[i+3] = SkPMFloat(d).trunc(); 124 a += dcdx4; 125 b += dcdx4; 126 c += dcdx4; 127 d += dcdx4; 128 } 129 } 130 } 131}; 132 133DEF_BENCH(return new PMFloatGradientBench;) 134