1848b8605Smrg# 2848b8605Smrg# Copyright 2009 VMware, Inc. 3848b8605Smrg# Copyright 2014 Intel Corporation 4848b8605Smrg# All Rights Reserved. 5848b8605Smrg# 6848b8605Smrg# Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg# copy of this software and associated documentation files (the 8848b8605Smrg# "Software"), to deal in the Software without restriction, including 9848b8605Smrg# without limitation the rights to use, copy, modify, merge, publish, 10848b8605Smrg# distribute, sub license, and/or sell copies of the Software, and to 11848b8605Smrg# permit persons to whom the Software is furnished to do so, subject to 12848b8605Smrg# the following conditions: 13848b8605Smrg# 14848b8605Smrg# The above copyright notice and this permission notice (including the 15848b8605Smrg# next paragraph) shall be included in all copies or substantial portions 16848b8605Smrg# of the Software. 17848b8605Smrg# 18848b8605Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19848b8605Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20848b8605Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21848b8605Smrg# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22848b8605Smrg# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23848b8605Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24848b8605Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25848b8605Smrg 26b8e80941Smrgimport sys 27b8e80941Smrg 28848b8605SmrgVOID = 'x' 29848b8605SmrgUNSIGNED = 'u' 30848b8605SmrgSIGNED = 's' 31848b8605SmrgFLOAT = 'f' 32848b8605Smrg 33848b8605SmrgARRAY = 'array' 34848b8605SmrgPACKED = 'packed' 35848b8605SmrgOTHER = 'other' 36848b8605Smrg 37848b8605SmrgRGB = 'rgb' 38848b8605SmrgSRGB = 'srgb' 39848b8605SmrgYUV = 'yuv' 40848b8605SmrgZS = 'zs' 41848b8605Smrg 42848b8605SmrgVERY_LARGE = 99999999999999999999999 43848b8605Smrg 44848b8605Smrgclass Channel: 45848b8605Smrg """Describes a color channel.""" 46848b8605Smrg 47848b8605Smrg def __init__(self, type, norm, size): 48848b8605Smrg self.type = type 49848b8605Smrg self.norm = norm 50848b8605Smrg self.size = size 51848b8605Smrg self.sign = type in (SIGNED, FLOAT) 52848b8605Smrg self.name = None # Set when the channels are added to the format 53848b8605Smrg self.shift = -1 # Set when the channels are added to the format 54848b8605Smrg self.index = -1 # Set when the channels are added to the format 55848b8605Smrg 56848b8605Smrg def __str__(self): 57848b8605Smrg s = str(self.type) 58848b8605Smrg if self.norm: 59848b8605Smrg s += 'n' 60848b8605Smrg s += str(self.size) 61848b8605Smrg return s 62848b8605Smrg 63848b8605Smrg def __eq__(self, other): 64b8e80941Smrg if other is None: 65b8e80941Smrg return False 66b8e80941Smrg 67848b8605Smrg return self.type == other.type and self.norm == other.norm and self.size == other.size 68848b8605Smrg 69b8e80941Smrg def __ne__(self, other): 70b8e80941Smrg return not self.__eq__(other) 71b8e80941Smrg 72848b8605Smrg def max(self): 73848b8605Smrg """Returns the maximum representable number.""" 74848b8605Smrg if self.type == FLOAT: 75848b8605Smrg return VERY_LARGE 76848b8605Smrg if self.norm: 77848b8605Smrg return 1 78848b8605Smrg if self.type == UNSIGNED: 79848b8605Smrg return (1 << self.size) - 1 80848b8605Smrg if self.type == SIGNED: 81848b8605Smrg return (1 << (self.size - 1)) - 1 82848b8605Smrg assert False 83848b8605Smrg 84848b8605Smrg def min(self): 85848b8605Smrg """Returns the minimum representable number.""" 86848b8605Smrg if self.type == FLOAT: 87848b8605Smrg return -VERY_LARGE 88848b8605Smrg if self.type == UNSIGNED: 89848b8605Smrg return 0 90848b8605Smrg if self.norm: 91848b8605Smrg return -1 92848b8605Smrg if self.type == SIGNED: 93848b8605Smrg return -(1 << (self.size - 1)) 94848b8605Smrg assert False 95848b8605Smrg 96848b8605Smrg def one(self): 97848b8605Smrg """Returns the value that represents 1.0f.""" 98848b8605Smrg if self.type == UNSIGNED: 99848b8605Smrg return (1 << self.size) - 1 100848b8605Smrg if self.type == SIGNED: 101848b8605Smrg return (1 << (self.size - 1)) - 1 102848b8605Smrg else: 103848b8605Smrg return 1 104848b8605Smrg 105b8e80941Smrg def datatype(self): 106b8e80941Smrg """Returns the datatype corresponding to a channel type and size""" 107b8e80941Smrg return _get_datatype(self.type, self.size) 108848b8605Smrg 109848b8605Smrgclass Swizzle: 110848b8605Smrg """Describes a swizzle operation. 111848b8605Smrg 112848b8605Smrg A Swizzle is a mapping from one set of channels in one format to the 113848b8605Smrg channels in another. Each channel in the destination format is 114848b8605Smrg associated with one of the following constants: 115848b8605Smrg 116848b8605Smrg * SWIZZLE_X: The first channel in the source format 117848b8605Smrg * SWIZZLE_Y: The second channel in the source format 118848b8605Smrg * SWIZZLE_Z: The third channel in the source format 119848b8605Smrg * SWIZZLE_W: The fourth channel in the source format 120848b8605Smrg * SWIZZLE_ZERO: The numeric constant 0 121848b8605Smrg * SWIZZLE_ONE: THe numeric constant 1 122848b8605Smrg * SWIZZLE_NONE: No data available for this channel 123848b8605Smrg 124848b8605Smrg Sometimes a Swizzle is represented by a 4-character string. In this 125848b8605Smrg case, the source channels are represented by the characters "x", "y", 126848b8605Smrg "z", and "w"; the numeric constants are represented as "0" and "1"; and 127848b8605Smrg no mapping is represented by "_". For instance, the map from 128848b8605Smrg luminance-alpha to rgba is given by "xxxy" because each of the three rgb 129848b8605Smrg channels maps to the first luminance-alpha channel and the alpha channel 130848b8605Smrg maps to second luminance-alpha channel. The mapping from bgr to rgba is 131848b8605Smrg given by "zyx1" because the first three colors are reversed and alpha is 132848b8605Smrg always 1. 133848b8605Smrg """ 134848b8605Smrg 135848b8605Smrg __identity_str = 'xyzw01_' 136848b8605Smrg 137848b8605Smrg SWIZZLE_X = 0 138848b8605Smrg SWIZZLE_Y = 1 139848b8605Smrg SWIZZLE_Z = 2 140848b8605Smrg SWIZZLE_W = 3 141848b8605Smrg SWIZZLE_ZERO = 4 142848b8605Smrg SWIZZLE_ONE = 5 143848b8605Smrg SWIZZLE_NONE = 6 144848b8605Smrg 145848b8605Smrg def __init__(self, swizzle): 146848b8605Smrg """Creates a Swizzle object from a string or array.""" 147848b8605Smrg if isinstance(swizzle, str): 148848b8605Smrg swizzle = [Swizzle.__identity_str.index(c) for c in swizzle] 149848b8605Smrg else: 150848b8605Smrg swizzle = list(swizzle) 151848b8605Smrg for s in swizzle: 152848b8605Smrg assert isinstance(s, int) and 0 <= s and s <= Swizzle.SWIZZLE_NONE 153848b8605Smrg 154848b8605Smrg assert len(swizzle) <= 4 155848b8605Smrg 156848b8605Smrg self.__list = swizzle + [Swizzle.SWIZZLE_NONE] * (4 - len(swizzle)) 157848b8605Smrg assert len(self.__list) == 4 158848b8605Smrg 159848b8605Smrg def __iter__(self): 160848b8605Smrg """Returns an iterator that iterates over this Swizzle. 161848b8605Smrg 162848b8605Smrg The values that the iterator produces are described by the SWIZZLE_* 163848b8605Smrg constants. 164848b8605Smrg """ 165848b8605Smrg return self.__list.__iter__() 166848b8605Smrg 167848b8605Smrg def __str__(self): 168848b8605Smrg """Returns a string representation of this Swizzle.""" 169848b8605Smrg return ''.join(Swizzle.__identity_str[i] for i in self.__list) 170848b8605Smrg 171848b8605Smrg def __getitem__(self, idx): 172848b8605Smrg """Returns the SWIZZLE_* constant for the given destination channel. 173848b8605Smrg 174848b8605Smrg Valid values for the destination channel include any of the SWIZZLE_* 175848b8605Smrg constants or any of the following single-character strings: "x", "y", 176848b8605Smrg "z", "w", "r", "g", "b", "a", "z" "s". 177848b8605Smrg """ 178848b8605Smrg 179848b8605Smrg if isinstance(idx, int): 180848b8605Smrg assert idx >= Swizzle.SWIZZLE_X and idx <= Swizzle.SWIZZLE_NONE 181848b8605Smrg if idx <= Swizzle.SWIZZLE_W: 182848b8605Smrg return self.__list.__getitem__(idx) 183848b8605Smrg else: 184848b8605Smrg return idx 185848b8605Smrg elif isinstance(idx, str): 186848b8605Smrg if idx in 'xyzw': 187848b8605Smrg idx = 'xyzw'.find(idx) 188848b8605Smrg elif idx in 'rgba': 189848b8605Smrg idx = 'rgba'.find(idx) 190848b8605Smrg elif idx in 'zs': 191848b8605Smrg idx = 'zs'.find(idx) 192848b8605Smrg else: 193848b8605Smrg assert False 194848b8605Smrg return self.__list.__getitem__(idx) 195848b8605Smrg else: 196848b8605Smrg assert False 197848b8605Smrg 198848b8605Smrg def __mul__(self, other): 199848b8605Smrg """Returns the composition of this Swizzle with another Swizzle. 200848b8605Smrg 201848b8605Smrg The resulting swizzle is such that, for any valid input to 202848b8605Smrg __getitem__, (a * b)[i] = a[b[i]]. 203848b8605Smrg """ 204848b8605Smrg assert isinstance(other, Swizzle) 205848b8605Smrg return Swizzle(self[x] for x in other) 206848b8605Smrg 207848b8605Smrg def inverse(self): 208848b8605Smrg """Returns a pseudo-inverse of this swizzle. 209848b8605Smrg 210848b8605Smrg Since swizzling isn't necisaraly a bijection, a Swizzle can never 211848b8605Smrg be truely inverted. However, the swizzle returned is *almost* the 212848b8605Smrg inverse of this swizzle in the sense that, for each i in range(3), 213848b8605Smrg a[a.inverse()[i]] is either i or SWIZZLE_NONE. If swizzle is just 214848b8605Smrg a permutation with no channels added or removed, then this 215848b8605Smrg function returns the actual inverse. 216848b8605Smrg 217848b8605Smrg This "pseudo-inverse" idea can be demonstrated by mapping from 218848b8605Smrg luminance-alpha to rgba that is given by "xxxy". To get from rgba 219848b8605Smrg to lumanence-alpha, we use Swizzle("xxxy").inverse() or "xw__". 220848b8605Smrg This maps the first component in the lumanence-alpha texture is 221848b8605Smrg the red component of the rgba image and the second to the alpha 222848b8605Smrg component, exactly as you would expect. 223848b8605Smrg """ 224848b8605Smrg rev = [Swizzle.SWIZZLE_NONE] * 4 225b8e80941Smrg for i in range(4): 226b8e80941Smrg for j in range(4): 227848b8605Smrg if self.__list[j] == i and rev[i] == Swizzle.SWIZZLE_NONE: 228848b8605Smrg rev[i] = j 229848b8605Smrg return Swizzle(rev) 230848b8605Smrg 231848b8605Smrg 232848b8605Smrgclass Format: 233848b8605Smrg """Describes a pixel format.""" 234848b8605Smrg 235b8e80941Smrg def __init__(self, name, layout, block_width, block_height, block_depth, channels, swizzle, colorspace): 236848b8605Smrg """Constructs a Format from some metadata and a list of channels. 237848b8605Smrg 238848b8605Smrg The channel objects must be unique to this Format and should not be 239848b8605Smrg re-used to construct another Format. This is because certain channel 240848b8605Smrg information such as shift, offset, and the channel name are set when 241848b8605Smrg the Format is created and are calculated based on the entire list of 242848b8605Smrg channels. 243848b8605Smrg 244848b8605Smrg Arguments: 245848b8605Smrg name -- Name of the format such as 'MESA_FORMAT_A8R8G8B8' 246848b8605Smrg layout -- One of 'array', 'packed' 'other', or a compressed layout 247848b8605Smrg block_width -- The block width if the format is compressed, 1 otherwise 248848b8605Smrg block_height -- The block height if the format is compressed, 1 otherwise 249b8e80941Smrg block_depth -- The block depth if the format is compressed, 1 otherwise 250848b8605Smrg channels -- A list of Channel objects 251848b8605Smrg swizzle -- A Swizzle from this format to rgba 252848b8605Smrg colorspace -- one of 'rgb', 'srgb', 'yuv', or 'zs' 253848b8605Smrg """ 254848b8605Smrg self.name = name 255848b8605Smrg self.layout = layout 256848b8605Smrg self.block_width = block_width 257848b8605Smrg self.block_height = block_height 258b8e80941Smrg self.block_depth = block_depth 259848b8605Smrg self.channels = channels 260848b8605Smrg assert isinstance(swizzle, Swizzle) 261848b8605Smrg self.swizzle = swizzle 262848b8605Smrg self.name = name 263848b8605Smrg assert colorspace in (RGB, SRGB, YUV, ZS) 264848b8605Smrg self.colorspace = colorspace 265848b8605Smrg 266848b8605Smrg # Name the channels 267848b8605Smrg chan_names = ['']*4 268848b8605Smrg if self.colorspace in (RGB, SRGB): 269848b8605Smrg for (i, s) in enumerate(swizzle): 270848b8605Smrg if s < 4: 271848b8605Smrg chan_names[s] += 'rgba'[i] 272848b8605Smrg elif colorspace == ZS: 273848b8605Smrg for (i, s) in enumerate(swizzle): 274848b8605Smrg if s < 4: 275848b8605Smrg chan_names[s] += 'zs'[i] 276848b8605Smrg else: 277848b8605Smrg chan_names = ['x', 'y', 'z', 'w'] 278848b8605Smrg 279848b8605Smrg for c, name in zip(self.channels, chan_names): 280848b8605Smrg assert c.name is None 281848b8605Smrg if name == 'rgb': 282848b8605Smrg c.name = 'l' 283848b8605Smrg elif name == 'rgba': 284848b8605Smrg c.name = 'i' 285848b8605Smrg elif name == '': 286848b8605Smrg c.name = 'x' 287848b8605Smrg else: 288848b8605Smrg c.name = name 289848b8605Smrg 290848b8605Smrg # Set indices and offsets 291848b8605Smrg if self.layout == PACKED: 292848b8605Smrg shift = 0 293848b8605Smrg for channel in self.channels: 294848b8605Smrg assert channel.shift == -1 295848b8605Smrg channel.shift = shift 296848b8605Smrg shift += channel.size 297848b8605Smrg for idx, channel in enumerate(self.channels): 298848b8605Smrg assert channel.index == -1 299848b8605Smrg channel.index = idx 300848b8605Smrg else: 301848b8605Smrg pass # Shift means nothing here 302848b8605Smrg 303848b8605Smrg def __str__(self): 304848b8605Smrg return self.name 305848b8605Smrg 306848b8605Smrg def short_name(self): 307848b8605Smrg """Returns a short name for a format. 308848b8605Smrg 309848b8605Smrg The short name should be suitable to be used as suffix in function 310848b8605Smrg names. 311848b8605Smrg """ 312848b8605Smrg 313848b8605Smrg name = self.name 314848b8605Smrg if name.startswith('MESA_FORMAT_'): 315848b8605Smrg name = name[len('MESA_FORMAT_'):] 316848b8605Smrg name = name.lower() 317848b8605Smrg return name 318848b8605Smrg 319848b8605Smrg def block_size(self): 320848b8605Smrg """Returns the block size (in bits) of the format.""" 321848b8605Smrg size = 0 322848b8605Smrg for channel in self.channels: 323848b8605Smrg size += channel.size 324848b8605Smrg return size 325848b8605Smrg 326848b8605Smrg def num_channels(self): 327848b8605Smrg """Returns the number of channels in the format.""" 328848b8605Smrg nr_channels = 0 329848b8605Smrg for channel in self.channels: 330848b8605Smrg if channel.size: 331848b8605Smrg nr_channels += 1 332848b8605Smrg return nr_channels 333848b8605Smrg 334848b8605Smrg def array_element(self): 335848b8605Smrg """Returns a non-void channel if this format is an array, otherwise None. 336848b8605Smrg 337848b8605Smrg If the returned channel is not None, then this format can be 338848b8605Smrg considered to be an array of num_channels() channels identical to the 339848b8605Smrg returned channel. 340848b8605Smrg """ 341848b8605Smrg if self.layout == ARRAY: 342848b8605Smrg return self.channels[0] 343848b8605Smrg elif self.layout == PACKED: 344848b8605Smrg ref_channel = self.channels[0] 345848b8605Smrg if ref_channel.type == VOID: 346848b8605Smrg ref_channel = self.channels[1] 347848b8605Smrg for channel in self.channels: 348848b8605Smrg if channel.size == 0 or channel.type == VOID: 349848b8605Smrg continue 350848b8605Smrg if channel.size != ref_channel.size or channel.size % 8 != 0: 351848b8605Smrg return None 352848b8605Smrg if channel.type != ref_channel.type: 353848b8605Smrg return None 354848b8605Smrg if channel.norm != ref_channel.norm: 355848b8605Smrg return None 356848b8605Smrg return ref_channel 357848b8605Smrg else: 358848b8605Smrg return None 359848b8605Smrg 360848b8605Smrg def is_array(self): 361848b8605Smrg """Returns true if this format can be considered an array format. 362848b8605Smrg 363848b8605Smrg This function will return true if self.layout == 'array'. However, 364848b8605Smrg some formats, such as MESA_FORMAT_A8G8B8R8, can be considered as 365848b8605Smrg array formats even though they are technically packed. 366848b8605Smrg """ 367848b8605Smrg return self.array_element() != None 368848b8605Smrg 369848b8605Smrg def is_compressed(self): 370848b8605Smrg """Returns true if this is a compressed format.""" 371b8e80941Smrg return self.block_width != 1 or self.block_height != 1 or self.block_depth != 1 372848b8605Smrg 373848b8605Smrg def is_int(self): 374848b8605Smrg """Returns true if this format is an integer format. 375848b8605Smrg 376848b8605Smrg See also: is_norm() 377848b8605Smrg """ 378848b8605Smrg if self.layout not in (ARRAY, PACKED): 379848b8605Smrg return False 380848b8605Smrg for channel in self.channels: 381848b8605Smrg if channel.type not in (VOID, UNSIGNED, SIGNED): 382848b8605Smrg return False 383848b8605Smrg return True 384848b8605Smrg 385848b8605Smrg def is_float(self): 386848b8605Smrg """Returns true if this format is an floating-point format.""" 387848b8605Smrg if self.layout not in (ARRAY, PACKED): 388848b8605Smrg return False 389848b8605Smrg for channel in self.channels: 390848b8605Smrg if channel.type not in (VOID, FLOAT): 391848b8605Smrg return False 392848b8605Smrg return True 393848b8605Smrg 394848b8605Smrg def channel_type(self): 395848b8605Smrg """Returns the type of the channels in this format.""" 396848b8605Smrg _type = VOID 397848b8605Smrg for c in self.channels: 398848b8605Smrg if c.type == VOID: 399848b8605Smrg continue 400848b8605Smrg if _type == VOID: 401848b8605Smrg _type = c.type 402848b8605Smrg assert c.type == _type 403848b8605Smrg return _type 404848b8605Smrg 405848b8605Smrg def channel_size(self): 406848b8605Smrg """Returns the size (in bits) of the channels in this format. 407848b8605Smrg 408848b8605Smrg This function should only be called if all of the channels have the 409848b8605Smrg same size. This is always the case if is_array() returns true. 410848b8605Smrg """ 411848b8605Smrg size = None 412848b8605Smrg for c in self.channels: 413848b8605Smrg if c.type == VOID: 414848b8605Smrg continue 415848b8605Smrg if size is None: 416848b8605Smrg size = c.size 417848b8605Smrg assert c.size == size 418848b8605Smrg return size 419848b8605Smrg 420848b8605Smrg def max_channel_size(self): 421848b8605Smrg """Returns the size of the largest channel.""" 422848b8605Smrg size = 0 423848b8605Smrg for c in self.channels: 424848b8605Smrg if c.type == VOID: 425848b8605Smrg continue 426848b8605Smrg size = max(size, c.size) 427848b8605Smrg return size 428848b8605Smrg 429848b8605Smrg def is_normalized(self): 430848b8605Smrg """Returns true if this format is normalized. 431848b8605Smrg 432848b8605Smrg While only integer formats can be normalized, not all integer formats 433848b8605Smrg are normalized. Normalized integer formats are those where the 434848b8605Smrg integer value is re-interpreted as a fixed point value in the range 435848b8605Smrg [0, 1]. 436848b8605Smrg """ 437848b8605Smrg norm = None 438848b8605Smrg for c in self.channels: 439848b8605Smrg if c.type == VOID: 440848b8605Smrg continue 441848b8605Smrg if norm is None: 442848b8605Smrg norm = c.norm 443848b8605Smrg assert c.norm == norm 444848b8605Smrg return norm 445848b8605Smrg 446848b8605Smrg def has_channel(self, name): 447848b8605Smrg """Returns true if this format has the given channel.""" 448848b8605Smrg if self.is_compressed(): 449848b8605Smrg # Compressed formats are a bit tricky because the list of channels 450848b8605Smrg # contains a single channel of type void. Since we don't have any 451848b8605Smrg # channel information there, we pull it from the swizzle. 452848b8605Smrg if str(self.swizzle) == 'xxxx': 453848b8605Smrg return name == 'i' 454848b8605Smrg elif str(self.swizzle)[0:3] in ('xxx', 'yyy'): 455848b8605Smrg if name == 'l': 456848b8605Smrg return True 457848b8605Smrg elif name == 'a': 458848b8605Smrg return self.swizzle['a'] <= Swizzle.SWIZZLE_W 459848b8605Smrg else: 460848b8605Smrg return False 461848b8605Smrg elif name in 'rgba': 462848b8605Smrg return self.swizzle[name] <= Swizzle.SWIZZLE_W 463848b8605Smrg else: 464848b8605Smrg return False 465848b8605Smrg else: 466848b8605Smrg for channel in self.channels: 467848b8605Smrg if channel.name == name: 468848b8605Smrg return True 469848b8605Smrg return False 470848b8605Smrg 471848b8605Smrg def get_channel(self, name): 472848b8605Smrg """Returns the channel with the given name if it exists.""" 473848b8605Smrg for channel in self.channels: 474848b8605Smrg if channel.name == name: 475848b8605Smrg return channel 476848b8605Smrg return None 477848b8605Smrg 478b8e80941Smrg def datatype(self): 479b8e80941Smrg """Returns the datatype corresponding to a format's channel type and size""" 480b8e80941Smrg if self.layout == PACKED: 481b8e80941Smrg if self.block_size() == 8: 482b8e80941Smrg return 'uint8_t' 483b8e80941Smrg if self.block_size() == 16: 484b8e80941Smrg return 'uint16_t' 485b8e80941Smrg if self.block_size() == 32: 486b8e80941Smrg return 'uint32_t' 487b8e80941Smrg else: 488b8e80941Smrg assert False 489b8e80941Smrg else: 490b8e80941Smrg return _get_datatype(self.channel_type(), self.channel_size()) 491b8e80941Smrg 492b8e80941Smrgdef _get_datatype(type, size): 493b8e80941Smrg if type == FLOAT: 494b8e80941Smrg if size == 32: 495b8e80941Smrg return 'float' 496b8e80941Smrg elif size == 16: 497b8e80941Smrg return 'uint16_t' 498b8e80941Smrg else: 499b8e80941Smrg assert False 500b8e80941Smrg elif type == UNSIGNED: 501b8e80941Smrg if size <= 8: 502b8e80941Smrg return 'uint8_t' 503b8e80941Smrg elif size <= 16: 504b8e80941Smrg return 'uint16_t' 505b8e80941Smrg elif size <= 32: 506b8e80941Smrg return 'uint32_t' 507b8e80941Smrg else: 508b8e80941Smrg assert False 509b8e80941Smrg elif type == SIGNED: 510b8e80941Smrg if size <= 8: 511b8e80941Smrg return 'int8_t' 512b8e80941Smrg elif size <= 16: 513b8e80941Smrg return 'int16_t' 514b8e80941Smrg elif size <= 32: 515b8e80941Smrg return 'int32_t' 516b8e80941Smrg else: 517b8e80941Smrg assert False 518b8e80941Smrg else: 519b8e80941Smrg assert False 520b8e80941Smrg 521848b8605Smrgdef _parse_channels(fields, layout, colorspace, swizzle): 522848b8605Smrg channels = [] 523848b8605Smrg for field in fields: 524848b8605Smrg if not field: 525848b8605Smrg continue 526848b8605Smrg 527848b8605Smrg type = field[0] if field[0] else 'x' 528848b8605Smrg 529848b8605Smrg if field[1] == 'n': 530848b8605Smrg norm = True 531848b8605Smrg size = int(field[2:]) 532848b8605Smrg else: 533848b8605Smrg norm = False 534848b8605Smrg size = int(field[1:]) 535848b8605Smrg 536848b8605Smrg channel = Channel(type, norm, size) 537848b8605Smrg channels.append(channel) 538848b8605Smrg 539848b8605Smrg return channels 540848b8605Smrg 541848b8605Smrgdef parse(filename): 542b8e80941Smrg """Parse a format description in CSV format. 543848b8605Smrg 544848b8605Smrg This function parses the given CSV file and returns an iterable of 545848b8605Smrg channels.""" 546848b8605Smrg 547848b8605Smrg with open(filename) as stream: 548848b8605Smrg for line in stream: 549848b8605Smrg try: 550848b8605Smrg comment = line.index('#') 551848b8605Smrg except ValueError: 552848b8605Smrg pass 553848b8605Smrg else: 554848b8605Smrg line = line[:comment] 555848b8605Smrg line = line.strip() 556848b8605Smrg if not line: 557848b8605Smrg continue 558848b8605Smrg 559848b8605Smrg fields = [field.strip() for field in line.split(',')] 560848b8605Smrg 561848b8605Smrg name = fields[0] 562848b8605Smrg layout = fields[1] 563848b8605Smrg block_width = int(fields[2]) 564848b8605Smrg block_height = int(fields[3]) 565b8e80941Smrg block_depth = int(fields[4]) 566b8e80941Smrg colorspace = fields[10] 567848b8605Smrg 568b8e80941Smrg try: 569b8e80941Smrg swizzle = Swizzle(fields[9]) 570b8e80941Smrg except: 571b8e80941Smrg sys.exit("error parsing swizzle for format " + name) 572b8e80941Smrg channels = _parse_channels(fields[5:9], layout, colorspace, swizzle) 573848b8605Smrg 574b8e80941Smrg yield Format(name, layout, block_width, block_height, block_depth, channels, swizzle, colorspace) 575