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 print_function
41 from u_format_parse
import *
44 def inv_swizzles(swizzles
):
45 '''Return an array[4] of inverse swizzle terms'''
46 '''Only pick the first matching value to avoid l8 getting blue and i8 getting alpha'''
47 inv_swizzle
= [None]*4
50 if swizzle
< 4 and inv_swizzle
[swizzle
] == None:
51 inv_swizzle
[swizzle
] = i
54 def print_channels(format
, func
):
55 if format
.nr_channels() <= 1:
56 func(format
.le_channels
, format
.le_swizzles
)
58 print('#ifdef PIPE_ARCH_BIG_ENDIAN')
59 func(format
.be_channels
, format
.be_swizzles
)
61 func(format
.le_channels
, format
.le_swizzles
)
64 def generate_format_type(format
):
65 '''Generate a structure that describes the format.'''
67 assert format
.layout
== PLAIN
69 def generate_bitfields(channels
, swizzles
):
70 for channel
in channels
:
71 if channel
.type == VOID
:
73 print(' unsigned %s:%u;' % (channel
.name
, channel
.size
))
74 elif channel
.type == UNSIGNED
:
75 print(' unsigned %s:%u;' % (channel
.name
, channel
.size
))
76 elif channel
.type in (SIGNED
, FIXED
):
77 print(' int %s:%u;' % (channel
.name
, channel
.size
))
78 elif channel
.type == FLOAT
:
79 if channel
.size
== 64:
80 print(' double %s;' % (channel
.name
))
81 elif channel
.size
== 32:
82 print(' float %s;' % (channel
.name
))
84 print(' unsigned %s:%u;' % (channel
.name
, channel
.size
))
88 def generate_full_fields(channels
, swizzles
):
89 for channel
in channels
:
90 assert channel
.size
% 8 == 0 and is_pot(channel
.size
)
91 if channel
.type == VOID
:
93 print(' uint%u_t %s;' % (channel
.size
, channel
.name
))
94 elif channel
.type == UNSIGNED
:
95 print(' uint%u_t %s;' % (channel
.size
, channel
.name
))
96 elif channel
.type in (SIGNED
, FIXED
):
97 print(' int%u_t %s;' % (channel
.size
, channel
.name
))
98 elif channel
.type == FLOAT
:
99 if channel
.size
== 64:
100 print(' double %s;' % (channel
.name
))
101 elif channel
.size
== 32:
102 print(' float %s;' % (channel
.name
))
103 elif channel
.size
== 16:
104 print(' uint16_t %s;' % (channel
.name
))
110 print('union util_format_%s {' % format
.short_name())
112 if format
.block_size() in (8, 16, 32, 64):
113 print(' uint%u_t value;' % (format
.block_size(),))
115 use_bitfields
= False
116 for channel
in format
.le_channels
:
117 if channel
.size
% 8 or not is_pot(channel
.size
):
122 print_channels(format
, generate_bitfields
)
124 print_channels(format
, generate_full_fields
)
130 def is_format_supported(format
):
131 '''Determines whether we actually have the plumbing necessary to generate the
132 to read/write to/from this format.'''
134 # FIXME: Ideally we would support any format combination here.
136 if format
.layout
!= PLAIN
:
140 channel
= format
.le_channels
[i
]
141 if channel
.type not in (VOID
, UNSIGNED
, SIGNED
, FLOAT
, FIXED
):
143 if channel
.type == FLOAT
and channel
.size
not in (16, 32, 64):
148 def native_type(format
):
149 '''Get the native appropriate for a format.'''
151 if format
.name
== 'PIPE_FORMAT_R11G11B10_FLOAT':
153 if format
.name
== 'PIPE_FORMAT_R9G9B9E5_FLOAT':
156 if format
.layout
== PLAIN
:
157 if not format
.is_array():
158 # For arithmetic pixel formats return the integer type that matches the whole pixel
159 return 'uint%u_t' % format
.block_size()
161 # For array pixel formats return the integer type that matches the color channel
162 channel
= format
.array_element()
163 if channel
.type in (UNSIGNED
, VOID
):
164 return 'uint%u_t' % channel
.size
165 elif channel
.type in (SIGNED
, FIXED
):
166 return 'int%u_t' % channel
.size
167 elif channel
.type == FLOAT
:
168 if channel
.size
== 16:
170 elif channel
.size
== 32:
172 elif channel
.size
== 64:
182 def intermediate_native_type(bits
, sign
):
183 '''Find a native type adequate to hold intermediate results of the request bit size.'''
185 bytes
= 4 # don't use anything smaller than 32bits
186 while bytes
* 8 < bits
:
191 return 'int%u_t' % bits
193 return 'uint%u_t' % bits
196 def get_one_shift(type):
197 '''Get the number of the bit that matches unity for this type.'''
198 if type.type == 'FLOAT':
202 if type.type == UNSIGNED
:
204 if type.type == SIGNED
:
206 if type.type == FIXED
:
211 def truncate_mantissa(x
, bits
):
212 '''Truncate an integer so it can be represented exactly with a floating
215 assert isinstance(x
, (int, long))
222 # We can represent integers up to mantissa + 1 bits exactly
223 mask
= (1 << (bits
+ 1)) - 1
225 # Slide the mask until the MSB matches
227 while (x
>> shift
) & ~mask
:
235 def value_to_native(type, value
):
236 '''Get the value of unity for this type.'''
237 if type.type == FLOAT
:
239 and isinstance(value
, (int, long)):
240 return truncate_mantissa(value
, 23)
242 if type.type == FIXED
:
243 return int(value
* (1 << (type.size
/2)))
246 if type.type == UNSIGNED
:
247 return int(value
* ((1 << type.size
) - 1))
248 if type.type == SIGNED
:
249 return int(value
* ((1 << (type.size
- 1)) - 1))
253 def native_to_constant(type, value
):
254 '''Get the value of unity for this type.'''
255 if type.type == FLOAT
:
257 return "%.1ff" % float(value
)
259 return "%.1f" % float(value
)
261 return str(int(value
))
265 '''Get the value of unity for this type.'''
266 return value_to_native(type, 1)
269 def clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
):
270 '''Generate the expression to clamp the value in the source type to the
271 destination type range.'''
273 if src_channel
== dst_channel
:
276 src_min
= src_channel
.min()
277 src_max
= src_channel
.max()
278 dst_min
= dst_channel
.min()
279 dst_max
= dst_channel
.max()
281 # Translate the destination range to the src native value
282 dst_min_native
= native_to_constant(src_channel
, value_to_native(src_channel
, dst_min
))
283 dst_max_native
= native_to_constant(src_channel
, value_to_native(src_channel
, dst_max
))
285 if src_min
< dst_min
and src_max
> dst_max
:
286 return 'CLAMP(%s, %s, %s)' % (value
, dst_min_native
, dst_max_native
)
288 if src_max
> dst_max
:
289 return 'MIN2(%s, %s)' % (value
, dst_max_native
)
291 if src_min
< dst_min
:
292 return 'MAX2(%s, %s)' % (value
, dst_min_native
)
297 def conversion_expr(src_channel
,
298 dst_channel
, dst_native_type
,
301 src_colorspace
= RGB
,
302 dst_colorspace
= RGB
):
303 '''Generate the expression to convert a value between two types.'''
305 if src_colorspace
!= dst_colorspace
:
306 if src_colorspace
== SRGB
:
307 assert src_channel
.type == UNSIGNED
308 assert src_channel
.norm
309 assert src_channel
.size
<= 8
310 assert src_channel
.size
>= 4
311 assert dst_colorspace
== RGB
312 if src_channel
.size
< 8:
313 value
= '%s << %x | %s >> %x' % (value
, 8 - src_channel
.size
, value
, 2 * src_channel
.size
- 8)
314 if dst_channel
.type == FLOAT
:
315 return 'util_format_srgb_8unorm_to_linear_float(%s)' % value
317 assert dst_channel
.type == UNSIGNED
318 assert dst_channel
.norm
319 assert dst_channel
.size
== 8
320 return 'util_format_srgb_to_linear_8unorm(%s)' % value
321 elif dst_colorspace
== SRGB
:
322 assert dst_channel
.type == UNSIGNED
323 assert dst_channel
.norm
324 assert dst_channel
.size
<= 8
325 assert src_colorspace
== RGB
326 if src_channel
.type == FLOAT
:
327 value
= 'util_format_linear_float_to_srgb_8unorm(%s)' % value
329 assert src_channel
.type == UNSIGNED
330 assert src_channel
.norm
331 assert src_channel
.size
== 8
332 value
= 'util_format_linear_to_srgb_8unorm(%s)' % value
333 # XXX rounding is all wrong.
334 if dst_channel
.size
< 8:
335 return '%s >> %x' % (value
, 8 - dst_channel
.size
)
338 elif src_colorspace
== ZS
:
340 elif dst_colorspace
== ZS
:
345 if src_channel
== dst_channel
:
348 src_type
= src_channel
.type
349 src_size
= src_channel
.size
350 src_norm
= src_channel
.norm
351 src_pure
= src_channel
.pure
353 # Promote half to float
354 if src_type
== FLOAT
and src_size
== 16:
355 value
= 'util_half_to_float(%s)' % value
358 # Special case for float <-> ubytes for more accurate results
359 # Done before clamping since these functions already take care of that
360 if src_type
== UNSIGNED
and src_norm
and src_size
== 8 and dst_channel
.type == FLOAT
and dst_channel
.size
== 32:
361 return 'ubyte_to_float(%s)' % value
362 if src_type
== FLOAT
and src_size
== 32 and dst_channel
.type == UNSIGNED
and dst_channel
.norm
and dst_channel
.size
== 8:
363 return 'float_to_ubyte(%s)' % value
366 if dst_channel
.type != FLOAT
or src_type
!= FLOAT
:
367 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
369 if src_type
in (SIGNED
, UNSIGNED
) and dst_channel
.type in (SIGNED
, UNSIGNED
):
370 if not src_norm
and not dst_channel
.norm
:
371 # neither is normalized -- just cast
372 return '(%s)%s' % (dst_native_type
, value
)
374 src_one
= get_one(src_channel
)
375 dst_one
= get_one(dst_channel
)
377 if src_one
> dst_one
and src_norm
and dst_channel
.norm
:
378 # We can just bitshift
379 src_shift
= get_one_shift(src_channel
)
380 dst_shift
= get_one_shift(dst_channel
)
381 value
= '(%s >> %s)' % (value
, src_shift
- dst_shift
)
383 # We need to rescale using an intermediate type big enough to hold the multiplication of both
384 tmp_native_type
= intermediate_native_type(src_size
+ dst_channel
.size
, src_channel
.sign
and dst_channel
.sign
)
385 value
= '((%s)%s)' % (tmp_native_type
, value
)
386 value
= '(%s * 0x%x / 0x%x)' % (value
, dst_one
, src_one
)
387 value
= '(%s)%s' % (dst_native_type
, value
)
390 # Promote to either float or double
391 if src_type
!= FLOAT
:
392 if src_norm
or src_type
== FIXED
:
393 one
= get_one(src_channel
)
395 value
= '(%s * (1.0f/0x%x))' % (value
, one
)
396 if dst_channel
.size
<= 32:
397 value
= '(float)%s' % value
400 # bigger than single precision mantissa, use double
401 value
= '(%s * (1.0/0x%x))' % (value
, one
)
405 if src_size
<= 23 or dst_channel
.size
<= 32:
406 value
= '(float)%s' % value
409 # bigger than single precision mantissa, use double
410 value
= '(double)%s' % value
414 # Convert double or float to non-float
415 if dst_channel
.type != FLOAT
:
416 if dst_channel
.norm
or dst_channel
.type == FIXED
:
417 dst_one
= get_one(dst_channel
)
418 if dst_channel
.size
<= 23:
419 value
= 'util_iround(%s * 0x%x)' % (value
, dst_one
)
421 # bigger than single precision mantissa, use double
422 value
= '(%s * (double)0x%x)' % (value
, dst_one
)
423 value
= '(%s)%s' % (dst_native_type
, value
)
425 # Cast double to float when converting to either half or float
426 if dst_channel
.size
<= 32 and src_size
> 32:
427 value
= '(float)%s' % value
430 if dst_channel
.size
== 16:
431 value
= 'util_float_to_half(%s)' % value
432 elif dst_channel
.size
== 64 and src_size
< 64:
433 value
= '(double)%s' % value
438 def generate_unpack_kernel(format
, dst_channel
, dst_native_type
):
440 if not is_format_supported(format
):
443 assert format
.layout
== PLAIN
445 src_native_type
= native_type(format
)
447 def unpack_from_bitmask(channels
, swizzles
):
448 depth
= format
.block_size()
449 print(' uint%u_t value = *(const uint%u_t *)src;' % (depth
, depth
))
451 # Declare the intermediate variables
452 for i
in range(format
.nr_channels()):
453 src_channel
= channels
[i
]
454 if src_channel
.type == UNSIGNED
:
455 print(' uint%u_t %s;' % (depth
, src_channel
.name
))
456 elif src_channel
.type == SIGNED
:
457 print(' int%u_t %s;' % (depth
, src_channel
.name
))
459 # Compute the intermediate unshifted values
460 for i
in range(format
.nr_channels()):
461 src_channel
= channels
[i
]
463 shift
= src_channel
.shift
464 if src_channel
.type == UNSIGNED
:
466 value
= '%s >> %u' % (value
, shift
)
467 if shift
+ src_channel
.size
< depth
:
468 value
= '(%s) & 0x%x' % (value
, (1 << src_channel
.size
) - 1)
469 elif src_channel
.type == SIGNED
:
470 if shift
+ src_channel
.size
< depth
:
472 lshift
= depth
- (shift
+ src_channel
.size
)
473 value
= '%s << %u' % (value
, lshift
)
475 value
= '(int%u_t)(%s) ' % (depth
, value
)
476 if src_channel
.size
< depth
:
478 rshift
= depth
- src_channel
.size
479 value
= '(%s) >> %u' % (value
, rshift
)
483 if value
is not None:
484 print(' %s = %s;' % (src_channel
.name
, value
))
486 # Convert, swizzle, and store final values
488 swizzle
= swizzles
[i
]
490 src_channel
= channels
[swizzle
]
491 src_colorspace
= format
.colorspace
492 if src_colorspace
== SRGB
and i
== 3:
493 # Alpha channel is linear
495 value
= src_channel
.name
496 value
= conversion_expr(src_channel
,
497 dst_channel
, dst_native_type
,
499 src_colorspace
= src_colorspace
)
500 elif swizzle
== SWIZZLE_0
:
502 elif swizzle
== SWIZZLE_1
:
503 value
= get_one(dst_channel
)
504 elif swizzle
== SWIZZLE_NONE
:
508 print(' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
]))
510 def unpack_from_union(channels
, swizzles
):
511 print(' union util_format_%s pixel;' % format
.short_name())
512 print(' memcpy(&pixel, src, sizeof pixel);')
515 swizzle
= swizzles
[i
]
517 src_channel
= channels
[swizzle
]
518 src_colorspace
= format
.colorspace
519 if src_colorspace
== SRGB
and i
== 3:
520 # Alpha channel is linear
522 value
= 'pixel.chan.%s' % src_channel
.name
523 value
= conversion_expr(src_channel
,
524 dst_channel
, dst_native_type
,
526 src_colorspace
= src_colorspace
)
527 elif swizzle
== SWIZZLE_0
:
529 elif swizzle
== SWIZZLE_1
:
530 value
= get_one(dst_channel
)
531 elif swizzle
== SWIZZLE_NONE
:
535 print(' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
]))
537 if format
.is_bitmask():
538 print_channels(format
, unpack_from_bitmask
)
540 print_channels(format
, unpack_from_union
)
543 def generate_pack_kernel(format
, src_channel
, src_native_type
):
545 if not is_format_supported(format
):
548 dst_native_type
= native_type(format
)
550 assert format
.layout
== PLAIN
552 def pack_into_bitmask(channels
, swizzles
):
553 inv_swizzle
= inv_swizzles(swizzles
)
555 depth
= format
.block_size()
556 print(' uint%u_t value = 0;' % depth
)
559 dst_channel
= channels
[i
]
560 shift
= dst_channel
.shift
561 if inv_swizzle
[i
] is not None:
562 value
='src[%u]' % inv_swizzle
[i
]
563 dst_colorspace
= format
.colorspace
564 if dst_colorspace
== SRGB
and inv_swizzle
[i
] == 3:
565 # Alpha channel is linear
567 value
= conversion_expr(src_channel
,
568 dst_channel
, dst_native_type
,
570 dst_colorspace
= dst_colorspace
)
571 if dst_channel
.type in (UNSIGNED
, SIGNED
):
572 if shift
+ dst_channel
.size
< depth
:
573 value
= '(%s) & 0x%x' % (value
, (1 << dst_channel
.size
) - 1)
575 value
= '(%s) << %u' % (value
, shift
)
576 if dst_channel
.type == SIGNED
:
578 value
= '(uint%u_t)(%s) ' % (depth
, value
)
581 if value
is not None:
582 print(' value |= %s;' % (value
))
584 print(' *(uint%u_t *)dst = value;' % depth
)
586 def pack_into_union(channels
, swizzles
):
587 inv_swizzle
= inv_swizzles(swizzles
)
589 print(' union util_format_%s pixel;' % format
.short_name())
592 dst_channel
= channels
[i
]
593 width
= dst_channel
.size
594 if inv_swizzle
[i
] is None:
596 dst_colorspace
= format
.colorspace
597 if dst_colorspace
== SRGB
and inv_swizzle
[i
] == 3:
598 # Alpha channel is linear
600 value
='src[%u]' % inv_swizzle
[i
]
601 value
= conversion_expr(src_channel
,
602 dst_channel
, dst_native_type
,
604 dst_colorspace
= dst_colorspace
)
605 print(' pixel.chan.%s = %s;' % (dst_channel
.name
, value
))
607 print(' memcpy(dst, &pixel, sizeof pixel);')
609 if format
.is_bitmask():
610 print_channels(format
, pack_into_bitmask
)
612 print_channels(format
, pack_into_union
)
615 def generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
):
616 '''Generate the function to unpack pixels from a particular format'''
618 name
= format
.short_name()
620 print('static inline void')
621 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
))
624 if is_format_supported(format
):
625 print(' unsigned x, y;')
626 print(' for(y = 0; y < height; y += %u) {' % (format
.block_height
,))
627 print(' %s *dst = dst_row;' % (dst_native_type
))
628 print(' const uint8_t *src = src_row;')
629 print(' for(x = 0; x < width; x += %u) {' % (format
.block_width
,))
631 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
633 print(' src += %u;' % (format
.block_size() / 8,))
636 print(' src_row += src_stride;')
637 print(' dst_row += dst_stride/sizeof(*dst_row);')
644 def generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
):
645 '''Generate the function to pack pixels to a particular format'''
647 name
= format
.short_name()
649 print('static inline void')
650 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
))
653 if is_format_supported(format
):
654 print(' unsigned x, y;')
655 print(' for(y = 0; y < height; y += %u) {' % (format
.block_height
,))
656 print(' const %s *src = src_row;' % (src_native_type
))
657 print(' uint8_t *dst = dst_row;')
658 print(' for(x = 0; x < width; x += %u) {' % (format
.block_width
,))
660 generate_pack_kernel(format
, src_channel
, src_native_type
)
663 print(' dst += %u;' % (format
.block_size() / 8,))
665 print(' dst_row += dst_stride;')
666 print(' src_row += src_stride/sizeof(*src_row);')
673 def generate_format_fetch(format
, dst_channel
, dst_native_type
, dst_suffix
):
674 '''Generate the function to unpack pixels from a particular format'''
676 name
= format
.short_name()
678 print('static inline void')
679 print('util_format_%s_fetch_%s(%s *dst, const uint8_t *src, UNUSED unsigned i, UNUSED unsigned j)' % (name
, dst_suffix
, dst_native_type
))
682 if is_format_supported(format
):
683 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
689 def is_format_hand_written(format
):
690 return format
.layout
in ('s3tc', 'rgtc', 'etc', 'bptc', 'astc', 'subsampled', 'other') or format
.colorspace
== ZS
693 def generate(formats
):
695 print('#include "pipe/p_compiler.h"')
696 print('#include "u_math.h"')
697 print('#include "u_half.h"')
698 print('#include "u_format.h"')
699 print('#include "u_format_other.h"')
700 print('#include "util/format_srgb.h"')
701 print('#include "u_format_yuv.h"')
702 print('#include "u_format_zs.h"')
705 for format
in formats
:
706 if not is_format_hand_written(format
):
708 if is_format_supported(format
):
709 generate_format_type(format
)
711 if format
.is_pure_unsigned():
712 native_type
= 'unsigned'
714 channel
= Channel(UNSIGNED
, False, True, 32)
716 generate_format_unpack(format
, channel
, native_type
, suffix
)
717 generate_format_pack(format
, channel
, native_type
, suffix
)
718 generate_format_fetch(format
, channel
, native_type
, suffix
)
720 channel
= Channel(SIGNED
, False, True, 32)
723 generate_format_unpack(format
, channel
, native_type
, suffix
)
724 generate_format_pack(format
, channel
, native_type
, suffix
)
725 elif format
.is_pure_signed():
728 channel
= Channel(SIGNED
, False, True, 32)
730 generate_format_unpack(format
, channel
, native_type
, suffix
)
731 generate_format_pack(format
, channel
, native_type
, suffix
)
732 generate_format_fetch(format
, channel
, native_type
, suffix
)
734 native_type
= 'unsigned'
736 channel
= Channel(UNSIGNED
, False, True, 32)
737 generate_format_unpack(format
, channel
, native_type
, suffix
)
738 generate_format_pack(format
, channel
, native_type
, suffix
)
740 channel
= Channel(FLOAT
, False, False, 32)
741 native_type
= 'float'
742 suffix
= 'rgba_float'
744 generate_format_unpack(format
, channel
, native_type
, suffix
)
745 generate_format_pack(format
, channel
, native_type
, suffix
)
746 generate_format_fetch(format
, channel
, native_type
, suffix
)
748 channel
= Channel(UNSIGNED
, True, False, 8)
749 native_type
= 'uint8_t'
750 suffix
= 'rgba_8unorm'
752 generate_format_unpack(format
, channel
, native_type
, suffix
)
753 generate_format_pack(format
, channel
, native_type
, suffix
)