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 if other is None: 77 return False 78 79 return self.type == other.type and self.norm == other.norm and self.pure == other.pure and self.size == other.size and self.scaled == other.scaled 80 81 def __ne__(self, other): 82 return not self == other 83 84 def max(self): 85 '''Maximum representable number.''' 86 if self.type == FLOAT: 87 return VERY_LARGE 88 if self.type == FIXED: 89 return (1 << (self.size/2)) - 1 90 if self.norm: 91 return 1 92 if self.type == UNSIGNED: 93 return (1 << self.size) - 1 94 if self.type == SIGNED: 95 return (1 << (self.size - 1)) - 1 96 assert False 97 98 def min(self): 99 '''Minimum representable number.''' 100 if self.type == FLOAT: 101 return -VERY_LARGE 102 if self.type == FIXED: 103 return -(1 << (self.size/2)) 104 if self.type == UNSIGNED: 105 return 0 106 if self.norm: 107 return -1 108 if self.type == SIGNED: 109 return -(1 << (self.size - 1)) 110 assert False 111 112 113class Format: 114 '''Describe a pixel format.''' 115 116 def __init__(self, name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace, width_divisor, height_divisor, plane_formats): 117 self.name = name 118 self.layout = layout 119 self.block_width = block_width 120 self.block_height = block_height 121 self.le_channels = le_channels 122 self.le_swizzles = le_swizzles 123 self.be_channels = be_channels 124 self.be_swizzles = be_swizzles 125 self.name = name 126 self.colorspace = colorspace 127 self.plane_count = len(plane_formats) 128 self.width_divisor = width_divisor 129 self.height_divisor = height_divisor 130 self.plane_formats = plane_formats 131 132 while len(self.plane_formats) < 3: 133 self.plane_formats.append("VK_FORMAT_UNDEFINED") 134 135 def __str__(self): 136 return self.name 137 138 def short_name(self): 139 '''Make up a short norm for a format, suitable to be used as suffix in 140 function names.''' 141 142 name = self.name 143 if name.startswith('VK_FORMAT_'): 144 name = name[len('VK_FORMAT_'):] 145 name = name.lower() 146 return name 147 148 def block_size(self): 149 size = 0 150 for channel in self.le_channels: 151 size += channel.size 152 return size 153 154 def nr_channels(self): 155 nr_channels = 0 156 for channel in self.le_channels: 157 if channel.size: 158 nr_channels += 1 159 return nr_channels 160 161 def array_element(self): 162 if self.layout != PLAIN: 163 return None 164 ref_channel = self.le_channels[0] 165 if ref_channel.type == VOID: 166 ref_channel = self.le_channels[1] 167 for channel in self.le_channels: 168 if channel.size and (channel.size != ref_channel.size or channel.size % 8): 169 return None 170 if channel.type != VOID: 171 if channel.type != ref_channel.type: 172 return None 173 if channel.norm != ref_channel.norm: 174 return None 175 if channel.pure != ref_channel.pure: 176 return None 177 if channel.scaled != ref_channel.scaled: 178 return None 179 return ref_channel 180 181 def is_array(self): 182 return self.array_element() != None 183 184 def is_mixed(self): 185 if self.layout != PLAIN: 186 return False 187 ref_channel = self.le_channels[0] 188 if ref_channel.type == VOID: 189 ref_channel = self.le_channels[1] 190 for channel in self.le_channels[1:]: 191 if channel.type != VOID: 192 if channel.type != ref_channel.type: 193 return True 194 if channel.norm != ref_channel.norm: 195 return True 196 if channel.pure != ref_channel.pure: 197 return True 198 if channel.scaled != ref_channel.scaled: 199 return True 200 return False 201 202 def is_pot(self): 203 return is_pot(self.block_size()) 204 205 def is_int(self): 206 if self.layout != PLAIN: 207 return False 208 for channel in self.le_channels: 209 if channel.type not in (VOID, UNSIGNED, SIGNED): 210 return False 211 return True 212 213 def is_float(self): 214 if self.layout != PLAIN: 215 return False 216 for channel in self.le_channels: 217 if channel.type not in (VOID, FLOAT): 218 return False 219 return True 220 221 def is_bitmask(self): 222 if self.layout != PLAIN: 223 return False 224 if self.block_size() not in (8, 16, 32): 225 return False 226 for channel in self.le_channels: 227 if channel.type not in (VOID, UNSIGNED, SIGNED): 228 return False 229 return True 230 231 def is_pure_color(self): 232 if self.layout != PLAIN or self.colorspace == ZS: 233 return False 234 pures = [channel.pure 235 for channel in self.le_channels 236 if channel.type != VOID] 237 for x in pures: 238 assert x == pures[0] 239 return pures[0] 240 241 def channel_type(self): 242 types = [channel.type 243 for channel in self.le_channels 244 if channel.type != VOID] 245 for x in types: 246 assert x == types[0] 247 return types[0] 248 249 def is_pure_signed(self): 250 return self.is_pure_color() and self.channel_type() == SIGNED 251 252 def is_pure_unsigned(self): 253 return self.is_pure_color() and self.channel_type() == UNSIGNED 254 255 def has_channel(self, id): 256 return self.le_swizzles[id] != SWIZZLE_NONE 257 258 def has_depth(self): 259 return self.colorspace == ZS and self.has_channel(0) 260 261 def has_stencil(self): 262 return self.colorspace == ZS and self.has_channel(1) 263 264 def stride(self): 265 return self.block_size()/8 266 267 268_type_parse_map = { 269 '': VOID, 270 'x': VOID, 271 'u': UNSIGNED, 272 's': SIGNED, 273 'h': FIXED, 274 'f': FLOAT, 275} 276 277_swizzle_parse_map = { 278 'x': SWIZZLE_X, 279 'y': SWIZZLE_Y, 280 'z': SWIZZLE_Z, 281 'w': SWIZZLE_W, 282 '0': SWIZZLE_0, 283 '1': SWIZZLE_1, 284 '_': SWIZZLE_NONE, 285} 286 287def _parse_channels(fields, layout, colorspace, swizzles): 288 if layout == PLAIN: 289 names = ['']*4 290 if colorspace in (RGB, SRGB): 291 for i in range(4): 292 swizzle = swizzles[i] 293 if swizzle < 4: 294 names[swizzle] += 'rgba'[i] 295 elif colorspace == ZS: 296 for i in range(4): 297 swizzle = swizzles[i] 298 if swizzle < 4: 299 names[swizzle] += 'zs'[i] 300 else: 301 assert False 302 for i in range(4): 303 if names[i] == '': 304 names[i] = 'x' 305 else: 306 names = ['x', 'y', 'z', 'w'] 307 308 channels = [] 309 for i in range(0, 4): 310 field = fields[i] 311 if field: 312 type = _type_parse_map[field[0]] 313 if field[1] == 'n': 314 norm = True 315 pure = False 316 scaled = False 317 size = int(field[2:]) 318 elif field[1] == 'p': 319 pure = True 320 norm = False 321 scaled = False 322 size = int(field[2:]) 323 elif field[1] == 's': 324 pure = False 325 norm = False 326 scaled = True 327 size = int(field[2:]) 328 else: 329 norm = False 330 pure = False 331 scaled = False 332 size = int(field[1:]) 333 else: 334 type = VOID 335 norm = False 336 pure = False 337 scaled = False 338 size = 0 339 channel = Channel(type, norm, pure, scaled, size, names[i]) 340 channels.append(channel) 341 342 return channels 343 344def parse_plane_divisor(format): 345 if format == '444': 346 return (1, 1) 347 elif format == '422': 348 return (2, 1) 349 elif format == '420': 350 return (2, 2) 351 else: 352 return (1, 1) 353 354def parse(filename): 355 '''Parse the format description in CSV format in terms of the 356 Channel and Format classes above.''' 357 358 stream = open(filename) 359 formats = [] 360 for line in stream: 361 try: 362 comment = line.index('#') 363 except ValueError: 364 pass 365 else: 366 line = line[:comment] 367 line = line.strip() 368 if not line: 369 continue 370 371 fields = [field.strip() for field in line.split(',')] 372 if len (fields) < 10: 373 continue 374 375 be_fields = fields[4:9] 376 377 name = fields[0] 378 layout = fields[1] 379 block_width, block_height = map(int, fields[2:4]) 380 colorspace = fields[9] 381 382 le_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]] 383 le_channels = _parse_channels(fields[4:8], layout, colorspace, le_swizzles) 384 385 be_swizzles = [_swizzle_parse_map[swizzle] for swizzle in be_fields[4]] 386 be_channels = _parse_channels(be_fields, layout, colorspace, be_swizzles) 387 388 le_shift = 0 389 for channel in le_channels: 390 channel.shift = le_shift 391 le_shift += channel.size 392 393 be_shift = 0 394 for channel in be_channels[3::-1]: 395 channel.shift = be_shift 396 be_shift += channel.size 397 398 assert le_shift == be_shift 399 for i in range(4): 400 assert (le_swizzles[i] != SWIZZLE_NONE) == (be_swizzles[i] != SWIZZLE_NONE) 401 402 width_divisor = 1 403 height_divisor = 1 404 plane_formats = [name] 405 if layout == "multiplane": 406 plane_formats = [] 407 (width_divisor, height_divisor) = parse_plane_divisor(fields[10]) 408 409 for i in range(11, len(fields)): 410 plane_formats.append(fields[i]) 411 assert (len(plane_formats) > 1) 412 413 format = Format(name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace, width_divisor, height_divisor, plane_formats) 414 formats.append(format) 415 return formats 416 417