"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / cogl-util.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2007,2008,2009,2010 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-util.h"
29 #include "cogl-private.h"
30
31 /*
32  * cogl_util_next_p2:
33  * @a: Value to get the next power of two
34  *
35  * Calculates the next power of two greater than or equal to @a.
36  *
37  * Return value: @a if @a is already a power of two, otherwise returns
38  *   the next nearest power of two.
39  */
40 int
41 _cogl_util_next_p2 (int a)
42 {
43   int rval = 1;
44
45   while (rval < a)
46     rval <<= 1;
47
48   return rval;
49 }
50
51 unsigned int
52 _cogl_util_one_at_a_time_mix (unsigned int hash)
53 {
54   hash += ( hash << 3 );
55   hash ^= ( hash >> 11 );
56   hash += ( hash << 15 );
57
58   return hash;
59 }
60
61 /* The 'ffs' function is part of C99 so it isn't always available */
62 #ifndef HAVE_FFS
63
64 int
65 _cogl_util_ffs (int num)
66 {
67   int i = 1;
68
69   if (num == 0)
70     return 0;
71
72   while ((num & 1) == 0)
73     {
74       num >>= 1;
75       i++;
76     }
77
78   return i;
79 }
80 #endif /* HAVE_FFS */
81
82 /* The 'ffsl' is non-standard but when building with GCC we'll use its
83    builtin instead */
84 #ifndef COGL_UTIL_HAVE_BUILTIN_FFSL
85
86 int
87 _cogl_util_ffsl_wrapper (long int num)
88 {
89   int i = 1;
90
91   if (num == 0)
92     return 0;
93
94   while ((num & 1) == 0)
95     {
96       num >>= 1;
97       i++;
98     }
99
100   return i;
101 }
102
103 #endif /* COGL_UTIL_HAVE_BUILTIN_FFSL */
104
105 #ifndef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL
106
107 const unsigned char
108 _cogl_util_popcount_table[256] =
109   {
110     0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4,
111     2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
112     2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
113     2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
114     2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
115     4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
116     2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
117     3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
118     2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
119     4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
120     4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
121   };
122
123 #endif /* COGL_UTIL_HAVE_BUILTIN_POPCOUNTL */
124
125 /* tests/conform/test-bitmask.c tests some cogl internals and includes this
126  * file directly but since these functions depend on other internal Cogl
127  * symbols we hide them from test-bitmask.c
128  *
129  * XXX: maybe there's a better way for us to handle internal testing
130  * to avoid needing hacks like this.
131  */
132 #ifndef _COGL_IN_TEST_BITMASK
133
134 /* Given a set of red, green and blue component masks, a depth and
135  * bits per pixel this function tries to determine a corresponding
136  * CoglPixelFormat.
137  *
138  * The depth is measured in bits not including padding for un-used
139  * alpha. The bits per pixel (bpp) does include padding for un-used
140  * alpha.
141  *
142  * This function firstly aims to match formats with RGB ordered
143  * components and only considers alpha coming first, in the most
144  * significant bits. If the function fails to match then it recurses
145  * by either switching the r and b masks around to check for BGR
146  * ordered formats or it recurses with the masks shifted to check for
147  * formats where the alpha component is the least significant bits.
148  */
149 static CoglPixelFormat
150 _cogl_util_pixel_format_from_masks_real (unsigned long r_mask,
151                                          unsigned long g_mask,
152                                          unsigned long b_mask,
153                                          int depth, int bpp,
154                                          gboolean check_bgr,
155                                          gboolean check_afirst,
156                                          int recursion_depth)
157 {
158   CoglPixelFormat image_format;
159
160   if (depth == 24 && bpp == 24 &&
161       r_mask == 0xff0000 && g_mask == 0xff00 && b_mask == 0xff)
162     {
163       return COGL_PIXEL_FORMAT_RGB_888;
164     }
165   else if ((depth == 24 || depth == 32) && bpp == 32 &&
166            r_mask == 0xff0000 && g_mask == 0xff00 && b_mask == 0xff)
167     {
168       return COGL_PIXEL_FORMAT_ARGB_8888_PRE;
169     }
170   else if ((depth == 30 || depth == 32) &&
171            r_mask == 0x3ff00000 && g_mask == 0xffc00 && b_mask == 0x3ff)
172     {
173       return COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
174     }
175   else if (depth == 16 && bpp == 16 &&
176            r_mask == 0xf800 && g_mask == 0x7e0 && b_mask == 0x1f)
177     {
178       return COGL_PIXEL_FORMAT_RGB_565;
179     }
180
181   if (recursion_depth == 2)
182     return 0;
183
184   /* Check for BGR ordering if we didn't find a match */
185   if (check_bgr)
186     {
187       image_format =
188         _cogl_util_pixel_format_from_masks_real (b_mask, g_mask, r_mask,
189                                                  depth, bpp,
190                                                  FALSE,
191                                                  TRUE,
192                                                  recursion_depth + 1);
193       if (image_format)
194         return image_format ^ COGL_BGR_BIT;
195     }
196
197   /* Check for alpha in the least significant bits if we still
198    * haven't found a match... */
199   if (check_afirst && depth != bpp)
200     {
201       int shift = bpp - depth;
202
203       image_format =
204         _cogl_util_pixel_format_from_masks_real (r_mask >> shift,
205                                                  g_mask >> shift,
206                                                  b_mask >> shift,
207                                                  depth, bpp,
208                                                  TRUE,
209                                                  FALSE,
210                                                  recursion_depth + 1);
211       if (image_format)
212         return image_format ^ COGL_AFIRST_BIT;
213     }
214
215   return 0;
216 }
217
218 CoglPixelFormat
219 _cogl_util_pixel_format_from_masks (unsigned long r_mask,
220                                     unsigned long g_mask,
221                                     unsigned long b_mask,
222                                     int depth, int bpp,
223                                     gboolean byte_order_is_lsb_first)
224 {
225   CoglPixelFormat image_format =
226     _cogl_util_pixel_format_from_masks_real (r_mask, g_mask, b_mask,
227                                              depth, bpp,
228                                              TRUE,
229                                              TRUE,
230                                              0);
231
232   if (!image_format)
233     {
234       const char *byte_order[] = { "MSB first", "LSB first" };
235       g_warning ("Could not find a matching pixel format for red mask=0x%lx,"
236                  "green mask=0x%lx, blue mask=0x%lx at depth=%d, bpp=%d "
237                  "and byte order=%s\n", r_mask, g_mask, b_mask, depth, bpp,
238                  byte_order[!!byte_order_is_lsb_first]);
239       return 0;
240     }
241
242   /* If the image is in little-endian then the order in memory is
243      reversed */
244   if (byte_order_is_lsb_first &&
245       _cogl_pixel_format_is_endian_dependant (image_format))
246     {
247       image_format ^= COGL_BGR_BIT;
248       if (image_format & COGL_A_BIT)
249         image_format ^= COGL_AFIRST_BIT;
250     }
251
252   return image_format;
253 }
254
255 #endif /* _COGL_IN_TEST_BITMASK */