/src/mozilla-central/gfx/2d/Swizzle.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "Swizzle.h" |
8 | | #include "Logging.h" |
9 | | #include "Tools.h" |
10 | | #include "mozilla/CheckedInt.h" |
11 | | #include "mozilla/EndianUtils.h" |
12 | | |
13 | | #ifdef USE_SSE2 |
14 | | #include "mozilla/SSE.h" |
15 | | #endif |
16 | | |
17 | | #ifdef BUILD_ARM_NEON |
18 | | #include "mozilla/arm.h" |
19 | | #endif |
20 | | |
21 | | namespace mozilla { |
22 | | namespace gfx { |
23 | | |
24 | | /** |
25 | | * Convenience macros for dispatching to various format combinations. |
26 | | */ |
27 | | |
28 | | // Hash the formats to a relatively dense value to optimize jump table generation. |
29 | | // The first 6 formats in SurfaceFormat are the 32-bit BGRA variants and are the most |
30 | | // common formats dispatched here. Room is reserved in the lowish bits for up to |
31 | | // these 6 destination formats. If a destination format is >= 6, the 6th bit is set |
32 | | // to avoid collisions. |
33 | | #define FORMAT_KEY(aSrcFormat, aDstFormat) \ |
34 | 0 | (int(aSrcFormat) * 6 + int(aDstFormat) + (int(int(aDstFormat) >= 6) << 6)) |
35 | | |
36 | | #define FORMAT_CASE_EXPR(aSrcFormat, aDstFormat, ...) \ |
37 | 0 | case FORMAT_KEY(aSrcFormat, aDstFormat): \ |
38 | 0 | __VA_ARGS__; \ |
39 | 0 | return true; |
40 | | |
41 | | #define FORMAT_CASE(aSrcFormat, aDstFormat, ...) \ |
42 | 0 | FORMAT_CASE_EXPR(aSrcFormat, aDstFormat, FORMAT_CASE_CALL(__VA_ARGS__)) |
43 | | |
44 | | /** |
45 | | * Constexpr functions for analyzing format attributes in templates. |
46 | | */ |
47 | | |
48 | | // Whether B comes before R in pixel memory layout. |
49 | | static constexpr bool |
50 | | IsBGRFormat(SurfaceFormat aFormat) |
51 | 0 | { |
52 | 0 | return aFormat == SurfaceFormat::B8G8R8A8 || |
53 | 0 | #if MOZ_LITTLE_ENDIAN |
54 | 0 | aFormat == SurfaceFormat::R5G6B5_UINT16 || |
55 | 0 | #endif |
56 | 0 | aFormat == SurfaceFormat::B8G8R8X8 || |
57 | 0 | aFormat == SurfaceFormat::B8G8R8; |
58 | 0 | } |
59 | | |
60 | | // Whether the order of B and R need to be swapped to map from src to dst. |
61 | | static constexpr bool |
62 | | ShouldSwapRB(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) |
63 | 0 | { |
64 | 0 | return IsBGRFormat(aSrcFormat) != IsBGRFormat(aDstFormat); |
65 | 0 | } |
66 | | |
67 | | // The starting byte of the RGB components in pixel memory. |
68 | | static constexpr uint32_t |
69 | | RGBByteIndex(SurfaceFormat aFormat) |
70 | 0 | { |
71 | 0 | return aFormat == SurfaceFormat::A8R8G8B8 || |
72 | 0 | aFormat == SurfaceFormat::X8R8G8B8 |
73 | 0 | ? 1 : 0; |
74 | 0 | } |
75 | | |
76 | | // The byte of the alpha component, which just comes after RGB. |
77 | | static constexpr uint32_t |
78 | | AlphaByteIndex(SurfaceFormat aFormat) |
79 | 0 | { |
80 | 0 | return (RGBByteIndex(aFormat) + 3) % 4; |
81 | 0 | } |
82 | | |
83 | | // The endian-dependent bit shift to access RGB of a UINT32 pixel. |
84 | | static constexpr uint32_t |
85 | | RGBBitShift(SurfaceFormat aFormat) |
86 | 0 | { |
87 | 0 | #if MOZ_LITTLE_ENDIAN |
88 | 0 | return 8 * RGBByteIndex(aFormat); |
89 | 0 | #else |
90 | 0 | return 24 - 8 * RGBByteIndex(aFormat); |
91 | 0 | #endif |
92 | 0 | } |
93 | | |
94 | | // The endian-dependent bit shift to access alpha of a UINT32 pixel. |
95 | | static constexpr uint32_t |
96 | | AlphaBitShift(SurfaceFormat aFormat) |
97 | 0 | { |
98 | 0 | return (RGBBitShift(aFormat) + 24) % 32; |
99 | 0 | } |
100 | | |
101 | | // Whether the pixel format should ignore the value of the alpha channel and treat it as opaque. |
102 | | static constexpr bool |
103 | | IgnoreAlpha(SurfaceFormat aFormat) |
104 | 0 | { |
105 | 0 | return aFormat == SurfaceFormat::B8G8R8X8 || |
106 | 0 | aFormat == SurfaceFormat::R8G8B8X8 || |
107 | 0 | aFormat == SurfaceFormat::X8R8G8B8; |
108 | 0 | } |
109 | | |
110 | | // Whether to force alpha to opaque to map from src to dst. |
111 | | static constexpr bool |
112 | | ShouldForceOpaque(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) |
113 | 0 | { |
114 | 0 | return IgnoreAlpha(aSrcFormat) != IgnoreAlpha(aDstFormat); |
115 | 0 | } |
116 | | |
117 | | #ifdef USE_SSE2 |
118 | | /** |
119 | | * SSE2 optimizations |
120 | | */ |
121 | | |
122 | | template<bool aSwapRB, bool aOpaqueAlpha> |
123 | | void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); |
124 | | |
125 | | #define PREMULTIPLY_SSE2(aSrcFormat, aDstFormat) \ |
126 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
127 | 0 | Premultiply_SSE2 \ |
128 | 0 | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
129 | 0 | ShouldForceOpaque(aSrcFormat, aDstFormat)>) |
130 | | |
131 | | template<bool aSwapRB> |
132 | | void Unpremultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); |
133 | | |
134 | | #define UNPREMULTIPLY_SSE2(aSrcFormat, aDstFormat) \ |
135 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
136 | 0 | Unpremultiply_SSE2<ShouldSwapRB(aSrcFormat, aDstFormat)>) |
137 | | |
138 | | template<bool aSwapRB, bool aOpaqueAlpha> |
139 | | void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); |
140 | | |
141 | | #define SWIZZLE_SSE2(aSrcFormat, aDstFormat) \ |
142 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
143 | 0 | Swizzle_SSE2 \ |
144 | 0 | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
145 | 0 | ShouldForceOpaque(aSrcFormat, aDstFormat)>) |
146 | | |
147 | | #endif |
148 | | |
149 | | #ifdef BUILD_ARM_NEON |
150 | | /** |
151 | | * ARM NEON optimizations |
152 | | */ |
153 | | |
154 | | template<bool aSwapRB, bool aOpaqueAlpha> |
155 | | void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); |
156 | | |
157 | | #define PREMULTIPLY_NEON(aSrcFormat, aDstFormat) \ |
158 | | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
159 | | Premultiply_NEON \ |
160 | | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
161 | | ShouldForceOpaque(aSrcFormat, aDstFormat)>) |
162 | | |
163 | | template<bool aSwapRB> |
164 | | void Unpremultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); |
165 | | |
166 | | #define UNPREMULTIPLY_NEON(aSrcFormat, aDstFormat) \ |
167 | | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
168 | | Unpremultiply_NEON<ShouldSwapRB(aSrcFormat, aDstFormat)>) |
169 | | |
170 | | template<bool aSwapRB, bool aOpaqueAlpha> |
171 | | void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); |
172 | | |
173 | | #define SWIZZLE_NEON(aSrcFormat, aDstFormat) \ |
174 | | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
175 | | Swizzle_NEON \ |
176 | | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
177 | | ShouldForceOpaque(aSrcFormat, aDstFormat)>) |
178 | | |
179 | | #endif |
180 | | |
181 | | /** |
182 | | * Premultiplying |
183 | | */ |
184 | | |
185 | | // Fallback premultiply implementation that uses splayed pixel math to reduce the |
186 | | // multiplications used. That is, the R and B components are isolated from the G and A |
187 | | // components, which then can be multiplied as if they were two 2-component vectors. |
188 | | // Otherwise, an approximation if divide-by-255 is used which is faster than an actual |
189 | | // division. These optimizations are also used for the SSE2 and NEON implementations. |
190 | | template<bool aSwapRB, bool aOpaqueAlpha, |
191 | | uint32_t aSrcRGBShift, uint32_t aSrcAShift, |
192 | | uint32_t aDstRGBShift, uint32_t aDstAShift> |
193 | | static void |
194 | | PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap, |
195 | | uint8_t* aDst, int32_t aDstGap, |
196 | | IntSize aSize) |
197 | 0 | { |
198 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
199 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
200 | 0 | do { |
201 | 0 | // Load and process 1 entire pixel at a time. |
202 | 0 | uint32_t color = *reinterpret_cast<const uint32_t*>(aSrc); |
203 | 0 |
|
204 | 0 | uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF; |
205 | 0 |
|
206 | 0 | // Isolate the R and B components. |
207 | 0 | uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF; |
208 | 0 | // Swap the order of R and B if necessary. |
209 | 0 | if (aSwapRB) { |
210 | 0 | rb = (rb >> 16) | (rb << 16); |
211 | 0 | } |
212 | 0 | // Approximate the multiply by alpha and divide by 255 which is essentially: |
213 | 0 | // c = c*a + 255; c = (c + (c >> 8)) >> 8; |
214 | 0 | // However, we omit the final >> 8 to fold it with the final shift into place |
215 | 0 | // depending on desired output format. |
216 | 0 | rb = rb*a + 0x00FF00FF; |
217 | 0 | rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00; |
218 | 0 |
|
219 | 0 | // Use same approximation as above, but G is shifted 8 bits left. |
220 | 0 | // Alpha is left out and handled separately. |
221 | 0 | uint32_t g = color & (0xFF00 << aSrcRGBShift); |
222 | 0 | g = g*a + (0xFF00 << aSrcRGBShift); |
223 | 0 | g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift); |
224 | 0 |
|
225 | 0 | // The above math leaves RGB shifted left by 8 bits. |
226 | 0 | // Shift them right if required for the output format. |
227 | 0 | // then combine them back together to produce output pixel. |
228 | 0 | // Add the alpha back on if the output format is not opaque. |
229 | 0 | *reinterpret_cast<uint32_t*>(aDst) = |
230 | 0 | (rb >> (8 - aDstRGBShift)) | |
231 | 0 | (g >> (8 + aSrcRGBShift - aDstRGBShift)) | |
232 | 0 | (aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift); |
233 | 0 |
|
234 | 0 | aSrc += 4; |
235 | 0 | aDst += 4; |
236 | 0 | } while (aSrc < end); |
237 | 0 |
|
238 | 0 | aSrc += aSrcGap; |
239 | 0 | aDst += aDstGap; |
240 | 0 | } |
241 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, false, 0u, 24u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, true, 0u, 24u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<true, false, 0u, 24u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<true, true, 0u, 24u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<true, false, 0u, 24u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<true, true, 0u, 24u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, false, 0u, 24u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, true, 0u, 24u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<true, false, 8u, 0u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<true, true, 8u, 0u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, false, 8u, 0u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, true, 8u, 0u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, false, 8u, 0u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PremultiplyFallback<false, true, 8u, 0u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
242 | | |
243 | | #define PREMULTIPLY_FALLBACK_CASE(aSrcFormat, aDstFormat) \ |
244 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
245 | 0 | PremultiplyFallback \ |
246 | 0 | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
247 | 0 | ShouldForceOpaque(aSrcFormat, aDstFormat), \ |
248 | 0 | RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \ |
249 | 0 | RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>) |
250 | | |
251 | | #define PREMULTIPLY_FALLBACK(aSrcFormat) \ |
252 | 0 | PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8A8) \ |
253 | 0 | PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8X8) \ |
254 | 0 | PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8A8) \ |
255 | 0 | PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8X8) \ |
256 | 0 | PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \ |
257 | 0 | PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8) |
258 | | |
259 | | // If rows are tightly packed, and the size of the total area will fit within |
260 | | // the precision range of a single row, then process all the data as if it was |
261 | | // a single row. |
262 | | static inline IntSize |
263 | | CollapseSize(const IntSize& aSize, int32_t aSrcStride, int32_t aDstStride) |
264 | 0 | { |
265 | 0 | if (aSrcStride == aDstStride && |
266 | 0 | (aSrcStride & 3) == 0 && |
267 | 0 | aSrcStride / 4 == aSize.width) { |
268 | 0 | CheckedInt32 area = CheckedInt32(aSize.width) * CheckedInt32(aSize.height); |
269 | 0 | if (area.isValid()) { |
270 | 0 | return IntSize(area.value(), 1); |
271 | 0 | } |
272 | 0 | } |
273 | 0 | return aSize; |
274 | 0 | } |
275 | | |
276 | | static inline int32_t |
277 | | GetStrideGap(int32_t aWidth, SurfaceFormat aFormat, int32_t aStride) |
278 | 0 | { |
279 | 0 | CheckedInt32 used = CheckedInt32(aWidth) * BytesPerPixel(aFormat); |
280 | 0 | if (!used.isValid() || used.value() < 0) { |
281 | 0 | return -1; |
282 | 0 | } |
283 | 0 | return aStride - used.value(); |
284 | 0 | } |
285 | | |
286 | | bool |
287 | | PremultiplyData(const uint8_t* aSrc, int32_t aSrcStride, SurfaceFormat aSrcFormat, |
288 | | uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat, |
289 | | const IntSize& aSize) |
290 | 0 | { |
291 | 0 | if (aSize.IsEmpty()) { |
292 | 0 | return true; |
293 | 0 | } |
294 | 0 | IntSize size = CollapseSize(aSize, aSrcStride, aDstStride); |
295 | 0 | // Find gap from end of row to the start of the next row. |
296 | 0 | int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride); |
297 | 0 | int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride); |
298 | 0 | MOZ_ASSERT(srcGap >= 0 && dstGap >= 0); |
299 | 0 | if (srcGap < 0 || dstGap < 0) { |
300 | 0 | return false; |
301 | 0 | } |
302 | 0 | |
303 | 0 | #define FORMAT_CASE_CALL(...) __VA_ARGS__(aSrc, srcGap, aDst, dstGap, size) |
304 | 0 | |
305 | 0 | #ifdef USE_SSE2 |
306 | 0 | if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
307 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8) |
308 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8) |
309 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
310 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) |
311 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8) |
312 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8) |
313 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
314 | 0 | PREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) |
315 | 0 | default: break; |
316 | 0 | } |
317 | 0 | #endif |
318 | 0 | |
319 | | #ifdef BUILD_ARM_NEON |
320 | | if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
321 | | PREMULTIPLY_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8) |
322 | | PREMULTIPLY_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8) |
323 | | PREMULTIPLY_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
324 | | PREMULTIPLY_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) |
325 | | PREMULTIPLY_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8) |
326 | | PREMULTIPLY_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8) |
327 | | PREMULTIPLY_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
328 | | PREMULTIPLY_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) |
329 | | default: break; |
330 | | } |
331 | | #endif |
332 | | |
333 | 0 | switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
334 | 0 | PREMULTIPLY_FALLBACK(SurfaceFormat::B8G8R8A8) |
335 | 0 | PREMULTIPLY_FALLBACK(SurfaceFormat::R8G8B8A8) |
336 | 0 | PREMULTIPLY_FALLBACK(SurfaceFormat::A8R8G8B8) |
337 | 0 | default: break; |
338 | 0 | } |
339 | 0 | |
340 | 0 | #undef FORMAT_CASE_CALL |
341 | 0 | |
342 | 0 | MOZ_ASSERT(false, "Unsupported premultiply formats"); |
343 | 0 | return false; |
344 | 0 | } |
345 | | |
346 | | /** |
347 | | * Unpremultiplying |
348 | | */ |
349 | | |
350 | | // Generate a table of 8.16 fixed-point reciprocals representing 1/alpha. |
351 | | #define UNPREMULQ(x) (0xFF00FFU / (x)) |
352 | | #define UNPREMULQ_2(x) UNPREMULQ(x), UNPREMULQ((x) + 1) |
353 | | #define UNPREMULQ_4(x) UNPREMULQ_2(x), UNPREMULQ_2((x) + 2) |
354 | | #define UNPREMULQ_8(x) UNPREMULQ_4(x), UNPREMULQ_4((x) + 4) |
355 | | #define UNPREMULQ_16(x) UNPREMULQ_8(x), UNPREMULQ_8((x) + 8) |
356 | | #define UNPREMULQ_32(x) UNPREMULQ_16(x), UNPREMULQ_16((x) + 16) |
357 | | static const uint32_t sUnpremultiplyTable[256] = |
358 | | { |
359 | | 0, UNPREMULQ(1), UNPREMULQ_2(2), UNPREMULQ_4(4), |
360 | | UNPREMULQ_8(8), UNPREMULQ_16(16), UNPREMULQ_32(32), |
361 | | UNPREMULQ_32(64), UNPREMULQ_32(96), UNPREMULQ_32(128), |
362 | | UNPREMULQ_32(160), UNPREMULQ_32(192), UNPREMULQ_32(224) |
363 | | }; |
364 | | |
365 | | // Fallback unpremultiply implementation that uses 8.16 fixed-point reciprocal math |
366 | | // to eliminate any division by the alpha component. This optimization is used for the |
367 | | // SSE2 and NEON implementations, with some adaptations. This implementation also accesses |
368 | | // color components using individual byte accesses as this profiles faster than accessing |
369 | | // the pixel as a uint32_t and shifting/masking to access components. |
370 | | template<bool aSwapRB, |
371 | | uint32_t aSrcRGBIndex, uint32_t aSrcAIndex, |
372 | | uint32_t aDstRGBIndex, uint32_t aDstAIndex> |
373 | | static void |
374 | | UnpremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap, |
375 | | uint8_t* aDst, int32_t aDstGap, |
376 | | IntSize aSize) |
377 | 0 | { |
378 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
379 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
380 | 0 | do { |
381 | 0 | uint8_t r = aSrc[aSrcRGBIndex + (aSwapRB ? 2 : 0)]; |
382 | 0 | uint8_t g = aSrc[aSrcRGBIndex + 1]; |
383 | 0 | uint8_t b = aSrc[aSrcRGBIndex + (aSwapRB ? 0 : 2)]; |
384 | 0 | uint8_t a = aSrc[aSrcAIndex]; |
385 | 0 |
|
386 | 0 | // Access the 8.16 reciprocal from the table based on alpha. Multiply by the |
387 | 0 | // reciprocal and shift off the fraction bits to approximate the division by alpha. |
388 | 0 | uint32_t q = sUnpremultiplyTable[a]; |
389 | 0 | aDst[aDstRGBIndex + 0] = (r * q) >> 16; |
390 | 0 | aDst[aDstRGBIndex + 1] = (g * q) >> 16; |
391 | 0 | aDst[aDstRGBIndex + 2] = (b * q) >> 16; |
392 | 0 | aDst[aDstAIndex] = a; |
393 | 0 |
|
394 | 0 | aSrc += 4; |
395 | 0 | aDst += 4; |
396 | 0 | } while (aSrc < end); |
397 | 0 |
|
398 | 0 | aSrc += aSrcGap; |
399 | 0 | aDst += aDstGap; |
400 | 0 | } |
401 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<false, 0u, 3u, 0u, 3u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<true, 0u, 3u, 0u, 3u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<true, 0u, 3u, 1u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<false, 0u, 3u, 1u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<true, 1u, 0u, 0u, 3u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<false, 1u, 0u, 0u, 3u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::UnpremultiplyFallback<false, 1u, 0u, 1u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
402 | | |
403 | | #define UNPREMULTIPLY_FALLBACK_CASE(aSrcFormat, aDstFormat) \ |
404 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
405 | 0 | UnpremultiplyFallback \ |
406 | 0 | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
407 | 0 | RGBByteIndex(aSrcFormat), AlphaByteIndex(aSrcFormat), \ |
408 | 0 | RGBByteIndex(aDstFormat), AlphaByteIndex(aDstFormat)>) |
409 | | |
410 | | #define UNPREMULTIPLY_FALLBACK(aSrcFormat) \ |
411 | 0 | UNPREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8A8) \ |
412 | 0 | UNPREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8A8) \ |
413 | 0 | UNPREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) |
414 | | |
415 | | bool |
416 | | UnpremultiplyData(const uint8_t* aSrc, int32_t aSrcStride, SurfaceFormat aSrcFormat, |
417 | | uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat, |
418 | | const IntSize& aSize) |
419 | 0 | { |
420 | 0 | if (aSize.IsEmpty()) { |
421 | 0 | return true; |
422 | 0 | } |
423 | 0 | IntSize size = CollapseSize(aSize, aSrcStride, aDstStride); |
424 | 0 | // Find gap from end of row to the start of the next row. |
425 | 0 | int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride); |
426 | 0 | int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride); |
427 | 0 | MOZ_ASSERT(srcGap >= 0 && dstGap >= 0); |
428 | 0 | if (srcGap < 0 || dstGap < 0) { |
429 | 0 | return false; |
430 | 0 | } |
431 | 0 | |
432 | 0 | #define FORMAT_CASE_CALL(...) __VA_ARGS__(aSrc, srcGap, aDst, dstGap, size) |
433 | 0 | |
434 | 0 | #ifdef USE_SSE2 |
435 | 0 | if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
436 | 0 | UNPREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8) |
437 | 0 | UNPREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
438 | 0 | UNPREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8) |
439 | 0 | UNPREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
440 | 0 | default: break; |
441 | 0 | } |
442 | 0 | #endif |
443 | 0 | |
444 | | #ifdef BUILD_ARM_NEON |
445 | | if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
446 | | UNPREMULTIPLY_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8) |
447 | | UNPREMULTIPLY_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
448 | | UNPREMULTIPLY_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8) |
449 | | UNPREMULTIPLY_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
450 | | default: break; |
451 | | } |
452 | | #endif |
453 | | |
454 | 0 | switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
455 | 0 | UNPREMULTIPLY_FALLBACK(SurfaceFormat::B8G8R8A8) |
456 | 0 | UNPREMULTIPLY_FALLBACK(SurfaceFormat::R8G8B8A8) |
457 | 0 | UNPREMULTIPLY_FALLBACK(SurfaceFormat::A8R8G8B8) |
458 | 0 | default: break; |
459 | 0 | } |
460 | 0 | |
461 | 0 | #undef FORMAT_CASE_CALL |
462 | 0 | |
463 | 0 | MOZ_ASSERT(false, "Unsupported unpremultiply formats"); |
464 | 0 | return false; |
465 | 0 | } |
466 | | |
467 | | /** |
468 | | * Swizzling |
469 | | */ |
470 | | |
471 | | // Fallback swizzle implementation that uses shifting and masking to reorder pixels. |
472 | | template<bool aSwapRB, bool aOpaqueAlpha, |
473 | | uint32_t aSrcRGBShift, uint32_t aSrcAShift, |
474 | | uint32_t aDstRGBShift, uint32_t aDstAShift> |
475 | | static void |
476 | | SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, |
477 | | uint8_t* aDst, int32_t aDstGap, |
478 | | IntSize aSize) |
479 | 0 | { |
480 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
481 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
482 | 0 | do { |
483 | 0 | uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc); |
484 | 0 |
|
485 | 0 | if (aSwapRB) { |
486 | 0 | // Handle R and B swaps by exchanging words and masking. |
487 | 0 | uint32_t rb = ((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift); |
488 | 0 | uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift)); |
489 | 0 | rgba = rb | ga; |
490 | 0 | } |
491 | 0 |
|
492 | 0 | // If src and dst shifts differ, rotate left or right to move RGB into place, |
493 | 0 | // i.e. ARGB -> RGBA or ARGB -> RGBA. |
494 | 0 | if (aDstRGBShift > aSrcRGBShift) { |
495 | 0 | rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24); |
496 | 0 | } else if (aSrcRGBShift > aDstRGBShift) { |
497 | 0 | rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24); |
498 | 0 | } else if (aOpaqueAlpha) { |
499 | 0 | rgba |= 0xFF << aDstAShift; |
500 | 0 | } |
501 | 0 |
|
502 | 0 | *reinterpret_cast<uint32_t*>(aDst) = rgba; |
503 | 0 |
|
504 | 0 | aSrc += 4; |
505 | 0 | aDst += 4; |
506 | 0 | } while (aSrc < end); |
507 | 0 |
|
508 | 0 | aSrc += aSrcGap; |
509 | 0 | aDst += aDstGap; |
510 | 0 | } |
511 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleFallback<true, false, 0u, 24u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleFallback<true, true, 0u, 24u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleFallback<false, false, 0u, 24u, 8u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleFallback<false, false, 8u, 0u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleFallback<false, true, 8u, 0u, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
512 | | |
513 | | #define SWIZZLE_FALLBACK(aSrcFormat, aDstFormat) \ |
514 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
515 | 0 | SwizzleFallback \ |
516 | 0 | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
517 | 0 | ShouldForceOpaque(aSrcFormat, aDstFormat), \ |
518 | 0 | RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \ |
519 | 0 | RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>) |
520 | | |
521 | | // Fast-path for matching formats. |
522 | | static void |
523 | | SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, |
524 | | uint8_t* aDst, int32_t aDstGap, |
525 | | IntSize aSize, int32_t aBPP) |
526 | 0 | { |
527 | 0 | if (aSrc != aDst) { |
528 | 0 | int32_t rowLength = aBPP * aSize.width; |
529 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
530 | 0 | memcpy(aDst, aSrc, rowLength); |
531 | 0 | aSrc += rowLength + aSrcGap; |
532 | 0 | aDst += rowLength + aDstGap; |
533 | 0 | } |
534 | 0 | } |
535 | 0 | } |
536 | | |
537 | | // Fast-path for conversions that swap all bytes. |
538 | | template<bool aOpaqueAlpha, uint32_t aSrcAShift, uint32_t aDstAShift> |
539 | | static void |
540 | | SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, |
541 | | uint8_t* aDst, int32_t aDstGap, |
542 | | IntSize aSize) |
543 | 0 | { |
544 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
545 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
546 | 0 | do { |
547 | 0 | // Use an endian swap to move the bytes, i.e. BGRA -> ARGB. |
548 | 0 | uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc); |
549 | 0 | #if MOZ_LITTLE_ENDIAN |
550 | 0 | rgba = NativeEndian::swapToBigEndian(rgba); |
551 | | #else |
552 | | rgba = NativeEndian::swapToLittleEndian(rgba); |
553 | | #endif |
554 | 0 | if (aOpaqueAlpha) { |
555 | 0 | rgba |= 0xFF << aDstAShift; |
556 | 0 | } |
557 | 0 | *reinterpret_cast<uint32_t*>(aDst) = rgba; |
558 | 0 | aSrc += 4; |
559 | 0 | aDst += 4; |
560 | 0 | } while (aSrc < end); |
561 | 0 | aSrc += aSrcGap; |
562 | 0 | aDst += aDstGap; |
563 | 0 | } |
564 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleSwap<false, 24u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleSwap<true, 24u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleSwap<false, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleSwap<true, 0u, 24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
565 | | |
566 | | #define SWIZZLE_SWAP(aSrcFormat, aDstFormat) \ |
567 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
568 | 0 | SwizzleSwap \ |
569 | 0 | <ShouldForceOpaque(aSrcFormat, aDstFormat), \ |
570 | 0 | AlphaBitShift(aSrcFormat), AlphaBitShift(aDstFormat)>) |
571 | | |
572 | | // Fast-path for conversions that force alpha to opaque. |
573 | | template<uint32_t aDstAShift> |
574 | | static void |
575 | | SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, |
576 | | uint8_t* aDst, int32_t aDstGap, |
577 | | IntSize aSize) |
578 | 0 | { |
579 | 0 | if (aSrc == aDst) { |
580 | 0 | // Modifying in-place, so just write out the alpha. |
581 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
582 | 0 | const uint8_t* end = aDst + 4 * aSize.width; |
583 | 0 | do { |
584 | 0 | // ORing directly onto destination memory profiles faster than writing |
585 | 0 | // individually to the alpha byte and also profiles equivalently to a |
586 | 0 | // SSE2 implementation. |
587 | 0 | *reinterpret_cast<uint32_t*>(aDst) |= 0xFF << aDstAShift; |
588 | 0 | aDst += 4; |
589 | 0 | } while (aDst < end); |
590 | 0 | aDst += aDstGap; |
591 | 0 | } |
592 | 0 | } else { |
593 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
594 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
595 | 0 | do { |
596 | 0 | uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc); |
597 | 0 | // Just add on the alpha bits to the source. |
598 | 0 | rgba |= 0xFF << aDstAShift; |
599 | 0 | *reinterpret_cast<uint32_t*>(aDst) = rgba; |
600 | 0 | aSrc += 4; |
601 | 0 | aDst += 4; |
602 | 0 | } while (aSrc < end); |
603 | 0 | aSrc += aSrcGap; |
604 | 0 | aDst += aDstGap; |
605 | 0 | } |
606 | 0 | } |
607 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleOpaque<24u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::SwizzleOpaque<0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
608 | | |
609 | | #define SWIZZLE_OPAQUE(aSrcFormat, aDstFormat) \ |
610 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
611 | 0 | SwizzleOpaque<AlphaBitShift(aDstFormat)>) |
612 | | |
613 | | // Packing of 32-bit formats to RGB565. |
614 | | template<bool aSwapRB, uint32_t aSrcRGBShift, uint32_t aSrcRGBIndex> |
615 | | static void |
616 | | PackToRGB565(const uint8_t* aSrc, int32_t aSrcGap, |
617 | | uint8_t* aDst, int32_t aDstGap, |
618 | | IntSize aSize) |
619 | 0 | { |
620 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
621 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
622 | 0 | do { |
623 | 0 | uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc); |
624 | 0 |
|
625 | 0 | // Isolate the R, G, and B components and shift to final endian-dependent locations. |
626 | 0 | uint16_t rgb565; |
627 | 0 | if (aSwapRB) { |
628 | 0 | rgb565 = ((rgba & (0xF8 << aSrcRGBShift)) << (8 - aSrcRGBShift)) | |
629 | 0 | ((rgba & (0xFC00 << aSrcRGBShift)) >> (5 + aSrcRGBShift)) | |
630 | 0 | ((rgba & (0xF80000 << aSrcRGBShift)) >> (19 + aSrcRGBShift)); |
631 | 0 | } else { |
632 | 0 | rgb565 = ((rgba & (0xF8 << aSrcRGBShift)) >> (3 + aSrcRGBShift)) | |
633 | 0 | ((rgba & (0xFC00 << aSrcRGBShift)) >> (5 + aSrcRGBShift)) | |
634 | 0 | ((rgba & (0xF80000 << aSrcRGBShift)) >> (8 + aSrcRGBShift)); |
635 | 0 | } |
636 | 0 |
|
637 | 0 | *reinterpret_cast<uint16_t*>(aDst) = rgb565; |
638 | 0 |
|
639 | 0 | aSrc += 4; |
640 | 0 | aDst += 2; |
641 | 0 | } while (aSrc < end); |
642 | 0 |
|
643 | 0 | aSrc += aSrcGap; |
644 | 0 | aDst += aDstGap; |
645 | 0 | } |
646 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB565<false, 0u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB565<true, 0u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB565<true, 8u, 1u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
647 | | |
648 | | // Packing of 32-bit formats to 24-bit formats. |
649 | | template<bool aSwapRB, uint32_t aSrcRGBShift, uint32_t aSrcRGBIndex> |
650 | | static void |
651 | | PackToRGB24(const uint8_t* aSrc, int32_t aSrcGap, |
652 | | uint8_t* aDst, int32_t aDstGap, |
653 | | IntSize aSize) |
654 | 0 | { |
655 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
656 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
657 | 0 | do { |
658 | 0 | uint8_t r = aSrc[aSrcRGBIndex + (aSwapRB ? 2 : 0)]; |
659 | 0 | uint8_t g = aSrc[aSrcRGBIndex + 1]; |
660 | 0 | uint8_t b = aSrc[aSrcRGBIndex + (aSwapRB ? 0 : 2)]; |
661 | 0 |
|
662 | 0 | aDst[0] = r; |
663 | 0 | aDst[1] = g; |
664 | 0 | aDst[2] = b; |
665 | 0 |
|
666 | 0 | aSrc += 4; |
667 | 0 | aDst += 3; |
668 | 0 | } while (aSrc < end); |
669 | 0 |
|
670 | 0 | aSrc += aSrcGap; |
671 | 0 | aDst += aDstGap; |
672 | 0 | } |
673 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB24<false, 0u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB24<true, 0u, 0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB24<true, 8u, 1u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToRGB24<false, 8u, 1u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
674 | | |
675 | | #define PACK_RGB_CASE(aSrcFormat, aDstFormat, aPackFunc) \ |
676 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
677 | 0 | aPackFunc \ |
678 | 0 | <ShouldSwapRB(aSrcFormat, aDstFormat), \ |
679 | 0 | RGBBitShift(aSrcFormat), RGBByteIndex(aSrcFormat)>) |
680 | | |
681 | | #define PACK_RGB(aDstFormat, aPackFunc) \ |
682 | 0 | PACK_RGB_CASE(SurfaceFormat::B8G8R8A8, aDstFormat, aPackFunc) \ |
683 | 0 | PACK_RGB_CASE(SurfaceFormat::B8G8R8X8, aDstFormat, aPackFunc) \ |
684 | 0 | PACK_RGB_CASE(SurfaceFormat::R8G8B8A8, aDstFormat, aPackFunc) \ |
685 | 0 | PACK_RGB_CASE(SurfaceFormat::R8G8B8X8, aDstFormat, aPackFunc) \ |
686 | 0 | PACK_RGB_CASE(SurfaceFormat::A8R8G8B8, aDstFormat, aPackFunc) \ |
687 | 0 | PACK_RGB_CASE(SurfaceFormat::X8R8G8B8, aDstFormat, aPackFunc) |
688 | | |
689 | | // Packing of 32-bit formats to A8. |
690 | | template<uint32_t aSrcAIndex> |
691 | | static void |
692 | | PackToA8(const uint8_t* aSrc, int32_t aSrcGap, |
693 | | uint8_t* aDst, int32_t aDstGap, |
694 | | IntSize aSize) |
695 | 0 | { |
696 | 0 | for (int32_t height = aSize.height; height > 0; height--) { |
697 | 0 | const uint8_t* end = aSrc + 4 * aSize.width; |
698 | 0 | do { |
699 | 0 | *aDst++ = aSrc[aSrcAIndex]; |
700 | 0 | aSrc += 4; |
701 | 0 | } while (aSrc < end); |
702 | 0 | aSrc += aSrcGap; |
703 | 0 | aDst += aDstGap; |
704 | 0 | } |
705 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToA8<3u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) Unexecuted instantiation: Unified_cpp_gfx_2d2.cpp:void mozilla::gfx::PackToA8<0u>(unsigned char const*, int, unsigned char*, int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>) |
706 | | |
707 | | #define PACK_ALPHA_CASE(aSrcFormat, aDstFormat, aPackFunc) \ |
708 | 0 | FORMAT_CASE(aSrcFormat, aDstFormat, \ |
709 | 0 | aPackFunc<AlphaByteIndex(aSrcFormat)>) |
710 | | |
711 | | #define PACK_ALPHA(aDstFormat, aPackFunc) \ |
712 | 0 | PACK_ALPHA_CASE(SurfaceFormat::B8G8R8A8, aDstFormat, aPackFunc) \ |
713 | 0 | PACK_ALPHA_CASE(SurfaceFormat::R8G8B8A8, aDstFormat, aPackFunc) \ |
714 | 0 | PACK_ALPHA_CASE(SurfaceFormat::A8R8G8B8, aDstFormat, aPackFunc) |
715 | | |
716 | | bool |
717 | | SwizzleData(const uint8_t* aSrc, int32_t aSrcStride, SurfaceFormat aSrcFormat, |
718 | | uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat, |
719 | | const IntSize& aSize) |
720 | 0 | { |
721 | 0 | if (aSize.IsEmpty()) { |
722 | 0 | return true; |
723 | 0 | } |
724 | 0 | IntSize size = CollapseSize(aSize, aSrcStride, aDstStride); |
725 | 0 | // Find gap from end of row to the start of the next row. |
726 | 0 | int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride); |
727 | 0 | int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride); |
728 | 0 | MOZ_ASSERT(srcGap >= 0 && dstGap >= 0); |
729 | 0 | if (srcGap < 0 || dstGap < 0) { |
730 | 0 | return false; |
731 | 0 | } |
732 | 0 | |
733 | 0 | #define FORMAT_CASE_CALL(...) __VA_ARGS__(aSrc, srcGap, aDst, dstGap, size) |
734 | 0 | |
735 | 0 | #ifdef USE_SSE2 |
736 | 0 | if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
737 | 0 | SWIZZLE_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
738 | 0 | SWIZZLE_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8) |
739 | 0 | SWIZZLE_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) |
740 | 0 | SWIZZLE_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8) |
741 | 0 | SWIZZLE_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
742 | 0 | SWIZZLE_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8) |
743 | 0 | SWIZZLE_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) |
744 | 0 | SWIZZLE_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8) |
745 | 0 | default: break; |
746 | 0 | } |
747 | 0 | #endif |
748 | 0 | |
749 | | #ifdef BUILD_ARM_NEON |
750 | | if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
751 | | SWIZZLE_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
752 | | SWIZZLE_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8) |
753 | | SWIZZLE_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) |
754 | | SWIZZLE_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8) |
755 | | SWIZZLE_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
756 | | SWIZZLE_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8) |
757 | | SWIZZLE_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) |
758 | | SWIZZLE_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8) |
759 | | default: break; |
760 | | } |
761 | | #endif |
762 | | |
763 | 0 | switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { |
764 | 0 |
|
765 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) |
766 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8) |
767 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) |
768 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8) |
769 | 0 |
|
770 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) |
771 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8) |
772 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) |
773 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8) |
774 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::A8R8G8B8) |
775 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::X8R8G8B8) |
776 | 0 |
|
777 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::A8R8G8B8, SurfaceFormat::R8G8B8A8) |
778 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::X8R8G8B8, SurfaceFormat::R8G8B8X8) |
779 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::A8R8G8B8, SurfaceFormat::R8G8B8X8) |
780 | 0 | SWIZZLE_FALLBACK(SurfaceFormat::X8R8G8B8, SurfaceFormat::R8G8B8A8) |
781 | 0 |
|
782 | 0 | SWIZZLE_SWAP(SurfaceFormat::B8G8R8A8, SurfaceFormat::A8R8G8B8) |
783 | 0 | SWIZZLE_SWAP(SurfaceFormat::B8G8R8A8, SurfaceFormat::X8R8G8B8) |
784 | 0 | SWIZZLE_SWAP(SurfaceFormat::B8G8R8X8, SurfaceFormat::X8R8G8B8) |
785 | 0 | SWIZZLE_SWAP(SurfaceFormat::B8G8R8X8, SurfaceFormat::A8R8G8B8) |
786 | 0 | SWIZZLE_SWAP(SurfaceFormat::A8R8G8B8, SurfaceFormat::B8G8R8A8) |
787 | 0 | SWIZZLE_SWAP(SurfaceFormat::A8R8G8B8, SurfaceFormat::B8G8R8X8) |
788 | 0 | SWIZZLE_SWAP(SurfaceFormat::X8R8G8B8, SurfaceFormat::B8G8R8X8) |
789 | 0 | SWIZZLE_SWAP(SurfaceFormat::X8R8G8B8, SurfaceFormat::B8G8R8A8) |
790 | 0 |
|
791 | 0 | SWIZZLE_OPAQUE(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8) |
792 | 0 | SWIZZLE_OPAQUE(SurfaceFormat::B8G8R8X8, SurfaceFormat::B8G8R8A8) |
793 | 0 | SWIZZLE_OPAQUE(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8) |
794 | 0 | SWIZZLE_OPAQUE(SurfaceFormat::R8G8B8X8, SurfaceFormat::R8G8B8A8) |
795 | 0 | SWIZZLE_OPAQUE(SurfaceFormat::A8R8G8B8, SurfaceFormat::X8R8G8B8) |
796 | 0 | SWIZZLE_OPAQUE(SurfaceFormat::X8R8G8B8, SurfaceFormat::A8R8G8B8) |
797 | 0 |
|
798 | 0 | PACK_RGB(SurfaceFormat::R5G6B5_UINT16, PackToRGB565) |
799 | 0 | PACK_RGB(SurfaceFormat::B8G8R8, PackToRGB24) |
800 | 0 | PACK_RGB(SurfaceFormat::R8G8B8, PackToRGB24) |
801 | 0 | PACK_ALPHA(SurfaceFormat::A8, PackToA8) |
802 | 0 |
|
803 | 0 | default: break; |
804 | 0 | } |
805 | 0 | |
806 | 0 | if (aSrcFormat == aDstFormat) { |
807 | 0 | // If the formats match, just do a generic copy. |
808 | 0 | SwizzleCopy(aSrc, srcGap, aDst, dstGap, size, BytesPerPixel(aSrcFormat)); |
809 | 0 | return true; |
810 | 0 | } |
811 | 0 | |
812 | 0 | #undef FORMAT_CASE_CALL |
813 | 0 | |
814 | 0 | MOZ_ASSERT(false, "Unsupported swizzle formats"); |
815 | 0 | return false; |
816 | 0 | } |
817 | | |
818 | | } // namespace gfx |
819 | | } // namespace mozilla |