~oem-solutions-group/unity-2d/clutter-1.0

« back to all changes in this revision

Viewing changes to clutter/cogl/cogl/cogl-bitmap-fallback.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Cogl
 
3
 *
 
4
 * An object oriented GL/GLES Abstraction/Utility Layer
 
5
 *
 
6
 * Copyright (C) 2007,2008,2009 Intel Corporation.
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 *
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include "config.h"
 
26
#endif
 
27
 
 
28
#include "cogl.h"
 
29
#include "cogl-internal.h"
 
30
#include "cogl-bitmap-private.h"
 
31
 
 
32
#include <string.h>
 
33
 
 
34
/* TO rgba */
 
35
 
 
36
inline static void
 
37
_cogl_g_to_rgba (const guint8 *src, guint8 *dst)
 
38
{
 
39
  dst[0] = src[0];
 
40
  dst[1] = src[0];
 
41
  dst[2] = src[0];
 
42
  dst[3] = 255;
 
43
}
 
44
 
 
45
inline static void
 
46
_cogl_rgb_to_rgba (const guint8 *src, guint8 *dst)
 
47
{
 
48
  dst[0] = src[0];
 
49
  dst[1] = src[1];
 
50
  dst[2] = src[2];
 
51
  dst[3] = 255;
 
52
}
 
53
 
 
54
inline static void
 
55
_cogl_bgr_to_rgba (const guint8 *src, guint8 *dst)
 
56
{
 
57
  dst[0] = src[2];
 
58
  dst[1] = src[1];
 
59
  dst[2] = src[0];
 
60
  dst[3] = 255;
 
61
}
 
62
 
 
63
inline static void
 
64
_cogl_bgra_to_rgba (const guint8 *src, guint8 *dst)
 
65
{
 
66
  dst[0] = src[2];
 
67
  dst[1] = src[1];
 
68
  dst[2] = src[0];
 
69
  dst[3] = src[3];
 
70
}
 
71
 
 
72
inline static void
 
73
_cogl_argb_to_rgba (const guint8 *src, guint8 *dst)
 
74
{
 
75
  dst[0] = src[1];
 
76
  dst[1] = src[2];
 
77
  dst[2] = src[3];
 
78
  dst[3] = src[0];
 
79
}
 
80
 
 
81
inline static void
 
82
_cogl_abgr_to_rgba (const guint8 *src, guint8 *dst)
 
83
{
 
84
  dst[0] = src[3];
 
85
  dst[1] = src[2];
 
86
  dst[2] = src[1];
 
87
  dst[3] = src[0];
 
88
}
 
89
 
 
90
inline static void
 
91
_cogl_rgba_to_rgba (const guint8 *src, guint8 *dst)
 
92
{
 
93
  dst[0] = src[0];
 
94
  dst[1] = src[1];
 
95
  dst[2] = src[2];
 
96
  dst[3] = src[3];
 
97
}
 
98
 
 
99
/* FROM rgba */
 
100
 
 
101
inline static void
 
102
_cogl_rgba_to_g (const guint8 *src, guint8 *dst)
 
103
{
 
104
  dst[0] = (src[0] + src[1] + src[2]) / 3;
 
105
}
 
106
 
 
107
inline static void
 
108
_cogl_rgba_to_rgb (const guint8 *src, guint8 *dst)
 
109
{
 
110
  dst[0] = src[0];
 
111
  dst[1] = src[1];
 
112
  dst[2] = src[2];
 
113
}
 
114
 
 
115
inline static void
 
116
_cogl_rgba_to_bgr (const guint8 *src, guint8 *dst)
 
117
{
 
118
  dst[0] = src[2];
 
119
  dst[1] = src[1];
 
120
  dst[2] = src[0];
 
121
}
 
122
 
 
123
inline static void
 
124
_cogl_rgba_to_bgra (const guint8 *src, guint8 *dst)
 
125
{
 
126
  dst[0] = src[2];
 
127
  dst[1] = src[1];
 
128
  dst[2] = src[0];
 
129
  dst[3] = src[3];
 
130
}
 
131
 
 
132
inline static void
 
133
_cogl_rgba_to_argb (const guint8 *src, guint8 *dst)
 
134
{
 
135
  dst[0] = src[3];
 
136
  dst[1] = src[0];
 
137
  dst[2] = src[1];
 
138
  dst[3] = src[2];
 
139
}
 
