1 2''' 3/************************************************************************** 4 * 5 * Copyright 2009 VMware, Inc. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 23 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29''' 30 31 32VOID, UNSIGNED, SIGNED, FIXED, FLOAT = range(5) 33 34SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_0, SWIZZLE_1, SWIZZLE_NONE, = range(7) 35 36PLAIN = 'plain' 37SCALED = 'scaled' 38 39RGB = 'rgb' 40SRGB = 'srgb' 41YUV = 'yuv' 42ZS = 'zs' 43 44 45def is_pot(x): 46 return (x & (x - 1)) == 0 47 48 49VERY_LARGE = 99999999999999999999999 50 51 52class Channel: 53 '''Describe the channel of a color channel.''' 54 55 def __init__(self, type, norm, pure, scaled, size, name = ''): 56 self.type = type 57 self.norm = norm 58 self.pure = pure 59 self.size = size 60 self.scaled = scaled 61 self.sign = type in (SIGNED, FIXED, FLOAT) 62 self.name = name 63 64 def __str__(self): 65 s = str(self.type) 66 if self.norm: 67 s += 'n' 68 if self.pure: 69 s += 'p' 70 if self.scaled: 71 s += 's' 72 s += str(self.size) 73 return s 74 75 def __eq__(self, other): 76 return (other is not None and 77 self.type == other.type and 78 self.norm == other.norm and 79 self.pure == other.pure and 80 self.size == other.size and 81 self.scaled == other.scaled) 82 83 def max(self): 84 '''Maximum representable number.''' 85 if self.type == FLOAT: 86 return VERY_LARGE 87 if self.type == FIXED: 88 return (1 << (self.size/2)) - 1 89 if self.norm: 90 return 1 91 if self.type == UNSIGNED: 92 return (1 << self.size) - 1 93 if self.type == SIGNED: 94 return (1 << (self.size - 1)) - 1 95 assert False 96 97 def min(self): 98 '''Minimum representable number.''' 99 if self.type == FLOAT: 100 return -VERY_LARGE 101 if self.type == FIXED: 102 return -(1 << (self.size/2)) 103 if self.type == UNSIGNED: 104 return 0 105 if self.norm: 106 return -1 107 if self.type == SIGNED: 108 return -(1 << (self.size - 1)) 109 assert False 110 111 112class Format: 113 '''Describe a pixel format.''' 114 115 def __init__(self, name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace): 116 self.name = name 117 self.layout = layout 118 self.block_width = block_width 119 self.block_height = block_height 120 self.le_channels = le_channels 121 self.le_swizzles = le_swizzles 122 self.be_channels = be_channels 123 self.be_swizzles = be_swizzles 124 self.name = name 125 self.colorspace = colorspace 126 127 def __str__(self): 128 return self.name 129 130 def short_name(self): 131 '''Make up a short norm for a format, suitable to be used as suffix in 132 function names.''' 133 134 name = self.name 135 if name.startswith('VK_FORMAT_'): 136 name = name[len('VK_FORMAT_'):] 137 name = name.lower() 138 return name 139 140 def block_size(self): 141 size = 0 142 for channel in self.le_channels: 143 size += channel.size 144 return size 145 146 def nr_channels(self): 147 nr_channels = 0 148 for channel in self.le_channels: 149 if channel.size: 150 nr_channels += 1 151 return nr_channels 152 153 def array_element(self): 154 if self.layout != PLAIN: 155 return None 156 ref_channel = self.le_channels[0] 157 if ref_channel.type == VOID: 158 ref_channel = self.le_channels[1] 159 for channel in self.le_channels: 160 if channel.size and (channel.size != ref_channel.size or channel.size % 8): 161 return None 162 if channel.type != VOID: 163 if channel.type != ref_channel.type: 164 return None 165 if channel.norm != ref_channel.norm: 166 return None 167 if channel.pure != ref_channel.pure: 168 return None 169 if channel.scaled != ref_channel.scaled: 170 return None 171 return ref_channel 172 173 def is_array(self): 174 return self.array_element() != None 175 176 def is_mixed(self): 177 if self.layout != PLAIN: 178 return False 179 ref_channel = self.le_channels[0] 180 if ref_channel.type == VOID: 181 ref_channel = self.le_channels[1] 182 for channel in self.le_channels[1:]: 183 if channel.type != VOID: 184 if channel.type != ref_channel.type: 185 return True 186 if channel.norm != ref_channel.norm: 187 return True 188 if channel.pure != ref_channel.pure: 189 return True 190 if channel.scaled != ref_channel.scaled: 191 return True 192 return False 193 194 def is_pot(self): 195 return is_pot(self.block_size()) 196 197 def is_int(self): 198 if self.layout != PLAIN: 199 return False 200 for channel in self.le_channels: 201 if channel.type not in (VOID, UNSIGNED, SIGNED): 202 return False 203 return True 204 205 def is_float(self): 206 if self.layout != PLAIN: 207 return False 208 for channel in self.le_channels: 209 if channel.type not in (VOID, FLOAT): 210 return False 211 return True 212 213 def is_bitmask(self): 214 if self.layout != PLAIN: 215 return False 216 if self.block_size() not in (8, 16, 32): 217 return False 218 for channel in self.le_channels: 219 if channel.type not in (VOID, UNSIGNED, SIGNED): 220 return False 221 return True 222 223 def is_pure_color(self): 224 if self.layout != PLAIN or self.colorspace == ZS: 225 return False 226 pures = [channel.pure 227 for channel in self.le_channels 228 if channel.type != VOID] 229 for x in pures: 230 assert x == pures[0] 231 return pures[0] 232 233 def channel_type(self): 234 types = [channel.type 235 for channel in self.le_channels 236 if channel.type != VOID] 237 for x in types: 238 assert x == types[0] 239 return types[0] 240 241 def is_pure_signed(self): 242 return self.is_pure_color() and self.channel_type() == SIGNED 243 244 def is_pure_unsigned(self): 245 return self.is_pure_color() and self.channel_type() == UNSIGNED 246 247 def has_channel(self, id): 248 return self.le_swizzles[id] != SWIZZLE_NONE 249 250 def has_depth(self): 251 return self.colorspace == ZS and self.has_channel(0) 252 253 def has_stencil(self): 254 return self.colorspace == ZS and self.has_channel(1) 255 256 def stride(self): 257 return self.block_size()/8 258 259 260_type_parse_map = { 261 '': VOID, 262 'x': VOID, 263 'u': UNSIGNED, 264 's': SIGNED, 265 'h': FIXED, 266 'f': FLOAT, 267} 268 269_swizzle_parse_map = { 270 'x': SWIZZLE_X, 271 'y': SWIZZLE_Y, 272 'z': SWIZZLE_Z, 273 'w': SWIZZLE_W, 274 '0': SWIZZLE_0, 275 '1': SWIZZLE_1, 276 '_': SWIZZLE_NONE, 277} 278 279def _parse_channels(fields, layout, colorspace, swizzles): 280 if layout == PLAIN: 281 names = ['']*4 282 if colorspace in (RGB, SRGB): 283 for i in range(4): 284 swizzle = swizzles[i] 285 if swizzle < 4: 286 names[swizzle] += 'rgba'[i] 287 elif colorspace == ZS: 288 for i in range(4): 289 swizzle = swizzles[i] 290 if swizzle < 4: 291 names[swizzle] += 'zs'[i] 292 else: 293 assert False 294 for i in range(4): 295 if names[i] == '': 296 names[i] = 'x' 297 else: 298 names = ['x', 'y', 'z', 'w'] 299 300 channels = [] 301 for i in range(0, 4): 302 field = fields[i] 303 if field: 304 type = _type_parse_map[field[0]] 305 if field[1] == 'n': 306 norm = True 307 pure = False 308 scaled = False 309 size = int(field[2:]) 310 elif field[1] == 'p': 311 pure = True 312 norm = False 313 scaled = False 314 size = int(field[2:]) 315 elif field[1] == 's': 316 pure = False 317 norm = False 318 scaled = True 319 size = int(field[2:]) 320 else: 321 norm = False 322 pure = False 323 scaled = False 324 size = int(field[1:]) 325 else: 326 type = VOID 327 norm = False 328 pure = False 329 scaled = False 330 size = 0 331 channel = Channel(type, norm, pure, scaled, size, names[i]) 332 channels.append(channel) 333 334 return channels 335 336def parse(filename): 337 '''Parse the format description in CSV format in terms of the 338 Channel and Format classes above.''' 339 340 stream = open(filename) 341 formats = [] 342 for line in stream: 343 try: 344 comment = line.index('#') 345 except ValueError: 346 pass 347 else: 348 line = line[:comment] 349 line = line.strip() 350 if not line: 351 continue 352 353 fields = [field.strip() for field in line.split(',')] 354 if len (fields) < 10: 355 continue 356 if len (fields) == 10: 357 fields += fields[4:9] 358 assert len (fields) == 15 359 360 name = fields[0] 361 layout = fields[1] 362 block_width, block_height = map(int, fields[2:4]) 363 colorspace = fields[9] 364 365 le_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]] 366 le_channels = _parse_channels(fields[4:8], layout, colorspace, le_swizzles) 367 368 be_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[14]] 369 be_channels = _parse_channels(fields[10:14], layout, colorspace, be_swizzles) 370 371 le_shift = 0 372 for channel in le_channels: 373 channel.shift = le_shift 374 le_shift += channel.size 375 376 be_shift = 0 377 for channel in be_channels[3::-1]: 378 channel.shift = be_shift 379 be_shift += channel.size 380 381 assert le_shift == be_shift 382 for i in range(4): 383 assert (le_swizzles[i] != SWIZZLE_NONE) == (be_swizzles[i] != SWIZZLE_NONE) 384 385 format = Format(name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace) 386 formats.append(format) 387 return formats 388 389