1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Copyright (C) 2010 Mozilla Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29
30#if USE(3D_GRAPHICS)
31
32#include "FormatConverter.h"
33
34#if HAVE(ARM_NEON_INTRINSICS)
35#include "GraphicsContext3DNEON.h"
36#endif
37
38// Visual Studio crashes with a C1063 Fatal Error if everything is inlined.
39#if COMPILER(MSVC)
40#define ALWAYS_INLINE_EXCEPT_MSVC
41#else
42#define ALWAYS_INLINE_EXCEPT_MSVC ALWAYS_INLINE
43#endif
44
45namespace WebCore {
46
47
48// Following Float to Half-Float converion code is from the implementation of ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf,
49// "Fast Half Float Conversions" by Jeroen van der Zijp, November 2008 (Revised September 2010).
50// Specially, the basetable[512] and shifttable[512] are generated as follows:
51/*
52unsigned short basetable[512];
53unsigned char shifttable[512];
54
55void generatetables(){
56    unsigned int i;
57    int e;
58    for (i = 0; i < 256; ++i){
59        e = i - 127;
60        if (e < -24){ // Very small numbers map to zero
61            basetable[i | 0x000] = 0x0000;
62            basetable[i | 0x100] = 0x8000;
63            shifttable[i | 0x000] = 24;
64            shifttable[i | 0x100] = 24;
65        }
66        else if (e < -14) { // Small numbers map to denorms
67            basetable[i | 0x000] = (0x0400>>(-e-14));
68            basetable[i | 0x100] = (0x0400>>(-e-14)) | 0x8000;
69            shifttable[i | 0x000] = -e-1;
70            shifttable[i | 0x100] = -e-1;
71        }
72        else if (e <= 15){ // Normal numbers just lose precision
73            basetable[i | 0x000] = ((e+15)<<10);
74            basetable[i| 0x100] = ((e+15)<<10) | 0x8000;
75            shifttable[i|0x000] = 13;
76            shifttable[i|0x100] = 13;
77        }
78        else if (e<128){ // Large numbers map to Infinity
79            basetable[i|0x000] = 0x7C00;
80            basetable[i|0x100] = 0xFC00;
81            shifttable[i|0x000] = 24;
82            shifttable[i|0x100] = 24;
83        }
84        else { // Infinity and NaN's stay Infinity and NaN's
85            basetable[i|0x000] = 0x7C00;
86            basetable[i|0x100] = 0xFC00;
87            shifttable[i|0x000] = 13;
88            shifttable[i|0x100] = 13;
89       }
90    }
91}
92*/
93
94unsigned short baseTable[512] = {
950,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
960,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
970,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
980,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
990,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1000,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
1010,      0,      0,      0,      0,      0,      0,      1,      2,      4,      8,      16,     32,     64,     128,    256,
102512,    1024,   2048,   3072,   4096,   5120,   6144,   7168,   8192,   9216,   10240,  11264,  12288,  13312,  14336,  15360,
10316384,  17408,  18432,  19456,  20480,  21504,  22528,  23552,  24576,  25600,  26624,  27648,  28672,  29696,  30720,  31744,
10431744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
10531744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
10631744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
10731744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
10831744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
10931744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
11031744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,  31744,
11132768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
11232768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
11332768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
11432768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
11532768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
11632768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,  32768,
11732768,  32768,  32768,  32768,  32768,  32768,  32768,  32769,  32770,  32772,  32776,  32784,  32800,  32832,  32896,  33024,
11833280,  33792,  34816,  35840,  36864,  37888,  38912,  39936,  40960,  41984,  43008,  44032,  45056,  46080,  47104,  48128,
11949152,  50176,  51200,  52224,  53248,  54272,  55296,  56320,  57344,  58368,  59392,  60416,  61440,  62464,  63488,  64512,
12064512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
12164512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
12264512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
12364512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
12464512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
12564512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,
12664512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512,  64512
127};
128
129unsigned char shiftTable[512] = {
13024,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
13124,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
13224,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
13324,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
13424,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
13524,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
13624,     24,     24,     24,     24,     24,     24,     23,     22,     21,     20,     19,     18,     17,     16,     15,
13714,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,
13813,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     24,
13924,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14024,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14124,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14224,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14324,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14424,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14524,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     13,
14624,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14724,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14824,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
14924,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15024,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15124,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15224,     24,     24,     24,     24,     24,     24,     23,     22,     21,     20,     19,     18,     17,     16,     15,
15314,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,
15413,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     13,     24,
15524,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15624,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15724,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15824,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
15924,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
16024,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,
16124,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     24,     13
162};
163
164inline unsigned short convertFloatToHalfFloat(float f)
165{
166    unsigned temp = *(reinterpret_cast<unsigned *>(&f));
167    unsigned signexp = (temp >> 23) & 0x1ff;
168    return baseTable[signexp] + ((temp & 0x007fffff) >> shiftTable[signexp]);
169}
170
171/* BEGIN CODE SHARED WITH MOZILLA FIREFOX */
172
173// The following packing and unpacking routines are expressed in terms of function templates and inline functions to achieve generality and speedup.
174// Explicit template specializations correspond to the cases that would occur.
175// Some code are merged back from Mozilla code in http://mxr.mozilla.org/mozilla-central/source/content/canvas/src/WebGLTexelConversions.h
176
177//----------------------------------------------------------------------
178// Pixel unpacking routines.
179template<int format, typename SourceType, typename DstType>
180ALWAYS_INLINE void unpack(const SourceType*, DstType*, unsigned)
181{
182    ASSERT_NOT_REACHED();
183}
184
185template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
186{
187    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
188        destination[0] = source[0];
189        destination[1] = source[1];
190        destination[2] = source[2];
191        destination[3] = 0xFF;
192        source += 3;
193        destination += 4;
194    }
195}
196
197template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatBGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
198{
199    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
200        destination[0] = source[2];
201        destination[1] = source[1];
202        destination[2] = source[0];
203        destination[3] = 0xFF;
204        source += 3;
205        destination += 4;
206    }
207}
208
209template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatARGB8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
210{
211    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
212        destination[0] = source[1];
213        destination[1] = source[2];
214        destination[2] = source[3];
215        destination[3] = source[0];
216        source += 4;
217        destination += 4;
218    }
219}
220
221template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatABGR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
222{
223    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
224        destination[0] = source[3];
225        destination[1] = source[2];
226        destination[2] = source[1];
227        destination[3] = source[0];
228        source += 4;
229        destination += 4;
230    }
231}
232
233template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatBGRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
234{
235    const uint32_t* source32 = reinterpret_cast_ptr<const uint32_t*>(source);
236    uint32_t* destination32 = reinterpret_cast_ptr<uint32_t*>(destination);
237    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
238        uint32_t bgra = source32[i];
239#if CPU(BIG_ENDIAN)
240        uint32_t brMask = 0xff00ff00;
241        uint32_t gaMask = 0x00ff00ff;
242#else
243        uint32_t brMask = 0x00ff00ff;
244        uint32_t gaMask = 0xff00ff00;
245#endif
246        uint32_t rgba = (((bgra >> 16) | (bgra << 16)) & brMask) | (bgra & gaMask);
247        destination32[i] = rgba;
248    }
249}
250
251template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGBA5551, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
252{
253#if HAVE(ARM_NEON_INTRINSICS)
254    SIMD::unpackOneRowOfRGBA5551ToRGBA8(source, destination, pixelsPerRow);
255#endif
256    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
257        uint16_t packedValue = source[0];
258        uint8_t r = packedValue >> 11;
259        uint8_t g = (packedValue >> 6) & 0x1F;
260        uint8_t b = (packedValue >> 1) & 0x1F;
261        destination[0] = (r << 3) | (r & 0x7);
262        destination[1] = (g << 3) | (g & 0x7);
263        destination[2] = (b << 3) | (b & 0x7);
264        destination[3] = (packedValue & 0x1) ? 0xFF : 0x0;
265        source += 1;
266        destination += 4;
267    }
268}
269
270template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGBA4444, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
271{
272#if HAVE(ARM_NEON_INTRINSICS)
273    SIMD::unpackOneRowOfRGBA4444ToRGBA8(source, destination, pixelsPerRow);
274#endif
275    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
276        uint16_t packedValue = source[0];
277        uint8_t r = packedValue >> 12;
278        uint8_t g = (packedValue >> 8) & 0x0F;
279        uint8_t b = (packedValue >> 4) & 0x0F;
280        uint8_t a = packedValue & 0x0F;
281        destination[0] = r << 4 | r;
282        destination[1] = g << 4 | g;
283        destination[2] = b << 4 | b;
284        destination[3] = a << 4 | a;
285        source += 1;
286        destination += 4;
287    }
288}
289
290template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGB565, uint16_t, uint8_t>(const uint16_t* source, uint8_t* destination, unsigned pixelsPerRow)
291{
292#if HAVE(ARM_NEON_INTRINSICS)
293    SIMD::unpackOneRowOfRGB565ToRGBA8(source, destination, pixelsPerRow);
294#endif
295    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
296        uint16_t packedValue = source[0];
297        uint8_t r = packedValue >> 11;
298        uint8_t g = (packedValue >> 5) & 0x3F;
299        uint8_t b = packedValue & 0x1F;
300        destination[0] = (r << 3) | (r & 0x7);
301        destination[1] = (g << 2) | (g & 0x3);
302        destination[2] = (b << 3) | (b & 0x7);
303        destination[3] = 0xFF;
304        source += 1;
305        destination += 4;
306    }
307}
308
309template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
310{
311    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
312        destination[0] = source[0];
313        destination[1] = source[0];
314        destination[2] = source[0];
315        destination[3] = 0xFF;
316        source += 1;
317        destination += 4;
318    }
319}
320
321template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
322{
323    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
324        destination[0] = source[0];
325        destination[1] = source[0];
326        destination[2] = source[0];
327        destination[3] = source[1];
328        source += 2;
329        destination += 4;
330    }
331}
332
333template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatAR8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
334{
335    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
336        destination[0] = source[1];
337        destination[1] = source[1];
338        destination[2] = source[1];
339        destination[3] = source[0];
340        source += 2;
341        destination += 4;
342    }
343}
344
345template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatA8, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
346{
347    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
348        destination[0] = 0x0;
349        destination[1] = 0x0;
350        destination[2] = 0x0;
351        destination[3] = source[0];
352        source += 1;
353        destination += 4;
354    }
355}
356
357template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGBA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
358{
359    const float scaleFactor = 1.0f / 255.0f;
360    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
361        destination[0] = source[0] * scaleFactor;
362        destination[1] = source[1] * scaleFactor;
363        destination[2] = source[2] * scaleFactor;
364        destination[3] = source[3] * scaleFactor;
365        source += 4;
366        destination += 4;
367    }
368}
369
370template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatBGRA8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
371{
372    const float scaleFactor = 1.0f / 255.0f;
373    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
374        destination[0] = source[2] * scaleFactor;
375        destination[1] = source[1] * scaleFactor;
376        destination[2] = source[0] * scaleFactor;
377        destination[3] = source[3] * scaleFactor;
378        source += 4;
379        destination += 4;
380    }
381}
382
383template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatABGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
384{
385    const float scaleFactor = 1.0f / 255.0f;
386    for (unsigned i = 0; i < pixelsPerRow; ++i) {
387        destination[0] = source[3] * scaleFactor;
388        destination[1] = source[2] * scaleFactor;
389        destination[2] = source[1] * scaleFactor;
390        destination[3] = source[0] * scaleFactor;
391        source += 4;
392        destination += 4;
393    }
394}
395
396template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatARGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
397{
398    const float scaleFactor = 1.0f / 255.0f;
399    for (unsigned i = 0; i < pixelsPerRow; ++i) {
400        destination[0] = source[1] * scaleFactor;
401        destination[1] = source[2] * scaleFactor;
402        destination[2] = source[3] * scaleFactor;
403        destination[3] = source[0] * scaleFactor;
404        source += 4;
405        destination += 4;
406    }
407}
408
409template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGB8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
410{
411    const float scaleFactor = 1.0f / 255.0f;
412    for (unsigned i = 0; i < pixelsPerRow; ++i) {
413        destination[0] = source[0] * scaleFactor;
414        destination[1] = source[1] * scaleFactor;
415        destination[2] = source[2] * scaleFactor;
416        destination[3] = 1;
417        source += 3;
418        destination += 4;
419    }
420}
421
422template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatBGR8, uint8_t, float>(const uint8_t* source, float* destination, unsigned pixelsPerRow)
423{
424    const float scaleFactor = 1.0f / 255.0f;
425    for (unsigned i = 0; i < pixelsPerRow; ++i) {
426        destination[0] = source[2] * scaleFactor;
427        destination[1] = source[1] * scaleFactor;
428        destination[2] = source[0] * scaleFactor;
429        destination[3] = 1;
430        source += 3;
431        destination += 4;
432    }
433}
434
435template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRGB32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
436{
437    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
438        destination[0] = source[0];
439        destination[1] = source[1];
440        destination[2] = source[2];
441        destination[3] = 1;
442        source += 3;
443        destination += 4;
444    }
445}
446
447template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatR32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
448{
449    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
450        destination[0] = source[0];
451        destination[1] = source[0];
452        destination[2] = source[0];
453        destination[3] = 1;
454        source += 1;
455        destination += 4;
456    }
457}
458
459template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatRA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
460{
461    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
462        destination[0] = source[0];
463        destination[1] = source[0];
464        destination[2] = source[0];
465        destination[3] = source[1];
466        source += 2;
467        destination += 4;
468    }
469}
470
471template<> ALWAYS_INLINE void unpack<GraphicsContext3D::DataFormatA32F, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
472{
473    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
474        destination[0] = 0;
475        destination[1] = 0;
476        destination[2] = 0;
477        destination[3] = source[0];
478        source += 1;
479        destination += 4;
480    }
481}
482
483//----------------------------------------------------------------------
484// Pixel packing routines.
485//
486
487template<int format, int alphaOp, typename SourceType, typename DstType>
488ALWAYS_INLINE void pack(const SourceType*, DstType*, unsigned)
489{
490    ASSERT_NOT_REACHED();
491}
492
493template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatA8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
494{
495    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
496        destination[0] = source[3];
497        source += 4;
498        destination += 1;
499    }
500}
501
502template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
503{
504    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
505        destination[0] = source[0];
506        source += 4;
507        destination += 1;
508    }
509}
510
511template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
512{
513    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
514        float scaleFactor = source[3] / 255.0f;
515        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
516        destination[0] = sourceR;
517        source += 4;
518        destination += 1;
519    }
520}
521
522// FIXME: this routine is lossy and must be removed.
523template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
524{
525    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
526        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
527        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
528        destination[0] = sourceR;
529        source += 4;
530        destination += 1;
531    }
532}
533
534template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
535{
536    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
537        destination[0] = source[0];
538        destination[1] = source[3];
539        source += 4;
540        destination += 2;
541    }
542}
543
544template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
545{
546    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
547        float scaleFactor = source[3] / 255.0f;
548        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
549        destination[0] = sourceR;
550        destination[1] = source[3];
551        source += 4;
552        destination += 2;
553    }
554}
555
556// FIXME: this routine is lossy and must be removed.
557template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
558{
559    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
560        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
561        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
562        destination[0] = sourceR;
563        destination[1] = source[3];
564        source += 4;
565        destination += 2;
566    }
567}
568
569template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
570{
571    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
572        destination[0] = source[0];
573        destination[1] = source[1];
574        destination[2] = source[2];
575        source += 4;
576        destination += 3;
577    }
578}
579
580template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
581{
582    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
583        float scaleFactor = source[3] / 255.0f;
584        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
585        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
586        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
587        destination[0] = sourceR;
588        destination[1] = sourceG;
589        destination[2] = sourceB;
590        source += 4;
591        destination += 3;
592    }
593}
594
595// FIXME: this routine is lossy and must be removed.
596template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
597{
598    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
599        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
600        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
601        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
602        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
603        destination[0] = sourceR;
604        destination[1] = sourceG;
605        destination[2] = sourceB;
606        source += 4;
607        destination += 3;
608    }
609}
610
611
612template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::AlphaDoNothing, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
613{
614    memcpy(destination, source, pixelsPerRow * 4);
615}
616
617template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
618{
619    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
620        float scaleFactor = source[3] / 255.0f;
621        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
622        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
623        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
624        destination[0] = sourceR;
625        destination[1] = sourceG;
626        destination[2] = sourceB;
627        destination[3] = source[3];
628        source += 4;
629        destination += 4;
630    }
631}
632
633// FIXME: this routine is lossy and must be removed.
634template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA8, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint8_t>(const uint8_t* source, uint8_t* destination, unsigned pixelsPerRow)
635{
636    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
637        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
638        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
639        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
640        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
641        destination[0] = sourceR;
642        destination[1] = sourceG;
643        destination[2] = sourceB;
644        destination[3] = source[3];
645        source += 4;
646        destination += 4;
647    }
648}
649
650template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
651{
652#if HAVE(ARM_NEON_INTRINSICS)
653    SIMD::packOneRowOfRGBA8ToUnsignedShort4444(source, destination, pixelsPerRow);
654#endif
655    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
656        *destination = (((source[0] & 0xF0) << 8)
657                        | ((source[1] & 0xF0) << 4)
658                        | (source[2] & 0xF0)
659                        | (source[3] >> 4));
660        source += 4;
661        destination += 1;
662    }
663}
664
665template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
666{
667    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
668        float scaleFactor = source[3] / 255.0f;
669        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
670        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
671        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
672        *destination = (((sourceR & 0xF0) << 8)
673                        | ((sourceG & 0xF0) << 4)
674                        | (sourceB & 0xF0)
675                        | (source[3] >> 4));
676        source += 4;
677        destination += 1;
678    }
679}
680
681// FIXME: this routine is lossy and must be removed.
682template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA4444, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
683{
684    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
685        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
686        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
687        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
688        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
689        *destination = (((sourceR & 0xF0) << 8)
690                        | ((sourceG & 0xF0) << 4)
691                        | (sourceB & 0xF0)
692                        | (source[3] >> 4));
693        source += 4;
694        destination += 1;
695    }
696}
697
698template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
699{
700#if HAVE(ARM_NEON_INTRINSICS)
701    SIMD::packOneRowOfRGBA8ToUnsignedShort5551(source, destination, pixelsPerRow);
702#endif
703    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
704        *destination = (((source[0] & 0xF8) << 8)
705                        | ((source[1] & 0xF8) << 3)
706                        | ((source[2] & 0xF8) >> 2)
707                        | (source[3] >> 7));
708        source += 4;
709        destination += 1;
710    }
711}
712
713template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
714{
715    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
716        float scaleFactor = source[3] / 255.0f;
717        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
718        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
719        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
720        *destination = (((sourceR & 0xF8) << 8)
721                        | ((sourceG & 0xF8) << 3)
722                        | ((sourceB & 0xF8) >> 2)
723                        | (source[3] >> 7));
724        source += 4;
725        destination += 1;
726    }
727}
728
729// FIXME: this routine is lossy and must be removed.
730template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA5551, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
731{
732    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
733        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
734        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
735        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
736        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
737        *destination = (((sourceR & 0xF8) << 8)
738                        | ((sourceG & 0xF8) << 3)
739                        | ((sourceB & 0xF8) >> 2)
740                        | (source[3] >> 7));
741        source += 4;
742        destination += 1;
743    }
744}
745
746template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::AlphaDoNothing, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
747{
748#if HAVE(ARM_NEON_INTRINSICS)
749    SIMD::packOneRowOfRGBA8ToUnsignedShort565(source, destination, pixelsPerRow);
750#endif
751    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
752        *destination = (((source[0] & 0xF8) << 8)
753                        | ((source[1] & 0xFC) << 3)
754                        | ((source[2] & 0xF8) >> 3));
755        source += 4;
756        destination += 1;
757    }
758}
759
760template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::AlphaDoPremultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
761{
762    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
763        float scaleFactor = source[3] / 255.0f;
764        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
765        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
766        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
767        *destination = (((sourceR & 0xF8) << 8)
768                        | ((sourceG & 0xFC) << 3)
769                        | ((sourceB & 0xF8) >> 3));
770        source += 4;
771        destination += 1;
772    }
773}
774
775// FIXME: this routine is lossy and must be removed.
776template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB565, GraphicsContext3D::AlphaDoUnmultiply, uint8_t, uint16_t>(const uint8_t* source, uint16_t* destination, unsigned pixelsPerRow)
777{
778    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
779        float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
780        uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
781        uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
782        uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
783        *destination = (((sourceR & 0xF8) << 8)
784                        | ((sourceG & 0xFC) << 3)
785                        | ((sourceB & 0xF8) >> 3));
786        source += 4;
787        destination += 1;
788    }
789}
790
791template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
792{
793    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
794        destination[0] = source[0];
795        destination[1] = source[1];
796        destination[2] = source[2];
797        source += 4;
798        destination += 3;
799    }
800}
801
802template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
803{
804    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
805        float scaleFactor = source[3];
806        destination[0] = source[0] * scaleFactor;
807        destination[1] = source[1] * scaleFactor;
808        destination[2] = source[2] * scaleFactor;
809        source += 4;
810        destination += 3;
811    }
812}
813
814template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
815{
816    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
817        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
818        destination[0] = source[0] * scaleFactor;
819        destination[1] = source[1] * scaleFactor;
820        destination[2] = source[2] * scaleFactor;
821        source += 4;
822        destination += 3;
823    }
824}
825
826// Used only during RGBA8 or BGRA8 -> floating-point uploads.
827template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
828{
829    memcpy(destination, source, pixelsPerRow * 4 * sizeof(float));
830}
831
832template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
833{
834    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
835        float scaleFactor = source[3];
836        destination[0] = source[0] * scaleFactor;
837        destination[1] = source[1] * scaleFactor;
838        destination[2] = source[2] * scaleFactor;
839        destination[3] = source[3];
840        source += 4;
841        destination += 4;
842    }
843}
844
845template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
846{
847    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
848        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
849        destination[0] = source[0] * scaleFactor;
850        destination[1] = source[1] * scaleFactor;
851        destination[2] = source[2] * scaleFactor;
852        destination[3] = source[3];
853        source += 4;
854        destination += 4;
855    }
856}
857
858template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatA32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
859{
860    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
861        destination[0] = source[3];
862        source += 4;
863        destination += 1;
864    }
865}
866
867template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
868{
869    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
870        destination[0] = source[0];
871        source += 4;
872        destination += 1;
873    }
874}
875
876template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
877{
878    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
879        float scaleFactor = source[3];
880        destination[0] = source[0] * scaleFactor;
881        source += 4;
882        destination += 1;
883    }
884}
885
886template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
887{
888    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
889        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
890        destination[0] = source[0] * scaleFactor;
891        source += 4;
892        destination += 1;
893    }
894}
895
896template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::AlphaDoNothing, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
897{
898    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
899        destination[0] = source[0];
900        destination[1] = source[3];
901        source += 4;
902        destination += 2;
903    }
904}
905
906template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::AlphaDoPremultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
907{
908    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
909        float scaleFactor = source[3];
910        destination[0] = source[0] * scaleFactor;
911        destination[1] = source[3];
912        source += 4;
913        destination += 2;
914    }
915}
916
917template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA32F, GraphicsContext3D::AlphaDoUnmultiply, float, float>(const float* source, float* destination, unsigned pixelsPerRow)
918{
919    for (unsigned int i = 0; i < pixelsPerRow; ++i) {
920        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
921        destination[0] = source[0] * scaleFactor;
922        destination[1] = source[3];
923        source += 4;
924        destination += 2;
925    }
926}
927
928template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
929{
930    for (unsigned i = 0; i < pixelsPerRow; ++i) {
931        destination[0] = convertFloatToHalfFloat(source[0]);
932        destination[1] = convertFloatToHalfFloat(source[1]);
933        destination[2] = convertFloatToHalfFloat(source[2]);
934        destination[3] = convertFloatToHalfFloat(source[3]);
935        source += 4;
936        destination += 4;
937    }
938}
939
940template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
941{
942    for (unsigned i = 0; i < pixelsPerRow; ++i) {
943        float scaleFactor = source[3];
944        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
945        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
946        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
947        destination[3] = convertFloatToHalfFloat(source[3]);
948        source += 4;
949        destination += 4;
950    }
951}
952
953template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGBA16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
954{
955    for (unsigned i = 0; i < pixelsPerRow; ++i) {
956        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
957        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
958        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
959        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
960        destination[3] = convertFloatToHalfFloat(source[3]);
961        source += 4;
962        destination += 4;
963    }
964}
965
966template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
967{
968    for (unsigned i = 0; i < pixelsPerRow; ++i) {
969        destination[0] = convertFloatToHalfFloat(source[0]);
970        destination[1] = convertFloatToHalfFloat(source[1]);
971        destination[2] = convertFloatToHalfFloat(source[2]);
972        source += 4;
973        destination += 3;
974    }
975}
976
977template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
978{
979    for (unsigned i = 0; i < pixelsPerRow; ++i) {
980        float scaleFactor = source[3];
981        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
982        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
983        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
984        source += 4;
985        destination += 3;
986    }
987}
988
989template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRGB16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
990{
991    for (unsigned i = 0; i < pixelsPerRow; ++i) {
992        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
993        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
994        destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
995        destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
996        source += 4;
997        destination += 3;
998    }
999}
1000
1001template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1002{
1003    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1004        destination[0] = convertFloatToHalfFloat(source[0]);
1005        destination[1] = convertFloatToHalfFloat(source[3]);
1006        source += 4;
1007        destination += 2;
1008    }
1009}
1010
1011template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1012{
1013    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1014        float scaleFactor = source[3];
1015        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1016        destination[1] = convertFloatToHalfFloat(source[3]);
1017        source += 4;
1018        destination += 2;
1019    }
1020}
1021
1022template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatRA16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1023{
1024    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1025        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
1026        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1027        destination[1] = convertFloatToHalfFloat(source[3]);
1028        source += 4;
1029        destination += 2;
1030    }
1031}
1032
1033template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1034{
1035    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1036        destination[0] = convertFloatToHalfFloat(source[0]);
1037        source += 4;
1038        destination += 1;
1039    }
1040}
1041
1042template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::AlphaDoPremultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1043{
1044    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1045        float scaleFactor = source[3];
1046        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1047        source += 4;
1048        destination += 1;
1049    }
1050}
1051
1052template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatR16F, GraphicsContext3D::AlphaDoUnmultiply, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1053{
1054    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1055        float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
1056        destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
1057        source += 4;
1058        destination += 1;
1059    }
1060}
1061
1062template<> ALWAYS_INLINE void pack<GraphicsContext3D::DataFormatA16F, GraphicsContext3D::AlphaDoNothing, float, uint16_t>(const float* source, uint16_t* destination, unsigned pixelsPerRow)
1063{
1064    for (unsigned i = 0; i < pixelsPerRow; ++i) {
1065        destination[0] = convertFloatToHalfFloat(source[3]);
1066        source += 4;
1067        destination += 1;
1068    }
1069}
1070
1071template<int Format>
1072struct IsFloatFormat {
1073    static const bool Value =
1074        Format == GraphicsContext3D::DataFormatRGBA32F
1075        || Format == GraphicsContext3D::DataFormatRGB32F
1076        || Format == GraphicsContext3D::DataFormatRA32F
1077        || Format == GraphicsContext3D::DataFormatR32F
1078        || Format == GraphicsContext3D::DataFormatA32F;
1079};
1080
1081template<int Format>
1082struct IsHalfFloatFormat {
1083    static const bool Value =
1084        Format == GraphicsContext3D::DataFormatRGBA16F
1085        || Format == GraphicsContext3D::DataFormatRGB16F
1086        || Format == GraphicsContext3D::DataFormatRA16F
1087        || Format == GraphicsContext3D::DataFormatR16F
1088        || Format == GraphicsContext3D::DataFormatA16F;
1089};
1090
1091template<int Format>
1092struct Is16bppFormat {
1093    static const bool Value =
1094        Format == GraphicsContext3D::DataFormatRGBA5551
1095        || Format == GraphicsContext3D::DataFormatRGBA4444
1096        || Format == GraphicsContext3D::DataFormatRGB565;
1097};
1098
1099template<int Format, bool IsFloat = IsFloatFormat<Format>::Value, bool IsHalfFloat = IsHalfFloatFormat<Format>::Value, bool Is16bpp = Is16bppFormat<Format>::Value>
1100struct DataTypeForFormat {
1101    typedef uint8_t Type;
1102};
1103
1104template<int Format>
1105struct DataTypeForFormat<Format, true, false, false> {
1106    typedef float Type;
1107};
1108
1109template<int Format>
1110struct DataTypeForFormat<Format, false, true, false> {
1111    typedef uint16_t Type;
1112};
1113
1114template<int Format>
1115struct DataTypeForFormat<Format, false, false, true> {
1116    typedef uint16_t Type;
1117};
1118
1119template<int Format>
1120struct IntermediateFormat {
1121    static const int Value = (IsFloatFormat<Format>::Value || IsHalfFloatFormat<Format>::Value) ? GraphicsContext3D::DataFormatRGBA32F : GraphicsContext3D::DataFormatRGBA8;
1122};
1123
1124
1125/* END CODE SHARED WITH MOZILLA FIREFOX */
1126
1127void FormatConverter::convert(GraphicsContext3D::DataFormat srcFormat, GraphicsContext3D::DataFormat dstFormat, GraphicsContext3D::AlphaOp alphaOp)
1128{
1129#define FORMATCONVERTER_CASE_SRCFORMAT(SrcFormat) \
1130    case SrcFormat: \
1131        return convert<SrcFormat>(dstFormat, alphaOp);
1132
1133        switch (srcFormat) {
1134            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatR8)
1135            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatA8)
1136            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatR32F)
1137            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatA32F)
1138            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRA8)
1139            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRA32F)
1140            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGB8)
1141            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatBGR8)
1142            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGB565)
1143            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGB32F)
1144            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA8)
1145            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatARGB8)
1146            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatABGR8)
1147            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatAR8)
1148            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatBGRA8)
1149            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA5551)
1150            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA4444)
1151            FORMATCONVERTER_CASE_SRCFORMAT(GraphicsContext3D::DataFormatRGBA32F)
1152        default:
1153            ASSERT_NOT_REACHED();
1154        }
1155#undef FORMATCONVERTER_CASE_SRCFORMAT
1156}
1157
1158template<GraphicsContext3D::DataFormat SrcFormat>
1159ALWAYS_INLINE void FormatConverter::convert(GraphicsContext3D::DataFormat dstFormat, GraphicsContext3D::AlphaOp alphaOp)
1160{
1161#define FORMATCONVERTER_CASE_DSTFORMAT(DstFormat) \
1162    case DstFormat: \
1163        return convert<SrcFormat, DstFormat>(alphaOp);
1164
1165        switch (dstFormat) {
1166            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatR8)
1167            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatR16F)
1168            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatR32F)
1169            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatA8)
1170            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatA16F)
1171            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatA32F)
1172            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRA8)
1173            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRA16F)
1174            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRA32F)
1175            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB8)
1176            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB565)
1177            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB16F)
1178            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGB32F)
1179            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA8)
1180            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA5551)
1181            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA4444)
1182            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA16F)
1183            FORMATCONVERTER_CASE_DSTFORMAT(GraphicsContext3D::DataFormatRGBA32F)
1184        default:
1185            ASSERT_NOT_REACHED();
1186        }
1187
1188#undef FORMATCONVERTER_CASE_DSTFORMAT
1189}
1190
1191template<GraphicsContext3D::DataFormat SrcFormat, GraphicsContext3D::DataFormat DstFormat>
1192ALWAYS_INLINE void FormatConverter::convert(GraphicsContext3D::AlphaOp alphaOp)
1193{
1194#define FORMATCONVERTER_CASE_ALPHAOP(alphaOp) \
1195    case alphaOp: \
1196        return convert<SrcFormat, DstFormat, alphaOp>();
1197
1198        switch (alphaOp) {
1199            FORMATCONVERTER_CASE_ALPHAOP(GraphicsContext3D::AlphaDoNothing)
1200            FORMATCONVERTER_CASE_ALPHAOP(GraphicsContext3D::AlphaDoPremultiply)
1201            FORMATCONVERTER_CASE_ALPHAOP(GraphicsContext3D::AlphaDoUnmultiply)
1202        default:
1203            ASSERT_NOT_REACHED();
1204        }
1205#undef FORMATCONVERTER_CASE_ALPHAOP
1206}
1207
1208template<GraphicsContext3D::DataFormat SrcFormat, GraphicsContext3D::DataFormat DstFormat, GraphicsContext3D::AlphaOp alphaOp>
1209ALWAYS_INLINE_EXCEPT_MSVC void FormatConverter::convert()
1210{
1211    // Many instantiations of this template function will never be entered, so we try
1212    // to return immediately in these cases to avoid the compiler to generate useless code.
1213    if (SrcFormat == DstFormat && alphaOp == GraphicsContext3D::AlphaDoNothing) {
1214        ASSERT_NOT_REACHED();
1215        return;
1216    }
1217    if (!IsFloatFormat<DstFormat>::Value && IsFloatFormat<SrcFormat>::Value) {
1218        ASSERT_NOT_REACHED();
1219        return;
1220    }
1221
1222    // Only textures uploaded from DOM elements or ImageData can allow DstFormat != SrcFormat.
1223    const bool srcFormatComesFromDOMElementOrImageData = GraphicsContext3D::srcFormatComesFromDOMElementOrImageData(SrcFormat);
1224    if (!srcFormatComesFromDOMElementOrImageData && SrcFormat != DstFormat) {
1225        ASSERT_NOT_REACHED();
1226        return;
1227    }
1228    // Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied.
1229    if (!srcFormatComesFromDOMElementOrImageData && alphaOp == GraphicsContext3D::AlphaDoUnmultiply) {
1230        ASSERT_NOT_REACHED();
1231        return;
1232    }
1233    if ((!GraphicsContext3D::hasAlpha(SrcFormat) || !GraphicsContext3D::hasColor(SrcFormat) || !GraphicsContext3D::hasColor(DstFormat)) && alphaOp != GraphicsContext3D::AlphaDoNothing) {
1234        ASSERT_NOT_REACHED();
1235        return;
1236    }
1237
1238    typedef typename DataTypeForFormat<SrcFormat>::Type SrcType;
1239    typedef typename DataTypeForFormat<DstFormat>::Type DstType;
1240    const int IntermediateSrcFormat = IntermediateFormat<DstFormat>::Value;
1241    typedef typename DataTypeForFormat<IntermediateSrcFormat>::Type IntermediateSrcType;
1242    const ptrdiff_t srcStrideInElements = m_srcStride / sizeof(SrcType);
1243    const ptrdiff_t dstStrideInElements = m_dstStride / sizeof(DstType);
1244    const bool trivialUnpack = (SrcFormat == GraphicsContext3D::DataFormatRGBA8 && !IsFloatFormat<DstFormat>::Value && !IsHalfFloatFormat<DstFormat>::Value) || SrcFormat == GraphicsContext3D::DataFormatRGBA32F;
1245    const bool trivialPack = (DstFormat == GraphicsContext3D::DataFormatRGBA8 || DstFormat == GraphicsContext3D::DataFormatRGBA32F) && alphaOp == GraphicsContext3D::AlphaDoNothing && m_dstStride > 0;
1246    ASSERT(!trivialUnpack || !trivialPack);
1247
1248    const SrcType *srcRowStart = static_cast<const SrcType*>(m_srcStart);
1249    DstType* dstRowStart = static_cast<DstType*>(m_dstStart);
1250    if (!trivialUnpack && trivialPack) {
1251        for (size_t i = 0; i < m_height; ++i) {
1252            unpack<SrcFormat>(srcRowStart, dstRowStart, m_width);
1253            srcRowStart += srcStrideInElements;
1254            dstRowStart += dstStrideInElements;
1255        }
1256    } else if (!trivialUnpack && !trivialPack) {
1257        for (size_t i = 0; i < m_height; ++i) {
1258            unpack<SrcFormat>(srcRowStart, reinterpret_cast_ptr<IntermediateSrcType*>(m_unpackedIntermediateSrcData.get()), m_width);
1259            pack<DstFormat, alphaOp>(reinterpret_cast_ptr<IntermediateSrcType*>(m_unpackedIntermediateSrcData.get()), dstRowStart, m_width);
1260            srcRowStart += srcStrideInElements;
1261            dstRowStart += dstStrideInElements;
1262        }
1263    } else {
1264        for (size_t i = 0; i < m_height; ++i) {
1265            pack<DstFormat, alphaOp>(srcRowStart, dstRowStart, m_width);
1266            srcRowStart += srcStrideInElements;
1267            dstRowStart += dstStrideInElements;
1268        }
1269    }
1270    m_success = true;
1271    return;
1272}
1273
1274} // namespace WebCore
1275
1276#endif // USE(3D_GRAPHICS)
1277