3 /**************************************************************************
5 * Copyright 2009-2010 VMware, Inc.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
32 * Pixel format packing and unpacking functions.
34 * @author Jose Fonseca <jfonseca@vmware.com>
39 from __future__
import division
, print_function
43 from u_format_parse
import *
46 if sys
.version_info
< (3, 0):
47 integer_types
= (int, long)
50 integer_types
= (int, )
53 def inv_swizzles(swizzles
):
54 '''Return an array[4] of inverse swizzle terms'''
55 '''Only pick the first matching value to avoid l8 getting blue and i8 getting alpha'''
56 inv_swizzle
= [None]*4
59 if swizzle
< 4 and inv_swizzle
[swizzle
] == None:
60 inv_swizzle
[swizzle
] = i
63 def print_channels(format
, func
):
64 if format
.nr_channels() <= 1:
65 func(format
.le_channels
, format
.le_swizzles
)
67 if (format
.le_channels
== format
.be_channels
and
68 [c
.shift
for c
in format
.le_channels
] ==
69 [c
.shift
for c
in format
.be_channels
] and
70 format
.le_swizzles
== format
.be_swizzles
):
71 func(format
.le_channels
, format
.le_swizzles
)
73 print('#if UTIL_ARCH_BIG_ENDIAN')
74 func(format
.be_channels
, format
.be_swizzles
)
76 func(format
.le_channels
, format
.le_swizzles
)
79 def generate_format_type(format
):
80 '''Generate a structure that describes the format.'''
82 assert format
.layout
== PLAIN
84 def generate_bitfields(channels
, swizzles
):
85 for channel
in channels
:
86 if channel
.type == VOID
:
88 print(' unsigned %s:%u;' % (channel
.name
, channel
.size
))
89 elif channel
.type == UNSIGNED
:
90 print(' unsigned %s:%u;' % (channel
.name
, channel
.size
))
91 elif channel
.type in (SIGNED
, FIXED
):
92 print(' int %s:%u;' % (channel
.name
, channel
.size
))
93 elif channel
.type == FLOAT
:
94 if channel
.size
== 64:
95 print(' double %s;' % (channel
.name
))
96 elif channel
.size
== 32:
97 print(' float %s;' % (channel
.name
))
99 print(' unsigned %s:%u;' % (channel
.name
, channel
.size
))
103 def generate_full_fields(channels
, swizzles
):
104 for channel
in channels
:
105 assert channel
.size
% 8 == 0 and is_pot(channel
.size
)
106 if channel
.type == VOID
:
108 print(' uint%u_t %s;' % (channel
.size
, channel
.name
))
109 elif channel
.type == UNSIGNED
:
110 print(' uint%u_t %s;' % (channel
.size
, channel
.name
))
111 elif channel
.type in (SIGNED
, FIXED
):
112 print(' int%u_t %s;' % (channel
.size
, channel
.name
))
113 elif channel
.type == FLOAT
:
114 if channel
.size
== 64:
115 print(' double %s;' % (channel
.name
))
116 elif channel
.size
== 32:
117 print(' float %s;' % (channel
.name
))
118 elif channel
.size
== 16:
119 print(' uint16_t %s;' % (channel
.name
))
125 use_bitfields
= False
126 for channel
in format
.le_channels
:
127 if channel
.size
% 8 or not is_pot(channel
.size
):
130 print('struct util_format_%s {' % format
.short_name())
132 print_channels(format
, generate_bitfields
)
134 print_channels(format
, generate_full_fields
)
139 def is_format_supported(format
):
140 '''Determines whether we actually have the plumbing necessary to generate the
141 to read/write to/from this format.'''
143 # FIXME: Ideally we would support any format combination here.
145 if format
.layout
!= PLAIN
:
149 channel
= format
.le_channels
[i
]
150 if channel
.type not in (VOID
, UNSIGNED
, SIGNED
, FLOAT
, FIXED
):
152 if channel
.type == FLOAT
and channel
.size
not in (16, 32, 64):
157 def native_type(format
):
158 '''Get the native appropriate for a format.'''
160 if format
.name
== 'PIPE_FORMAT_R11G11B10_FLOAT':
162 if format
.name
== 'PIPE_FORMAT_R9G9B9E5_FLOAT':
165 if format
.layout
== PLAIN
:
166 if not format
.is_array():
167 # For arithmetic pixel formats return the integer type that matches the whole pixel
168 return 'uint%u_t' % format
.block_size()
170 # For array pixel formats return the integer type that matches the color channel
171 channel
= format
.array_element()
172 if channel
.type in (UNSIGNED
, VOID
):
173 return 'uint%u_t' % channel
.size
174 elif channel
.type in (SIGNED
, FIXED
):
175 return 'int%u_t' % channel
.size
176 elif channel
.type == FLOAT
:
177 if channel
.size
== 16:
179 elif channel
.size
== 32:
181 elif channel
.size
== 64:
191 def intermediate_native_type(bits
, sign
):
192 '''Find a native type adequate to hold intermediate results of the request bit size.'''
194 bytes
= 4 # don't use anything smaller than 32bits
195 while bytes
* 8 < bits
:
200 return 'int%u_t' % bits
202 return 'uint%u_t' % bits
205 def get_one_shift(type):
206 '''Get the number of the bit that matches unity for this type.'''
207 if type.type == 'FLOAT':
211 if type.type == UNSIGNED
:
213 if type.type == SIGNED
:
215 if type.type == FIXED
:
220 def truncate_mantissa(x
, bits
):
221 '''Truncate an integer so it can be represented exactly with a floating
224 assert isinstance(x
, integer_types
)
231 # We can represent integers up to mantissa + 1 bits exactly
232 mask
= (1 << (bits
+ 1)) - 1
234 # Slide the mask until the MSB matches
236 while (x
>> shift
) & ~mask
:
244 def value_to_native(type, value
):
245 '''Get the value of unity for this type.'''
246 if type.type == FLOAT
:
248 and isinstance(value
, integer_types
):
249 return truncate_mantissa(value
, 23)
251 if type.type == FIXED
:
252 return int(value
* (1 << (type.size
// 2)))
255 if type.type == UNSIGNED
:
256 return int(value
* ((1 << type.size
) - 1))
257 if type.type == SIGNED
:
258 return int(value
* ((1 << (type.size
- 1)) - 1))
262 def native_to_constant(type, value
):
263 '''Get the value of unity for this type.'''
264 if type.type == FLOAT
:
266 return "%.1ff" % float(value
)
268 return "%.1f" % float(value
)
270 return str(int(value
))
274 '''Get the value of unity for this type.'''
275 return value_to_native(type, 1)
278 def clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
):
279 '''Generate the expression to clamp the value in the source type to the
280 destination type range.'''
282 if src_channel
== dst_channel
:
285 src_min
= src_channel
.min()
286 src_max
= src_channel
.max()
287 dst_min
= dst_channel
.min()
288 dst_max
= dst_channel
.max()
290 # Translate the destination range to the src native value
291 dst_min_native
= native_to_constant(src_channel
, value_to_native(src_channel
, dst_min
))
292 dst_max_native
= native_to_constant(src_channel
, value_to_native(src_channel
, dst_max
))
294 if src_min
< dst_min
and src_max
> dst_max
:
295 return 'CLAMP(%s, %s, %s)' % (value
, dst_min_native
, dst_max_native
)
297 if src_max
> dst_max
:
298 return 'MIN2(%s, %s)' % (value
, dst_max_native
)
300 if src_min
< dst_min
:
301 return 'MAX2(%s, %s)' % (value
, dst_min_native
)
306 def conversion_expr(src_channel
,
307 dst_channel
, dst_native_type
,
310 src_colorspace
= RGB
,
311 dst_colorspace
= RGB
):
312 '''Generate the expression to convert a value between two types.'''
314 if src_colorspace
!= dst_colorspace
:
315 if src_colorspace
== SRGB
:
316 assert src_channel
.type == UNSIGNED
317 assert src_channel
.norm
318 assert src_channel
.size
<= 8
319 assert src_channel
.size
>= 4
320 assert dst_colorspace
== RGB
321 if src_channel
.size
< 8:
322 value
= '%s << %x | %s >> %x' % (value
, 8 - src_channel
.size
, value
, 2 * src_channel
.size
- 8)
323 if dst_channel
.type == FLOAT
:
324 return 'util_format_srgb_8unorm_to_linear_float(%s)' % value
326 assert dst_channel
.type == UNSIGNED
327 assert dst_channel
.norm
328 assert dst_channel
.size
== 8
329 return 'util_format_srgb_to_linear_8unorm(%s)' % value
330 elif dst_colorspace
== SRGB
:
331 assert dst_channel
.type == UNSIGNED
332 assert dst_channel
.norm
333 assert dst_channel
.size
<= 8
334 assert src_colorspace
== RGB
335 if src_channel
.type == FLOAT
:
336 value
= 'util_format_linear_float_to_srgb_8unorm(%s)' % value
338 assert src_channel
.type == UNSIGNED
339 assert src_channel
.norm
340 assert src_channel
.size
== 8
341 value
= 'util_format_linear_to_srgb_8unorm(%s)' % value
342 # XXX rounding is all wrong.
343 if dst_channel
.size
< 8:
344 return '%s >> %x' % (value
, 8 - dst_channel
.size
)
347 elif src_colorspace
== ZS
:
349 elif dst_colorspace
== ZS
:
354 if src_channel
== dst_channel
:
357 src_type
= src_channel
.type
358 src_size
= src_channel
.size
359 src_norm
= src_channel
.norm
360 src_pure
= src_channel
.pure
362 # Promote half to float
363 if src_type
== FLOAT
and src_size
== 16:
364 value
= 'util_half_to_float(%s)' % value
367 # Special case for float <-> ubytes for more accurate results
368 # Done before clamping since these functions already take care of that
369 if src_type
== UNSIGNED
and src_norm
and src_size
== 8 and dst_channel
.type == FLOAT
and dst_channel
.size
== 32:
370 return 'ubyte_to_float(%s)' % value
371 if src_type
== FLOAT
and src_size
== 32 and dst_channel
.type == UNSIGNED
and dst_channel
.norm
and dst_channel
.size
== 8:
372 return 'float_to_ubyte(%s)' % value
375 if dst_channel
.type != FLOAT
or src_type
!= FLOAT
:
376 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
378 if src_type
in (SIGNED
, UNSIGNED
) and dst_channel
.type in (SIGNED
, UNSIGNED
):
379 if not src_norm
and not dst_channel
.norm
:
380 # neither is normalized -- just cast
381 return '(%s)%s' % (dst_native_type
, value
)
383 src_one
= get_one(src_channel
)
384 dst_one
= get_one(dst_channel
)
386 if src_one
> dst_one
and src_norm
and dst_channel
.norm
:
387 # We can just bitshift
388 src_shift
= get_one_shift(src_channel
)
389 dst_shift
= get_one_shift(dst_channel
)
390 value
= '(%s >> %s)' % (value
, src_shift
- dst_shift
)
392 # We need to rescale using an intermediate type big enough to hold the multiplication of both
393 tmp_native_type
= intermediate_native_type(src_size
+ dst_channel
.size
, src_channel
.sign
and dst_channel
.sign
)
394 value
= '((%s)%s)' % (tmp_native_type
, value
)
395 value
= '(%s * 0x%x / 0x%x)' % (value
, dst_one
, src_one
)
396 value
= '(%s)%s' % (dst_native_type
, value
)
399 # Promote to either float or double
400 if src_type
!= FLOAT
:
401 if src_norm
or src_type
== FIXED
:
402 one
= get_one(src_channel
)
404 value
= '(%s * (1.0f/0x%x))' % (value
, one
)
405 if dst_channel
.size
<= 32:
406 value
= '(float)%s' % value
409 # bigger than single precision mantissa, use double
410 value
= '(%s * (1.0/0x%x))' % (value
, one
)
414 if src_size
<= 23 or dst_channel
.size
<= 32:
415 value
= '(float)%s' % value
418 # bigger than single precision mantissa, use double
419 value
= '(double)%s' % value
423 # Convert double or float to non-float
424 if dst_channel
.type != FLOAT
:
425 if dst_channel
.norm
or dst_channel
.type == FIXED
:
426 dst_one
= get_one(dst_channel
)
427 if dst_channel
.size
<= 23:
428 value
= 'util_iround(%s * 0x%x)' % (value
, dst_one
)
430 # bigger than single precision mantissa, use double
431 value
= '(%s * (double)0x%x)' % (value
, dst_one
)
432 value
= '(%s)%s' % (dst_native_type
, value
)
434 # Cast double to float when converting to either half or float
435 if dst_channel
.size
<= 32 and src_size
> 32:
436 value
= '(float)%s' % value
439 if dst_channel
.size
== 16:
440 value
= 'util_float_to_half_rtz(%s)' % value
441 elif dst_channel
.size
== 64 and src_size
< 64:
442 value
= '(double)%s' % value
447 def generate_unpack_kernel(format
, dst_channel
, dst_native_type
):
449 if not is_format_supported(format
):
452 assert format
.layout
== PLAIN
454 def unpack_from_bitmask(channels
, swizzles
):
455 depth
= format
.block_size()
456 print(' uint%u_t value = *(const uint%u_t *)src;' % (depth
, depth
))
458 # Declare the intermediate variables
459 for i
in range(format
.nr_channels()):
460 src_channel
= channels
[i
]
461 if src_channel
.type == UNSIGNED
:
462 print(' uint%u_t %s;' % (depth
, src_channel
.name
))
463 elif src_channel
.type == SIGNED
:
464 print(' int%u_t %s;' % (depth
, src_channel
.name
))
466 # Compute the intermediate unshifted values
467 for i
in range(format
.nr_channels()):
468 src_channel
= channels
[i
]
470 shift
= src_channel
.shift
471 if src_channel
.type == UNSIGNED
:
473 value
= '%s >> %u' % (value
, shift
)
474 if shift
+ src_channel
.size
< depth
:
475 value
= '(%s) & 0x%x' % (value
, (1 << src_channel
.size
) - 1)
476 elif src_channel
.type == SIGNED
:
477 if shift
+ src_channel
.size
< depth
:
479 lshift
= depth
- (shift
+ src_channel
.size
)
480 value
= '%s << %u' % (value
, lshift
)
482 value
= '(int%u_t)(%s) ' % (depth
, value
)
483 if src_channel
.size
< depth
:
485 rshift
= depth
- src_channel
.size
486 value
= '(%s) >> %u' % (value
, rshift
)
490 if value
is not None:
491 print(' %s = %s;' % (src_channel
.name
, value
))
493 # Convert, swizzle, and store final values
495 swizzle
= swizzles
[i
]
497 src_channel
= channels
[swizzle
]
498 src_colorspace
= format
.colorspace
499 if src_colorspace
== SRGB
and i
== 3:
500 # Alpha channel is linear
502 value
= src_channel
.name
503 value
= conversion_expr(src_channel
,
504 dst_channel
, dst_native_type
,
506 src_colorspace
= src_colorspace
)
507 elif swizzle
== SWIZZLE_0
:
509 elif swizzle
== SWIZZLE_1
:
510 value
= get_one(dst_channel
)
511 elif swizzle
== SWIZZLE_NONE
:
515 print(' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
]))
517 def unpack_from_struct(channels
, swizzles
):
518 print(' struct util_format_%s pixel;' % format
.short_name())
519 print(' memcpy(&pixel, src, sizeof pixel);')
522 swizzle
= swizzles
[i
]
524 src_channel
= channels
[swizzle
]
525 src_colorspace
= format
.colorspace
526 if src_colorspace
== SRGB
and i
== 3:
527 # Alpha channel is linear
529 value
= 'pixel.%s' % src_channel
.name
530 value
= conversion_expr(src_channel
,
531 dst_channel
, dst_native_type
,
533 src_colorspace
= src_colorspace
)
534 elif swizzle
== SWIZZLE_0
:
536 elif swizzle
== SWIZZLE_1
:
537 value
= get_one(dst_channel
)
538 elif swizzle
== SWIZZLE_NONE
:
542 print(' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
]))
544 if format
.is_bitmask():
545 print_channels(format
, unpack_from_bitmask
)
547 print_channels(format
, unpack_from_struct
)
550 def generate_pack_kernel(format
, src_channel
, src_native_type
):
552 if not is_format_supported(format
):
555 dst_native_type
= native_type(format
)
557 assert format
.layout
== PLAIN
559 def pack_into_bitmask(channels
, swizzles
):
560 inv_swizzle
= inv_swizzles(swizzles
)
562 depth
= format
.block_size()
563 print(' uint%u_t value = 0;' % depth
)
566 dst_channel
= channels
[i
]
567 shift
= dst_channel
.shift
568 if inv_swizzle
[i
] is not None:
569 value
='src[%u]' % inv_swizzle
[i
]
570 dst_colorspace
= format
.colorspace
571 if dst_colorspace
== SRGB
and inv_swizzle
[i
] == 3:
572 # Alpha channel is linear
574 value
= conversion_expr(src_channel
,
575 dst_channel
, dst_native_type
,
577 dst_colorspace
= dst_colorspace
)
578 if dst_channel
.type in (UNSIGNED
, SIGNED
):
579 if shift
+ dst_channel
.size
< depth
:
580 value
= '(%s) & 0x%x' % (value
, (1 << dst_channel
.size
) - 1)
582 value
= '(uint32_t)(%s) << %u' % (value
, shift
)
583 if dst_channel
.type == SIGNED
:
585 value
= '(uint%u_t)(%s) ' % (depth
, value
)
588 if value
is not None:
589 print(' value |= %s;' % (value
))
591 print(' *(uint%u_t *)dst = value;' % depth
)
593 def pack_into_struct(channels
, swizzles
):
594 inv_swizzle
= inv_swizzles(swizzles
)
596 print(' struct util_format_%s pixel;' % format
.short_name())
599 dst_channel
= channels
[i
]
600 width
= dst_channel
.size
601 if inv_swizzle
[i
] is None:
603 dst_colorspace
= format
.colorspace
604 if dst_colorspace
== SRGB
and inv_swizzle
[i
] == 3:
605 # Alpha channel is linear
607 value
='src[%u]' % inv_swizzle
[i
]
608 value
= conversion_expr(src_channel
,
609 dst_channel
, dst_native_type
,
611 dst_colorspace
= dst_colorspace
)
612 print(' pixel.%s = %s;' % (dst_channel
.name
, value
))
614 print(' memcpy(dst, &pixel, sizeof pixel);')
616 if format
.is_bitmask():
617 print_channels(format
, pack_into_bitmask
)
619 print_channels(format
, pack_into_struct
)
622 def generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
):
623 '''Generate the function to unpack pixels from a particular format'''
625 name
= format
.short_name()
627 print('static inline void')
628 print('util_format_%s_unpack_%s(%s *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height)' % (name
, dst_suffix
, dst_native_type
))
631 if is_format_supported(format
):
632 print(' unsigned x, y;')
633 print(' for(y = 0; y < height; y += %u) {' % (format
.block_height
,))
634 print(' %s *dst = dst_row;' % (dst_native_type
))
635 print(' const uint8_t *src = src_row;')
636 print(' for(x = 0; x < width; x += %u) {' % (format
.block_width
,))
638 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
640 print(' src += %u;' % (format
.block_size() / 8,))
643 print(' src_row += src_stride;')
644 print(' dst_row += dst_stride/sizeof(*dst_row);')
651 def generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
):
652 '''Generate the function to pack pixels to a particular format'''
654 name
= format
.short_name()
656 print('static inline void')
657 print('util_format_%s_pack_%s(uint8_t *dst_row, unsigned dst_stride, const %s *src_row, unsigned src_stride, unsigned width, unsigned height)' % (name
, src_suffix
, src_native_type
))
660 if is_format_supported(format
):
661 print(' unsigned x, y;')
662 print(' for(y = 0; y < height; y += %u) {' % (format
.block_height
,))
663 print(' const %s *src = src_row;' % (src_native_type
))
664 print(' uint8_t *dst = dst_row;')
665 print(' for(x = 0; x < width; x += %u) {' % (format
.block_width
,))
667 generate_pack_kernel(format
, src_channel
, src_native_type
)
670 print(' dst += %u;' % (format
.block_size() / 8,))
672 print(' dst_row += dst_stride;')
673 print(' src_row += src_stride/sizeof(*src_row);')
680 def generate_format_fetch(format
, dst_channel
, dst_native_type
, dst_suffix
):
681 '''Generate the function to unpack pixels from a particular format'''
683 name
= format
.short_name()
685 print('static inline void')
686 print('util_format_%s_fetch_%s(%s *dst, const uint8_t *src, UNUSED unsigned i, UNUSED unsigned j)' % (name
, dst_suffix
, dst_native_type
))
689 if is_format_supported(format
):
690 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
696 def is_format_hand_written(format
):
697 return format
.layout
!= PLAIN
or format
.colorspace
== ZS
700 def generate(formats
):
702 print('#include "pipe/p_compiler.h"')
703 print('#include "util/u_math.h"')
704 print('#include "util/u_half.h"')
705 print('#include "u_format.h"')
706 print('#include "u_format_other.h"')
707 print('#include "util/format_srgb.h"')
708 print('#include "u_format_yuv.h"')
709 print('#include "u_format_zs.h"')
712 for format
in formats
:
713 if not is_format_hand_written(format
):
715 if is_format_supported(format
) and not format
.is_bitmask():
716 generate_format_type(format
)
718 if format
.is_pure_unsigned():
719 native_type
= 'unsigned'
721 channel
= Channel(UNSIGNED
, False, True, 32)
723 generate_format_unpack(format
, channel
, native_type
, suffix
)
724 generate_format_pack(format
, channel
, native_type
, suffix
)
725 generate_format_fetch(format
, channel
, native_type
, suffix
)
727 channel
= Channel(SIGNED
, False, True, 32)
730 generate_format_pack(format
, channel
, native_type
, suffix
)
731 elif format
.is_pure_signed():
734 channel
= Channel(SIGNED
, False, True, 32)
736 generate_format_unpack(format
, channel
, native_type
, suffix
)
737 generate_format_pack(format
, channel
, native_type
, suffix
)
738 generate_format_fetch(format
, channel
, native_type
, suffix
)
740 native_type
= 'unsigned'
742 channel
= Channel(UNSIGNED
, False, True, 32)
743 generate_format_pack(format
, channel
, native_type
, suffix
)
745 channel
= Channel(FLOAT
, False, False, 32)
746 native_type
= 'float'
747 suffix
= 'rgba_float'
749 generate_format_unpack(format
, channel
, native_type
, suffix
)
750 generate_format_pack(format
, channel
, native_type
, suffix
)
751 generate_format_fetch(format
, channel
, native_type
, suffix
)
753 channel
= Channel(UNSIGNED
, True, False, 8)
754 native_type
= 'uint8_t'
755 suffix
= 'rgba_8unorm'
757 generate_format_unpack(format
, channel
, native_type
, suffix
)
758 generate_format_pack(format
, channel
, native_type
, suffix
)