140
 
 
141
inline static void
 
142
_cogl_rgba_to_abgr (const guint8 *src, guint8 *dst)
 
143
{
 
144
  dst[0] = src[3];
 
145
  dst[1] = src[2];
 
146
  dst[2] = src[1];
 
147
  dst[3] = src[0];
 
148
}
 
149
 
 
150
/* (Un)Premultiplication */
 
151
 
 
152
inline static void
 
153
_cogl_unpremult_alpha_0 (guint8 *dst)
 
154
{
 
155
  dst[0] = 0;
 
156
  dst[1] = 0;
 
157
  dst[2] = 0;
 
158
  dst[3] = 0;
 
159
}
 
160
 
 
161
inline static void
 
162
_cogl_unpremult_alpha_last (guint8 *dst)
 
163
{
 
164
  guint8 alpha = dst[3];
 
165
 
 
166
  dst[0] = (dst[0] * 255) / alpha;
 
167
  dst[1] = (dst[1] * 255) / alpha;
 
168
  dst[2] = (dst[2] * 255) / alpha;
 
169
}
 
170
 
 
171
inline static void
 
172
_cogl_unpremult_alpha_first (guint8 *dst)
 
173
{
 
174
  guint8 alpha = dst[0];
 
175
 
 
176
  dst[1] = (dst[1] * 255) / alpha;
 
177
  dst[2] = (dst[2] * 255) / alpha;
 
178
  dst[3] = (dst[3] * 255) / alpha;
 
179
}
 
180
 
 
181
/* No division form of floor((c*a + 128)/255) (I first encountered
 
182
 * this in the RENDER implementation in the X server.) Being exact
 
183
 * is important for a == 255 - we want to get exactly c.
 
184
 */
 
185
#define MULT(d,a,t)                             \
 
186
  G_STMT_START {                                \
 
187
    t = d * a + 128;                            \
 
188
    d = ((t >> 8) + t) >> 8;                    \
 
189
  } G_STMT_END
 
190
 
 
191
inline static void
 
192
_cogl_premult_alpha_last (guint8 *dst)
 
193
{
 
194
  guint8 alpha = dst[3];
 
195
  /* Using a separate temporary per component has given slightly better
 
196
   * code generation with GCC in the past; it shouldn't do any worse in
 
197
   * any case.
 
198
   */
 
199
  unsigned int t1, t2, t3;
 
200
  MULT(dst[0], alpha, t1);
 
201
  MULT(dst[1], alpha, t2);
 
202
  MULT(dst[2], alpha, t3);
 
203
}
 
204
 
 
205
inline static void
 
206
_cogl_premult_alpha_first (guint8 *dst)
 
207
{
 
208
  guint8 alpha = dst[0];
 
209
  unsigned int t1, t2, t3;
 
210
 
 
211
  MULT(dst[1], alpha, t1);
 
212
  MULT(dst[2], alpha, t2);
 
213
  MULT(dst[3], alpha, t3);
 
214
}
 
215
 
 
216
#undef MULT
 
217
 
 
218
/* Use the SSE optimized version to premult four pixels at once when
 
219
   it is available. The same assembler code works for x86 and x86-64
 
220
   because it doesn't refer to any non-SSE registers directly */
 
221
#if defined(__SSE2__) && defined(__GNUC__) \
 
222
  && (defined(__x86_64) || defined(__i386))
 
223
#define COGL_USE_PREMULT_SSE2
 
224
#endif
 
225
 
 
226
#ifdef COGL_USE_PREMULT_SSE2
 
227
 
 
228
inline static void
 
229
_cogl_premult_alpha_last_four_pixels_sse2 (guint8 *p)
 
