summaryrefslogtreecommitdiff
path: root/chromium/third_party/skia/tools/SkVMBuilders.cpp
blob: 7bb46876e24af5382fe75f54fac0f7fe19efa16c (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
/*
 * Copyright 2019 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/SkVMBuilders.h"

// Some parts of this builder code are written less fluently than possible,
// to avoid any ambiguity of function argument evaluation order.  This lets
// our golden tests work portably.  In general there's no reason to fear
// nesting calls to Builder routines.

SrcoverBuilder_F32::SrcoverBuilder_F32(Fmt srcFmt, Fmt dstFmt) {
    auto load = [&](Fmt fmt, skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) {
        skvm::Arg ptr;
        switch (fmt) {
            case Fmt::A8: {
                ptr = varying<uint8_t>();
                *r = *g = *b = splat(0.0f);
                *a = from_unorm(8, load8(ptr));
            } break;

            case Fmt::G8: {
                ptr = varying<uint8_t>();
                *r = *g = *b = from_unorm(8, load8(ptr));
                *a = splat(1.0f);
            } break;

            case Fmt::RGBA_8888: {
                ptr = varying<int>();
                skvm::I32 rgba = load32(ptr);
                *r = from_unorm(8, extract(rgba,  0, splat(0xff)));
                *g = from_unorm(8, extract(rgba,  8, splat(0xff)));
                *b = from_unorm(8, extract(rgba, 16, splat(0xff)));
                *a = from_unorm(8, extract(rgba, 24, splat(0xff)));
            } break;
        }
        return ptr;
    };

    skvm::F32 r,g,b,a;
    (void)load(srcFmt, &r,&g,&b,&a);

    skvm::F32 dr,dg,db,da;
    skvm::Arg dst = load(dstFmt, &dr,&dg,&db,&da);

    skvm::F32 invA = sub(splat(1.0f), a);
    r = mad(dr, invA, r);
    g = mad(dg, invA, g);
    b = mad(db, invA, b);
    a = mad(da, invA, a);

    switch (dstFmt) {
        case Fmt::A8: {
            store8(dst, to_unorm(8, a));
        } break;

        case Fmt::G8: {
            skvm::F32 _2126 = splat(0.2126f),
                      _7152 = splat(0.7152f),
                      _0722 = splat(0.0722f);
            store8(dst, to_unorm(8, mad(r, _2126,
                                    mad(g, _7152,
                                    mul(b, _0722)))));
        } break;

        case Fmt::RGBA_8888: {
            skvm::I32 R = to_unorm(8, r),
                      G = to_unorm(8, g),
                      B = to_unorm(8, b),
                      A = to_unorm(8, a);

            R = pack(R, G, 8);
            B = pack(B, A, 8);
            R = pack(R, B, 16);

            store32(dst, R);
        } break;
    }
}

SrcoverBuilder_I32_Naive::SrcoverBuilder_I32_Naive() {
    skvm::Arg src = varying<int>(),
              dst = varying<int>();

    auto load = [&](skvm::Arg ptr,
                    skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) {
        skvm::I32 rgba = load32(ptr);
        *r = extract(rgba,  0, splat(0xff));
        *g = extract(rgba,  8, splat(0xff));
        *b = extract(rgba, 16, splat(0xff));
        *a = extract(rgba, 24, splat(0xff));
    };

    skvm::I32 r,g,b,a;
    load(src, &r,&g,&b,&a);

    skvm::I32 dr,dg,db,da;
    load(dst, &dr,&dg,&db,&da);

    // (xy + x)/256 is a good approximation of (xy + 127)/255
    //
    //   == (d*(255-a) + d)/256
    //   == (d*(255-a+1)  )/256
    //   == (d*(256-a  )  )/256

    skvm::I32 invA = sub(splat(256), a);
    r = add(r, shr(mul(dr, invA), 8));
    g = add(g, shr(mul(dg, invA), 8));
    b = add(b, shr(mul(db, invA), 8));
    a = add(a, shr(mul(da, invA), 8));

    r = pack(r, g, 8);
    b = pack(b, a, 8);
    r = pack(r, b, 16);
    store32(dst, r);
}