util: Use python names consistent with u_format.h
[mesa.git] / src / gallium / auxiliary / util / u_format_access.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 accessor 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 is_format_supported(format):
46 '''Determines whether we actually have the plumbing necessary to generate the
47 to read/write to/from this format.'''
48
49 # FIXME: Ideally we would support any format combination here.
50
51 # XXX: It should be straightforward to support srgb
52 if format.colorspace not in ('rgb', 'zs'):
53 return False
54
55 if format.layout != PLAIN:
56 return False
57
58 for i in range(4):
59 channel = format.channels[i]
60 if channel.type not in (VOID, UNSIGNED, FLOAT):
61 return False
62
63 # We can only read a color from a depth/stencil format if the depth channel is present
64 if format.colorspace == 'zs' and format.swizzles[0] == SWIZZLE_NONE:
65 return False
66
67 return True
68
69
70 def native_type(format):
71 '''Get the native appropriate for a format.'''
72
73 if format.layout == PLAIN:
74 if not format.is_array():
75 # For arithmetic pixel formats return the integer type that matches the whole pixel
76 return 'uint%u_t' % format.block_size()
77 else:
78 # For array pixel formats return the integer type that matches the color channel
79 channel = format.channels[0]
80 if channel.type == UNSIGNED:
81 return 'uint%u_t' % channel.size
82 elif channel.type == SIGNED:
83 return 'int%u_t' % channel.size
84 elif channel.type == FLOAT:
85 if channel.size == 32:
86 return 'float'
87 elif channel.size == 64:
88 return 'double'
89 else:
90 assert False
91 else:
92 assert False
93 else:
94 assert False
95
96
97 def intermediate_native_type(bits, sign):
98 '''Find a native type adequate to hold intermediate results of the request bit size.'''
99
100 bytes = 4 # don't use anything smaller than 32bits
101 while bytes * 8 < bits:
102 bytes *= 2
103 bits = bytes*8
104
105 if sign:
106 return 'int%u_t' % bits
107 else:
108 return 'uint%u_t' % bits
109
110
111 def get_one_shift(channel):
112 '''Get the number of the bit that matches unity for this channel.'''
113 if channel.type == 'FLOAT':
114 assert False
115 if not channel.norm:
116 return 0
117 if channel.type == UNSIGNED:
118 return channel.size
119 if channel.type == SIGNED:
120 return channel.size - 1
121 if channel.type == FIXED:
122 return channel.size / 2
123 assert False
124
125
126 def get_one(channel):
127 '''Get the value of unity for this channel.'''
128 if channel.type == 'FLOAT' or not channel.norm:
129 return 1
130 else:
131 return (1 << get_one_shift(channel)) - 1
132
133
134 def generate_clamp():
135 '''Code generate the clamping functions for each type.
136
137 We don't use a macro so that arguments with side effects,
138 like *src_pixel++ are correctly handled.
139 '''
140
141 for suffix, native_type in [
142 ('', 'double'),
143 ('f', 'float'),
144 ('ui', 'unsigned int'),
145 ('si', 'int'),
146 ]:
147 print 'static INLINE %s' % native_type
148 print 'clamp%s(%s value, %s lbound, %s ubound)' % (suffix, native_type, native_type, native_type)
149 print '{'
150 print ' if(value < lbound)'
151 print ' return lbound;'
152 print ' if(value > ubound)'
153 print ' return ubound;'
154 print ' return value;'
155 print '}'
156 print
157
158
159 def clamp_expr(src_channel, dst_channel, dst_native_type, value):
160 '''Generate the expression to clamp the value in the source type to the
161 destination type range.'''
162
163 if src_channel == dst_channel:
164 return value
165
166 # Pick the approriate clamp function
167 if src_channel.type == FLOAT:
168 if src_channel.size == 32:
169 func = 'clampf'
170 elif src_channel.size == 64:
171 func = 'clamp'
172 else:
173 assert False
174 elif src_channel.type == UNSIGNED:
175 func = 'clampui'
176 elif src_channel.type == SIGNED:
177 func = 'clampsi'
178 else:
179 assert False
180
181 # Clamp floats to [-1, 1] or [0, 1] range
182 if src_channel.type == FLOAT and dst_channel.norm:
183 max = 1
184 if src_channel.sign and dst_channel.sign:
185 min = -1
186 else:
187 min = 0
188 return '%s(%s, %s, %s)' % (func, value, min, max)
189
190 # FIXME: Also clamp scaled values
191
192 return value
193
194
195 def conversion_expr(src_channel, dst_channel, dst_native_type, value):
196 '''Generate the expression to convert a value between two types.'''
197
198 if src_channel == dst_channel:
199 return value
200
201 if src_channel.type == FLOAT and dst_channel.type == FLOAT:
202 return '(%s)%s' % (dst_native_type, value)
203
204 if not src_channel.norm and not dst_channel.norm:
205 return '(%s)%s' % (dst_native_type, value)
206
207 value = clamp_expr(src_channel, dst_channel, dst_native_type, value)
208
209 if dst_channel.type == FLOAT:
210 if src_channel.norm:
211 one = get_one(src_channel)
212 if src_channel.size <= 23:
213 scale = '(1.0f/0x%x)' % one
214 else:
215 # bigger than single precision mantissa, use double
216 scale = '(1.0/0x%x)' % one
217 value = '(%s * %s)' % (value, scale)
218 return '(%s)%s' % (dst_native_type, value)
219
220 if src_channel.type == FLOAT:
221 if dst_channel.norm:
222 dst_one = get_one(dst_channel)
223 if dst_channel.size <= 23:
224 scale = '0x%x' % dst_one
225 else:
226 # bigger than single precision mantissa, use double
227 scale = '(double)0x%x' % dst_one
228 value = '(%s * %s)' % (value, scale)
229 return '(%s)%s' % (dst_native_type, value)
230
231 if src_channel.type == dst_channel.type:
232 src_one = get_one(src_channel)
233 dst_one = get_one(dst_channel)
234
235 if src_one > dst_one and src_channel.norm and dst_channel.norm:
236 # We can just bitshift
237 src_shift = get_one_shift(src_channel)
238 dst_shift = get_one_shift(dst_channel)
239 value = '(%s >> %s)' % (value, src_shift - dst_shift)
240 else:
241 # We need to rescale using an intermediate type big enough to hold the multiplication of both
242 tmp_native_type = intermediate_native_type(src_channel.size + dst_channel.size, src_channel.sign and dst_channel.sign)
243 value = '(%s)%s' % (tmp_native_type, value)
244 value = '%s * 0x%x / 0x%x' % (value, dst_one, src_one)
245 value = '(%s)%s' % (dst_native_type, value)
246 return value
247
248 assert False
249
250
251 def compute_inverse_swizzle(format):
252 '''Return an array[4] of inverse swizzle terms'''
253 inv_swizzle = [None]*4
254 if format.colorspace == 'rgb':
255 for i in range(4):
256 swizzle = format.swizzles[i]
257 if swizzle < 4:
258 inv_swizzle[swizzle] = i
259 elif format.colorspace == 'zs':
260 swizzle = format.swizzles[0]
261 if swizzle < 4:
262 inv_swizzle[swizzle] = 0
263 else:
264 assert False
265
266 return inv_swizzle
267
268
269 def generate_format_read(format, dst_channel, dst_native_type, dst_suffix):
270 '''Generate the function to read pixels from a particular format'''
271
272 name = format.short_name()
273
274 src_native_type = native_type(format)
275
276 print 'static void'
277 print 'util_format_%s_read_%s(%s *dst, unsigned dst_stride, const uint8_t *src, unsigned src_stride, unsigned x0, unsigned y0, unsigned w, unsigned h)' % (name, dst_suffix, dst_native_type)
278 print '{'
279 print ' unsigned x, y;'
280 print ' const uint8_t *src_row = src + y0*src_stride;'
281 print ' %s *dst_row = dst;' % dst_native_type
282 print ' for (y = 0; y < h; ++y) {'
283 print ' const %s *src_pixel = (const %s *)(src_row + x0*%u);' % (src_native_type, src_native_type, format.stride())
284 print ' %s *dst_pixel = dst_row;' %dst_native_type
285 print ' for (x = 0; x < w; ++x) {'
286
287 names = ['']*4
288 if format.colorspace == 'rgb':
289 for i in range(4):
290 swizzle = format.swizzles[i]
291 if swizzle < 4:
292 names[swizzle] += 'rgba'[i]
293 elif format.colorspace == 'zs':
294 swizzle = format.swizzles[0]
295 if swizzle < 4:
296 names[swizzle] = 'z'
297 else:
298 assert False
299 else:
300 assert False
301
302 if format.layout == PLAIN:
303 if not format.is_array():
304 print ' %s pixel = *src_pixel++;' % src_native_type
305 shift = 0;
306 for i in range(4):
307 src_channel = format.channels[i]
308 width = src_channel.size
309 if names[i]:
310 value = 'pixel'
311 mask = (1 << width) - 1
312 if shift:
313 value = '(%s >> %u)' % (value, shift)
314 if shift + width < format.block_size():
315 value = '(%s & 0x%x)' % (value, mask)
316 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
317 print ' %s %s = %s;' % (dst_native_type, names[i], value)
318 shift += width
319 else:
320 for i in range(4):
321 src_channel = format.channels[i]
322 if names[i]:
323 value = '(*src_pixel++)'
324 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
325 print ' %s %s = %s;' % (dst_native_type, names[i], value)
326 else:
327 assert False
328
329 for i in range(4):
330 if format.colorspace == 'rgb':
331 swizzle = format.swizzles[i]
332 if swizzle < 4:
333 value = names[swizzle]
334 elif swizzle == SWIZZLE_0:
335 value = '0'
336 elif swizzle == SWIZZLE_1:
337 value = get_one(dst_channel)
338 else:
339 assert False
340 elif format.colorspace == 'zs':
341 if i < 3:
342 value = 'z'
343 else:
344 value = get_one(dst_channel)
345 else:
346 assert False
347 print ' *dst_pixel++ = %s; /* %s */' % (value, 'rgba'[i])
348
349 print ' }'
350 print ' src_row += src_stride;'
351 print ' dst_row += dst_stride/sizeof(*dst_row);'
352 print ' }'
353 print '}'
354 print
355
356
357 def generate_format_write(format, src_channel, src_native_type, src_suffix):
358 '''Generate the function to write pixels to a particular format'''
359
360 name = format.short_name()
361
362 dst_native_type = native_type(format)
363
364 print 'static void'
365 print 'util_format_%s_write_%s(const %s *src, unsigned src_stride, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h)' % (name, src_suffix, src_native_type)
366 print '{'
367 print ' unsigned x, y;'
368 print ' uint8_t *dst_row = dst + y0*dst_stride;'
369 print ' const %s *src_row = src;' % src_native_type
370 print ' for (y = 0; y < h; ++y) {'
371 print ' %s *dst_pixel = (%s *)(dst_row + x0*%u);' % (dst_native_type, dst_native_type, format.stride())
372 print ' const %s *src_pixel = src_row;' %src_native_type
373 print ' for (x = 0; x < w; ++x) {'
374
375 inv_swizzle = compute_inverse_swizzle(format)
376
377 if format.layout == PLAIN:
378 if not format.is_array():
379 print ' %s pixel = 0;' % dst_native_type
380 shift = 0;
381 for i in range(4):
382 dst_channel = format.channels[i]
383 width = dst_channel.size
384 if inv_swizzle[i] is not None:
385 value = 'src_pixel[%u]' % inv_swizzle[i]
386 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
387 if shift:
388 value = '(%s << %u)' % (value, shift)
389 print ' pixel |= %s;' % value
390 shift += width
391 print ' *dst_pixel++ = pixel;'
392 else:
393 for i in range(4):
394 dst_channel = format.channels[i]
395 if inv_swizzle[i] is not None:
396 value = 'src_pixel[%u]' % inv_swizzle[i]
397 value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
398 print ' *dst_pixel++ = %s;' % value
399 else:
400 assert False
401 print ' src_pixel += 4;'
402
403 print ' }'
404 print ' dst_row += dst_stride;'
405 print ' src_row += src_stride/sizeof(*src_row);'
406 print ' }'
407 print '}'
408 print
409
410
411 def generate_read(formats, dst_channel, dst_native_type, dst_suffix):
412 '''Generate the dispatch function to read pixels from any format'''
413
414 for format in formats:
415 if is_format_supported(format):
416 generate_format_read(format, dst_channel, dst_native_type, dst_suffix)
417
418 print 'void'
419 print 'util_format_read_%s(enum pipe_format format, %s *dst, unsigned dst_stride, const void *src, unsigned src_stride, unsigned x, unsigned y, unsigned w, unsigned h)' % (dst_suffix, dst_native_type)
420 print '{'
421 print ' void (*func)(%s *dst, unsigned dst_stride, const uint8_t *src, unsigned src_stride, unsigned x0, unsigned y0, unsigned w, unsigned h);' % dst_native_type
422 print ' switch(format) {'
423 for format in formats:
424 if is_format_supported(format):
425 print ' case %s:' % format.name
426 print ' func = &util_format_%s_read_%s;' % (format.short_name(), dst_suffix)
427 print ' break;'
428 print ' default:'
429 print ' debug_printf("unsupported format\\n");'
430 print ' return;'
431 print ' }'
432 print ' func(dst, dst_stride, (const uint8_t *)src, src_stride, x, y, w, h);'
433 print '}'
434 print
435
436
437 def generate_write(formats, src_channel, src_native_type, src_suffix):
438 '''Generate the dispatch function to write pixels to any format'''
439
440 for format in formats:
441 if is_format_supported(format):
442 generate_format_write(format, src_channel, src_native_type, src_suffix)
443
444 print 'void'
445 print 'util_format_write_%s(enum pipe_format format, const %s *src, unsigned src_stride, void *dst, unsigned dst_stride, unsigned x, unsigned y, unsigned w, unsigned h)' % (src_suffix, src_native_type)
446
447 print '{'
448 print ' void (*func)(const %s *src, unsigned src_stride, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h);' % src_native_type
449 print ' switch(format) {'
450 for format in formats:
451 if is_format_supported(format):
452 print ' case %s:' % format.name
453 print ' func = &util_format_%s_write_%s;' % (format.short_name(), src_suffix)
454 print ' break;'
455 print ' default:'
456 print ' debug_printf("unsupported format\\n");'
457 print ' return;'
458 print ' }'
459 print ' func(src, src_stride, (uint8_t *)dst, dst_stride, x, y, w, h);'
460 print '}'
461 print
462
463
464 def main():
465 formats = []
466 for arg in sys.argv[1:]:
467 formats.extend(parse(arg))
468
469 print '/* This file is autogenerated by u_format_access.py from u_format.csv. Do not edit directly. */'
470 print
471 # This will print the copyright message on the top of this file
472 print __doc__.strip()
473 print
474 print '#include "pipe/p_compiler.h"'
475 print '#include "u_format.h"'
476 print '#include "u_math.h"'
477 print
478
479 generate_clamp()
480
481 type = Channel(FLOAT, False, 32)
482 native_type = 'float'
483 suffix = '4f'
484
485 generate_read(formats, type, native_type, suffix)
486 generate_write(formats, type, native_type, suffix)
487
488 type = Channel(UNSIGNED, True, 8)
489 native_type = 'uint8_t'
490 suffix = '4ub'
491
492 generate_read(formats, type, native_type, suffix)
493 generate_write(formats, type, native_type, suffix)
494
495
496 if __name__ == '__main__':
497 main()