230
{
 
231
  /* 8 copies of 128 used below */
 
232
  static const gint16 eight_halves[8] __attribute__ ((aligned (16))) =
 
233
    { 128, 128, 128, 128, 128, 128, 128, 128 };
 
234
  /* Mask of the rgb components of the four pixels */
 
235
  static const gint8 just_rgb[16] __attribute__ ((aligned (16))) =
 
236
    { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
 
237
      0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00 };
 
238
  /* Each SSE register only holds two pixels because we need to work
 
239
     with 16-bit intermediate values. We still do four pixels by
 
240
     interleaving two registers in the hope that it will pipeline
 
241
     better */
 
242
  asm (/* Load eight_halves into xmm5 for later */
 
243
       "movdqa (%1), %%xmm5\n"
 
244
       /* Clear xmm3 */
 
245
       "pxor %%xmm3, %%xmm3\n"
 
246
       /* Load two pixels from p into the low half of xmm0 */
 
247
       "movlps (%0), %%xmm0\n"
 
248
       /* Load the next set of two pixels from p into the low half of xmm1 */
 
249
       "movlps 8(%0), %%xmm1\n"
 
250
       /* Unpack 8 bytes from the low quad-words in each register to 8
 
251
          16-bit values */
 
252
       "punpcklbw %%xmm3, %%xmm0\n"
 
253
       "punpcklbw %%xmm3, %%xmm1\n"
 
254
       /* Copy alpha values of the first pixel in xmm0 to all
 
255
          components of the first pixel in xmm2 */
 
256
       "pshuflw $255, %%xmm0, %%xmm2\n"
 
257
       /* same for xmm1 and xmm3 */
 
258
       "pshuflw $255, %%xmm1, %%xmm3\n"
 
259
       /* The above also copies the second pixel directly so we now
 
260
          want to replace the RGB components with copies of the alpha
 
261
          components */
 
262
       "pshufhw $255, %%xmm2, %%xmm2\n"
 
263
       "pshufhw $255, %%xmm3, %%xmm3\n"
 
264
       /* Multiply the rgb components by the alpha */
 
265
       "pmullw %%xmm2, %%xmm0\n"
 
266
       "pmullw %%xmm3, %%xmm1\n"
 
267
       /* Add 128 to each component */
 
268
       "paddw %%xmm5, %%xmm0\n"
 
269
       "paddw %%xmm5, %%xmm1\n"
 
270
       /* Copy the results to temporary registers xmm4 and xmm5 */
 
271
       "movdqa %%xmm0, %%xmm4\n"
 
272
       "movdqa %%xmm1, %%xmm5\n"
 
273
       /* Divide the results by 256 */
 
274
       "psrlw $8, %%xmm0\n"
 
275
       "psrlw $8, %%xmm1\n"
 
276
       /* Add the temporaries back in */
 
277
       "paddw %%xmm4, %%xmm0\n"
 
278
       "paddw %%xmm5, %%xmm1\n"
 
279
       /* Divide again */
 
280
       "psrlw $8, %%xmm0\n"
 
281
       "psrlw $8, %%xmm1\n"
 
282
       /* Pack the results back as bytes */
 
283
       "packuswb %%xmm1, %%xmm0\n"
 
284
       /* Load just_rgb into xmm3 for later */
 
285
       "movdqa (%2), %%xmm3\n"
 
286
       /* Reload all four pixels into xmm2 */
 
287
       "movups (%0), %%xmm2\n"
 
288
       /* Mask out the alpha from the results */
 
289
       "andps %%xmm3, %%xmm0\n"
 
290
       /* Mask out the RGB from the original four pixels */
 
291
       "andnps %%xmm2, %%xmm3\n"
 
292
       /* Combine the two to get the right alpha values */
 
293
       "orps %%xmm3, %%xmm0\n"
 
294
       /* Write to memory */
 
295
       "movdqu %%xmm0, (%0)\n"
 
296
       : /* no outputs */
 
297
       : "r" (p), "r" (eight_halves), "r" (just_rgb)
 
298
       : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
 
299
}
 
300
 
 
301
#endif /* COGL_USE_PREMULT_SSE2 */
 
302
 
 
303
gboolean
 
304
_cogl_bitmap_fallback_can_convert (CoglPixelFormat src, CoglPixelFormat dst)
 
305
{
 
306
  if (src == dst)
 
307
    return FALSE;
 
308
 
 
309
  switch (src & COGL_UNORDERED_MASK)
 
310
    {
 
311
    case COGL_PIXEL_FORMAT_G_8:
 
312
    case COGL_PIXEL_FORMAT_24:
 
313
    case COGL_PIXEL_FORMAT_32:
 
314
 
 
315
      if ((dst & COGL_UNORDERED_MASK) != COGL_PIXEL_FORMAT_24 &&
 
316
          (dst & COGL_UNORDERED_MASK) != COGL_PIXEL_FORMAT_32 &&
 
317
          (dst & COGL_UNORDERED_MASK) != COGL_PIXEL_FORMAT_G_8)
 
318
        return FALSE;
 
319
      break;
 
320
 
 
321
    default:
 
322
      return FALSE;
 
323
    }
 
324
 
 
325
  return TRUE;
 
326
}
 
327
 
 
328
gboolean
 
329
_cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format)
 
