Tizen 2.0 Release
[profile/ivi/osmesa.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, size, name = ''):
56         self.type = type
57         self.norm = norm
58         self.size = size
59         self.sign = type in (SIGNED, FIXED, FLOAT)
60         self.name = name
61
62     def __str__(self):
63         s = str(self.type)
64         if self.norm:
65             s += 'n'
66         s += str(self.size)
67         return s
68
69     def __eq__(self, other):
70         return self.type == other.type and self.norm == other.norm and self.size == other.size
71
72     def max(self):
73         '''Maximum representable number.'''
74         if self.type == FLOAT:
75             return VERY_LARGE
76         if self.type == FIXED:
77             return (1 << (self.size/2)) - 1
78         if self.norm:
79             return 1
80         if self.type == UNSIGNED:
81             return (1 << self.size) - 1
82         if self.type == SIGNED:
83             return (1 << (self.size - 1)) - 1
84         assert False
85     
86     def min(self):
87         '''Minimum representable number.'''
88         if self.type == FLOAT:
89             return -VERY_LARGE
90         if self.type == FIXED:
91             return -(1 << (self.size/2))
92         if self.type == UNSIGNED:
93             return 0
94         if self.norm:
95             return -1
96         if self.type == SIGNED:
97             return -(1 << (self.size - 1))
98         assert False
99
100
101 class Format:
102     '''Describe a pixel format.'''
103
104     def __init__(self, name, layout, block_width, block_height, channels, swizzles, colorspace):
105         self.name = name
106         self.layout = layout
107         self.block_width = block_width
108         self.block_height = block_height
109         self.channels = channels
110         self.swizzles = swizzles
111         self.name = name
112         self.colorspace = colorspace
113
114     def __str__(self):
115         return self.name
116
117     def short_name(self):
118         '''Make up a short norm for a format, suitable to be used as suffix in
119         function names.'''
120
121         name = self.name
122         if name.startswith('PIPE_FORMAT_'):
123             name = name[len('PIPE_FORMAT_'):]
124         name = name.lower()
125         return name
126
127     def block_size(self):
128         size = 0
129         for channel in self.channels:
130             size += channel.size
131         return size
132
133     def nr_channels(self):
134         nr_channels = 0
135         for channel in self.channels:
136             if channel.size:
137                 nr_channels += 1
138         return nr_channels
139
140     def is_array(self):
141         if self.layout != PLAIN:
142             return False
143         ref_channel = self.channels[0]
144         for channel in self.channels[1:]:
145             if channel.size and (channel.size != ref_channel.size or channel.size % 8):
146                 return False
147         return True
148
149     def is_mixed(self):
150         if self.layout != PLAIN:
151             return False
152         ref_channel = self.channels[0]
153         if ref_channel.type == VOID:
154            ref_channel = self.channels[1]
155         for channel in self.channels[1:]:
156             if channel.type != VOID:
157                 if channel.type != ref_channel.type:
158                     return True
159                 if channel.norm != ref_channel.norm:
160                     return True
161         return False
162
163     def is_pot(self):
164         return is_pot(self.block_size())
165
166     def is_int(self):
167         if self.layout != PLAIN:
168             return False
169         for channel in self.channels:
170             if channel.type not in (VOID, UNSIGNED, SIGNED):
171                 return False
172         return True
173
174     def is_float(self):
175         if self.layout != PLAIN:
176             return False
177         for channel in self.channels:
178             if channel.type not in (VOID, FLOAT):
179                 return False
180         return True
181
182     def is_bitmask(self):
183         if self.layout != PLAIN:
184             return False
185         if self.block_size() not in (8, 16, 32):
186             return False
187         for channel in self.channels:
188             if channel.type not in (VOID, UNSIGNED, SIGNED):
189                 return False
190         return True
191
192     def inv_swizzles(self):
193         '''Return an array[4] of inverse swizzle terms'''
194         inv_swizzle = [None]*4
195         for i in range(4):
196             swizzle = self.swizzles[i]
197             if swizzle < 4:
198                 inv_swizzle[swizzle] = i
199         return inv_swizzle
200
201     def stride(self):
202         return self.block_size()/8
203
204
205 _type_parse_map = {
206     '':  VOID,
207     'x': VOID,
208     'u': UNSIGNED,
209     's': SIGNED,
210     'h': FIXED,
211     'f': FLOAT,
212 }
213
214 _swizzle_parse_map = {
215     'x': SWIZZLE_X,
216     'y': SWIZZLE_Y,
217     'z': SWIZZLE_Z,
218     'w': SWIZZLE_W,
219     '0': SWIZZLE_0,
220     '1': SWIZZLE_1,
221     '_': SWIZZLE_NONE,
222 }
223
224 def parse(filename):
225     '''Parse the format descrition in CSV format in terms of the 
226     Channel and Format classes above.'''
227
228     stream = open(filename)
229     formats = []
230     for line in stream:
231         try:
232             comment = line.index('#')
233         except ValueError:
234             pass
235         else:
236             line = line[:comment]
237         line = line.strip()
238         if not line:
239             continue
240
241         fields = [field.strip() for field in line.split(',')]
242         
243         name = fields[0]
244         layout = fields[1]
245         block_width, block_height = map(int, fields[2:4])
246
247         swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
248         colorspace = fields[9]
249         
250         if layout == PLAIN:
251             names = ['']*4
252             if colorspace in (RGB, SRGB):
253                 for i in range(4):
254                     swizzle = swizzles[i]
255                     if swizzle < 4:
256                         names[swizzle] += 'rgba'[i]
257             elif colorspace == ZS:
258                 for i in range(4):
259                     swizzle = swizzles[i]
260                     if swizzle < 4:
261                         names[swizzle] += 'zs'[i]
262             else:
263                 assert False
264             for i in range(4):
265                 if names[i] == '':
266                     names[i] = 'x'
267         else:
268             names = ['x', 'y', 'z', 'w']
269
270         channels = []
271         for i in range(0, 4):
272             field = fields[4 + i]
273             if field:
274                 type = _type_parse_map[field[0]]
275                 if field[1] == 'n':
276                     norm = True
277                     size = int(field[2:])
278                 else:
279                     norm = False
280                     size = int(field[1:])
281             else:
282                 type = VOID
283                 norm = False
284                 size = 0
285             channel = Channel(type, norm, size, names[i])
286             channels.append(channel)
287
288         format = Format(name, layout, block_width, block_height, channels, swizzles, colorspace)
289         formats.append(format)
290     return formats
291