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