330
{
 
331
  return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32);
 
332
}
 
333
 
 
334
gboolean
 
335
_cogl_bitmap_fallback_can_premult (CoglPixelFormat format)
 
336
{
 
337
  return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32);
 
338
}
 
339
 
 
340
gboolean
 
341
_cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
 
342
                               CoglBitmap       *dst_bmp,
 
343
                               CoglPixelFormat   dst_format)
 
344
{
 
345
  guint8  *src;
 
346
  guint8  *dst;
 
347
  int      src_bpp;
 
348
  int      dst_bpp;
 
349
  int      x,y;
 
350
  guint8   temp_rgba[4] = {0,0,0,0};
 
351
 
 
352
  /* Make sure conversion supported */
 
353
  if (!_cogl_bitmap_fallback_can_convert (bmp->format, dst_format))
 
354
    return FALSE;
 
355
 
 
356
  src_bpp = _cogl_get_format_bpp (bmp->format);
 
357
  dst_bpp = _cogl_get_format_bpp (dst_format);
 
358
 
 
359
  /* Initialize destination bitmap */
 
360
  *dst_bmp = *bmp;
 
361
  dst_bmp->rowstride = sizeof(guint8) * dst_bpp * dst_bmp->width;
 
362
  dst_bmp->format = ((bmp->format & COGL_PREMULT_BIT) |
 
363
                     (dst_format & COGL_UNPREMULT_MASK));
 
364
 
 
365
  /* Allocate a new buffer to hold converted data */
 
366
  dst_bmp->data = g_malloc (sizeof(guint8)
 
367
                            * dst_bmp->height
 
368
                            * dst_bmp->rowstride);
 
369
 
 
370
  /* FIXME: Optimize */
 
371
  for (y = 0; y < bmp->height; y++)
 
372
    {
 
373
      src = (guint8*)bmp->data      + y * bmp->rowstride;
 
374
      dst = (guint8*)dst_bmp->data  + y * dst_bmp->rowstride;
 
375
 
 
376
      for (x = 0; x < bmp->width; x++)
 
377
        {
 
378
          /* FIXME: Would be nice to at least remove this inner
 
379
           * branching, but not sure it can be done without
 
380
           * rewriting of the whole loop */
 
381
          switch (bmp->format & COGL_UNPREMULT_MASK)
 
382
            {
 
383
            case COGL_PIXEL_FORMAT_G_8:
 
384
              _cogl_g_to_rgba (src, temp_rgba); break;
 
385
            case COGL_PIXEL_FORMAT_RGB_888:
 
386
              _cogl_rgb_to_rgba (src, temp_rgba); break;
 
387
            case COGL_PIXEL_FORMAT_BGR_888:
 
388
              _cogl_bgr_to_rgba (src, temp_rgba); break;
 
389
            case COGL_PIXEL_FORMAT_RGBA_8888:
 
390
              _cogl_rgba_to_rgba (src, temp_rgba); break;
 
391
            case COGL_PIXEL_FORMAT_BGRA_8888:
 
392
              _cogl_bgra_to_rgba (src, temp_rgba); break;
 
393
            case COGL_PIXEL_FORMAT_ARGB_8888:
 
394
              _cogl_argb_to_rgba (src, temp_rgba); break;
 
395
            case COGL_PIXEL_FORMAT_ABGR_8888:
 
396
              _cogl_abgr_to_rgba (src, temp_rgba); break;
 
397
            default:
 
398
              break;
 
399
            }
 
400
 
 
401
          switch (dst_format & COGL_UNPREMULT_MASK)
 
402
            {
 
403
            case COGL_PIXEL_FORMAT_G_8:
 
404
              _cogl_rgba_to_g (temp_rgba, dst); break;
 
405
            case COGL_PIXEL_FORMAT_RGB_888:
 
406
              _cogl_rgba_to_rgb (temp_rgba, dst); break;
 
407
            case COGL_PIXEL_FORMAT_BGR_888:
 
408
              _cogl_rgba_to_bgr (temp_rgba, dst); break;
 
409
            case COGL_PIXEL_FORMAT_RGBA_8888:
 
410
              _cogl_rgba_to_rgba (temp_rgba, dst); break;
 
411
            case COGL_PIXEL_FORMAT_BGRA_8888:
 
412
              _cogl_rgba_to_bgra (temp_rgba, dst); break;
 
413
            case COGL_PIXEL_FORMAT_ARGB_8888:
 
414
              _cogl_rgba_to_argb (temp_rgba, dst); break;
 
415
            case COGL_PIXEL_FORMAT_ABGR_8888:
 
416
              _cogl_rgba_to_abgr (temp_rgba, dst); break;
 
417
            default:
 
418
              break;
 
419
            }
 
420
 
 
421
          src += src_bpp;
 
422
          dst += dst_bpp;
 
423
        }
 
424
    }
 
425
 
 
426
  return TRUE;
 
427
}
 
