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