4 /**************************************************************************
6 * Copyright 2009-2010 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>
43 from u_format_parse
import *
46 def generate_format_type(format
):
47 '''Generate a structure that describes the format.'''
49 assert format
.layout
== PLAIN
51 print 'union util_format_%s {' % format
.short_name()
53 if format
.block_size() in (8, 16, 32, 64):
54 print ' uint%u_t value;' % (format
.block_size(),)
57 for channel
in format
.channels
:
58 if channel
.size
% 8 or not is_pot(channel
.size
):
62 for channel
in format
.channels
:
64 if channel
.type == VOID
:
66 print ' unsigned %s:%u;' % (channel
.name
, channel
.size
)
67 elif channel
.type == UNSIGNED
:
68 print ' unsigned %s:%u;' % (channel
.name
, channel
.size
)
69 elif channel
.type in (SIGNED
, FIXED
):
70 print ' int %s:%u;' % (channel
.name
, channel
.size
)
71 elif channel
.type == FLOAT
:
72 if channel
.size
== 64:
73 print ' double %s;' % (channel
.name
)
74 elif channel
.size
== 32:
75 print ' float %s;' % (channel
.name
)
77 print ' unsigned %s:%u;' % (channel
.name
, channel
.size
)
81 assert channel
.size
% 8 == 0 and is_pot(channel
.size
)
82 if channel
.type == VOID
:
84 print ' uint%u_t %s;' % (channel
.size
, channel
.name
)
85 elif channel
.type == UNSIGNED
:
86 print ' uint%u_t %s;' % (channel
.size
, channel
.name
)
87 elif channel
.type in (SIGNED
, FIXED
):
88 print ' int%u_t %s;' % (channel
.size
, channel
.name
)
89 elif channel
.type == FLOAT
:
90 if channel
.size
== 64:
91 print ' double %s;' % (channel
.name
)
92 elif channel
.size
== 32:
93 print ' float %s;' % (channel
.name
)
94 elif channel
.size
== 16:
95 print ' uint16_t %s;' % (channel
.name
)
105 def bswap_format(format
):
106 '''Generate a structure that describes the format.'''
108 if format
.is_bitmask() and not format
.is_array() and format
.block_size() > 8:
109 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
110 print ' pixel.value = util_bswap%u(pixel.value);' % format
.block_size()
114 def is_format_supported(format
):
115 '''Determines whether we actually have the plumbing necessary to generate the
116 to read/write to/from this format.'''
118 # FIXME: Ideally we would support any format combination here.
120 if format
.layout
!= PLAIN
:
124 channel
= format
.channels
[i
]
125 if channel
.type not in (VOID
, UNSIGNED
, SIGNED
, FLOAT
, FIXED
):
127 if channel
.type == FLOAT
and channel
.size
not in (16, 32, 64):
133 def native_type(format
):
134 '''Get the native appropriate for a format.'''
136 if format
.layout
== PLAIN
:
137 if not format
.is_array():
138 # For arithmetic pixel formats return the integer type that matches the whole pixel
139 return 'uint%u_t' % format
.block_size()
141 # For array pixel formats return the integer type that matches the color channel
142 channel
= format
.channels
[0]
143 if channel
.type in (UNSIGNED
, VOID
):
144 return 'uint%u_t' % channel
.size
145 elif channel
.type in (SIGNED
, FIXED
):
146 return 'int%u_t' % channel
.size
147 elif channel
.type == FLOAT
:
148 if channel
.size
== 16:
150 elif channel
.size
== 32:
152 elif channel
.size
== 64:
162 def intermediate_native_type(bits
, sign
):
163 '''Find a native type adequate to hold intermediate results of the request bit size.'''
165 bytes
= 4 # don't use anything smaller than 32bits
166 while bytes
* 8 < bits
:
171 return 'int%u_t' % bits
173 return 'uint%u_t' % bits
176 def get_one_shift(type):
177 '''Get the number of the bit that matches unity for this type.'''
178 if type.type == 'FLOAT':
182 if type.type == UNSIGNED
:
184 if type.type == SIGNED
:
186 if type.type == FIXED
:
191 def value_to_native(type, value
):
192 '''Get the value of unity for this type.'''
193 if type.type == FLOAT
:
195 if type.type == FIXED
:
196 return int(value
* (1 << (type.size
/2)))
199 if type.type == UNSIGNED
:
200 return int(value
* ((1 << type.size
) - 1))
201 if type.type == SIGNED
:
202 return int(value
* ((1 << (type.size
- 1)) - 1))
206 def native_to_constant(type, value
):
207 '''Get the value of unity for this type.'''
208 if type.type == FLOAT
:
214 return str(int(value
))
218 '''Get the value of unity for this type.'''
219 return value_to_native(type, 1)
222 def clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
):
223 '''Generate the expression to clamp the value in the source type to the
224 destination type range.'''
226 if src_channel
== dst_channel
:
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 # Translate the destination range to the src native value
235 dst_min_native
= value_to_native(src_channel
, dst_min
)
236 dst_max_native
= value_to_native(src_channel
, dst_max
)
238 if src_min
< dst_min
and src_max
> dst_max
:
239 return 'CLAMP(%s, %s, %s)' % (value
, dst_min_native
, dst_max_native
)
241 if src_max
> dst_max
:
242 return 'MIN2(%s, %s)' % (value
, dst_max_native
)
244 if src_min
< dst_min
:
245 return 'MAX2(%s, %s)' % (value
, dst_min_native
)
250 def conversion_expr(src_channel
,
251 dst_channel
, dst_native_type
,
254 src_colorspace
= RGB
,
255 dst_colorspace
= RGB
):
256 '''Generate the expression to convert a value between two types.'''
258 if src_colorspace
!= dst_colorspace
:
259 if src_colorspace
== SRGB
:
260 assert src_channel
.type == UNSIGNED
261 assert src_channel
.norm
262 assert src_channel
.size
== 8
263 assert dst_colorspace
== RGB
264 if dst_channel
.type == FLOAT
:
265 return 'util_format_srgb_8unorm_to_linear_float(%s)' % value
267 assert dst_channel
.type == UNSIGNED
268 assert dst_channel
.norm
269 assert dst_channel
.size
== 8
270 return 'util_format_srgb_to_linear_8unorm(%s)' % value
271 elif dst_colorspace
== SRGB
:
272 assert dst_channel
.type == UNSIGNED
273 assert dst_channel
.norm
274 assert dst_channel
.size
== 8
275 assert src_colorspace
== RGB
276 if src_channel
.type == FLOAT
:
277 return 'util_format_linear_float_to_srgb_8unorm(%s)' % value
279 assert src_channel
.type == UNSIGNED
280 assert src_channel
.norm
281 assert src_channel
.size
== 8
282 return 'util_format_linear_to_srgb_8unorm(%s)' % value
283 elif src_colorspace
== ZS
:
285 elif dst_colorspace
== ZS
:
290 if src_channel
== dst_channel
:
293 src_type
= src_channel
.type
294 src_size
= src_channel
.size
295 src_norm
= src_channel
.norm
297 # Promote half to float
298 if src_type
== FLOAT
and src_size
== 16:
299 value
= 'util_half_to_float(%s)' % value
302 # Special case for float <-> ubytes for more accurate results
303 # Done before clamping since these functions already take care of that
304 if src_type
== UNSIGNED
and src_norm
and src_size
== 8 and dst_channel
.type == FLOAT
and dst_channel
.size
== 32:
305 return 'ubyte_to_float(%s)' % value
306 if src_type
== FLOAT
and src_size
== 32 and dst_channel
.type == UNSIGNED
and dst_channel
.norm
and dst_channel
.size
== 8:
307 return 'float_to_ubyte(%s)' % value
310 if dst_channel
.type != FLOAT
or src_type
!= FLOAT
:
311 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
313 if src_type
in (SIGNED
, UNSIGNED
) and dst_channel
.type in (SIGNED
, UNSIGNED
):
314 if not src_norm
and not dst_channel
.norm
:
315 # neither is normalized -- just cast
316 return '(%s)%s' % (dst_native_type
, value
)
318 src_one
= get_one(src_channel
)
319 dst_one
= get_one(dst_channel
)
321 if src_one
> dst_one
and src_norm
and dst_channel
.norm
:
322 # We can just bitshift
323 src_shift
= get_one_shift(src_channel
)
324 dst_shift
= get_one_shift(dst_channel
)
325 value
= '(%s >> %s)' % (value
, src_shift
- dst_shift
)
327 # We need to rescale using an intermediate type big enough to hold the multiplication of both
328 tmp_native_type
= intermediate_native_type(src_size
+ dst_channel
.size
, src_channel
.sign
and dst_channel
.sign
)
329 value
= '((%s)%s)' % (tmp_native_type
, value
)
330 value
= '(%s * 0x%x / 0x%x)' % (value
, dst_one
, src_one
)
331 value
= '(%s)%s' % (dst_native_type
, value
)
334 # Promote to either float or double
335 if src_type
!= FLOAT
:
336 if src_norm
or src_type
== FIXED
:
337 one
= get_one(src_channel
)
339 value
= '(%s * (1.0f/0x%x))' % (value
, one
)
340 if dst_channel
.size
<= 32:
341 value
= '(float)%s' % value
344 # bigger than single precision mantissa, use double
345 value
= '(%s * (1.0/0x%x))' % (value
, one
)
349 if src_size
<= 23 or dst_channel
.size
<= 32:
350 value
= '(float)%s' % value
353 # bigger than single precision mantissa, use double
354 value
= '(double)%s' % value
358 # Convert double or float to non-float
359 if dst_channel
.type != FLOAT
:
360 if dst_channel
.norm
or dst_channel
.type == FIXED
:
361 dst_one
= get_one(dst_channel
)
362 if dst_channel
.size
<= 23:
363 value
= '(%s * 0x%x)' % (value
, dst_one
)
365 # bigger than single precision mantissa, use double
366 value
= '(%s * (double)0x%x)' % (value
, dst_one
)
367 value
= '(%s)%s' % (dst_native_type
, value
)
369 # Cast double to float when converting to either half or float
370 if dst_channel
.size
<= 32 and src_size
> 32:
371 value
= '(float)%s' % value
374 if dst_channel
.size
== 16:
375 value
= 'util_float_to_half(%s)' % value
376 elif dst_channel
.size
== 64 and src_size
< 64:
377 value
= '(double)%s' % value
382 def generate_unpack_kernel(format
, dst_channel
, dst_native_type
):
384 if not is_format_supported(format
):
387 assert format
.layout
== PLAIN
389 src_native_type
= native_type(format
)
391 if format
.is_bitmask():
392 depth
= format
.block_size()
393 print ' uint%u_t value = *(const uint%u_t *)src;' % (depth
, depth
)
395 # Declare the intermediate variables
396 for i
in range(format
.nr_channels()):
397 src_channel
= format
.channels
[i
]
398 if src_channel
.type == UNSIGNED
:
399 print ' uint%u_t %s;' % (depth
, src_channel
.name
)
400 elif src_channel
.type == SIGNED
:
401 print ' int%u_t %s;' % (depth
, src_channel
.name
)
404 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
405 print ' value = util_bswap%u(value);' % depth
408 # Compute the intermediate unshifted values
410 for i
in range(format
.nr_channels()):
411 src_channel
= format
.channels
[i
]
413 if src_channel
.type == UNSIGNED
:
415 value
= '%s >> %u' % (value
, shift
)
416 if shift
+ src_channel
.size
< depth
:
417 value
= '(%s) & 0x%x' % (value
, (1 << src_channel
.size
) - 1)
418 elif src_channel
.type == SIGNED
:
419 if shift
+ src_channel
.size
< depth
:
421 lshift
= depth
- (shift
+ src_channel
.size
)
422 value
= '%s << %u' % (value
, lshift
)
424 value
= '(int%u_t)(%s) ' % (depth
, value
)
425 if src_channel
.size
< depth
:
427 rshift
= depth
- src_channel
.size
428 value
= '(%s) >> %u' % (value
, rshift
)
432 if value
is not None:
433 print ' %s = %s;' % (src_channel
.name
, value
)
435 shift
+= src_channel
.size
437 # Convert, swizzle, and store final values
439 swizzle
= format
.swizzles
[i
]
441 src_channel
= format
.channels
[swizzle
]
442 src_colorspace
= format
.colorspace
443 if src_colorspace
== SRGB
and i
== 3:
444 # Alpha channel is linear
446 value
= src_channel
.name
447 value
= conversion_expr(src_channel
,
448 dst_channel
, dst_native_type
,
450 src_colorspace
= src_colorspace
)
451 elif swizzle
== SWIZZLE_0
:
453 elif swizzle
== SWIZZLE_1
:
454 value
= get_one(dst_channel
)
455 elif swizzle
== SWIZZLE_NONE
:
459 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
462 print ' union util_format_%s pixel;' % format
.short_name()
463 print ' memcpy(&pixel, src, sizeof pixel);'
467 swizzle
= format
.swizzles
[i
]
469 src_channel
= format
.channels
[swizzle
]
470 src_colorspace
= format
.colorspace
471 if src_colorspace
== SRGB
and i
== 3:
472 # Alpha channel is linear
474 value
= 'pixel.chan.%s' % src_channel
.name
475 value
= conversion_expr(src_channel
,
476 dst_channel
, dst_native_type
,
478 src_colorspace
= src_colorspace
)
479 elif swizzle
== SWIZZLE_0
:
481 elif swizzle
== SWIZZLE_1
:
482 value
= get_one(dst_channel
)
483 elif swizzle
== SWIZZLE_NONE
:
487 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
490 def generate_pack_kernel(format
, src_channel
, src_native_type
):
492 if not is_format_supported(format
):
495 dst_native_type
= native_type(format
)
497 assert format
.layout
== PLAIN
499 inv_swizzle
= format
.inv_swizzles()
501 if format
.is_bitmask():
502 depth
= format
.block_size()
503 print ' uint%u_t value = 0;' % depth
507 dst_channel
= format
.channels
[i
]
508 if inv_swizzle
[i
] is not None:
509 value
='src[%u]' % inv_swizzle
[i
]
510 dst_colorspace
= format
.colorspace
511 if dst_colorspace
== SRGB
and inv_swizzle
[i
] == 3:
512 # Alpha channel is linear
514 value
= conversion_expr(src_channel
,
515 dst_channel
, dst_native_type
,
517 dst_colorspace
= dst_colorspace
)
518 if dst_channel
.type in (UNSIGNED
, SIGNED
):
519 if shift
+ dst_channel
.size
< depth
:
520 value
= '(%s) & 0x%x' % (value
, (1 << dst_channel
.size
) - 1)
522 value
= '(%s) << %u' % (value
, shift
)
523 if dst_channel
.type == SIGNED
:
525 value
= '(uint%u_t)(%s) ' % (depth
, value
)
528 if value
is not None:
529 print ' value |= %s;' % (value
)
531 shift
+= dst_channel
.size
534 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
535 print ' value = util_bswap%u(value);' % depth
538 print ' *(uint%u_t *)dst = value;' % depth
541 print ' union util_format_%s pixel;' % format
.short_name()
544 dst_channel
= format
.channels
[i
]
545 width
= dst_channel
.size
546 if inv_swizzle
[i
] is None:
548 dst_colorspace
= format
.colorspace
549 if dst_colorspace
== SRGB
and inv_swizzle
[i
] == 3:
550 # Alpha channel is linear
552 value
='src[%u]' % inv_swizzle
[i
]
553 value
= conversion_expr(src_channel
,
554 dst_channel
, dst_native_type
,
556 dst_colorspace
= dst_colorspace
)
557 print ' pixel.chan.%s = %s;' % (dst_channel
.name
, value
)
560 print ' memcpy(dst, &pixel, sizeof pixel);'
563 def generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
):
564 '''Generate the function to unpack pixels from a particular format'''
566 name
= format
.short_name()
568 print 'static INLINE void'
569 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
)
572 if is_format_supported(format
):
573 print ' unsigned x, y;'
574 print ' for(y = 0; y < height; y += %u) {' % (format
.block_height
,)
575 print ' %s *dst = dst_row;' % (dst_native_type
)
576 print ' const uint8_t *src = src_row;'
577 print ' for(x = 0; x < width; x += %u) {' % (format
.block_width
,)
579 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
581 print ' src += %u;' % (format
.block_size() / 8,)
584 print ' src_row += src_stride;'
585 print ' dst_row += dst_stride/sizeof(*dst_row);'
592 def generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
):
593 '''Generate the function to pack pixels to a particular format'''
595 name
= format
.short_name()
597 print 'static INLINE void'
598 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
)
601 if is_format_supported(format
):
602 print ' unsigned x, y;'
603 print ' for(y = 0; y < height; y += %u) {' % (format
.block_height
,)
604 print ' const %s *src = src_row;' % (src_native_type
)
605 print ' uint8_t *dst = dst_row;'
606 print ' for(x = 0; x < width; x += %u) {' % (format
.block_width
,)
608 generate_pack_kernel(format
, src_channel
, src_native_type
)
611 print ' dst += %u;' % (format
.block_size() / 8,)
613 print ' dst_row += dst_stride;'
614 print ' src_row += src_stride/sizeof(*src_row);'
621 def generate_format_fetch(format
, dst_channel
, dst_native_type
, dst_suffix
):
622 '''Generate the function to unpack pixels from a particular format'''
624 name
= format
.short_name()
626 print 'static INLINE void'
627 print 'util_format_%s_fetch_%s(%s *dst, const uint8_t *src, unsigned i, unsigned j)' % (name
, dst_suffix
, dst_native_type
)
630 if is_format_supported(format
):
631 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
637 def is_format_hand_written(format
):
638 return format
.layout
in ('s3tc', 'subsampled', 'other') or format
.colorspace
== ZS
641 def generate(formats
):
643 print '#include "pipe/p_compiler.h"'
644 print '#include "u_math.h"'
645 print '#include "u_half.h"'
646 print '#include "u_format.h"'
647 print '#include "u_format_other.h"'
648 print '#include "u_format_srgb.h"'
649 print '#include "u_format_yuv.h"'
650 print '#include "u_format_zs.h"'
653 for format
in formats
:
654 if not is_format_hand_written(format
):
656 if is_format_supported(format
):
657 generate_format_type(format
)
659 channel
= Channel(FLOAT
, False, 32)
660 native_type
= 'float'
661 suffix
= 'rgba_float'
663 generate_format_unpack(format
, channel
, native_type
, suffix
)
664 generate_format_pack(format
, channel
, native_type
, suffix
)
665 generate_format_fetch(format
, channel
, native_type
, suffix
)
667 channel
= Channel(UNSIGNED
, True, 8)
668 native_type
= 'uint8_t'
669 suffix
= 'rgba_8unorm'
671 generate_format_unpack(format
, channel
, native_type
, suffix
)
672 generate_format_pack(format
, channel
, native_type
, suffix
)