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