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