[Mesa-dev] [PATCH 6/8] util: Fix pack and unpack for big-endian

Richard Sandiford rsandifo at linux.vnet.ibm.com
Wed Jun 12 03:15:47 PDT 2013


The old code tried to emulate little-endian format layout on big-endian
targets by byte-swapping each pixel value.  This was OK for packed byte
formats, but isn't what we want for multibyte channels.  E.g. the floats
in R32G32B32A32_FLOAT should all have native endianness, and the red
component should always come first.  Formats with Z24 channels should
contain a native-endian 24-bit depth value.

The idea is to have a separate list of channels and swizzles for little
and big endian.  At the moment the channel order and swizzles are the
same for both endiannesses, only the shifts differ.  This will change
as more formats are "fixed" for big endian.

No piglit regressions on x86_64.  This patch on its own doesn't
help the results much on big-endian, but it's needed by later
patches that do.

Signed-off-by: Richard Sandiford <rsandifo at linux.vnet.ibm.com>
---
 src/gallium/auxiliary/util/u_format_pack.py  | 34 +++++-----------
 src/gallium/auxiliary/util/u_format_parse.py | 60 +++++++++++++++++-----------
 2 files changed, 46 insertions(+), 48 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_format_pack.py b/src/gallium/auxiliary/util/u_format_pack.py
index b4db0d1..1408085 100644
--- a/src/gallium/auxiliary/util/u_format_pack.py
+++ b/src/gallium/auxiliary/util/u_format_pack.py
@@ -51,7 +51,14 @@ def inv_swizzles(swizzles):
     return inv_swizzle
 
 def print_channels(format, func):
-    func(format.channels, format.swizzles)
+    if format.nr_channels() <= 1:
+        func(format.le_channels, format.le_swizzles)
+    else:
+        print '#ifdef PIPE_ARCH_BIG_ENDIAN'
+        func(format.be_channels, format.be_swizzles)
+        print '#else'
+        func(format.le_channels, format.le_swizzles)
+        print '#endif'
 
 def generate_format_type(format):
     '''Generate a structure that describes the format.'''
@@ -105,7 +112,7 @@ def generate_format_type(format):
         print '   uint%u_t value;' % (format.block_size(),)
 
     use_bitfields = False
-    for channel in format.channels:
+    for channel in format.le_channels:
         if channel.size % 8 or not is_pot(channel.size):
             use_bitfields = True
 
@@ -119,15 +126,6 @@ def generate_format_type(format):
     print
 
 
-def bswap_format(format):
-    '''Generate a structure that describes the format.'''
-
-    if format.is_bitmask() and not format.is_array() and format.block_size() > 8:
-        print '#ifdef PIPE_ARCH_BIG_ENDIAN'
-        print '   pixel.value = util_bswap%u(pixel.value);' % format.block_size()
-        print '#endif'
-
-
 def is_format_supported(format):
     '''Determines whether we actually have the plumbing necessary to generate the 
     to read/write to/from this format.'''
@@ -138,7 +136,7 @@ def is_format_supported(format):
         return False
 
     for i in range(4):
-        channel = format.channels[i]
+        channel = format.le_channels[i]
         if channel.type not in (VOID, UNSIGNED, SIGNED, FLOAT, FIXED):
             return False
         if channel.type == FLOAT and channel.size not in (16, 32, 64):
@@ -422,11 +420,6 @@ def generate_unpack_kernel(format, dst_channel, dst_native_type):
             elif src_channel.type == SIGNED:
                 print '         int%u_t %s;' % (depth, src_channel.name)
 
-        if depth > 8:
-            print '#ifdef PIPE_ARCH_BIG_ENDIAN'
-            print '         value = util_bswap%u(value);' % depth
-            print '#endif'
-
         # Compute the intermediate unshifted values 
         for i in range(4):
             src_channel = channels[i]
@@ -481,7 +474,6 @@ def generate_unpack_kernel(format, dst_channel, dst_native_type):
     def unpack_from_union(channels, swizzles):
         print '         union util_format_%s pixel;' % format.short_name()
         print '         memcpy(&pixel, src, sizeof pixel);'
-        bswap_format(format)
     
         for i in range(4):
             swizzle = swizzles[i]
@@ -553,11 +545,6 @@ def generate_pack_kernel(format, src_channel, src_native_type):
                 if value is not None:
                     print '         value |= %s;' % (value)
                 
-        if depth > 8:
-            print '#ifdef PIPE_ARCH_BIG_ENDIAN'
-            print '         value = util_bswap%u(value);' % depth
-            print '#endif'
-        
         print '         *(uint%u_t *)dst = value;' % depth 
 
     def pack_into_union(channels, swizzles):
@@ -581,7 +568,6 @@ def generate_pack_kernel(format, src_channel, src_native_type):
                                     dst_colorspace = dst_colorspace)
             print '         pixel.chan.%s = %s;' % (dst_channel.name, value)
     
-        bswap_format(format)
         print '         memcpy(dst, &pixel, sizeof pixel);'
     
     if format.is_bitmask():
