4 /**************************************************************************
6 * Copyright 2009 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 accessor functions.
35 * @author Jose Fonseca <jfonseca@vmware.com>
42 from u_format_parse
import *
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.'''
49 # FIXME: Ideally we would support any format combination here.
51 # XXX: It should be straightforward to support srgb
52 if format
.colorspace
not in ('rgb', 'zs'):
55 if format
.layout
!= PLAIN
:
59 channel
= format
.channels
[i
]
60 if channel
.type not in (VOID
, UNSIGNED
, FLOAT
):
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
:
70 def native_type(format
):
71 '''Get the native appropriate for a format.'''
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()
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:
87 elif channel
.size
== 64:
97 def intermediate_native_type(bits
, sign
):
98 '''Find a native type adequate to hold intermediate results of the request bit size.'''
100 bytes
= 4 # don't use anything smaller than 32bits
101 while bytes
* 8 < bits
:
106 return 'int%u_t' % bits
108 return 'uint%u_t' % bits
111 def get_one_shift(channel
):
112 '''Get the number of the bit that matches unity for this channel.'''
113 if channel
.type == 'FLOAT':
117 if channel
.type == UNSIGNED
:
119 if channel
.type == SIGNED
:
120 return channel
.size
- 1
121 if channel
.type == FIXED
:
122 return channel
.size
/ 2
126 def get_one(channel
):
127 '''Get the value of unity for this channel.'''
128 if channel
.type == 'FLOAT' or not channel
.norm
:
131 return (1 << get_one_shift(channel
)) - 1
134 def generate_clamp():
135 '''Code generate the clamping functions for each type.
137 We don't use a macro so that arguments with side effects,
138 like *src_pixel++ are correctly handled.
141 for suffix
, native_type
in [
144 ('ui', 'unsigned int'),
147 print 'static INLINE %s' % native_type
148 print 'clamp%s(%s value, %s lbound, %s ubound)' % (suffix
, native_type
, native_type
, native_type
)
150 print ' if(value < lbound)'
151 print ' return lbound;'
152 print ' if(value > ubound)'
153 print ' return ubound;'
154 print ' return value;'
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.'''
163 if src_channel
== dst_channel
:
166 # Pick the approriate clamp function
167 if src_channel
.type == FLOAT
:
168 if src_channel
.size
== 32:
170 elif src_channel
.size
== 64:
174 elif src_channel
.type == UNSIGNED
:
176 elif src_channel
.type == SIGNED
:
181 # Clamp floats to [-1, 1] or [0, 1] range
182 if src_channel
.type == FLOAT
and dst_channel
.norm
:
184 if src_channel
.sign
and dst_channel
.sign
:
188 return '%s(%s, %s, %s)' % (func
, value
, min, max)
190 # FIXME: Also clamp scaled values
195 def conversion_expr(src_channel
, dst_channel
, dst_native_type
, value
):
196 '''Generate the expression to convert a value between two types.'''
198 if src_channel
== dst_channel
:
201 if src_channel
.type == FLOAT
and dst_channel
.type == FLOAT
:
202 return '(%s)%s' % (dst_native_type
, value
)
204 if not src_channel
.norm
and not dst_channel
.norm
:
205 return '(%s)%s' % (dst_native_type
, value
)
207 value
= clamp_expr(src_channel
, dst_channel
, dst_native_type
, value
)
209 if dst_channel
.type == FLOAT
:
211 one
= get_one(src_channel
)
212 if src_channel
.size
<= 23:
213 scale
= '(1.0f/0x%x)' % one
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
)
220 if src_channel
.type == FLOAT
:
222 dst_one
= get_one(dst_channel
)
223 if dst_channel
.size
<= 23:
224 scale
= '0x%x' % dst_one
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
)
231 if src_channel
.type == dst_channel
.type:
232 src_one
= get_one(src_channel
)
233 dst_one
= get_one(dst_channel
)
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
)
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
)
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':
256 swizzle
= format
.swizzles
[i
]
258 inv_swizzle
[swizzle
] = i
259 elif format
.colorspace
== 'zs':
260 swizzle
= format
.swizzles
[0]
262 inv_swizzle
[swizzle
] = 0
269 def generate_format_read(format
, dst_channel
, dst_native_type
, dst_suffix
):
270 '''Generate the function to read pixels from a particular format'''
272 name
= format
.short_name()
274 src_native_type
= native_type(format
)
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
)
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) {'
288 if format
.colorspace
== 'rgb':
290 swizzle
= format
.swizzles
[i
]
292 names
[swizzle
] += 'rgba'[i
]
293 elif format
.colorspace
== 'zs':
294 swizzle
= format
.swizzles
[0]
302 if format
.layout
== PLAIN
:
303 if not format
.is_array():
304 print ' %s pixel = *src_pixel++;' % src_native_type
307 src_channel
= format
.channels
[i
]
308 width
= src_channel
.size
311 mask
= (1 << width
) - 1
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
)
321 src_channel
= format
.channels
[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
)
330 if format
.colorspace
== 'rgb':
331 swizzle
= format
.swizzles
[i
]
333 value
= names
[swizzle
]
334 elif swizzle
== SWIZZLE_0
:
336 elif swizzle
== SWIZZLE_1
:
337 value
= get_one(dst_channel
)
340 elif format
.colorspace
== 'zs':
344 value
= get_one(dst_channel
)
347 print ' *dst_pixel++ = %s; /* %s */' % (value
, 'rgba'[i
])
350 print ' src_row += src_stride;'
351 print ' dst_row += dst_stride/sizeof(*dst_row);'
357 def generate_format_write(format
, src_channel
, src_native_type
, src_suffix
):
358 '''Generate the function to write pixels to a particular format'''
360 name
= format
.short_name()
362 dst_native_type
= native_type(format
)
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
)
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) {'
375 inv_swizzle
= compute_inverse_swizzle(format
)
377 if format
.layout
== PLAIN
:
378 if not format
.is_array():
379 print ' %s pixel = 0;' % dst_native_type
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
)
388 value
= '(%s << %u)' % (value
, shift
)
389 print ' pixel |= %s;' % value
391 print ' *dst_pixel++ = pixel;'
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
401 print ' src_pixel += 4;'
404 print ' dst_row += dst_stride;'
405 print ' src_row += src_stride/sizeof(*src_row);'
411 def generate_read(formats
, dst_channel
, dst_native_type
, dst_suffix
):
412 '''Generate the dispatch function to read pixels from any format'''
414 for format
in formats
:
415 if is_format_supported(format
):
416 generate_format_read(format
, dst_channel
, dst_native_type
, dst_suffix
)
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
)
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
)
429 print ' debug_printf("unsupported format\\n");'
432 print ' func(dst, dst_stride, (const uint8_t *)src, src_stride, x, y, w, h);'
437 def generate_write(formats
, src_channel
, src_native_type
, src_suffix
):
438 '''Generate the dispatch function to write pixels to any format'''
440 for format
in formats
:
441 if is_format_supported(format
):
442 generate_format_write(format
, src_channel
, src_native_type
, src_suffix
)
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
)
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
)
456 print ' debug_printf("unsupported format\\n");'
459 print ' func(src, src_stride, (uint8_t *)dst, dst_stride, x, y, w, h);'
466 for arg
in sys
.argv
[1:]:
467 formats
.extend(parse(arg
))
469 print '/* This file is autogenerated by u_format_access.py from u_format.csv. Do not edit directly. */'
471 # This will print the copyright message on the top of this file
472 print __doc__
.strip()
474 print '#include "pipe/p_compiler.h"'
475 print '#include "u_format.h"'
476 print '#include "u_math.h"'
481 type = Channel(FLOAT
, False, 32)
482 native_type
= 'float'
485 generate_read(formats
, type, native_type
, suffix
)
486 generate_write(formats
, type, native_type
, suffix
)
488 type = Channel(UNSIGNED
, True, 8)
489 native_type
= 'uint8_t'
492 generate_read(formats
, type, native_type
, suffix
)
493 generate_write(formats
, type, native_type
, suffix
)
496 if __name__
== '__main__':