Merge remote branch 'origin/gallium-st-api-dri'
[mesa.git] / src / gallium / auxiliary / util / u_format_pack.py
1 #!/usr/bin/env python
2
3 '''
4 /**************************************************************************
5 *
6 * Copyright 2009 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
42 from u_format_parse import *
43
44
45 def generate_format_type(format):
46 '''Generate a structure that describes the format.'''
47
48 print 'union util_format_%s {' % format.short_name()
49 if format.is_bitmask():
50 print ' uint%u_t value;' % (format.block_size(),)
51 print ' struct {'
52 for channel in format.channels:
53 if format.is_bitmask() and not format.is_array():
54 if channel.type == VOID:
55 if channel.size:
56 print ' unsigned %s:%u;' % (channel.name, channel.size)
57 elif channel.type == UNSIGNED:
58 print ' unsigned %s:%u;' % (channel.name, channel.size)
59 elif channel.type == SIGNED:
60 print ' int %s:%u;' % (channel.name, channel.size)
61 else:
62 assert 0
63 else:
64 assert channel.size % 8 == 0 and is_pot(channel.size)
65 if channel.type == VOID:
66 if channel.size:
67 print ' uint%u_t %s;' % (channel.size, channel.name)
68 elif channel.type == UNSIGNED:
69 print ' uint%u_t %s;' % (channel.size, channel.name)
70 elif channel.type in (SIGNED, FIXED):
71 print ' int%u_t %s;' % (channel.size, channel.name)
72 elif channel.type == FLOAT:
73 if channel.size == 64:
74 print ' double %s;' % (channel.name)
75 elif channel.size == 32:
76 print ' float %s;' % (channel.name)
77 elif channel.size == 16:
78 print ' uint16_t %s;' % (channel.name)
79 else:
80 assert 0
81 else:
82 assert 0
83 print ' } chan;'
84 print '};'
85 print
86
87
88 def bswap_format(format):
89 '''Generate a structure that describes the format.'''
90
91 if format.is_bitmask() and not format.is_array():
92 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
93 print ' pixel.value = util_bswap%u(pixel.value);' % format.block_size()
94 print '#endif'
95
96
97 def is_format_supported(format):
98 '''Determines whether we actually have the plumbing necessary to generate the
99 to read/write to/from this format.'''
100
101 # FIXME: Ideally we would support any format combination here.
102
103 if format.layout != PLAIN:
104 return False
105
106 for i in range(4):
107 channel = format.channels[i]
108 if channel.type not in (VOID, UNSIGNED, SIGNED, FLOAT):
109 return False
110
111 # We can only read a color from a depth/stencil format if the depth channel is present
112 if format.colorspace == 'zs' and format.swizzles[0] == SWIZZLE_NONE:
113 return False
114
115 return True
116
117
118 def native_type(format):
119 '''Get the native appropriate for a format.'''
120
121 if format.layout == PLAIN:
122 if not format.is_array():
123 # For arithmetic pixel formats return the integer type that matches the whole pixel
124 return 'uint%u_t' % format.block_size()
125 else:
126 # For array pixel formats return the integer type that matches the color channel
127 type = format.channels[0]
128 if type.type == UNSIGNED:
129 return 'uint%u_t' % type.size
130 elif type.type == SIGNED:
131 return 'int%u_t' % type.size
132 elif type.type == FLOAT:
133 if type.size == 32:
134 return 'float'
135 elif type.size == 64:
136 return 'double'
137 else:
138 assert False
139 else:
140 assert False
141 else:
142 assert False
143
144
145 def intermediate_native_type(bits, sign):
146 '''Find a native type adequate to hold intermediate results of the request bit size.'''
147
148 bytes = 4 # don't use anything smaller than 32bits
149 while bytes * 8 < bits:
150 bytes *= 2
151 bits = bytes*8
152
153 if sign:
154 return 'int%u_t' % bits
155 else:
156 return 'uint%u_t' % bits
157
158
159 def get_one_shift(type):
160 '''Get the number of the bit that matches unity for this type.'''
161 if type.type == 'FLOAT':
162 assert False
163 if not type.norm:
164 return 0
165 if type.type == UNSIGNED:
166 return type.size
167 if type.type == SIGNED:
168 return type.size - 1
169 if type.type == FIXED:
170 return type.size / 2
171 assert False
172
173
174 def get_one(type):
175 '''Get the value of unity for this type.'''
176 if type.type == 'FLOAT' or not type.norm:
177 return 1
178 else:
179 return (1 << get_one_shift(type)) - 1
180
181
182 def generate_clamp():
183 '''Code generate the clamping functions for each type.
184
185 We don't use a macro so that arguments with side effects,
186 like *src_pixel++ are correctly handled.
187 '''
188
189 for suffix, native_type in [
190 ('', 'double'),
191 ('f', 'float'),
192 ('ui', 'unsigned int'),
193 ('si', 'int'),
194 ]:
195 print 'static INLINE %s' % native_type
196 print 'clamp%s(%s value, %s lbound, %s ubound)' % (suffix, native_type, native_type, native_type)
197 print '{'
198 print ' if(value < lbound)'
199 print ' return lbound;'
200 print ' if(value > ubound)'
201 print ' return ubound;'
202 print ' return value;'
203 print '}'
204 print
205
206
207 def clamp_expr(src_channel, dst_channel, dst_native_type, value):
208 '''Generate the expression to clamp the value in the source type to the
209 destination type range.'''
210
211 if src_channel == dst_channel:
212 return value
213
214 # Pick the approriate clamp function
215 if src_channel.type == FLOAT:
216 if src_channel.size == 32:
217 func = 'clampf'
218 elif src_channel.size == 64:
219 func = 'clamp'
220 else:
221 assert False
222 elif src_channel.type == UNSIGNED:
223 func = 'clampui'
224 elif src_channel.type == SIGNED:
225 func = 'clampsi'
226 else:
227 assert False
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 if src_min < dst_min and src_max > dst_max:
235 return 'CLAMP(%s, %s, %s)' % (value, dst_min, dst_max)
236
237 if src_max > dst_max:
238 return 'MIN2(%s, %s)' % (value, dst_max)
239
240 if src_min < dst_min:
241 return 'MAX2(%s, %s)' % (value, dst_min)
242
243 return value
244
245
246 def conversion_expr(src_channel, dst_channel, dst_native_type, value, clamp=True):
247 '''Generate the expression to convert a value between two types.'''
248
249 if src_channel == dst_channel:
250 return value
251
252 if src_channel.type == FLOAT and dst_channel.type == FLOAT:
253 return '(%s)%s' % (dst_native_type, value)
254
255 if clamp:
256 value = clamp_expr(src_channel, dst_channel, dst_native_type, value)
257
258 if dst_channel.type == FLOAT:
259 if src_channel.norm:
260 one = get_one(src_channel)
261 if src_channel.size <= 23:
262 scale = '(1.0f/0x%x)' % one
263 else:
264 # bigger than single precision mantissa, use double
265 scale = '(1.0/0x%x)' % one
266 value = '(%s * %s)' % (value, scale)
267 return '(%s)%s' % (dst_native_type, value)
268
269 if src_channel.type == FLOAT:
270 if dst_channel.norm:
271 dst_one = get_one(dst_channel)
272 if dst_channel.size <= 23:
273 scale = '0x%x' % dst_one
274 else:
275 # bigger than single precision mantissa, use double
276 scale = '(double)0x%x' % dst_one
277 value = '(%s * %s)' % (value, scale)
278 return '(%s)%s' % (dst_native_type, value)
279
280 if src_channel.type in (SIGNED, UNSIGNED) and dst_channel.type in (SIGNED, UNSIGNED):
281 if not src_channel.norm and not dst_channel.norm:
282 # neither is normalized -- just cast
283 return '(%s)%s' % (dst_native_type, value)
284
285 src_one = get_one(src_channel)
286 dst_one = get_one(dst_channel)
287
288 if src_one > dst_one and src_channel.norm and dst_channel.norm:
289 # We can just bitshift
290 src_shift = get_one_shift(src_channel)
291 dst_shift = get_one_shift(dst_channel)
292 value = '(%s >> %s)' % (value, src_shift - dst_shift)
293 else:
294 # We need to rescale using an intermediate type big enough to hold the multiplication of both
295 tmp_native_type = intermediate_native_type(src_channel.size + dst_channel.size, src_channel.sign and dst_channel.sign)
296 value = '((%s)%s)' % (tmp_native_type, value)
297 value = '(%s * 0x%x / 0x%x)' % (value, dst_one, src_one)
298 value = '(%s)%s' % (dst_native_type, value)
299 return value
300
301 assert False
302
303
304 def generate_format_unpack(format, dst_channel, dst_native_type, dst_suffix):
305 '''Generate the function to unpack pixels from a particular format'''
306
307 assert format.layout == PLAIN
308
309 name = format.short_name()
310
311 src_native_type = native_type(format)
312
313 print 'static INLINE void'
314 print 'util_format_%s_unpack_%s(%s *dst, const void *src)' % (name, dst_suffix, dst_native_type)
315 print '{'
316
317 if format.is_bitmask():
318 depth = format.block_size()
319 print ' uint%u_t value = *(uint%u_t *)src;' % (depth, depth)
320
321 # Declare the intermediate variables
322 for i in range(format.nr_channels()):
323 src_channel = format.channels[i]
324 if src_channel.type == UNSIGNED:
325 print ' uint%u_t %s;' % (depth, src_channel.name)
326 elif src_channel.type == SIGNED:
327 print ' int%u_t %s;' % (depth, src_channel.name)
328
329 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
330 print ' value = util_bswap%u(value);' % depth
331 print '#endif'
332
333 # Compute the intermediate unshifted values
334 shift = 0
335 for i in range(format.nr_channels()):
336 src_channel = format.channels[i]
337 value = 'value'
338 if src_channel.type == UNSIGNED:
339 if shift:
340 value = '%s >> %u' % (value, shift)
341 if shift + src_channel.size < depth:
342 value = '(%s) & 0x%x' % (value, (1 << src_channel.size) - 1)
343 elif src_channel.type == SIGNED:
344 if shift + src_channel.size < depth:
345 # Align the sign bit
346 lshift = depth - (shift + src_channel.size)
347 value = '%s << %u' % (value, lshift)
348 # Cast to signed
349 value = '(int%u_t)(%s) ' % (depth, value)
350 if src_channel.size < depth:
351 # Align the LSB bit
352 rshift = depth - src_channel.size
353 value = '(%s) >> %u' % (value, rshift)
354 else:
355 value = None
356
357 if value is not None:
358 print ' %s = %s;' % (src_channel.name, value)
359
360 shift += src_channel.size
361
362 # Convert, swizzle, and store final values
363 for i in range(4):
364 swizzle = format.swizzles[i]
365 if swizzle < 4:
366 src_channel = format.channels[swizzle]
367 value = src_channel.name
368 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
369 elif swizzle == SWIZZLE_0:
370 value = '0'
371 elif swizzle == SWIZZLE_1:
372 value = get_one(dst_channel)
373 elif swizzle == SWIZZLE_NONE:
374 value = '0'
375 else:
376 assert False
377 if format.colorspace == ZS:
378 if i == 3:
379 value = get_one(dst_channel)
380 elif i >= 1:
381 value = 'dst[0]'
382 print ' dst[%u] = %s; /* %s */' % (i, value, 'rgba'[i])
383
384 else:
385 print ' union util_format_%s pixel;' % format.short_name()
386 print ' memcpy(&pixel, src, sizeof pixel);'
387 bswap_format(format)
388
389 for i in range(4):
390 swizzle = format.swizzles[i]
391 if swizzle < 4:
392 src_channel = format.channels[swizzle]
393 value = 'pixel.chan.%s' % src_channel.name
394 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
395 elif swizzle == SWIZZLE_0:
396 value = '0'
397 elif swizzle == SWIZZLE_1:
398 value = get_one(dst_channel)
399 elif swizzle == SWIZZLE_NONE:
400 value = '0'
401 else:
402 assert False
403 if format.colorspace == ZS:
404 if i == 3:
405 value = get_one(dst_channel)
406 elif i >= 1:
407 value = 'dst[0]'
408 print ' dst[%u] = %s; /* %s */' % (i, value, 'rgba'[i])
409
410 print '}'
411 print
412
413
414 def generate_format_pack(format, src_channel, src_native_type, src_suffix):
415 '''Generate the function to pack pixels to a particular format'''
416
417 name = format.short_name()
418
419 dst_native_type = native_type(format)
420
421 assert format.layout == PLAIN
422
423 inv_swizzle = format.inv_swizzles()
424
425 print 'static INLINE void'
426 print 'util_format_%s_pack_%s(void *dst, %s r, %s g, %s b, %s a)' % (name, src_suffix, src_native_type, src_native_type, src_native_type, src_native_type)
427 print '{'
428
429 if format.is_bitmask():
430 depth = format.block_size()
431 print ' uint%u_t value = 0;' % depth
432
433 shift = 0
434 for i in range(4):
435 dst_channel = format.channels[i]
436 if inv_swizzle[i] is not None:
437 value = 'rgba'[inv_swizzle[i]]
438 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
439 if format.colorspace == ZS:
440 if i == 3:
441 value = get_one(dst_channel)
442 elif i >= 1:
443 value = '0'
444 if dst_channel.type in (UNSIGNED, SIGNED):
445 if shift + dst_channel.size < depth:
446 value = '(%s) & 0x%x' % (value, (1 << dst_channel.size) - 1)
447 if shift:
448 value = '(%s) << %u' % (value, shift)
449 if dst_channel.type == SIGNED:
450 # Cast to unsigned
451 value = '(uint%u_t)(%s) ' % (depth, value)
452 else:
453 value = None
454 if value is not None:
455 print ' value |= %s;' % (value)
456
457 shift += dst_channel.size
458
459 print '#ifdef PIPE_ARCH_BIG_ENDIAN'
460 print ' value = util_bswap%u(value);' % depth
461 print '#endif'
462
463 print ' *(uint%u_t *)dst = value;' % depth
464
465 else:
466 print ' union util_format_%s pixel;' % format.short_name()
467
468 for i in range(4):
469 dst_channel = format.channels[i]
470 width = dst_channel.size
471 if inv_swizzle[i] is None:
472 continue
473 value = 'rgba'[inv_swizzle[i]]
474 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
475 if format.colorspace == ZS:
476 if i == 3:
477 value = get_one(dst_channel)
478 elif i >= 1:
479 value = '0'
480 print ' pixel.chan.%s = %s;' % (dst_channel.name, value)
481
482 bswap_format(format)
483 print ' memcpy(dst, &pixel, sizeof pixel);'
484
485 print '}'
486 print
487
488
489 def generate_unpack(formats, dst_channel, dst_native_type, dst_suffix):
490 '''Generate the dispatch function to unpack pixels from any format'''
491
492 for format in formats:
493 if is_format_supported(format):
494 generate_format_unpack(format, dst_channel, dst_native_type, dst_suffix)
495
496 print 'static INLINE void'
497 print 'util_format_unpack_%s(enum pipe_format format, %s *dst, const void *src)' % (dst_suffix, dst_native_type)
498 print '{'
499 print ' void (*func)(%s *dst, const void *src);' % dst_native_type
500 print ' switch(format) {'
501 for format in formats:
502 if is_format_supported(format):
503 print ' case %s:' % format.name
504 print ' func = &util_format_%s_unpack_%s;' % (format.short_name(), dst_suffix)
505 print ' break;'
506 print ' default:'
507 print ' debug_printf("unsupported format\\n");'
508 print ' return;'
509 print ' }'
510 print ' func(dst, src);'
511 print '}'
512 print
513
514
515 def generate_pack(formats, src_channel, src_native_type, src_suffix):
516 '''Generate the dispatch function to pack pixels to any format'''
517
518 for format in formats:
519 if is_format_supported(format):
520 generate_format_pack(format, src_channel, src_native_type, src_suffix)
521
522 print 'static INLINE void'
523 print 'util_format_pack_%s(enum pipe_format format, void *dst, %s r, %s g, %s b, %s a)' % (src_suffix, src_native_type, src_native_type, src_native_type, src_native_type)
524 print '{'
525 print ' void (*func)(void *dst, %s r, %s g, %s b, %s a);' % (src_native_type, src_native_type, src_native_type, src_native_type)
526 print ' switch(format) {'
527 for format in formats:
528 if is_format_supported(format):
529 print ' case %s:' % format.name
530 print ' func = &util_format_%s_pack_%s;' % (format.short_name(), src_suffix)
531 print ' break;'
532 print ' default:'
533 print ' debug_printf("%s: unsupported format\\n", __FUNCTION__);'
534 print ' return;'
535 print ' }'
536 print ' func(dst, r, g, b, a);'
537 print '}'
538 print
539
540
541 def main():
542 formats = []
543 for arg in sys.argv[1:]:
544 formats.extend(parse(arg))
545
546 print '/* This file is autogenerated by u_format_pack.py from u_format.csv. Do not edit directly. */'
547 print
548 # This will print the copyright message on the top of this file
549 print __doc__.strip()
550
551 print
552 print '#ifndef U_FORMAT_PACK_H'
553 print '#define U_FORMAT_PACK_H'
554 print
555 print '#include "pipe/p_compiler.h"'
556 print '#include "u_math.h"'
557 print '#include "u_format.h"'
558 print
559
560 generate_clamp()
561
562 for format in formats:
563 if format.layout == PLAIN:
564 generate_format_type(format)
565
566 channel = Channel(FLOAT, False, 32)
567 native_type = 'float'
568 suffix = '4f'
569
570 generate_unpack(formats, channel, native_type, suffix)
571 generate_pack(formats, channel, native_type, suffix)
572
573 channel = Channel(UNSIGNED, True, 8)
574 native_type = 'uint8_t'
575 suffix = '4ub'
576
577 generate_unpack(formats, channel, native_type, suffix)
578 generate_pack(formats, channel, native_type, suffix)
579
580 print
581 print '#ifdef __cplusplus'
582 print '}'
583 print '#endif'
584 print
585 print '#endif /* ! U_FORMAT_PACK_H */'
586
587
588 if __name__ == '__main__':
589 main()