diff --git a/src/gallium/auxiliary/util/u_format_parse.py b/src/gallium/auxiliary/util/u_format_parse.py
index d60a0a2..15cc6d4 100755
--- a/src/gallium/auxiliary/util/u_format_parse.py
+++ b/src/gallium/auxiliary/util/u_format_parse.py
@@ -104,13 +104,15 @@ class Channel:
 class Format:
     '''Describe a pixel format.'''
 
-    def __init__(self, name, layout, block_width, block_height, channels, swizzles, colorspace):
+    def __init__(self, name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace):
         self.name = name
         self.layout = layout
         self.block_width = block_width
         self.block_height = block_height
-        self.channels = channels
-        self.swizzles = swizzles
+        self.le_channels = le_channels
+        self.le_swizzles = le_swizzles
+        self.be_channels = be_channels
+        self.be_swizzles = be_swizzles
         self.name = name
         self.colorspace = colorspace
 
@@ -129,13 +131,13 @@ class Format:
 
     def block_size(self):
         size = 0
-        for channel in self.channels:
+        for channel in self.le_channels:
             size += channel.size
         return size
 
     def nr_channels(self):
         nr_channels = 0
-        for channel in self.channels:
+        for channel in self.le_channels:
             if channel.size:
                 nr_channels += 1
         return nr_channels
@@ -143,10 +145,10 @@ class Format:
     def array_element(self):
         if self.layout != PLAIN:
             return None
-        ref_channel = self.channels[0]
+        ref_channel = self.le_channels[0]
         if ref_channel.type == VOID:
-           ref_channel = self.channels[1]
-        for channel in self.channels:
+           ref_channel = self.le_channels[1]
+        for channel in self.le_channels:
             if channel.size and (channel.size != ref_channel.size or channel.size % 8):
                 return None
             if channel.type != VOID:
@@ -164,10 +166,10 @@ class Format:
     def is_mixed(self):
         if self.layout != PLAIN:
             return False
-        ref_channel = self.channels[0]
+        ref_channel = self.le_channels[0]
         if ref_channel.type == VOID:
-           ref_channel = self.channels[1]
-        for channel in self.channels[1:]:
+           ref_channel = self.le_channels[1]
+        for channel in self.le_channels[1:]:
             if channel.type != VOID:
                 if channel.type != ref_channel.type:
                     return True
@@ -183,7 +185,7 @@ class Format:
     def is_int(self):
         if self.layout != PLAIN:
             return False
-        for channel in self.channels:
+        for channel in self.le_channels:
             if channel.type not in (VOID, UNSIGNED, SIGNED):
                 return False
         return True
@@ -191,7 +193,7 @@ class Format:
     def is_float(self):
         if self.layout != PLAIN:
             return False
-        for channel in self.channels:
+        for channel in self.le_channels:
             if channel.type not in (VOID, FLOAT):
                 return False
         return True
@@ -201,7 +203,7 @@ class Format:
             return False
         if self.block_size() not in (8, 16, 32):
             return False
-        for channel in self.channels:
+        for channel in self.le_channels:
             if channel.type not in (VOID, UNSIGNED, SIGNED):
                 return False
         return True
@@ -210,7 +212,7 @@ class Format:
         if self.layout != PLAIN or self.colorspace == ZS:
             return False
         pures = [channel.pure
-                 for channel in self.channels
+                 for channel in self.le_channels
                  if channel.type != VOID]
         for x in pures:
            assert x == pures[0]
@@ -218,7 +220,7 @@ class Format:
 
     def channel_type(self):
         types = [channel.type
-                 for channel in self.channels
+                 for channel in self.le_channels
                  if channel.type != VOID]
         for x in types:
            assert x == types[0]
@@ -231,7 +233,7 @@ class Format:
         return self.is_pure_color() and self.channel_type() == UNSIGNED
 
     def has_channel(self, id):
-        return self.swizzles[id] != SWIZZLE_NONE
+        return self.le_swizzles[id] != SWIZZLE_NONE
 
     def has_depth(self):
         return self.colorspace == ZS and self.has_channel(0)
@@ -334,15 +336,25 @@ def parse(filename):
         block_width, block_height = map(int, fields[2:4])
         colorspace = fields[9]
 
-        swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
-        channels = _parse_channels(fields[4:8], layout, colorspace, swizzles)
+        le_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
+        le_channels = _parse_channels(fields[4:8], layout, colorspace, le_swizzles)
 
-        shift = 0
-        for channel in channels:
-            channel.shift = shift
-            shift += channel.size
+        be_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
+        be_channels = _parse_channels(fields[4:8], layout, colorspace, be_swizzles)
 
-        format = Format(name, layout, block_width, block_height, channels, swizzles, colorspace)
+        le_shift = 0
+        for channel in le_channels:
+            channel.shift = le_shift
+            le_shift += channel.size
+
+        be_shift = 0
+        for channel in be_channels[3::-1]:
+            channel.shift = be_shift
+            be_shift += channel.size
+
+        assert le_shift == be_shift
+
+        format = Format(name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace)
         formats.append(format)
     return formats
 
-- 
1.7.11.7



More information about the mesa-dev mailing list