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
)
256 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
258 if dst_channel
.type == FLOAT
:
260 one
= get_one(src_channel
)
261 if src_channel
.size
<= 23:
262 scale
= '(1.0f/0x%x)' % one
264 # bigger than single precision mantissa, use double
265 scale
= '(1.0/0x%x)' % one
266 value
= '(%s * %s)' % (value
, scale
)
267 return '(%s)%s' % (dst_native_type
, value
)
269 if src_channel
.type == FLOAT
:
271 dst_one
= get_one(dst_channel
)
272 if dst_channel
.size
<= 23:
273 scale
= '0x%x' % dst_one
275 # bigger than single precision mantissa, use double
276 scale
= '(double)0x%x' % dst_one
277 value
= '(%s * %s)' % (value
, scale
)
278 return '(%s)%s' % (dst_native_type
, value
)
280 if src_channel
.type in (SIGNED
, UNSIGNED
) and dst_channel
.type in (SIGNED
, UNSIGNED
):
281 if not src_channel
.norm
and not dst_channel
.norm
:
282 # neither is normalized -- just cast
283 return '(%s)%s' % (dst_native_type
, value
)
285 src_one
= get_one(src_channel
)
286 dst_one
= get_one(dst_channel
)
288 if src_one
> dst_one
and src_channel
.norm
and dst_channel
.norm
:
289 # We can just bitshift
290 src_shift
= get_one_shift(src_channel
)
291 dst_shift
= get_one_shift(dst_channel
)
292 value
= '(%s >> %s)' % (value
, src_shift
- dst_shift
)
294 # We need to rescale using an intermediate type big enough to hold the multiplication of both
295 tmp_native_type
= intermediate_native_type(src_channel
.size
+ dst_channel
.size
, src_channel
.sign
and dst_channel
.sign
)
296 value
= '((%s)%s)' % (tmp_native_type
, value
)
297 value
= '(%s * 0x%x / 0x%x)' % (value
, dst_one
, src_one
)
298 value
= '(%s)%s' % (dst_native_type
, value
)
304 def generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
):
305 '''Generate the function to unpack pixels from a particular format'''
307 assert format
.layout
== PLAIN
309 name
= format
.short_name()
311 src_native_type
= native_type(format
)
313 print 'static INLINE void'
314 print 'util_format_%s_unpack_%s(%s *dst, const void *src)' % (name
, dst_suffix
, dst_native_type
)
317 if format
.is_bitmask():
318 depth
= format
.block_size()
319 print ' uint%u_t value = *(uint%u_t *)src;' % (depth
, depth
)
321 # Declare the intermediate variables
322 for i
in range(format
.nr_channels()):
323 src_channel
= format
.channels
[i
]
324 if src_channel
.type == UNSIGNED
:
325 print ' uint%u_t %s;' % (depth
, src_channel
.name
)
326 elif src_channel
.type == SIGNED
:
327 print ' int%u_t %s;' % (depth
, src_channel
.name
)
329 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
330 print ' value = util_bswap%u(value);' % depth
333 # Compute the intermediate unshifted values
335 for i
in range(format
.nr_channels()):
336 src_channel
= format
.channels
[i
]
338 if src_channel
.type == UNSIGNED
:
340 value
= '%s >> %u' % (value
, shift
)
341 if shift
+ src_channel
.size
< depth
:
342 value
= '(%s) & 0x%x' % (value
, (1 << src_channel
.size
) - 1)
343 elif src_channel
.type == SIGNED
:
344 if shift
+ src_channel
.size
< depth
:
346 lshift
= depth
- (shift
+ src_channel
.size
)
347 value
= '%s << %u' % (value
, lshift
)
349 value
= '(int%u_t)(%s) ' % (depth
, value
)
350 if src_channel
.size
< depth
:
352 rshift
= depth
- src_channel
.size
353 value
= '(%s) >> %u' % (value
, rshift
)
357 if value
is not None:
358 print ' %s = %s;' % (src_channel
.name
, value
)
360 shift
+= src_channel
.size
362 # Convert, swizzle, and store final values
364 swizzle
= format
.swizzles
[i
]
366 src_channel
= format
.channels
[swizzle
]
367 value
= src_channel
.name
368 value
= conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
)
369 elif swizzle
== SWIZZLE_0
:
371 elif swizzle
== SWIZZLE_1
:
372 value
= get_one(dst_channel
)
373 elif swizzle
== SWIZZLE_NONE
:
377 if format
.colorspace
== ZS
:
379 value
= get_one(dst_channel
)
382 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
385 print ' union util_format_%s pixel;' % format
.short_name()
386 print ' memcpy(&pixel, src, sizeof pixel);'
390 swizzle
= format
.swizzles
[i
]
392 src_channel
= format
.channels
[swizzle
]
393 value
= 'pixel.chan.%s' % src_channel
.name
394 value
= conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
)
395 elif swizzle
== SWIZZLE_0
:
397 elif swizzle
== SWIZZLE_1
:
398 value
= get_one(dst_channel
)
399 elif swizzle
== SWIZZLE_NONE
:
403 if format
.colorspace
== ZS
:
405 value
= get_one(dst_channel
)
408 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
414 def generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
):
415 '''Generate the function to pack pixels to a particular format'''
417 name
= format
.short_name()
419 dst_native_type
= native_type(format
)
421 assert format
.layout
== PLAIN
423 inv_swizzle
= format
.inv_swizzles()
425 print 'static INLINE void'
426 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
)
429 if format
.is_bitmask():
430 depth
= format
.block_size()
431 print ' uint%u_t value = 0;' % depth
435 dst_channel
= format
.channels
[i
]
436 if inv_swizzle
[i
] is not None:
437 value
= 'rgba'[inv_swizzle
[i
]]
438 value
= conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
)
439 if format
.colorspace
== ZS
:
441 value
= get_one(dst_channel
)
444 if dst_channel
.type in (UNSIGNED
, SIGNED
):
445 if shift
+ dst_channel
.size
< depth
:
446 value
= '(%s) & 0x%x' % (value
, (1 << dst_channel
.size
) - 1)
448 value
= '(%s) << %u' % (value
, shift
)
449 if dst_channel
.type == SIGNED
:
451 value
= '(uint%u_t)(%s) ' % (depth
, value
)
454 if value
is not None:
455 print ' value |= %s;' % (value
)
457 shift
+= dst_channel
.size
459 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
460 print ' value = util_bswap%u(value);' % depth
463 print ' *(uint%u_t *)dst = value;' % depth
466 print ' union util_format_%s pixel;' % format
.short_name()
469 dst_channel
= format
.channels
[i
]
470 width
= dst_channel
.size
471 if inv_swizzle
[i
] is None:
473 value
= 'rgba'[inv_swizzle
[i
]]
474 value
= conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
)
475 if format
.colorspace
== ZS
:
477 value
= get_one(dst_channel
)
480 print ' pixel.chan.%s = %s;' % (dst_channel
.name
, value
)
483 print ' memcpy(dst, &pixel, sizeof pixel);'
489 def generate_unpack(formats
, dst_channel
, dst_native_type
, dst_suffix
):
490 '''Generate the dispatch function to unpack pixels from any format'''
492 for format
in formats
:
493 if is_format_supported(format
):
494 generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
)
496 print 'static INLINE void'
497 print 'util_format_unpack_%s(enum pipe_format format, %s *dst, const void *src)' % (dst_suffix
, dst_native_type
)
499 print ' void (*func)(%s *dst, const void *src);' % dst_native_type
500 print ' switch(format) {'
501 for format
in formats
:
502 if is_format_supported(format
):
503 print ' case %s:' % format
.name
504 print ' func = &util_format_%s_unpack_%s;' % (format
.short_name(), dst_suffix
)
507 print ' debug_printf("unsupported format\\n");'
510 print ' func(dst, src);'
515 def generate_pack(formats
, src_channel
, src_native_type
, src_suffix
):
516 '''Generate the dispatch function to pack pixels to any format'''
518 for format
in formats
:
519 if is_format_supported(format
):
520 generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
)
522 print 'static INLINE void'
523 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
)
525 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
)
526 print ' switch(format) {'
527 for format
in formats
:
528 if is_format_supported(format
):
529 print ' case %s:' % format
.name
530 print ' func = &util_format_%s_pack_%s;' % (format
.short_name(), src_suffix
)
533 print ' debug_printf("%s: unsupported format\\n", __FUNCTION__);'
536 print ' func(dst, r, g, b, a);'
543 for arg
in sys
.argv
[1:]:
544 formats
.extend(parse(arg
))
546 print '/* This file is autogenerated by u_format_pack.py from u_format.csv. Do not edit directly. */'
548 # This will print the copyright message on the top of this file
549 print __doc__
.strip()
552 print '#ifndef U_FORMAT_PACK_H'
553 print '#define U_FORMAT_PACK_H'
555 print '#include "pipe/p_compiler.h"'
556 print '#include "u_math.h"'
557 print '#include "u_format.h"'
562 for format
in formats
:
563 if format
.layout
== PLAIN
:
564 generate_format_type(format
)
566 channel
= Channel(FLOAT
, False, 32)
567 native_type
= 'float'
570 generate_unpack(formats
, channel
, native_type
, suffix
)
571 generate_pack(formats
, channel
, native_type
, suffix
)
573 channel
= Channel(UNSIGNED
, True, 8)
574 native_type
= 'uint8_t'
577 generate_unpack(formats
, channel
, native_type
, suffix
)
578 generate_pack(formats
, channel
, native_type
, suffix
)
581 print '#ifdef __cplusplus'
585 print '#endif /* ! U_FORMAT_PACK_H */'
588 if __name__
== '__main__':