1/*
2 * Copyright 2016 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 "SkHalf.h"
9#include "SkPM4fPriv.h"
10#include "SkUtils.h"
11#include "SkXfermode.h"
12
13static void sk_memset64(uint64_t dst[], uint64_t value, int count) {
14    for (int i = 0; i < count; ++i) {
15        dst[i] = value;
16    }
17}
18
19enum DstType {
20    kU16_Dst,
21    kF16_Dst,
22};
23
24static Sk4f lerp_by_coverage(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) {
25    return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f));
26}
27
28template <DstType D> Sk4f unit_to_bias(const Sk4f& x4) {
29    return (D == kU16_Dst) ? x4 * Sk4f(65535) : x4;
30}
31
32template <DstType D> Sk4f bias_to_unit(const Sk4f& x4) {
33    return (D == kU16_Dst) ? x4 * Sk4f(1.0f/65535) : x4;
34}
35
36// returns value already biased by 65535
37static Sk4f load_from_u16(uint64_t value) {
38    return SkNx_cast<float>(Sk4h::Load(&value));
39}
40
41// takes floats already biased by 65535
42static uint64_t store_to_u16(const Sk4f& x4) {
43    uint64_t value;
44    SkNx_cast<uint16_t>(x4 + Sk4f(0.5f)).store(&value);
45    return value;
46}
47
48// Returns dst in its "natural" bias (either unit-float or 16bit int)
49//
50template <DstType D> Sk4f load_from_dst(uint64_t dst) {
51    return (D == kU16_Dst) ? load_from_u16(dst) : SkHalfToFloat_01(dst);
52}
53
54// Assumes x4 is already in the "natural" bias (either unit-float or 16bit int)
55template <DstType D> uint64_t store_to_dst(const Sk4f& x4) {
56    return (D == kU16_Dst) ? store_to_u16(x4) : SkFloatToHalf_01(x4);
57}
58
59static inline Sk4f pm_to_rgba_order(const Sk4f& x) {
60    if (SkPM4f::R == 0) {
61        return x;   // we're already RGBA
62    } else {
63        // we're BGRA, so swap R and B
64        return SkNx_shuffle<2, 1, 0, 3>(x);
65    }
66}
67
68///////////////////////////////////////////////////////////////////////////////////////////////////
69
70template <DstType D> void xfer_u64_1(const SkXfermode* xfer, uint64_t dst[],
71                                     const SkPM4f* src, int count, const SkAlpha aa[]) {
72    SkXfermodeProc4f proc = xfer->getProc4f();
73    SkPM4f d;
74    if (aa) {
75        for (int i = 0; i < count; ++i) {
76            Sk4f d4 = bias_to_unit<D>(load_from_dst<D>(dst[i]));
77            d4.store(d.fVec);
78            Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(*src, d).fVec));
79            dst[i] = store_to_dst<D>(lerp_by_coverage(r4, d4, aa[i]));
80        }
81    } else {
82        for (int i = 0; i < count; ++i) {
83            bias_to_unit<D>(load_from_dst<D>(dst[i])).store(d.fVec);
84            Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(*src, d).fVec));
85            dst[i] = store_to_dst<D>(r4);
86        }
87    }
88}
89
90template <DstType D> void xfer_u64_n(const SkXfermode* xfer, uint64_t dst[],
91                                     const SkPM4f src[], int count, const SkAlpha aa[]) {
92    SkXfermodeProc4f proc = xfer->getProc4f();
93    SkPM4f d;
94    if (aa) {
95        for (int i = 0; i < count; ++i) {
96            Sk4f d4 = bias_to_unit<D>(load_from_dst<D>(dst[i]));
97            d4.store(d.fVec);
98            Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(src[i], d).fVec));
99            dst[i] = store_to_dst<D>(lerp_by_coverage(r4, d4, aa[i]));
100        }
101    } else {
102        for (int i = 0; i < count; ++i) {
103            bias_to_unit<D>(load_from_dst<D>(dst[i])).store(d.fVec);
104            Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(src[i], d).fVec));
105            dst[i] = store_to_dst<D>(r4);
106        }
107    }
108}
109
110const SkXfermode::D64Proc gProcs_General[] = {
111    xfer_u64_n<kU16_Dst>,   xfer_u64_n<kU16_Dst>,
112    xfer_u64_1<kU16_Dst>,   xfer_u64_1<kU16_Dst>,
113    xfer_u64_n<kF16_Dst>,   xfer_u64_n<kF16_Dst>,
114    xfer_u64_1<kF16_Dst>,   xfer_u64_1<kF16_Dst>,
115};
116
117///////////////////////////////////////////////////////////////////////////////////////////////////
118
119template <DstType D> void clear(const SkXfermode*, uint64_t dst[],
120                                const SkPM4f*, int count, const SkAlpha aa[]) {
121    if (aa) {
122        for (int i = 0; i < count; ++i) {
123            if (aa[i]) {
124                const Sk4f d4 = load_from_dst<D>(dst[i]);
125                dst[i] = store_to_dst<D>(d4 * Sk4f((255 - aa[i]) * 1.0f/255));
126            }
127        }
128    } else {
129        sk_memset64(dst, 0, count);
130    }
131}
132
133const SkXfermode::D64Proc gProcs_Clear[] = {
134    clear<kU16_Dst>,    clear<kU16_Dst>,
135    clear<kU16_Dst>,    clear<kU16_Dst>,
136    clear<kF16_Dst>,    clear<kF16_Dst>,
137    clear<kF16_Dst>,    clear<kF16_Dst>,
138};
139
140///////////////////////////////////////////////////////////////////////////////////////////////////
141
142template <DstType D> void src_1(const SkXfermode*, uint64_t dst[],
143                                const SkPM4f* src, int count, const SkAlpha aa[]) {
144    const Sk4f s4 = pm_to_rgba_order(unit_to_bias<D>(Sk4f::Load(src->fVec)));
145    if (aa) {
146        for (int i = 0; i < count; ++i) {
147            const Sk4f d4 = load_from_dst<D>(dst[i]);
148            dst[i] = store_to_dst<D>(lerp_by_coverage(s4, d4, aa[i]));
149        }
150    } else {
151        sk_memset64(dst, store_to_dst<D>(s4), count);
152    }
153}
154
155template <DstType D> void src_n(const SkXfermode*, uint64_t dst[],
156                                const SkPM4f src[], int count, const SkAlpha aa[]) {
157    if (aa) {
158        for (int i = 0; i < count; ++i) {
159            const Sk4f s4 = pm_to_rgba_order(unit_to_bias<D>(Sk4f::Load(src[i].fVec)));
160            const Sk4f d4 = load_from_dst<D>(dst[i]);
161            dst[i] = store_to_dst<D>(lerp_by_coverage(s4, d4, aa[i]));
162        }
163    } else {
164        for (int i = 0; i < count; ++i) {
165            const Sk4f s4 = pm_to_rgba_order(unit_to_bias<D>(Sk4f::Load(src[i].fVec)));
166            dst[i] = store_to_dst<D>(s4);
167        }
168    }
169}
170
171const SkXfermode::D64Proc gProcs_Src[] = {
172    src_n<kU16_Dst>,    src_n<kU16_Dst>,
173    src_1<kU16_Dst>,    src_1<kU16_Dst>,
174    src_n<kF16_Dst>,    src_n<kF16_Dst>,
175    src_1<kF16_Dst>,    src_1<kF16_Dst>,
176};
177
178///////////////////////////////////////////////////////////////////////////////////////////////////
179
180static void dst(const SkXfermode*, uint64_t*, const SkPM4f*, int count, const SkAlpha[]) {}
181
182const SkXfermode::D64Proc gProcs_Dst[] = {
183    dst, dst, dst, dst, dst, dst, dst, dst,
184};
185
186///////////////////////////////////////////////////////////////////////////////////////////////////
187
188template <DstType D> void srcover_1(const SkXfermode*, uint64_t dst[],
189                                    const SkPM4f* src, int count, const SkAlpha aa[]) {
190    const Sk4f s4 = pm_to_rgba_order(Sk4f::Load(src->fVec));
191    const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
192    const Sk4f s4bias = unit_to_bias<D>(s4);
193    for (int i = 0; i < count; ++i) {
194        const Sk4f d4bias = load_from_dst<D>(dst[i]);
195        const Sk4f r4bias = s4bias + d4bias * dst_scale;
196        if (aa) {
197            dst[i] = store_to_dst<D>(lerp_by_coverage(r4bias, d4bias, aa[i]));
198        } else {
199            dst[i] = store_to_dst<D>(r4bias);
200        }
201    }
202}
203
204template <DstType D> void srcover_n(const SkXfermode*, uint64_t dst[],
205                                    const SkPM4f src[], int count, const SkAlpha aa[]) {
206    for (int i = 0; i < count; ++i) {
207        const Sk4f s4 = pm_to_rgba_order(Sk4f::Load(src[i].fVec));
208        const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
209        const Sk4f s4bias = unit_to_bias<D>(s4);
210        const Sk4f d4bias = load_from_dst<D>(dst[i]);
211        const Sk4f r4bias = s4bias + d4bias * dst_scale;
212        if (aa) {
213            dst[i] = store_to_dst<D>(lerp_by_coverage(r4bias, d4bias, aa[i]));
214        } else {
215            dst[i] = store_to_dst<D>(r4bias);
216        }
217    }
218}
219
220const SkXfermode::D64Proc gProcs_SrcOver[] = {
221    srcover_n<kU16_Dst>,    src_n<kU16_Dst>,
222    srcover_1<kU16_Dst>,    src_1<kU16_Dst>,
223    srcover_n<kF16_Dst>,    src_n<kF16_Dst>,
224    srcover_1<kF16_Dst>,    src_1<kF16_Dst>,
225};
226
227///////////////////////////////////////////////////////////////////////////////////////////////////
228
229static SkXfermode::D64Proc find_proc(SkXfermode::Mode mode, uint32_t flags) {
230    SkASSERT(0 == (flags & ~7));
231    flags &= 7;
232
233    switch (mode) {
234        case SkXfermode::kClear_Mode:   return gProcs_Clear[flags];
235        case SkXfermode::kSrc_Mode:     return gProcs_Src[flags];
236        case SkXfermode::kDst_Mode:     return gProcs_Dst[flags];
237        case SkXfermode::kSrcOver_Mode: return gProcs_SrcOver[flags];
238        default:
239            break;
240    }
241    return gProcs_General[flags];
242}
243
244SkXfermode::D64Proc SkXfermode::onGetD64Proc(uint32_t flags) const {
245    SkASSERT(0 == (flags & ~7));
246    flags &= 7;
247
248    Mode mode;
249    return this->asMode(&mode) ? find_proc(mode, flags) : gProcs_General[flags];
250}
251
252SkXfermode::D64Proc SkXfermode::GetD64Proc(SkXfermode* xfer, uint32_t flags) {
253    return xfer ? xfer->onGetD64Proc(flags) : find_proc(SkXfermode::kSrcOver_Mode, flags);
254}
255
256