Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2009 VMware, Inc.
  4. # Copyright 2014 Intel Corporation
  5. # All Rights Reserved.
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a
  8. # copy of this software and associated documentation files (the
  9. # "Software"), to deal in the Software without restriction, including
  10. # without limitation the rights to use, copy, modify, merge, publish,
  11. # distribute, sub license, and/or sell copies of the Software, and to
  12. # permit persons to whom the Software is furnished to do so, subject to
  13. # the following conditions:
  14. #
  15. # The above copyright notice and this permission notice (including the
  16. # next paragraph) shall be included in all copies or substantial portions
  17. # of the Software.
  18. #
  19. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20. # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22. # IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  23. # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24. # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  
  27. import sys
  28.  
  29. VOID = 'x'
  30. UNSIGNED = 'u'
  31. SIGNED = 's'
  32. FLOAT = 'f'
  33.  
  34. ARRAY = 'array'
  35. PACKED = 'packed'
  36. OTHER = 'other'
  37.  
  38. RGB = 'rgb'
  39. SRGB = 'srgb'
  40. YUV = 'yuv'
  41. ZS = 'zs'
  42.  
  43. def is_power_of_two(x):
  44.    return not bool(x & (x - 1))
  45.  
  46. VERY_LARGE = 99999999999999999999999
  47.  
  48. class Channel:
  49.    """Describes a color channel."""
  50.  
  51.    def __init__(self, type, norm, size):
  52.       self.type = type
  53.       self.norm = norm
  54.       self.size = size
  55.       self.sign = type in (SIGNED, FLOAT)
  56.       self.name = None # Set when the channels are added to the format
  57.       self.shift = -1 # Set when the channels are added to the format
  58.       self.index = -1 # Set when the channels are added to the format
  59.  
  60.    def __str__(self):
  61.       s = str(self.type)
  62.       if self.norm:
  63.          s += 'n'
  64.       s += str(self.size)
  65.       return s
  66.  
  67.    def __eq__(self, other):
  68.       return self.type == other.type and self.norm == other.norm and self.size == other.size
  69.  
  70.    def max(self):
  71.       """Returns the maximum representable number."""
  72.       if self.type == FLOAT:
  73.          return VERY_LARGE
  74.       if self.norm:
  75.          return 1
  76.       if self.type == UNSIGNED:
  77.          return (1 << self.size) - 1
  78.       if self.type == SIGNED:
  79.          return (1 << (self.size - 1)) - 1
  80.       assert False
  81.  
  82.    def min(self):
  83.       """Returns the minimum representable number."""
  84.       if self.type == FLOAT:
  85.          return -VERY_LARGE
  86.       if self.type == UNSIGNED:
  87.          return 0
  88.       if self.norm:
  89.          return -1
  90.       if self.type == SIGNED:
  91.          return -(1 << (self.size - 1))
  92.       assert False
  93.  
  94.    def one(self):
  95.       """Returns the value that represents 1.0f."""
  96.       if self.type == UNSIGNED:
  97.          return (1 << self.size) - 1
  98.       if self.type == SIGNED:
  99.          return (1 << (self.size - 1)) - 1
  100.       else:
  101.          return 1
  102.  
  103.    def is_power_of_two(self):
  104.       """Returns true if the size of this channel is a power of two."""
  105.       return is_power_of_two(self.size)
  106.  
  107.    def datatype(self):
  108.       """Returns the datatype corresponding to a channel type and size"""
  109.       return _get_datatype(self.type, self.size)
  110.  
  111. class Swizzle:
  112.    """Describes a swizzle operation.
  113.  
  114.   A Swizzle is a mapping from one set of channels in one format to the
  115.   channels in another.  Each channel in the destination format is
  116.   associated with one of the following constants:
  117.  
  118.    * SWIZZLE_X: The first channel in the source format
  119.    * SWIZZLE_Y: The second channel in the source format
  120.    * SWIZZLE_Z: The third channel in the source format
  121.    * SWIZZLE_W: The fourth channel in the source format
  122.    * SWIZZLE_ZERO: The numeric constant 0
  123.    * SWIZZLE_ONE: THe numeric constant 1
  124.    * SWIZZLE_NONE: No data available for this channel
  125.  
  126.   Sometimes a Swizzle is represented by a 4-character string.  In this
  127.   case, the source channels are represented by the characters "x", "y",
  128.   "z", and "w"; the numeric constants are represented as "0" and "1"; and
  129.   no mapping is represented by "_".  For instance, the map from
  130.   luminance-alpha to rgba is given by "xxxy" because each of the three rgb
  131.   channels maps to the first luminance-alpha channel and the alpha channel
  132.   maps to second luminance-alpha channel.  The mapping from bgr to rgba is
  133.   given by "zyx1" because the first three colors are reversed and alpha is
  134.   always 1.
  135.   """
  136.  
  137.    __identity_str = 'xyzw01_'
  138.  
  139.    SWIZZLE_X = 0
  140.    SWIZZLE_Y = 1
  141.    SWIZZLE_Z = 2
  142.    SWIZZLE_W = 3
  143.    SWIZZLE_ZERO = 4
  144.    SWIZZLE_ONE = 5
  145.    SWIZZLE_NONE = 6
  146.  
  147.    def __init__(self, swizzle):
  148.       """Creates a Swizzle object from a string or array."""
  149.       if isinstance(swizzle, str):
  150.          swizzle = [Swizzle.__identity_str.index(c) for c in swizzle]
  151.       else:
  152.          swizzle = list(swizzle)
  153.          for s in swizzle:
  154.             assert isinstance(s, int) and 0 <= s and s <= Swizzle.SWIZZLE_NONE
  155.  
  156.       assert len(swizzle) <= 4
  157.  
  158.       self.__list = swizzle + [Swizzle.SWIZZLE_NONE] * (4 - len(swizzle))
  159.       assert len(self.__list) == 4
  160.  
  161.    def __iter__(self):
  162.       """Returns an iterator that iterates over this Swizzle.
  163.  
  164.      The values that the iterator produces are described by the SWIZZLE_*
  165.      constants.
  166.      """
  167.       return self.__list.__iter__()
  168.  
  169.    def __str__(self):
  170.       """Returns a string representation of this Swizzle."""
  171.       return ''.join(Swizzle.__identity_str[i] for i in self.__list)
  172.  
  173.    def __getitem__(self, idx):
  174.       """Returns the SWIZZLE_* constant for the given destination channel.
  175.  
  176.      Valid values for the destination channel include any of the SWIZZLE_*
  177.      constants or any of the following single-character strings: "x", "y",
  178.      "z", "w", "r", "g", "b", "a", "z" "s".
  179.      """
  180.  
  181.       if isinstance(idx, int):
  182.          assert idx >= Swizzle.SWIZZLE_X and idx <= Swizzle.SWIZZLE_NONE
  183.          if idx <= Swizzle.SWIZZLE_W:
  184.             return self.__list.__getitem__(idx)
  185.          else:
  186.             return idx
  187.       elif isinstance(idx, str):
  188.          if idx in 'xyzw':
  189.             idx = 'xyzw'.find(idx)
  190.          elif idx in 'rgba':
  191.             idx = 'rgba'.find(idx)
  192.          elif idx in 'zs':
  193.             idx = 'zs'.find(idx)
  194.          else:
  195.             assert False
  196.          return self.__list.__getitem__(idx)
  197.       else:
  198.          assert False
  199.  
  200.    def __mul__(self, other):
  201.       """Returns the composition of this Swizzle with another Swizzle.
  202.  
  203.      The resulting swizzle is such that, for any valid input to
  204.      __getitem__, (a * b)[i] = a[b[i]].
  205.      """
  206.       assert isinstance(other, Swizzle)
  207.       return Swizzle(self[x] for x in other)
  208.  
  209.    def inverse(self):
  210.       """Returns a pseudo-inverse of this swizzle.
  211.  
  212.      Since swizzling isn't necisaraly a bijection, a Swizzle can never
  213.      be truely inverted.  However, the swizzle returned is *almost* the
  214.      inverse of this swizzle in the sense that, for each i in range(3),
  215.      a[a.inverse()[i]] is either i or SWIZZLE_NONE.  If swizzle is just
  216.      a permutation with no channels added or removed, then this
  217.      function returns the actual inverse.
  218.  
  219.      This "pseudo-inverse" idea can be demonstrated by mapping from
  220.      luminance-alpha to rgba that is given by "xxxy".  To get from rgba
  221.      to lumanence-alpha, we use Swizzle("xxxy").inverse() or "xw__".
  222.      This maps the first component in the lumanence-alpha texture is
  223.      the red component of the rgba image and the second to the alpha
  224.      component, exactly as you would expect.
  225.      """
  226.       rev = [Swizzle.SWIZZLE_NONE] * 4
  227.       for i in xrange(4):
  228.          for j in xrange(4):
  229.             if self.__list[j] == i and rev[i] == Swizzle.SWIZZLE_NONE:
  230.                rev[i] = j
  231.       return Swizzle(rev)
  232.  
  233.  
  234. class Format:
  235.    """Describes a pixel format."""
  236.  
  237.    def __init__(self, name, layout, block_width, block_height, channels, swizzle, colorspace):
  238.       """Constructs a Format from some metadata and a list of channels.
  239.  
  240.      The channel objects must be unique to this Format and should not be
  241.      re-used to construct another Format.  This is because certain channel
  242.      information such as shift, offset, and the channel name are set when
  243.      the Format is created and are calculated based on the entire list of
  244.      channels.
  245.  
  246.      Arguments:
  247.      name -- Name of the format such as 'MESA_FORMAT_A8R8G8B8'
  248.      layout -- One of 'array', 'packed' 'other', or a compressed layout
  249.      block_width -- The block width if the format is compressed, 1 otherwise
  250.      block_height -- The block height if the format is compressed, 1 otherwise
  251.      channels -- A list of Channel objects
  252.      swizzle -- A Swizzle from this format to rgba
  253.      colorspace -- one of 'rgb', 'srgb', 'yuv', or 'zs'
  254.      """
  255.       self.name = name
  256.       self.layout = layout
  257.       self.block_width = block_width
  258.       self.block_height = block_height
  259.       self.channels = channels
  260.       assert isinstance(swizzle, Swizzle)
  261.       self.swizzle = swizzle
  262.       self.name = name
  263.       assert colorspace in (RGB, SRGB, YUV, ZS)
  264.       self.colorspace = colorspace
  265.  
  266.       # Name the channels
  267.       chan_names = ['']*4
  268.       if self.colorspace in (RGB, SRGB):
  269.          for (i, s) in enumerate(swizzle):
  270.             if s < 4:
  271.                chan_names[s] += 'rgba'[i]
  272.       elif colorspace == ZS:
  273.          for (i, s) in enumerate(swizzle):
  274.             if s < 4:
  275.                chan_names[s] += 'zs'[i]
  276.       else:
  277.          chan_names = ['x', 'y', 'z', 'w']
  278.  
  279.       for c, name in zip(self.channels, chan_names):
  280.          assert c.name is None
  281.          if name == 'rgb':
  282.             c.name = 'l'
  283.          elif name == 'rgba':
  284.             c.name = 'i'
  285.          elif name == '':
  286.             c.name = 'x'
  287.          else:
  288.             c.name = name
  289.  
  290.       # Set indices and offsets
  291.       if self.layout == PACKED:
  292.          shift = 0
  293.          for channel in self.channels:
  294.             assert channel.shift == -1
  295.             channel.shift = shift
  296.             shift += channel.size
  297.       for idx, channel in enumerate(self.channels):
  298.          assert channel.index == -1
  299.          channel.index = idx
  300.       else:
  301.          pass # Shift means nothing here
  302.  
  303.    def __str__(self):
  304.       return self.name
  305.  
  306.    def short_name(self):
  307.       """Returns a short name for a format.
  308.  
  309.      The short name should be suitable to be used as suffix in function
  310.      names.
  311.      """
  312.  
  313.       name = self.name
  314.       if name.startswith('MESA_FORMAT_'):
  315.          name = name[len('MESA_FORMAT_'):]
  316.       name = name.lower()
  317.       return name
  318.  
  319.    def block_size(self):
  320.       """Returns the block size (in bits) of the format."""
  321.       size = 0
  322.       for channel in self.channels:
  323.          size += channel.size
  324.       return size
  325.  
  326.    def num_channels(self):
  327.       """Returns the number of channels in the format."""
  328.       nr_channels = 0
  329.       for channel in self.channels:
  330.          if channel.size:
  331.             nr_channels += 1
  332.       return nr_channels
  333.  
  334.    def array_element(self):
  335.       """Returns a non-void channel if this format is an array, otherwise None.
  336.  
  337.      If the returned channel is not None, then this format can be
  338.      considered to be an array of num_channels() channels identical to the
  339.      returned channel.
  340.      """
  341.       if self.layout == ARRAY:
  342.          return self.channels[0]
  343.       elif self.layout == PACKED:
  344.          ref_channel = self.channels[0]
  345.          if ref_channel.type == VOID:
  346.             ref_channel = self.channels[1]
  347.          for channel in self.channels:
  348.             if channel.size == 0 or channel.type == VOID:
  349.                continue
  350.             if channel.size != ref_channel.size or channel.size % 8 != 0:
  351.                return None
  352.             if channel.type != ref_channel.type:
  353.                return None
  354.             if channel.norm != ref_channel.norm:
  355.                return None
  356.          return ref_channel
  357.       else:
  358.          return None
  359.  
  360.    def is_array(self):
  361.       """Returns true if this format can be considered an array format.
  362.  
  363.      This function will return true if self.layout == 'array'.  However,
  364.      some formats, such as MESA_FORMAT_A8G8B8R8, can be considered as
  365.      array formats even though they are technically packed.
  366.      """
  367.       return self.array_element() != None
  368.  
  369.    def is_compressed(self):
  370.       """Returns true if this is a compressed format."""
  371.       return self.block_width != 1 or self.block_height != 1
  372.  
  373.    def is_int(self):
  374.       """Returns true if this format is an integer format.
  375.  
  376.      See also: is_norm()
  377.      """
  378.       if self.layout not in (ARRAY, PACKED):
  379.          return False
  380.       for channel in self.channels:
  381.          if channel.type not in (VOID, UNSIGNED, SIGNED):
  382.             return False
  383.       return True
  384.  
  385.    def is_float(self):
  386.       """Returns true if this format is an floating-point format."""
  387.       if self.layout not in (ARRAY, PACKED):
  388.          return False
  389.       for channel in self.channels:
  390.          if channel.type not in (VOID, FLOAT):
  391.             return False
  392.       return True
  393.  
  394.    def channel_type(self):
  395.       """Returns the type of the channels in this format."""
  396.       _type = VOID
  397.       for c in self.channels:
  398.          if c.type == VOID:
  399.             continue
  400.          if _type == VOID:
  401.             _type = c.type
  402.          assert c.type == _type
  403.       return _type
  404.  
  405.    def channel_size(self):
  406.       """Returns the size (in bits) of the channels in this format.
  407.  
  408.      This function should only be called if all of the channels have the
  409.      same size.  This is always the case if is_array() returns true.
  410.      """
  411.       size = None
  412.       for c in self.channels:
  413.          if c.type == VOID:
  414.             continue
  415.          if size is None:
  416.             size = c.size
  417.          assert c.size == size
  418.       return size
  419.  
  420.    def max_channel_size(self):
  421.       """Returns the size of the largest channel."""
  422.       size = 0
  423.       for c in self.channels:
  424.          if c.type == VOID:
  425.             continue
  426.          size = max(size, c.size)
  427.       return size
  428.  
  429.    def is_normalized(self):
  430.       """Returns true if this format is normalized.
  431.  
  432.      While only integer formats can be normalized, not all integer formats
  433.      are normalized.  Normalized integer formats are those where the
  434.      integer value is re-interpreted as a fixed point value in the range
  435.      [0, 1].
  436.      """
  437.       norm = None
  438.       for c in self.channels:
  439.          if c.type == VOID:
  440.             continue
  441.          if norm is None:
  442.             norm = c.norm
  443.          assert c.norm == norm
  444.       return norm
  445.  
  446.    def has_channel(self, name):
  447.       """Returns true if this format has the given channel."""
  448.       if self.is_compressed():
  449.          # Compressed formats are a bit tricky because the list of channels
  450.          # contains a single channel of type void.  Since we don't have any
  451.          # channel information there, we pull it from the swizzle.
  452.          if str(self.swizzle) == 'xxxx':
  453.             return name == 'i'
  454.          elif str(self.swizzle)[0:3] in ('xxx', 'yyy'):
  455.             if name == 'l':
  456.                return True
  457.             elif name == 'a':
  458.                return self.swizzle['a'] <= Swizzle.SWIZZLE_W
  459.             else:
  460.                return False
  461.          elif name in 'rgba':
  462.             return self.swizzle[name] <= Swizzle.SWIZZLE_W
  463.          else:
  464.             return False
  465.       else:
  466.          for channel in self.channels:
  467.             if channel.name == name:
  468.                return True
  469.          return False
  470.  
  471.    def get_channel(self, name):
  472.       """Returns the channel with the given name if it exists."""
  473.       for channel in self.channels:
  474.          if channel.name == name:
  475.             return channel
  476.       return None
  477.  
  478.    def datatype(self):
  479.       """Returns the datatype corresponding to a format's channel type and size"""
  480.       if self.layout == PACKED:
  481.          if self.block_size() == 8:
  482.             return 'uint8_t'
  483.          if self.block_size() == 16:
  484.             return 'uint16_t'
  485.          if self.block_size() == 32:
  486.             return 'uint32_t'
  487.          else:
  488.             assert False
  489.       else:
  490.          return _get_datatype(self.channel_type(), self.channel_size())
  491.  
  492. def _get_datatype(type, size):
  493.    if type == FLOAT:
  494.       if size == 32:
  495.          return 'float'
  496.       elif size == 16:
  497.          return 'uint16_t'
  498.       else:
  499.          assert False
  500.    elif type == UNSIGNED:
  501.       if size <= 8:
  502.          return 'uint8_t'
  503.       elif size <= 16:
  504.          return 'uint16_t'
  505.       elif size <= 32:
  506.          return 'uint32_t'
  507.       else:
  508.          assert False
  509.    elif type == SIGNED:
  510.       if size <= 8:
  511.          return 'int8_t'
  512.       elif size <= 16:
  513.          return 'int16_t'
  514.       elif size <= 32:
  515.          return 'int32_t'
  516.       else:
  517.          assert False
  518.    else:
  519.       assert False
  520.  
  521. def _parse_channels(fields, layout, colorspace, swizzle):
  522.    channels = []
  523.    for field in fields:
  524.       if not field:
  525.          continue
  526.  
  527.       type = field[0] if field[0] else 'x'
  528.  
  529.       if field[1] == 'n':
  530.          norm = True
  531.          size = int(field[2:])
  532.       else:
  533.          norm = False
  534.          size = int(field[1:])
  535.  
  536.       channel = Channel(type, norm, size)
  537.       channels.append(channel)
  538.  
  539.    return channels
  540.  
  541. def parse(filename):
  542.    """Parse a format descrition in CSV format.
  543.  
  544.   This function parses the given CSV file and returns an iterable of
  545.   channels."""
  546.  
  547.    with open(filename) as stream:
  548.       for line in stream:
  549.          try:
  550.             comment = line.index('#')
  551.          except ValueError:
  552.             pass
  553.          else:
  554.             line = line[:comment]
  555.          line = line.strip()
  556.          if not line:
  557.             continue
  558.  
  559.          fields = [field.strip() for field in line.split(',')]
  560.  
  561.          name = fields[0]
  562.          layout = fields[1]
  563.          block_width = int(fields[2])
  564.          block_height = int(fields[3])
  565.          colorspace = fields[9]
  566.  
  567.          try:
  568.             swizzle = Swizzle(fields[8])
  569.          except:
  570.             sys.exit("error parsing swizzle for format " + name)
  571.          channels = _parse_channels(fields[4:8], layout, colorspace, swizzle)
  572.  
  573.          yield Format(name, layout, block_width, block_height, channels, swizzle, colorspace)
  574.