aboutsummaryrefslogtreecommitdiffhomepage
path: root/bench/PMFloatBench.cpp
blob: 14ccb33d0a805c74bff9cfc01b7c4ff8c845df06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Benchmark.h"
#include "SkPMFloat.h"

// Used to prevent the compiler from optimizing away the whole loop.
volatile uint32_t blackhole = 0;

// Not a great random number generator, but it's very fast.
// The code we're measuring is quite fast, so low overhead is essential.
static uint32_t lcg_rand(uint32_t* seed) {
    *seed *= 1664525;
    *seed += 1013904223;
    return *seed;
}

// I'm having better luck getting these to constant-propagate away as template parameters.
template <bool kClamp, bool kWide>
struct PMFloatGetSetBench : public Benchmark {
    PMFloatGetSetBench() {}

    const char* onGetName() override {
        switch (kClamp << 1 | kWide) {
            case 0: return "SkPMFloat_get_1x";
            case 1: return "SkPMFloat_get_4x";
            case 2: return "SkPMFloat_clamp_1x";
            case 3: return "SkPMFloat_clamp_4x";
        }
        SkFAIL("unreachable");
        return "oh bother";
    }
    bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }

    void onDraw(const int loops, SkCanvas* canvas) override {
        // Unlike blackhole, junk can and probably will be a register.
        uint32_t junk = 0;
        uint32_t seed = 0;
        for (int i = 0; i < loops; i++) {
            SkPMColor colors[4];
        #ifdef SK_DEBUG
            for (int i = 0; i < 4; i++) {
                // Our SkASSERTs will remind us that it's technically required that we premultiply.
                colors[i] = SkPreMultiplyColor(lcg_rand(&seed));
            }
        #else
            // But it's a lot faster not to, and this code won't really mind the non-PM colors.
            (void)lcg_rand(&seed);
            colors[0] = seed + 0;
            colors[1] = seed + 1;
            colors[2] = seed + 2;
            colors[3] = seed + 3;
        #endif

            SkPMFloat fa,fb,fc,fd;
            if (kWide) {
                SkPMFloat::From4PMColors(colors, &fa, &fb, &fc, &fd);
            } else {
                fa = SkPMFloat::FromPMColor(colors[0]);
                fb = SkPMFloat::FromPMColor(colors[1]);
                fc = SkPMFloat::FromPMColor(colors[2]);
                fd = SkPMFloat::FromPMColor(colors[3]);
            }

            SkPMColor back[4];
            switch (kClamp << 1 | kWide) {
                case 0: {
                    back[0] = fa.round();
                    back[1] = fb.round();
                    back[2] = fc.round();
                    back[3] = fd.round();
                } break;
                case 1: SkPMFloat::RoundTo4PMColors(fa, fb, fc, fd, back); break;
                case 2: {
                    back[0] = fa.roundClamp();
                    back[1] = fb.roundClamp();
                    back[2] = fc.roundClamp();
                    back[3] = fd.roundClamp();
                } break;
                case 3: SkPMFloat::RoundClampTo4PMColors(fa, fb, fc, fd, back); break;
            }
            for (int i = 0; i < 4; i++) {
                junk ^= back[i];
            }
        }
        blackhole ^= junk;
    }
};

// Extra () help DEF_BENCH not get confused by the comma inside the <>.
DEF_BENCH(return (new PMFloatGetSetBench< true,  true>);)
DEF_BENCH(return (new PMFloatGetSetBench<false,  true>);)
DEF_BENCH(return (new PMFloatGetSetBench< true, false>);)
DEF_BENCH(return (new PMFloatGetSetBench<false, false>);)

struct PMFloatGradientBench : public Benchmark {
    const char* onGetName() override { return "PMFloat_gradient"; }
    bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }

    SkPMColor fDevice[100];
    void onDraw(const int loops, SkCanvas*) override {
        Sk4f c0 = SkPMFloat::FromARGB(255, 255, 0, 0),
             c1 = SkPMFloat::FromARGB(255, 0, 0, 255),
             dc = c1 - c0,
             fx(0.1f),
             dx(0.002f),
             dcdx(dc*dx),
             dcdx4(dcdx+dcdx+dcdx+dcdx);

        for (int n = 0; n < loops; n++) {
            Sk4f a = c0 + dc*fx + Sk4f(0.5f),  // The +0.5f lets us call trunc() instead of get().
                 b = a + dcdx,
                 c = b + dcdx,
                 d = c + dcdx;
            for (size_t i = 0; i < SK_ARRAY_COUNT(fDevice); i += 4) {
                fDevice[i+0] = SkPMFloat(a).trunc();
                fDevice[i+1] = SkPMFloat(b).trunc();
                fDevice[i+2] = SkPMFloat(c).trunc();
                fDevice[i+3] = SkPMFloat(d).trunc();
                a += dcdx4;
                b += dcdx4;
                c += dcdx4;
                d += dcdx4;
            }
        }
    }
};

DEF_BENCH(return new PMFloatGradientBench;)