Merge branch '7.8'
[mesa.git] / src / gallium / auxiliary / util / u_format_pack.py
1 #!/usr/bin/env python
2
3 '''
4 /**************************************************************************
5 *
6 * Copyright 2009-2010 VMware, Inc.
7 * All Rights Reserved.
8 *
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:
16 *
17 * The above copyright notice and this permission notice (including the
18 * next paragraph) shall be included in all copies or substantial portions
19 * of the Software.
20 *
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.
28 *
29 **************************************************************************/
30
31 /**
32 * @file
33 * Pixel format packing and unpacking functions.
34 *
35 * @author Jose Fonseca <jfonseca@vmware.com>
36 */
37 '''
38
39
40 import sys
41 import math
42
43 from u_format_parse import *
44
45
46 def generate_format_type(format):
47 '''Generate a structure that describes the format.'''
48
49 assert format.layout == PLAIN
50
51 print 'union util_format_%s {' % format.short_name()
52
53 if format.block_size() in (8, 16, 32, 64):
54 print ' uint%u_t value;' % (format.block_size(),)
55
56 use_bitfields = False
57 for channel in format.channels:
58 if channel.size % 8 or not is_pot(channel.size):
59 use_bitfields = True
60
61 print ' struct {'
62 for channel in format.channels:
63 if use_bitfields:
64 if channel.type == VOID:
65 if channel.size:
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)
76 else:
77 print ' unsigned %s:%u;' % (channel.name, channel.size)
78 else:
79 assert 0
80 else:
81 assert channel.size % 8 == 0 and is_pot(channel.size)
82 if channel.type == VOID:
83 if channel.size:
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)
96 else:
97 assert 0
98 else:
99 assert 0
100 print ' } chan;'
101 print '};'
102 print
103
104
105 def bswap_format(format):
106 '''Generate a structure that describes the format.'''
107
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()
111 print '#endif'
112
113
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.'''
117
118 # FIXME: Ideally we would support any format combination here.
119
120 if format.layout != PLAIN:
121 return False
122
123 for i in range(4):
124 channel = format.channels[i]
125 if channel.type not in (VOID, UNSIGNED, SIGNED, FLOAT, FIXED):
126 return False
127 if channel.type == FLOAT and channel.size not in (16, 32, 64):
128 return False
129
130 return True
131
132
133 def native_type(format):
134 '''Get the native appropriate for a format.'''
135
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()
140 else:
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:
149 return 'uint16_t'
150 elif channel.size == 32:
151 return 'float'
152 elif channel.size == 64:
153 return 'double'
154 else:
155 assert False
156 else:
157 assert False
158 else:
159 assert False
160
161
162 def intermediate_native_type(bits, sign):
163 '''Find a native type adequate to hold intermediate results of the request bit size.'''
164
165 bytes = 4 # don't use anything smaller than 32bits
166 while bytes * 8 < bits:
167 bytes *= 2
168 bits = bytes*8
169
170 if sign:
171 return 'int%u_t' % bits
172 else:
173 return 'uint%u_t' % bits
174
175
176 def get_one_shift(type):
177 '''Get the number of the bit that matches unity for this type.'''
178 if type.type == 'FLOAT':
179 assert False
180 if not type.norm:
181 return 0
182 if type.type == UNSIGNED:
183 return type.size
184 if type.type == SIGNED:
185 return type.size - 1
186 if type.type == FIXED:
187 return type.size / 2
188 assert False
189
190
191 def value_to_native(type, value):
192 '''Get the value of unity for this type.'''
193 if type.type == FLOAT:
194 return value
195 if type.type == FIXED:
196 return int(value * (1 << (type.size/2)))
197 if not type.norm:
198 return int(value)
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))
203 assert False
204
205
206 def native_to_constant(type, value):
207 '''Get the value of unity for this type.'''
208 if type.type == FLOAT:
209 if type.size <= 32:
210 return "%ff" % value
211 else:
212 return "%ff" % value
213 else:
214 return str(int(value))
215
216
217 def get_one(type):
218 '''Get the value of unity for this type.'''
219 return value_to_native(type, 1)
220
221
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.'''
225
226 if src_channel == dst_channel:
227 return value
228
229 src_min = src_channel.min()
230 src_max = src_channel.max()
231 dst_min = dst_channel.min()
232 dst_max = dst_channel.max()
233
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)
237
238 if src_min < dst_min and src_max > dst_max:
239 return 'CLAMP(%s, %s, %s)' % (value, dst_min_native, dst_max_native)
240
241 if src_max > dst_max:
242 return 'MIN2(%s, %s)' % (value, dst_max_native)
243
244 if src_min < dst_min:
245 return 'MAX2(%s, %s)' % (value, dst_min_native)
246
247 return value
248
249
250 def conversion_expr(src_channel,
251 dst_channel, dst_native_type,
252 value,
253 clamp=True,
254 src_colorspace = RGB,
255 dst_colorspace = RGB):
256 '''Generate the expression to convert a value between two types.'''
257
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
266 else:
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
278 else:
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:
284 pass
285 elif dst_colorspace == ZS:
286 pass
287 else:
288 assert 0
289
290 if src_channel == dst_channel:
291 return value
292
293 src_type = src_channel.type
294 src_size = src_channel.size
295 src_norm = src_channel.norm
296
297 # Promote half to float
298 if src_type == FLOAT and src_size == 16:
299 value = 'util_half_to_float(%s)' % value
300 src_size = 32
301
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
308
309 if clamp:
310 if dst_channel.type != FLOAT or src_type != FLOAT:
311 value = clamp_expr(src_channel, dst_channel, dst_native_type, value)
312
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)
317
318 src_one = get_one(src_channel)
319 dst_one = get_one(dst_channel)
320
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)
326 else:
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)
332 return value
333
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)
338 if src_size <= 23:
339 value = '(%s * (1.0f/0x%x))' % (value, one)
340 if dst_channel.size <= 32:
341 value = '(float)%s' % value
342 src_size = 32
343 else:
344 # bigger than single precision mantissa, use double
345 value = '(%s * (1.0/0x%x))' % (value, one)
346 src_size = 64
347 src_norm = False
348 else:
349 if src_size <= 23 or dst_channel.size <= 32:
350 value = '(float)%s' % value
351 src_size = 32
352 else:
353 # bigger than single precision mantissa, use double
354 value = '(double)%s' % value
355 src_size = 64
356 src_type = FLOAT
357
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)
364 else:
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)
368 else:
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
372 src_size = 32
373
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
378
379 return value
380
381
382 def generate_unpack_kernel(format, dst_channel, dst_native_type):
383
384 if not is_format_supported(format):
385 return
386
387 assert format.layout == PLAIN
388
389 src_native_type = native_type(format)
390
391 if format.is_bitmask():
392 depth = format.block_size()
393 print ' uint%u_t value = *(const uint%u_t *)src;' % (depth, depth)
394
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)
402
403 if depth > 8:
404 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
405 print ' value = util_bswap%u(value);' % depth
406 print '#endif'
407
408 # Compute the intermediate unshifted values
409 shift = 0
410 for i in range(format.nr_channels()):
411 src_channel = format.channels[i]
412 value = 'value'
413 if src_channel.type == UNSIGNED:
414 if shift:
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:
420 # Align the sign bit
421 lshift = depth - (shift + src_channel.size)
422 value = '%s << %u' % (value, lshift)
423 # Cast to signed
424 value = '(int%u_t)(%s) ' % (depth, value)
425 if src_channel.size < depth:
426 # Align the LSB bit
427 rshift = depth - src_channel.size
428 value = '(%s) >> %u' % (value, rshift)
429 else:
430 value = None
431
432 if value is not None:
433 print ' %s = %s;' % (src_channel.name, value)
434
435 shift += src_channel.size
436
437 # Convert, swizzle, and store final values
438 for i in range(4):
439 swizzle = format.swizzles[i]
440 if swizzle < 4:
441 src_channel = format.channels[swizzle]
442 src_colorspace = format.colorspace
443 if src_colorspace == SRGB and i == 3:
444 # Alpha channel is linear
445 src_colorspace = RGB
446 value = src_channel.name
447 value = conversion_expr(src_channel,
448 dst_channel, dst_native_type,
449 value,
450 src_colorspace = src_colorspace)
451 elif swizzle == SWIZZLE_0:
452 value = '0'
453 elif swizzle == SWIZZLE_1:
454 value = get_one(dst_channel)
455 elif swizzle == SWIZZLE_NONE:
456 value = '0'
457 else:
458 assert False
459 print ' dst[%u] = %s; /* %s */' % (i, value, 'rgba'[i])
460
461 else:
462 print ' union util_format_%s pixel;' % format.short_name()
463 print ' memcpy(&pixel, src, sizeof pixel);'
464 bswap_format(format)
465
466 for i in range(4):
467 swizzle = format.swizzles[i]
468 if swizzle < 4:
469 src_channel = format.channels[swizzle]
470 src_colorspace = format.colorspace
471 if src_colorspace == SRGB and i == 3:
472 # Alpha channel is linear
473 src_colorspace = RGB
474 value = 'pixel.chan.%s' % src_channel.name
475 value = conversion_expr(src_channel,
476 dst_channel, dst_native_type,
477 value,
478 src_colorspace = src_colorspace)
479 elif swizzle == SWIZZLE_0:
480 value = '0'
481 elif swizzle == SWIZZLE_1:
482 value = get_one(dst_channel)
483 elif swizzle == SWIZZLE_NONE:
484 value = '0'
485 else:
486 assert False
487 print ' dst[%u] = %s; /* %s */' % (i, value, 'rgba'[i])
488
489
490 def generate_pack_kernel(format, src_channel, src_native_type):
491
492 if not is_format_supported(format):
493 return
494
495 dst_native_type = native_type(format)
496
497 assert format.layout == PLAIN
498
499 inv_swizzle = format.inv_swizzles()
500
501 if format.is_bitmask():
502 depth = format.block_size()
503 print ' uint%u_t value = 0;' % depth
504
505 shift = 0
506 for i in range(4):
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
513 dst_colorspace = RGB
514 value = conversion_expr(src_channel,
515 dst_channel, dst_native_type,
516 value,
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)
521 if shift:
522 value = '(%s) << %u' % (value, shift)
523 if dst_channel.type == SIGNED:
524 # Cast to unsigned
525 value = '(uint%u_t)(%s) ' % (depth, value)
526 else:
527 value = None
528 if value is not None:
529 print ' value |= %s;' % (value)
530
531 shift += dst_channel.size
532
533 if depth > 8:
534 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
535 print ' value = util_bswap%u(value);' % depth
536 print '#endif'
537
538 print ' *(uint%u_t *)dst = value;' % depth
539
540 else:
541 print ' union util_format_%s pixel;' % format.short_name()
542
543 for i in range(4):
544 dst_channel = format.channels[i]
545 width = dst_channel.size
546 if inv_swizzle[i] is None:
547 continue
548 dst_colorspace = format.colorspace
549 if dst_colorspace == SRGB and inv_swizzle[i] == 3:
550 # Alpha channel is linear
551 dst_colorspace = RGB
552 value ='src[%u]' % inv_swizzle[i]
553 value = conversion_expr(src_channel,
554 dst_channel, dst_native_type,
555 value,
556 dst_colorspace = dst_colorspace)
557 print ' pixel.chan.%s = %s;' % (dst_channel.name, value)
558
559 bswap_format(format)
560 print ' memcpy(dst, &pixel, sizeof pixel);'
561
562
563 def generate_format_unpack(format, dst_channel, dst_native_type, dst_suffix):
564 '''Generate the function to unpack pixels from a particular format'''
565
566 name = format.short_name()
567
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)
570 print '{'
571
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,)
578
579 generate_unpack_kernel(format, dst_channel, dst_native_type)
580
581 print ' src += %u;' % (format.block_size() / 8,)
582 print ' dst += 4;'
583 print ' }'
584 print ' src_row += src_stride;'
585 print ' dst_row += dst_stride/sizeof(*dst_row);'
586 print ' }'
587
588 print '}'
589 print
590
591
592 def generate_format_pack(format, src_channel, src_native_type, src_suffix):
593 '''Generate the function to pack pixels to a particular format'''
594
595 name = format.short_name()
596
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)
599 print '{'
600
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,)
607
608 generate_pack_kernel(format, src_channel, src_native_type)
609
610 print ' src += 4;'
611 print ' dst += %u;' % (format.block_size() / 8,)
612 print ' }'
613 print ' dst_row += dst_stride;'
614 print ' src_row += src_stride/sizeof(*src_row);'
615 print ' }'
616
617 print '}'
618 print
619
620
621 def generate_format_fetch(format, dst_channel, dst_native_type, dst_suffix):
622 '''Generate the function to unpack pixels from a particular format'''
623
624 name = format.short_name()
625
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)
628 print '{'
629
630 if is_format_supported(format):
631 generate_unpack_kernel(format, dst_channel, dst_native_type)
632
633 print '}'
634 print
635
636
637 def is_format_hand_written(format):
638 return format.layout in ('s3tc', 'subsampled', 'other') or format.colorspace == ZS
639
640
641 def generate(formats):
642 print
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"'
651 print
652
653 for format in formats:
654 if not is_format_hand_written(format):
655
656 if is_format_supported(format):
657 generate_format_type(format)
658
659 channel = Channel(FLOAT, False, 32)
660 native_type = 'float'
661 suffix = 'rgba_float'
662
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)
666
667 channel = Channel(UNSIGNED, True, 8)
668 native_type = 'uint8_t'
669 suffix = 'rgba_8unorm'
670
671 generate_format_unpack(format, channel, native_type, suffix)
672 generate_format_pack(format, channel, native_type, suffix)
673