4 /**************************************************************************
6 * Copyright 2009 VMware, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sub license, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice and this permission notice (including the
18 * next paragraph) shall be included in all copies or substantial portions
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
25 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
33 * Pixel format packing and unpacking functions.
35 * @author Jose Fonseca <jfonseca@vmware.com>
42 from u_format_parse
import *
45 def generate_format_type(format
):
46 '''Generate a structure that describes the format.'''
48 print 'union util_format_%s {' % format
.short_name()
49 if format
.is_bitmask():
50 print ' uint%u_t value;' % (format
.block_size(),)
52 for channel
in format
.channels
:
53 if format
.is_bitmask() and not format
.is_array():
54 if channel
.type == VOID
:
56 print ' unsigned %s:%u;' % (channel
.name
, channel
.size
)
57 elif channel
.type == UNSIGNED
:
58 print ' unsigned %s:%u;' % (channel
.name
, channel
.size
)
59 elif channel
.type == SIGNED
:
60 print ' int %s:%u;' % (channel
.name
, channel
.size
)
64 assert channel
.size
% 8 == 0 and is_pot(channel
.size
)
65 if channel
.type == VOID
:
67 print ' uint%u_t %s;' % (channel
.size
, channel
.name
)
68 elif channel
.type == UNSIGNED
:
69 print ' uint%u_t %s;' % (channel
.size
, channel
.name
)
70 elif channel
.type in (SIGNED
, FIXED
):
71 print ' int%u_t %s;' % (channel
.size
, channel
.name
)
72 elif channel
.type == FLOAT
:
73 if channel
.size
== 64:
74 print ' double %s;' % (channel
.name
)
75 elif channel
.size
== 32:
76 print ' float %s;' % (channel
.name
)
77 elif channel
.size
== 16:
78 print ' uint16_t %s;' % (channel
.name
)
88 def bswap_format(format
):
89 '''Generate a structure that describes the format.'''
91 if format
.is_bitmask() and not format
.is_array():
92 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
93 print ' pixel.value = util_bswap%u(pixel.value);' % format
.block_size()
97 def is_format_supported(format
):
98 '''Determines whether we actually have the plumbing necessary to generate the
99 to read/write to/from this format.'''
101 # FIXME: Ideally we would support any format combination here.
103 if format
.layout
!= PLAIN
:
107 channel
= format
.channels
[i
]
108 if channel
.type not in (VOID
, UNSIGNED
, SIGNED
, FLOAT
):
111 # We can only read a color from a depth/stencil format if the depth channel is present
112 if format
.colorspace
== 'zs' and format
.swizzles
[0] == SWIZZLE_NONE
:
118 def native_type(format
):
119 '''Get the native appropriate for a format.'''
121 if format
.layout
== PLAIN
:
122 if not format
.is_array():
123 # For arithmetic pixel formats return the integer type that matches the whole pixel
124 return 'uint%u_t' % format
.block_size()
126 # For array pixel formats return the integer type that matches the color channel
127 type = format
.channels
[0]
128 if type.type == UNSIGNED
:
129 return 'uint%u_t' % type.size
130 elif type.type == SIGNED
:
131 return 'int%u_t' % type.size
132 elif type.type == FLOAT
:
135 elif type.size
== 64:
145 def intermediate_native_type(bits
, sign
):
146 '''Find a native type adequate to hold intermediate results of the request bit size.'''
148 bytes
= 4 # don't use anything smaller than 32bits
149 while bytes
* 8 < bits
:
154 return 'int%u_t' % bits
156 return 'uint%u_t' % bits
159 def get_one_shift(type):
160 '''Get the number of the bit that matches unity for this type.'''
161 if type.type == 'FLOAT':
165 if type.type == UNSIGNED
:
167 if type.type == SIGNED
:
169 if type.type == FIXED
:
175 '''Get the value of unity for this type.'''
176 if type.type == 'FLOAT' or not type.norm
:
179 return (1 << get_one_shift(type)) - 1
182 def generate_clamp():
183 '''Code generate the clamping functions for each type.
185 We don't use a macro so that arguments with side effects,
186 like *src_pixel++ are correctly handled.
189 for suffix
, native_type
in [
192 ('ui', 'unsigned int'),
195 print 'static INLINE %s' % native_type
196 print 'clamp%s(%s value, %s lbound, %s ubound)' % (suffix
, native_type
, native_type
, native_type
)
198 print ' if(value < lbound)'
199 print ' return lbound;'
200 print ' if(value > ubound)'
201 print ' return ubound;'
202 print ' return value;'
207 def clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
):
208 '''Generate the expression to clamp the value in the source type to the
209 destination type range.'''
211 if src_channel
== dst_channel
:
214 # Pick the approriate clamp function
215 if src_channel
.type == FLOAT
:
216 if src_channel
.size
== 32:
218 elif src_channel
.size
== 64:
222 elif src_channel
.type == UNSIGNED
:
224 elif src_channel
.type == SIGNED
:
229 src_min
= src_channel
.min()
230 src_max
= src_channel
.max()
231 dst_min
= dst_channel
.min()
232 dst_max
= dst_channel
.max()
234 if src_min
< dst_min
and src_max
> dst_max
:
235 return 'CLAMP(%s, %s, %s)' % (value
, dst_min
, dst_max
)
237 if src_max
> dst_max
:
238 return 'MIN2(%s, %s)' % (value
, dst_max
)
240 if src_min
< dst_min
:
241 return 'MAX2(%s, %s)' % (value
, dst_min
)
246 def conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
, clamp
=True):
247 '''Generate the expression to convert a value between two types.'''
249 if src_channel
== dst_channel
:
252 if src_channel
.type == FLOAT
and dst_channel
.type == FLOAT
:
253 return '(%s)%s' % (dst_native_type
, value
)
255 if not src_channel
.norm
and not dst_channel
.norm
:
256 return '(%s)%s' % (dst_native_type
, value
)
259 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
261 if dst_channel
.type == FLOAT
:
263 one
= get_one(src_channel
)
264 if src_channel
.size
<= 23:
265 scale
= '(1.0f/0x%x)' % one
267 # bigger than single precision mantissa, use double
268 scale
= '(1.0/0x%x)' % one
269 value
= '(%s * %s)' % (value
, scale
)
270 return '(%s)%s' % (dst_native_type
, value
)
272 if src_channel
.type == FLOAT
:
274 dst_one
= get_one(dst_channel
)
275 if dst_channel
.size
<= 23:
276 scale
= '0x%x' % dst_one
278 # bigger than single precision mantissa, use double
279 scale
= '(double)0x%x' % dst_one
280 value
= '(%s * %s)' % (value
, scale
)
281 return '(%s)%s' % (dst_native_type
, value
)
283 if not src_channel
.norm
and not dst_channel
.norm
:
284 # neither is normalized -- just cast
285 return '(%s)%s' % (dst_native_type
, value
)
287 if src_channel
.type in (SIGNED
, UNSIGNED
) and dst_channel
.type in (SIGNED
, UNSIGNED
):
288 src_one
= get_one(src_channel
)
289 dst_one
= get_one(dst_channel
)
291 if src_one
> dst_one
and src_channel
.norm
:
292 # We can just bitshift
293 src_shift
= get_one_shift(src_channel
)
294 dst_shift
= get_one_shift(dst_channel
)
295 value
= '(%s >> %s)' % (value
, src_shift
- dst_shift
)
297 # We need to rescale using an intermediate type big enough to hold the multiplication of both
298 tmp_native_type
= intermediate_native_type(src_channel
.size
+ dst_channel
.size
, src_channel
.sign
and dst_channel
.sign
)
299 value
= '(%s)%s' % (tmp_native_type
, value
)
300 value
= '(%s * 0x%x / 0x%x)' % (value
, dst_one
, src_one
)
301 value
= '(%s)%s' % (dst_native_type
, value
)
307 def generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
):
308 '''Generate the function to unpack pixels from a particular format'''
310 name
= format
.short_name()
312 src_native_type
= native_type(format
)
314 print 'static INLINE void'
315 print 'util_format_%s_unpack_%s(%s *dst, const void *src)' % (name
, dst_suffix
, dst_native_type
)
317 print ' union util_format_%s pixel;' % format
.short_name()
318 print ' memcpy(&pixel, src, sizeof pixel);'
321 assert format
.layout
== PLAIN
324 swizzle
= format
.swizzles
[i
]
326 src_channel
= format
.channels
[swizzle
]
327 value
= 'pixel.chan.%s' % src_channel
.name
328 value
= conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
)
329 elif swizzle
== SWIZZLE_0
:
331 elif swizzle
== SWIZZLE_1
:
332 value
= get_one(dst_channel
)
333 elif swizzle
== SWIZZLE_NONE
:
337 if format
.colorspace
== ZS
:
339 value
= get_one(dst_channel
)
342 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
348 def generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
):
349 '''Generate the function to pack pixels to a particular format'''
351 name
= format
.short_name()
353 dst_native_type
= native_type(format
)
355 print 'static INLINE void'
356 print 'util_format_%s_pack_%s(void *dst, %s r, %s g, %s b, %s a)' % (name
, src_suffix
, src_native_type
, src_native_type
, src_native_type
, src_native_type
)
358 print ' union util_format_%s pixel;' % format
.short_name()
360 assert format
.layout
== PLAIN
362 inv_swizzle
= format
.inv_swizzles()
365 dst_channel
= format
.channels
[i
]
366 width
= dst_channel
.size
367 if inv_swizzle
[i
] is None:
369 value
= 'rgba'[inv_swizzle
[i
]]
370 value
= conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
)
371 if format
.colorspace
== ZS
:
373 value
= get_one(dst_channel
)
376 print ' pixel.chan.%s = %s;' % (dst_channel
.name
, value
)
379 print ' memcpy(dst, &pixel, sizeof pixel);'
384 def generate_unpack(formats
, dst_channel
, dst_native_type
, dst_suffix
):
385 '''Generate the dispatch function to unpack pixels from any format'''
387 for format
in formats
:
388 if is_format_supported(format
):
389 generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
)
391 print 'static INLINE void'
392 print 'util_format_unpack_%s(enum pipe_format format, %s *dst, const void *src)' % (dst_suffix
, dst_native_type
)
394 print ' void (*func)(%s *dst, const void *src);' % dst_native_type
395 print ' switch(format) {'
396 for format
in formats
:
397 if is_format_supported(format
):
398 print ' case %s:' % format
.name
399 print ' func = &util_format_%s_unpack_%s;' % (format
.short_name(), dst_suffix
)
402 print ' debug_printf("unsupported format\\n");'
405 print ' func(dst, src);'
410 def generate_pack(formats
, src_channel
, src_native_type
, src_suffix
):
411 '''Generate the dispatch function to pack pixels to any format'''
413 for format
in formats
:
414 if is_format_supported(format
):
415 generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
)
417 print 'static INLINE void'
418 print 'util_format_pack_%s(enum pipe_format format, void *dst, %s r, %s g, %s b, %s a)' % (src_suffix
, src_native_type
, src_native_type
, src_native_type
, src_native_type
)
420 print ' void (*func)(void *dst, %s r, %s g, %s b, %s a);' % (src_native_type
, src_native_type
, src_native_type
, src_native_type
)
421 print ' switch(format) {'
422 for format
in formats
:
423 if is_format_supported(format
):
424 print ' case %s:' % format
.name
425 print ' func = &util_format_%s_pack_%s;' % (format
.short_name(), src_suffix
)
428 print ' debug_printf("%s: unsupported format\\n", __FUNCTION__);'
431 print ' func(dst, r, g, b, a);'
438 for arg
in sys
.argv
[1:]:
439 formats
.extend(parse(arg
))
441 print '/* This file is autogenerated by u_format_pack.py from u_format.csv. Do not edit directly. */'
443 # This will print the copyright message on the top of this file
444 print __doc__
.strip()
447 print '#ifndef U_FORMAT_PACK_H'
448 print '#define U_FORMAT_PACK_H'
450 print '#include "pipe/p_compiler.h"'
451 print '#include "u_math.h"'
452 print '#include "u_format.h"'
457 for format
in formats
:
458 if format
.layout
== PLAIN
:
459 generate_format_type(format
)
461 channel
= Channel(FLOAT
, False, 32)
462 native_type
= 'float'
465 generate_unpack(formats
, channel
, native_type
, suffix
)
466 generate_pack(formats
, channel
, native_type
, suffix
)
468 channel
= Channel(UNSIGNED
, True, 8)
469 native_type
= 'uint8_t'
472 generate_unpack(formats
, channel
, native_type
, suffix
)
473 generate_pack(formats
, channel
, native_type
, suffix
)
476 print '#ifdef __cplusplus'
480 print '#endif /* ! U_FORMAT_PACK_H */'
483 if __name__
== '__main__':