r300g: implement MSAA
[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, channels, swizzles, colorspace):
108 self.name = name
109 self.layout = layout
110 self.block_width = block_width
111 self.block_height = block_height
112 self.channels = channels
113 self.swizzles = swizzles
114 self.name = name
115 self.colorspace = colorspace
116
117 def __str__(self):
118 return self.name
119
120 def short_name(self):
121 '''Make up a short norm for a format, suitable to be used as suffix in
122 function names.'''
123
124 name = self.name
125 if name.startswith('PIPE_FORMAT_'):
126 name = name[len('PIPE_FORMAT_'):]
127 name = name.lower()
128 return name
129
130 def block_size(self):
131 size = 0
132 for channel in self.channels:
133 size += channel.size
134 return size
135
136 def nr_channels(self):
137 nr_channels = 0
138 for channel in self.channels:
139 if channel.size:
140 nr_channels += 1
141 return nr_channels
142
143 def is_array(self):
144 if self.layout != PLAIN:
145 return False
146 ref_channel = self.channels[0]
147 if ref_channel.type == VOID:
148 ref_channel = self.channels[1]
149 for channel in self.channels:
150 if channel.size and (channel.size != ref_channel.size or channel.size % 8):
151 return False
152 if channel.type != VOID:
153 if channel.type != ref_channel.type:
154 return False
155 if channel.norm != ref_channel.norm:
156 return False
157 if channel.pure != ref_channel.pure:
158 return False
159 return True
160
161 def is_mixed(self):
162 if self.layout != PLAIN:
163 return False
164 ref_channel = self.channels[0]
165 if ref_channel.type == VOID:
166 ref_channel = self.channels[1]
167 for channel in self.channels[1:]:
168 if channel.type != VOID:
169 if channel.type != ref_channel.type:
170 return True
171 if channel.norm != ref_channel.norm:
172 return True
173 if channel.pure != ref_channel.pure:
174 return True
175 return False
176
177 def is_pot(self):
178 return is_pot(self.block_size())
179
180 def is_int(self):
181 if self.layout != PLAIN:
182 return False
183 for channel in self.channels:
184 if channel.type not in (VOID, UNSIGNED, SIGNED):
185 return False
186 return True
187
188 def is_float(self):
189 if self.layout != PLAIN:
190 return False
191 for channel in self.channels:
192 if channel.type not in (VOID, FLOAT):
193 return False
194 return True
195
196 def is_bitmask(self):
197 if self.layout != PLAIN:
198 return False
199 if self.block_size() not in (8, 16, 32):
200 return False
201 for channel in self.channels:
202 if channel.type not in (VOID, UNSIGNED, SIGNED):
203 return False
204 return True
205
206 def inv_swizzles(self):
207 '''Return an array[4] of inverse swizzle terms'''
208 '''Only pick the first matching value to avoid l8 getting blue and i8 getting alpha'''
209 inv_swizzle = [None]*4
210 for i in range(4):
211 swizzle = self.swizzles[i]
212 if swizzle < 4 and inv_swizzle[swizzle] == None:
213 inv_swizzle[swizzle] = i
214 return inv_swizzle
215
216 def stride(self):
217 return self.block_size()/8
218
219
220 _type_parse_map = {
221 '': VOID,
222 'x': VOID,
223 'u': UNSIGNED,
224 's': SIGNED,
225 'h': FIXED,
226 'f': FLOAT,
227 }
228
229 _swizzle_parse_map = {
230 'x': SWIZZLE_X,
231 'y': SWIZZLE_Y,
232 'z': SWIZZLE_Z,
233 'w': SWIZZLE_W,
234 '0': SWIZZLE_0,
235 '1': SWIZZLE_1,
236 '_': SWIZZLE_NONE,
237 }
238
239 def parse(filename):
240 '''Parse the format descrition in CSV format in terms of the
241 Channel and Format classes above.'''
242
243 stream = open(filename)
244 formats = []
245 for line in stream:
246 try:
247 comment = line.index('#')
248 except ValueError:
249 pass
250 else:
251 line = line[:comment]
252 line = line.strip()
253 if not line:
254 continue
255
256 fields = [field.strip() for field in line.split(',')]
257
258 name = fields[0]
259 layout = fields[1]
260 block_width, block_height = map(int, fields[2:4])
261
262 swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
263 colorspace = fields[9]
264
265 if layout == PLAIN:
266 names = ['']*4
267 if colorspace in (RGB, SRGB):
268 for i in range(4):
269 swizzle = swizzles[i]
270 if swizzle < 4:
271 names[swizzle] += 'rgba'[i]
272 elif colorspace == ZS:
273 for i in range(4):
274 swizzle = swizzles[i]
275 if swizzle < 4:
276 names[swizzle] += 'zs'[i]
277 else:
278 assert False
279 for i in range(4):
280 if names[i] == '':
281 names[i] = 'x'
282 else:
283 names = ['x', 'y', 'z', 'w']
284
285 channels = []
286 for i in range(0, 4):
287 field = fields[4 + i]
288 if field:
289 type = _type_parse_map[field[0]]
290 if field[1] == 'n':
291 norm = True
292 pure = False
293 size = int(field[2:])
294 elif field[1] == 'p':
295 pure = True
296 norm = False
297 size = int(field[2:])
298 else:
299 norm = False
300 pure = False
301 size = int(field[1:])
302 else:
303 type = VOID
304 norm = False
305 pure = False
306 size = 0
307 channel = Channel(type, norm, pure, size, names[i])
308 channels.append(channel)
309
310 format = Format(name, layout, block_width, block_height, channels, swizzles, colorspace)
311 formats.append(format)
312 return formats
313