st/mesa: fix incorrect RowStride computation
[mesa.git] / src / gallium / auxiliary / util / u_format_access.py
index 0b05ddb9312c700911b3073177fb6b1412bbbdd8..00424779d285ac59b1883f6a6e58f58ca77929e5 100644 (file)
 '''
 
 
+import math
 import sys
 
-from u_format_parse import *
-
-
-def short_name(format):
-    '''Make up a short norm for a format, suitable to be used as suffix in
-    function names.'''
-
-    name = format.name
-    if name.startswith('PIPE_FORMAT_'):
-        name = name[len('PIPE_FORMAT_'):]
-    name = name.lower()
-    return name
+from u_format_pack import *
 
 
 def is_format_supported(format):
@@ -63,16 +53,16 @@ def is_format_supported(format):
     if format.colorspace not in ('rgb', 'zs'):
         return False
 
-    if format.layout not in (ARITH, ARRAY):
+    if format.layout != PLAIN:
         return False
 
     for i in range(4):
-        type = format.in_types[i]
-        if type.kind not in (VOID, UNSIGNED, FLOAT):
+        channel = format.channels[i]
+        if channel.type not in (VOID, UNSIGNED, FLOAT):
             return False
 
     # We can only read a color from a depth/stencil format if the depth channel is present
-    if format.colorspace == 'zs' and format.out_swizzle[0] == SWIZZLE_NONE:
+    if format.colorspace == 'zs' and format.swizzles[0] == SWIZZLE_NONE:
         return False
 
     return True
@@ -81,187 +71,48 @@ def is_format_supported(format):
 def native_type(format):
     '''Get the native appropriate for a format.'''
 
-    if format.layout == ARITH:
-        # For arithmetic pixel formats return the integer type that matches the whole pixel
-        return 'uint%u_t' % format.block_size()
-    elif format.layout == ARRAY:
-        # For array pixel formats return the integer type that matches the color channel
-        type = format.in_types[0]
-        if type.kind == UNSIGNED:
-            return 'uint%u_t' % type.size
-        elif type.kind == SIGNED:
-            return 'int%u_t' % type.size
-        elif type.kind == FLOAT:
-            if type.size == 32:
-                return 'float'
-            elif type.size == 64:
-                return 'double'
+    if format.layout == PLAIN:
+        if not format.is_array():
+            # For arithmetic pixel formats return the integer type that matches the whole pixel
+            return 'uint%u_t' % format.block_size()
+        else:
+            # For array pixel formats return the integer type that matches the color channel
+            channel = format.channels[0]
+            if channel.type == UNSIGNED:
+                return 'uint%u_t' % channel.size
+            elif channel.type == SIGNED:
+                return 'int%u_t' % channel.size
+            elif channel.type == FLOAT:
+                if channel.size == 32:
+                    return 'float'
+                elif channel.size == 64:
+                    return 'double'
+                else:
+                    assert False
             else:
                 assert False
-        else:
-            assert False
-    else:
-        assert False
-
-
-def intermediate_native_type(bits, sign):
-    '''Find a native type adequate to hold intermediate results of the request bit size.'''
-
-    bytes = 4 # don't use anything smaller than 32bits
-    while bytes * 8 < bits:
-        bytes *= 2
-    bits = bytes*8
-
-    if sign:
-        return 'int%u_t' % bits
-    else:
-        return 'uint%u_t' % bits
-
-
-def get_one_shift(type):
-    '''Get the number of the bit that matches unity for this type.'''
-    if type.kind == 'FLOAT':
-        assert False
-    if not type.norm:
-        return 0
-    if type.kind == UNSIGNED:
-        return type.size
-    if type.kind == SIGNED:
-        return type.size - 1
-    if type.kind == FIXED:
-        return type.size / 2
-    assert False
-
-
-def get_one(type):
-    '''Get the value of unity for this type.'''
-    if type.kind == 'FLOAT' or not type.norm:
-        return 1
-    else:
-        return (1 << get_one_shift(type)) - 1
-
-
-def generate_clamp():
-    '''Code generate the clamping functions for each type.
-
-    We don't use a macro so that arguments with side effects, 
-    like *src_pixel++ are correctly handled.
-    '''
-
-    for suffix, native_type in [
-        ('', 'double'),
-        ('f', 'float'),
-        ('ui', 'unsigned int'),
-        ('si', 'int'),
-    ]:
-        print 'static INLINE %s' % native_type
-        print 'clamp%s(%s value, %s lbound, %s ubound)' % (suffix, native_type, native_type, native_type)
-        print '{'
-        print '   if(value < lbound)'
-        print '      return lbound;'
-        print '   if(value > ubound)'
-        print '      return ubound;'
-        print '   return value;'
-        print '}'
-        print
-
-
-def clamp_expr(src_type, dst_type, dst_native_type, value):
-    '''Generate the expression to clamp the value in the source type to the
-    destination type range.'''
-
-    if src_type == dst_type:
-        return value
-
-    # Pick the approriate clamp function
-    if src_type.kind == FLOAT:
-        if src_type.size == 32:
-            func = 'clampf'
-        elif src_type.size == 64:
-            func = 'clamp'
-        else:
-            assert False
-    elif src_type.kind == UNSIGNED:
-        func = 'clampui'
-    elif src_type.kind == SIGNED:
-        func = 'clampsi'
     else:
         assert False
 
-    # Clamp floats to [-1, 1] or [0, 1] range
-    if src_type.kind == FLOAT and dst_type.norm:
-        max = 1
-        if src_type.sign and dst_type.sign:
-            min = -1
-        else:
-            min = 0
-        return '%s(%s, %s, %s)' % (func, value, min, max)
-                
-    # FIXME: Also clamp scaled values
-
-    return value
-
-
-def conversion_expr(src_type, dst_type, dst_native_type, value):
-    '''Generate the expression to convert a value between two types.'''
-
-    if src_type == dst_type:
-        return value
 
-    if src_type.kind == FLOAT and dst_type.kind == FLOAT:
-        return '(%s)%s' % (dst_native_type, value)
-    
-    if not src_type.norm and not dst_type.norm:
-        return '(%s)%s' % (dst_native_type, value)
-
-    value = clamp_expr(src_type, dst_type, dst_native_type, value)
-
-    if dst_type.kind == FLOAT:
-        if src_type.norm:
-            one = get_one(src_type)
-            if src_type.size <= 23:
-                scale = '(1.0f/0x%x)' % one
-            else:
-                # bigger than single precision mantissa, use double
-                scale = '(1.0/0x%x)' % one
-            value = '(%s * %s)' % (value, scale)
-        return '(%s)%s' % (dst_native_type, value)
-
-    if src_type.kind == FLOAT:
-        if dst_type.norm:
-            dst_one = get_one(dst_type)
-            if dst_type.size <= 23:
-                scale = '0x%x' % dst_one
-            else:
-                # bigger than single precision mantissa, use double
-                scale = '(double)0x%x' % dst_one
-            value = '(%s * %s)' % (value, scale)
-        return '(%s)%s' % (dst_native_type, value)
-
-    if src_type.kind == dst_type.kind:
-        src_one = get_one(src_type)
-        dst_one = get_one(dst_type)
-
-        if src_one > dst_one and src_type.norm and dst_type.norm:
-            # We can just bitshift
-            src_shift = get_one_shift(src_type)
-            dst_shift = get_one_shift(dst_type)
-            value = '(%s >> %s)' % (value, src_shift - dst_shift)
-        else:
-            # We need to rescale using an intermediate type big enough to hold the multiplication of both
-            tmp_native_type = intermediate_native_type(src_type.size + dst_type.size, src_type.sign and dst_type.sign)
-            value = '(%s)%s' % (tmp_native_type, value)
-            value = '%s * 0x%x / 0x%x' % (value, dst_one, src_one)
-        value = '(%s)%s' % (dst_native_type, value)
-        return value
-
-    assert False
+def generate_srgb_tables():
+    print 'static ubyte srgb_to_linear[256] = {'
+    for i in range(256):
+        print '   %s,' % (int(math.pow((i / 255.0 + 0.055) / 1.055, 2.4) * 255))
+    print '};'
+    print
+    print 'static ubyte linear_to_srgb[256] = {'
+    print '   0,'
+    for i in range(1, 256):
+        print '   %s,' % (int((1.055 * math.pow(i / 255.0, 0.41666) - 0.055) * 255))
+    print '};'
+    print
 
 
-def generate_format_read(format, dst_type, dst_native_type, dst_suffix):
+def generate_format_read(format, dst_channel, dst_native_type, dst_suffix):
     '''Generate the function to read pixels from a particular format'''
 
-    name = short_name(format)
+    name = format.short_name()
 
     src_native_type = native_type(format)
 
@@ -279,11 +130,11 @@ def generate_format_read(format, dst_type, dst_native_type, dst_suffix):
     names = ['']*4
     if format.colorspace == 'rgb':
         for i in range(4):
-            swizzle = format.out_swizzle[i]
+            swizzle = format.swizzles[i]
             if swizzle < 4:
                 names[swizzle] += 'rgba'[i]
     elif format.colorspace == 'zs':
-        swizzle = format.out_swizzle[0]
+        swizzle = format.swizzles[0]
         if swizzle < 4:
             names[swizzle] = 'z'
         else:
@@ -291,64 +142,66 @@ def generate_format_read(format, dst_type, dst_native_type, dst_suffix):
     else:
         assert False
 
-    if format.layout == ARITH:
-        print '         %s pixel = *src_pixel++;' % src_native_type
-        shift = 0;
-        for i in range(4):
-            src_type = format.in_types[i]
-            width = src_type.size
-            if names[i]:
-                value = 'pixel'
-                mask = (1 << width) - 1
-                if shift:
-                    value = '(%s >> %u)' % (value, shift)
-                if shift + width < format.block_size():
-                    value = '(%s & 0x%x)' % (value, mask)
-                value = conversion_expr(src_type, dst_type, dst_native_type, value)
-                print '         %s %s = %s;' % (dst_native_type, names[i], value)
-            shift += width
-    elif format.layout == ARRAY:
-        for i in range(4):
-            src_type = format.in_types[i]
-            if names[i]:
-                value = '(*src_pixel++)'
-                value = conversion_expr(src_type, dst_type, dst_native_type, value)
-                print '         %s %s = %s;' % (dst_native_type, names[i], value)
+    if format.layout == PLAIN:
+        if not format.is_array():
+            print '         %s pixel = *src_pixel++;' % src_native_type
+            shift = 0;
+            for i in range(4):
+                src_channel = format.channels[i]
+                width = src_channel.size
+                if names[i]:
+                    value = 'pixel'
+                    mask = (1 << width) - 1
+                    if shift:
+                        value = '(%s >> %u)' % (value, shift)
+                    if shift + width < format.block_size():
+                        value = '(%s & 0x%x)' % (value, mask)
+                    value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
+                    print '         %s %s = %s;' % (dst_native_type, names[i], value)
+                shift += width
+        else:
+            for i in range(4):
+                src_channel = format.channels[i]
+                if names[i]:
+                    value = 'src_pixel[%u]' % i
+                    value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
+                    print '         %s %s = %s;' % (dst_native_type, names[i], value)
+            print '         src_pixel += %u;' % (format.nr_channels())
     else:
         assert False
 
     for i in range(4):
         if format.colorspace == 'rgb':
-            swizzle = format.out_swizzle[i]
+            swizzle = format.swizzles[i]
             if swizzle < 4:
                 value = names[swizzle]
             elif swizzle == SWIZZLE_0:
                 value = '0'
             elif swizzle == SWIZZLE_1:
-                value = get_one(dst_type)
+                value = get_one(dst_channel)
             else:
                 assert False
         elif format.colorspace == 'zs':
             if i < 3:
                 value = 'z'
             else:
-                value = get_one(dst_type)
+                value = get_one(dst_channel)
         else:
             assert False
         print '         *dst_pixel++ = %s; /* %s */' % (value, 'rgba'[i])
 
     print '      }'
     print '      src_row += src_stride;'
-    print '      dst_row += dst_stride/sizeof(%s);' % dst_native_type
+    print '      dst_row += dst_stride/sizeof(*dst_row);'
     print '   }'
     print '}'
     print
     
 
-def generate_format_write(format, src_type, src_native_type, src_suffix):
+def generate_format_write(format, src_channel, src_native_type, src_suffix):
     '''Generate the function to write pixels to a particular format'''
 
-    name = short_name(format)
+    name = format.short_name()
 
     dst_native_type = native_type(format)
 
@@ -363,58 +216,48 @@ def generate_format_write(format, src_type, src_native_type, src_suffix):
     print '      const %s *src_pixel = src_row;' %src_native_type
     print '      for (x = 0; x < w; ++x) {'
 
-    inv_swizzle = [None]*4
-    if format.colorspace == 'rgb':
-        for i in range(4):
-            swizzle = format.out_swizzle[i]
-            if swizzle < 4:
-                inv_swizzle[swizzle] = i
-    elif format.colorspace == 'zs':
-        swizzle = format.out_swizzle[0]
-        if swizzle < 4:
-            inv_swizzle[swizzle] = 0
-    else:
-        assert False
-
-    if format.layout == ARITH:
-        print '         %s pixel = 0;' % dst_native_type
-        shift = 0;
-        for i in range(4):
-            dst_type = format.in_types[i]
-            width = dst_type.size
-            if inv_swizzle[i] is not None:
-                value = 'src_pixel[%u]' % inv_swizzle[i]
-                value = conversion_expr(src_type, dst_type, dst_native_type, value)
-                if shift:
-                    value = '(%s << %u)' % (value, shift)
-                print '         pixel |= %s;' % value
-            shift += width
-        print '         *dst_pixel++ = pixel;'
-    elif format.layout == ARRAY:
-        for i in range(4):
-            dst_type = format.in_types[i]
-            if inv_swizzle[i] is not None:
-                value = 'src_pixel[%u]' % inv_swizzle[i]
-                value = conversion_expr(src_type, dst_type, dst_native_type, value)
-                print '         *dst_pixel++ = %s;' % value
+    inv_swizzle = format.inv_swizzles()
+
+    if format.layout == PLAIN:
+        if not format.is_array():
+            print '         %s pixel = 0;' % dst_native_type
+            shift = 0;
+            for i in range(4):
+                dst_channel = format.channels[i]
+                width = dst_channel.size
+                if inv_swizzle[i] is not None:
+                    value = 'src_pixel[%u]' % inv_swizzle[i]
+                    value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
+                    if shift:
+                        value = '(%s << %u)' % (value, shift)
+                    print '         pixel |= %s;' % value
+                shift += width
+            print '         *dst_pixel++ = pixel;'
+        else:
+            for i in range(4):
+                dst_channel = format.channels[i]
+                if inv_swizzle[i] is not None:
+                    value = 'src_pixel[%u]' % inv_swizzle[i]
+                    value = conversion_expr(src_channel, dst_channel, dst_native_type, value)
+                    print '         *dst_pixel++ = %s;' % value
     else:
         assert False
     print '         src_pixel += 4;'
 
     print '      }'
     print '      dst_row += dst_stride;'
-    print '      src_row += src_stride/sizeof(%s);' % src_native_type
+    print '      src_row += src_stride/sizeof(*src_row);'
     print '   }'
     print '}'
     print
     
 
-def generate_read(formats, dst_type, dst_native_type, dst_suffix):
+def generate_read(formats, dst_channel, dst_native_type, dst_suffix):
     '''Generate the dispatch function to read pixels from any format'''
 
     for format in formats:
         if is_format_supported(format):
-            generate_format_read(format, dst_type, dst_native_type, dst_suffix)
+            generate_format_read(format, dst_channel, dst_native_type, dst_suffix)
 
     print 'void'
     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)
@@ -424,7 +267,7 @@ def generate_read(formats, dst_type, dst_native_type, dst_suffix):
     for format in formats:
         if is_format_supported(format):
             print '   case %s:' % format.name
-            print '      func = &util_format_%s_read_%s;' % (short_name(format), dst_suffix)
+            print '      func = &util_format_%s_read_%s;' % (format.short_name(), dst_suffix)
             print '      break;'
     print '   default:'
     print '      debug_printf("unsupported format\\n");'
@@ -435,12 +278,12 @@ def generate_read(formats, dst_type, dst_native_type, dst_suffix):
     print
 
 
-def generate_write(formats, src_type, src_native_type, src_suffix):
+def generate_write(formats, src_channel, src_native_type, src_suffix):
     '''Generate the dispatch function to write pixels to any format'''
 
     for format in formats:
         if is_format_supported(format):
-            generate_format_write(format, src_type, src_native_type, src_suffix)
+            generate_format_write(format, src_channel, src_native_type, src_suffix)
 
     print 'void'
     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)
@@ -451,7 +294,7 @@ def generate_write(formats, src_type, src_native_type, src_suffix):
     for format in formats:
         if is_format_supported(format):
             print '   case %s:' % format.name
-            print '      func = &util_format_%s_write_%s;' % (short_name(format), src_suffix)
+            print '      func = &util_format_%s_write_%s;' % (format.short_name(), src_suffix)
             print '      break;'
     print '   default:'
     print '      debug_printf("unsupported format\\n");'
@@ -473,20 +316,20 @@ def main():
     print __doc__.strip()
     print
     print '#include "pipe/p_compiler.h"'
-    print '#include "u_format.h"'
     print '#include "u_math.h"'
+    print '#include "u_format_pack.h"'
     print
 
-    generate_clamp()
+    generate_srgb_tables()
 
-    type = Type(FLOAT, False, 32)
+    type = Channel(FLOAT, False, 32)
     native_type = 'float'
     suffix = '4f'
 
     generate_read(formats, type, native_type, suffix)
     generate_write(formats, type, native_type, suffix)
 
-    type = Type(UNSIGNED, True, 8)
+    type = Channel(UNSIGNED, True, 8)
     native_type = 'uint8_t'
     suffix = '4ub'