Coverage Report

Created: 2018-09-25 14:53

/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