7c5fa9c00a1d09edd4483fe597803ed1c5ea6db3
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
303 if dst_channel
.type != FLOAT
or src_type
!= FLOAT
:
304 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
306 if src_type
in (SIGNED
, UNSIGNED
) and dst_channel
.type in (SIGNED
, UNSIGNED
):
307 if not src_norm
and not dst_channel
.norm
:
308 # neither is normalized -- just cast
309 return '(%s)%s' % (dst_native_type
, value
)
311 src_one
= get_one(src_channel
)
312 dst_one
= get_one(dst_channel
)
314 if src_one
> dst_one
and src_norm
and dst_channel
.norm
:
315 # We can just bitshift
316 src_shift
= get_one_shift(src_channel
)
317 dst_shift
= get_one_shift(dst_channel
)
318 value
= '(%s >> %s)' % (value
, src_shift
- dst_shift
)
320 # We need to rescale using an intermediate type big enough to hold the multiplication of both
321 tmp_native_type
= intermediate_native_type(src_size
+ dst_channel
.size
, src_channel
.sign
and dst_channel
.sign
)
322 value
= '((%s)%s)' % (tmp_native_type
, value
)
323 value
= '(%s * 0x%x / 0x%x)' % (value
, dst_one
, src_one
)
324 value
= '(%s)%s' % (dst_native_type
, value
)
327 # Promote to either float or double
328 if src_type
!= FLOAT
:
329 if src_norm
or src_type
== FIXED
:
330 one
= get_one(src_channel
)
332 value
= '(%s * (1.0f/0x%x))' % (value
, one
)
333 if dst_channel
.size
<= 32:
334 value
= '(float)%s' % value
337 # bigger than single precision mantissa, use double
338 value
= '(%s * (1.0/0x%x))' % (value
, one
)
342 if src_size
<= 23 or dst_channel
.size
<= 32:
343 value
= '(float)%s' % value
346 # bigger than single precision mantissa, use double
347 value
= '(double)%s' % value
351 # Convert double or float to non-float
352 if dst_channel
.type != FLOAT
:
353 if dst_channel
.norm
or dst_channel
.type == FIXED
:
354 dst_one
= get_one(dst_channel
)
355 if dst_channel
.size
<= 23:
356 value
= '(%s * 0x%x)' % (value
, dst_one
)
358 # bigger than single precision mantissa, use double
359 value
= '(%s * (double)0x%x)' % (value
, dst_one
)
360 value
= '(%s)%s' % (dst_native_type
, value
)
362 # Cast double to float when converting to either half or float
363 if dst_channel
.size
<= 32 and src_size
> 32:
364 value
= '(float)%s' % value
367 if dst_channel
.size
== 16:
368 value
= 'util_float_to_half(%s)' % value
369 elif dst_channel
.size
== 64 and src_size
< 64:
370 value
= '(double)%s' % value
375 def generate_unpack_kernel(format
, dst_channel
, dst_native_type
):
377 if not is_format_supported(format
):
380 assert format
.layout
== PLAIN
382 src_native_type
= native_type(format
)
384 if format
.is_bitmask():
385 depth
= format
.block_size()
386 print ' uint%u_t value = *(const uint%u_t *)src;' % (depth
, depth
)
388 # Declare the intermediate variables
389 for i
in range(format
.nr_channels()):
390 src_channel
= format
.channels
[i
]
391 if src_channel
.type == UNSIGNED
:
392 print ' uint%u_t %s;' % (depth
, src_channel
.name
)
393 elif src_channel
.type == SIGNED
:
394 print ' int%u_t %s;' % (depth
, src_channel
.name
)
397 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
398 print ' value = util_bswap%u(value);' % depth
401 # Compute the intermediate unshifted values
403 for i
in range(format
.nr_channels()):
404 src_channel
= format
.channels
[i
]
406 if src_channel
.type == UNSIGNED
:
408 value
= '%s >> %u' % (value
, shift
)
409 if shift
+ src_channel
.size
< depth
:
410 value
= '(%s) & 0x%x' % (value
, (1 << src_channel
.size
) - 1)
411 elif src_channel
.type == SIGNED
:
412 if shift
+ src_channel
.size
< depth
:
414 lshift
= depth
- (shift
+ src_channel
.size
)
415 value
= '%s << %u' % (value
, lshift
)
417 value
= '(int%u_t)(%s) ' % (depth
, value
)
418 if src_channel
.size
< depth
:
420 rshift
= depth
- src_channel
.size
421 value
= '(%s) >> %u' % (value
, rshift
)
425 if value
is not None:
426 print ' %s = %s;' % (src_channel
.name
, value
)
428 shift
+= src_channel
.size
430 # Convert, swizzle, and store final values
432 swizzle
= format
.swizzles
[i
]
434 src_channel
= format
.channels
[swizzle
]
435 src_colorspace
= format
.colorspace
436 if src_colorspace
== 'srgb' and i
== 3:
437 # Alpha channel is linear
438 src_colorspace
= 'rgb'
439 value
= src_channel
.name
440 value
= conversion_expr(src_channel
,
441 dst_channel
, dst_native_type
,
443 src_colorspace
= src_colorspace
)
444 elif swizzle
== SWIZZLE_0
:
446 elif swizzle
== SWIZZLE_1
:
447 value
= get_one(dst_channel
)
448 elif swizzle
== SWIZZLE_NONE
:
452 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
455 print ' union util_format_%s pixel;' % format
.short_name()
456 print ' memcpy(&pixel, src, sizeof pixel);'
460 swizzle
= format
.swizzles
[i
]
462 src_channel
= format
.channels
[swizzle
]
463 src_colorspace
= format
.colorspace
464 if src_colorspace
== 'srgb' and i
== 3:
465 # Alpha channel is linear
466 src_colorspace
= 'rgb'
467 value
= 'pixel.chan.%s' % src_channel
.name
468 value
= conversion_expr(src_channel
,
469 dst_channel
, dst_native_type
,
471 src_colorspace
= src_colorspace
)
472 elif swizzle
== SWIZZLE_0
:
474 elif swizzle
== SWIZZLE_1
:
475 value
= get_one(dst_channel
)
476 elif swizzle
== SWIZZLE_NONE
:
480 print ' dst[%u] = %s; /* %s */' % (i
, value
, 'rgba'[i
])
483 def generate_pack_kernel(format
, src_channel
, src_native_type
):
485 if not is_format_supported(format
):
488 dst_native_type
= native_type(format
)
490 assert format
.layout
== PLAIN
492 inv_swizzle
= format
.inv_swizzles()
494 if format
.is_bitmask():
495 depth
= format
.block_size()
496 print ' uint%u_t value = 0;' % depth
500 dst_channel
= format
.channels
[i
]
501 if inv_swizzle
[i
] is not None:
502 value
='src[%u]' % inv_swizzle
[i
]
503 dst_colorspace
= format
.colorspace
504 if dst_colorspace
== 'srgb' and inv_swizzle
[i
] == 3:
505 # Alpha channel is linear
506 dst_colorspace
= 'rgb'
507 value
= conversion_expr(src_channel
,
508 dst_channel
, dst_native_type
,
510 dst_colorspace
= dst_colorspace
)
511 if dst_channel
.type in (UNSIGNED
, SIGNED
):
512 if shift
+ dst_channel
.size
< depth
:
513 value
= '(%s) & 0x%x' % (value
, (1 << dst_channel
.size
) - 1)
515 value
= '(%s) << %u' % (value
, shift
)
516 if dst_channel
.type == SIGNED
:
518 value
= '(uint%u_t)(%s) ' % (depth
, value
)
521 if value
is not None:
522 print ' value |= %s;' % (value
)
524 shift
+= dst_channel
.size
527 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
528 print ' value = util_bswap%u(value);' % depth
531 print ' *(uint%u_t *)dst = value;' % depth
534 print ' union util_format_%s pixel;' % format
.short_name()
537 dst_channel
= format
.channels
[i
]
538 width
= dst_channel
.size
539 if inv_swizzle
[i
] is None:
541 dst_colorspace
= format
.colorspace
542 if dst_colorspace
== 'srgb' and inv_swizzle
[i
] == 3:
543 # Alpha channel is linear
544 dst_colorspace
= 'rgb'
545 value
='src[%u]' % inv_swizzle
[i
]
546 value
= conversion_expr(src_channel
,
547 dst_channel
, dst_native_type
,
549 dst_colorspace
= dst_colorspace
)
550 print ' pixel.chan.%s = %s;' % (dst_channel
.name
, value
)
553 print ' memcpy(dst, &pixel, sizeof pixel);'
556 def generate_format_unpack(format
, dst_channel
, dst_native_type
, dst_suffix
):
557 '''Generate the function to unpack pixels from a particular format'''
559 name
= format
.short_name()
561 print 'static INLINE void'
562 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
)
565 if is_format_supported(format
):
566 print ' unsigned x, y;'
567 print ' for(y = 0; y < height; y += %u) {' % (format
.block_height
,)
568 print ' %s *dst = dst_row;' % (dst_native_type
)
569 print ' const uint8_t *src = src_row;'
570 print ' for(x = 0; x < width; x += %u) {' % (format
.block_width
,)
572 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
574 print ' src += %u;' % (format
.block_size() / 8,)
577 print ' src_row += src_stride;'
578 print ' dst_row += dst_stride/sizeof(*dst_row);'
585 def generate_format_pack(format
, src_channel
, src_native_type
, src_suffix
):
586 '''Generate the function to pack pixels to a particular format'''
588 name
= format
.short_name()
590 print 'static INLINE void'
591 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
)
594 if is_format_supported(format
):
595 print ' unsigned x, y;'
596 print ' for(y = 0; y < height; y += %u) {' % (format
.block_height
,)
597 print ' const %s *src = src_row;' % (src_native_type
)
598 print ' uint8_t *dst = dst_row;'
599 print ' for(x = 0; x < width; x += %u) {' % (format
.block_width
,)
601 generate_pack_kernel(format
, src_channel
, src_native_type
)
604 print ' dst += %u;' % (format
.block_size() / 8,)
606 print ' dst_row += dst_stride;'
607 print ' src_row += src_stride/sizeof(*src_row);'
614 def generate_format_fetch(format
, dst_channel
, dst_native_type
, dst_suffix
):
615 '''Generate the function to unpack pixels from a particular format'''
617 name
= format
.short_name()
619 print 'static INLINE void'
620 print 'util_format_%s_fetch_%s(%s *dst, const uint8_t *src, unsigned i, unsigned j)' % (name
, dst_suffix
, dst_native_type
)
623 if is_format_supported(format
):
624 generate_unpack_kernel(format
, dst_channel
, dst_native_type
)
630 def is_format_hand_written(format
):
631 return format
.layout
in ('s3tc', 'subsampled', 'other') or format
.colorspace
== ZS
634 def generate(formats
):
636 print '#include "pipe/p_compiler.h"'
637 print '#include "u_math.h"'
638 print '#include "u_half.h"'
639 print '#include "u_format.h"'
640 print '#include "u_format_other.h"'
641 print '#include "u_format_srgb.h"'
642 print '#include "u_format_yuv.h"'
643 print '#include "u_format_zs.h"'
646 for format
in formats
:
647 if not is_format_hand_written(format
):
649 if is_format_supported(format
):
650 generate_format_type(format
)
652 channel
= Channel(FLOAT
, False, 32)
653 native_type
= 'float'
654 suffix
= 'rgba_float'
656 generate_format_unpack(format
, channel
, native_type
, suffix
)
657 generate_format_pack(format
, channel
, native_type
, suffix
)
658 generate_format_fetch(format
, channel
, native_type
, suffix
)
660 channel
= Channel(UNSIGNED
, True, 8)
661 native_type
= 'uint8_t'
662 suffix
= 'rgba_8unorm'
664 generate_format_unpack(format
, channel
, native_type
, suffix
)
665 generate_format_pack(format
, channel
, native_type
, suffix
)