aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkXfermodeU64.cpp
blob: 6de5f1b09f871c4043aa70e001ba536c040ab98a (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkHalf.h"
#include "SkPM4fPriv.h"
#include "SkUtils.h"
#include "SkXfermode.h"

static void sk_memset64(uint64_t dst[], uint64_t value, int count) {
    for (int i = 0; i < count; ++i) {
        dst[i] = value;
    }
}

struct U64ProcPair {
    SkXfermode::U64Proc1 fP1;
    SkXfermode::U64ProcN fPN;
};

enum DstType {
    kU16_Dst,
    kF16_Dst,
};

static Sk4f lerp_by_coverage(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) {
    return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f));
}

template <DstType D> Sk4f unit_to_dst_bias(const Sk4f& x4) {
    return (D == kU16_Dst) ? x4 * Sk4f(65535) : x4;
}

// returns value already biased by 65535
static Sk4f load_from_u16(uint64_t value) {
    return SkNx_cast<float>(Sk4h::Load(&value));
}

// takes floats already biased by 65535
static uint64_t store_to_u16(const Sk4f& x4) {
    uint64_t value;
    SkNx_cast<uint16_t>(x4 + Sk4f(0.5f)).store(&value);
    return value;
}

// Returns dst in its "natural" bias (either unit-float or 16bit int)
//
template <DstType D> Sk4f load_from_dst(uint64_t dst) {
    return (D == kU16_Dst) ? load_from_u16(dst) : SkHalfToFloat_01(dst);
}

// Assumes x4 is already in the "natural" bias (either unit-float or 16bit int)
template <DstType D> uint64_t store_to_dst(const Sk4f& x4) {
    return (D == kU16_Dst) ? store_to_u16(x4) : SkFloatToHalf_01(x4);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

template <DstType D> void src_1(const SkXfermode::U64State& state, uint64_t dst[],
                                const SkPM4f& src, int count, const SkAlpha aa[]) {
    const Sk4f s4 = unit_to_dst_bias<D>(Sk4f::Load(src.fVec));
    if (aa) {
        for (int i = 0; i < count; ++i) {
            const Sk4f d4 = load_from_dst<D>(dst[i]);
            dst[i] = store_to_dst<D>(lerp_by_coverage(s4, d4, aa[i]));
        }
    } else {
        sk_memset64(dst, store_to_dst<D>(s4), count);
    }
}

template <DstType D> void src_n(const SkXfermode::U64State& state, uint64_t dst[],
                                const SkPM4f src[], int count, const SkAlpha aa[]) {
    if (aa) {
        for (int i = 0; i < count; ++i) {
            const Sk4f s4 = unit_to_dst_bias<D>(Sk4f::Load(src[i].fVec));
            const Sk4f d4 = load_from_dst<D>(dst[i]);
            dst[i] = store_to_dst<D>(lerp_by_coverage(s4, d4, aa[i]));
        }
    } else {
        for (int i = 0; i < count; ++i) {
            const Sk4f s4 = unit_to_dst_bias<D>(Sk4f::Load(src[i].fVec));
            dst[i] = store_to_dst<D>(s4);
        }
    }
}

const U64ProcPair gU64Procs_Src[] = {
    { src_1<kU16_Dst>, src_n<kU16_Dst>  },   // U16     alpha
    { src_1<kU16_Dst>, src_n<kU16_Dst>  },   // U16     opaque
    { src_1<kF16_Dst>, src_n<kF16_Dst>  },   // F16     alpha
    { src_1<kF16_Dst>, src_n<kF16_Dst>  },   // F16     opaque
};

///////////////////////////////////////////////////////////////////////////////////////////////////

template <DstType D> void srcover_1(const SkXfermode::U64State& state, uint64_t dst[],
                                    const SkPM4f& src, int count, const SkAlpha aa[]) {
    const Sk4f s4 = Sk4f::Load(src.fVec);
    const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
    const Sk4f s4bias = unit_to_dst_bias<D>(s4);
    for (int i = 0; i < count; ++i) {
        const Sk4f d4bias = load_from_dst<D>(dst[i]);
        const Sk4f r4bias = s4bias + d4bias * dst_scale;
        if (aa) {
            dst[i] = store_to_dst<D>(lerp_by_coverage(r4bias, d4bias, aa[i]));
        } else {
            dst[i] = store_to_dst<D>(r4bias);
        }
    }
}

template <DstType D> void srcover_n(const SkXfermode::U64State& state, uint64_t dst[],
                                    const SkPM4f src[], int count, const SkAlpha aa[]) {
    for (int i = 0; i < count; ++i) {
        const Sk4f s4 = Sk4f::Load(src[i].fVec);
        const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
        const Sk4f s4bias = unit_to_dst_bias<D>(s4);
        const Sk4f d4bias = load_from_dst<D>(dst[i]);
        const Sk4f r4bias = s4bias + d4bias * dst_scale;
        if (aa) {
            dst[i] = store_to_dst<D>(lerp_by_coverage(r4bias, d4bias, aa[i]));
        } else {
            dst[i] = store_to_dst<D>(r4bias);
        }
    }
}

const U64ProcPair gU64Procs_SrcOver[] = {
    { srcover_1<kU16_Dst>,  srcover_n<kU16_Dst> },   // U16     alpha
    { src_1<kU16_Dst>,      src_n<kU16_Dst>     },   // U16     opaque
    { srcover_1<kF16_Dst>,  srcover_n<kF16_Dst> },   // F16     alpha
    { src_1<kF16_Dst>,      src_n<kF16_Dst>     },   // F16     opaque
};

///////////////////////////////////////////////////////////////////////////////////////////////////

static U64ProcPair find_procs(SkXfermode::Mode mode, uint32_t flags) {
    SkASSERT(0 == (flags & ~3));
    flags &= 3;

    switch (mode) {
        case SkXfermode::kSrc_Mode:     return gU64Procs_Src[flags];
        case SkXfermode::kSrcOver_Mode: return gU64Procs_SrcOver[flags];
        default:
            break;
    }
    return { nullptr, nullptr };
}

SkXfermode::U64Proc1 SkXfermode::GetU64Proc1(Mode mode, uint32_t flags) {
    return find_procs(mode, flags).fP1;
}

SkXfermode::U64ProcN SkXfermode::GetU64ProcN(Mode mode, uint32_t flags) {
    return find_procs(mode, flags).fPN;
}