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