1/*
2 * Copyright 2011 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 "SkBlitRow.h"
9#include "SkBlitMask.h"
10#include "SkColorPriv.h"
11#include "SkUtils.h"
12
13#define UNROLL
14
15SkBlitRow::ColorRectProc PlatformColorRectProcFactory();
16
17static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
18                                 const SkPMColor* SK_RESTRICT src,
19                                 int count, U8CPU alpha) {
20    SkASSERT(255 == alpha);
21    memcpy(dst, src, count * sizeof(SkPMColor));
22}
23
24static void S32_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
25                                const SkPMColor* SK_RESTRICT src,
26                                int count, U8CPU alpha) {
27    SkASSERT(alpha <= 255);
28    if (count > 0) {
29        unsigned src_scale = SkAlpha255To256(alpha);
30        unsigned dst_scale = 256 - src_scale;
31
32#ifdef UNROLL
33        if (count & 1) {
34            *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
35            dst += 1;
36            count -= 1;
37        }
38
39        const SkPMColor* SK_RESTRICT srcEnd = src + count;
40        while (src != srcEnd) {
41            *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
42            dst += 1;
43            *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
44            dst += 1;
45        }
46#else
47        do {
48            *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale);
49            src += 1;
50            dst += 1;
51        } while (--count > 0);
52#endif
53    }
54}
55
56static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
57                                  const SkPMColor* SK_RESTRICT src,
58                                  int count, U8CPU alpha) {
59    SkASSERT(255 == alpha);
60    if (count > 0) {
61#ifdef UNROLL
62        if (count & 1) {
63            *dst = SkPMSrcOver(*(src++), *dst);
64            dst += 1;
65            count -= 1;
66        }
67
68        const SkPMColor* SK_RESTRICT srcEnd = src + count;
69        while (src != srcEnd) {
70            *dst = SkPMSrcOver(*(src++), *dst);
71            dst += 1;
72            *dst = SkPMSrcOver(*(src++), *dst);
73            dst += 1;
74        }
75#else
76        do {
77            *dst = SkPMSrcOver(*src, *dst);
78            src += 1;
79            dst += 1;
80        } while (--count > 0);
81#endif
82    }
83}
84
85static void S32A_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
86                                 const SkPMColor* SK_RESTRICT src,
87                                 int count, U8CPU alpha) {
88    SkASSERT(alpha <= 255);
89    if (count > 0) {
90#ifdef UNROLL
91        if (count & 1) {
92            *dst = SkBlendARGB32(*(src++), *dst, alpha);
93            dst += 1;
94            count -= 1;
95        }
96
97        const SkPMColor* SK_RESTRICT srcEnd = src + count;
98        while (src != srcEnd) {
99            *dst = SkBlendARGB32(*(src++), *dst, alpha);
100            dst += 1;
101            *dst = SkBlendARGB32(*(src++), *dst, alpha);
102            dst += 1;
103        }
104#else
105        do {
106            *dst = SkBlendARGB32(*src, *dst, alpha);
107            src += 1;
108            dst += 1;
109        } while (--count > 0);
110#endif
111    }
112}
113
114///////////////////////////////////////////////////////////////////////////////
115
116static const SkBlitRow::Proc32 gDefault_Procs32[] = {
117    S32_Opaque_BlitRow32,
118    S32_Blend_BlitRow32,
119    S32A_Opaque_BlitRow32,
120    S32A_Blend_BlitRow32
121};
122
123SkBlitRow::Proc32 SkBlitRow::Factory32(unsigned flags) {
124    SkASSERT(flags < SK_ARRAY_COUNT(gDefault_Procs32));
125    // just so we don't crash
126    flags &= kFlags32_Mask;
127
128    SkBlitRow::Proc32 proc = PlatformProcs32(flags);
129    if (NULL == proc) {
130        proc = gDefault_Procs32[flags];
131    }
132    SkASSERT(proc);
133    return proc;
134}
135
136SkBlitRow::Proc32 SkBlitRow::ColorProcFactory() {
137    SkBlitRow::ColorProc proc = PlatformColorProc();
138    if (NULL == proc) {
139        proc = Color32;
140    }
141    SkASSERT(proc);
142    return proc;
143}
144
145void SkBlitRow::Color32(SkPMColor* SK_RESTRICT dst,
146                        const SkPMColor* SK_RESTRICT src,
147                        int count, SkPMColor color) {
148    if (count > 0) {
149        if (0 == color) {
150            if (src != dst) {
151                memcpy(dst, src, count * sizeof(SkPMColor));
152            }
153            return;
154        }
155        unsigned colorA = SkGetPackedA32(color);
156        if (255 == colorA) {
157            sk_memset32(dst, color, count);
158        } else {
159            unsigned scale = 256 - SkAlpha255To256(colorA);
160            do {
161                *dst = color + SkAlphaMulQ(*src, scale);
162                src += 1;
163                dst += 1;
164            } while (--count);
165        }
166    }
167}
168
169template <size_t N> void assignLoop(SkPMColor* dst, SkPMColor color) {
170    for (size_t i = 0; i < N; ++i) {
171        *dst++ = color;
172    }
173}
174
175static inline void assignLoop(SkPMColor dst[], SkPMColor color, int count) {
176    while (count >= 4) {
177        *dst++ = color;
178        *dst++ = color;
179        *dst++ = color;
180        *dst++ = color;
181        count -= 4;
182    }
183    if (count >= 2) {
184        *dst++ = color;
185        *dst++ = color;
186        count -= 2;
187    }
188    if (count > 0) {
189        *dst++ = color;
190    }
191}
192
193void SkBlitRow::ColorRect32(SkPMColor* dst, int width, int height,
194                            size_t rowBytes, SkPMColor color) {
195    if (width <= 0 || height <= 0 || 0 == color) {
196        return;
197    }
198
199    // Just made up this value, since I saw it once in a SSE2 file.
200    // We should consider writing some tests to find the optimimal break-point
201    // (or query the Platform proc?)
202    static const int MIN_WIDTH_FOR_SCANLINE_PROC = 32;
203
204    bool isOpaque = (0xFF == SkGetPackedA32(color));
205
206    if (!isOpaque || width >= MIN_WIDTH_FOR_SCANLINE_PROC) {
207        SkBlitRow::ColorProc proc = SkBlitRow::ColorProcFactory();
208        while (--height >= 0) {
209            (*proc)(dst, dst, width, color);
210            dst = (SkPMColor*) ((char*)dst + rowBytes);
211        }
212    } else {
213        switch (width) {
214            case 1:
215                while (--height >= 0) {
216                    assignLoop<1>(dst, color);
217                    dst = (SkPMColor*) ((char*)dst + rowBytes);
218                }
219                break;
220            case 2:
221                while (--height >= 0) {
222                    assignLoop<2>(dst, color);
223                    dst = (SkPMColor*) ((char*)dst + rowBytes);
224                }
225                break;
226            case 3:
227                while (--height >= 0) {
228                    assignLoop<3>(dst, color);
229                    dst = (SkPMColor*) ((char*)dst + rowBytes);
230                }
231                break;
232            default:
233                while (--height >= 0) {
234                    assignLoop(dst, color, width);
235                    dst = (SkPMColor*) ((char*)dst + rowBytes);
236                }
237                break;
238        }
239    }
240}
241
242SkBlitRow::ColorRectProc SkBlitRow::ColorRectProcFactory() {
243    SkBlitRow::ColorRectProc proc = PlatformColorRectProcFactory();
244    if (NULL == proc) {
245        proc = ColorRect32;
246    }
247    SkASSERT(proc);
248    return proc;
249}
250