428
 
 
429
gboolean
 
430
_cogl_bitmap_fallback_unpremult (CoglBitmap *bmp)
 
431
{
 
432
  guint8  *p;
 
433
  int      x,y;
 
434
 
 
435
  /* Make sure format supported for un-premultiplication */
 
436
  if (!_cogl_bitmap_fallback_can_unpremult (bmp->format))
 
437
    return FALSE;
 
438
 
 
439
  for (y = 0; y < bmp->height; y++)
 
440
    {
 
441
      p = (guint8*) bmp->data + y * bmp->rowstride;
 
442
 
 
443
      if (bmp->format & COGL_AFIRST_BIT)
 
444
        {
 
445
          for (x = 0; x < bmp->width; x++)
 
446
            {
 
447
              if (p[0] == 0)
 
448
                _cogl_unpremult_alpha_0 (p);
 
449
              else
 
450
                _cogl_unpremult_alpha_first (p);
 
451
              p += 4;
 
452
            }
 
453
        }
 
454
      else
 
455
        {
 
456
          for (x = 0; x < bmp->width; x++)
 
457
            {
 
458
              if (p[3] == 0)
 
459
                _cogl_unpremult_alpha_0 (p);
 
460
              else
 
461
                _cogl_unpremult_alpha_last (p);
 
462
              p += 4;
 
463
            }
 
464
        }
 
465
    }
 
466
 
 
467
  bmp->format &= ~COGL_PREMULT_BIT;
 
468
 
 
469
  return TRUE;
 
470
}
 
471
 
 
472
gboolean
 
473
_cogl_bitmap_fallback_premult (CoglBitmap *bmp)
 
474
{
 
475
  guint8  *p;
 
476
  int      x,y;
 
477
 
 
478
  /* Make sure format supported for un-premultiplication */
 
479
  if (!_cogl_bitmap_fallback_can_premult (bmp->format))
 
480
    return FALSE;
 
481
 
 
482
  for (y = 0; y < bmp->height; y++)
 
483
    {
 
484
      p = (guint8*) bmp->data + y * bmp->rowstride;
 
485
 
 
486
      if (bmp->format & COGL_AFIRST_BIT)
 
487
        {
 
488
          for (x = 0; x < bmp->width; x++)
 
489
            {
 
490
              _cogl_premult_alpha_first (p);
 
491
              p += 4;
 
492
            }
 
493
        }
 
494
      else
 
495
        {
 
496
          x = bmp->width;
 
497
 
 
498
#ifdef COGL_USE_PREMULT_SSE2
 
499
 
 
500
          /* Process 4 pixels at a time */
 
501
          while (x >= 4)
 
502
            {
 
503
              _cogl_premult_alpha_last_four_pixels_sse2 (p);
 
504
              p += 4 * 4;
 
505
              x -= 4;
 
506
            }
 
507
 
 
508
          /* If there are any pixels left we will fall through and
 
509
             handle them below */
 
510
 
 
511
#endif /* COGL_USE_PREMULT_SSE2 */
 
512
 
 
513
          while (x-- > 0)
 
514
            {
 
515
              _cogl_premult_alpha_last (p);
 
516
              p += 4;
 
517
            }
 
518
        }
 
519
    }
 
520
 
 
521
  bmp->format |= COGL_PREMULT_BIT;
 
522
 
 
523
  return TRUE;
 
524
}
 
525
 
 
526
gboolean
 
527
_cogl_bitmap_fallback_from_file (CoglBitmap  *bmp,
 
528
                                 const char  *filename)
 
529
{
 
530
  /* FIXME: use jpeglib, libpng, etc. manually maybe */
 
531
  return FALSE;
 
532
}