mapi/new: use the static_data offsets in the new generator
[mesa.git] / src / mapi / new / genCommon.py
1 #!/usr/bin/env python
2
3 # (C) Copyright 2015, NVIDIA CORPORATION.
4 # All Rights Reserved.
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the "Software"),
8 # to deal in the Software without restriction, including without limitation
9 # on the rights to use, copy, modify, merge, publish, distribute, sub
10 # license, and/or sell copies of the Software, and to permit persons to whom
11 # the Software is furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice (including the next
14 # paragraph) shall be included in all copies or substantial portions of the
15 # Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24 #
25 # Authors:
26 # Kyle Brenneman <kbrenneman@nvidia.com>
27
28 import collections
29 import re
30 import sys
31 import xml.etree.cElementTree as etree
32
33 import os
34 GLAPI = os.path.join(os.path.dirname(__file__), "..", "glapi", "gen")
35 sys.path.insert(0, GLAPI)
36 import static_data
37
38 MAPI_TABLE_NUM_DYNAMIC = 4096
39
40 _LIBRARY_FEATURE_NAMES = {
41 # libGL and libGLdiapatch both include every function.
42 "gl" : None,
43 "gldispatch" : None,
44 "opengl" : frozenset(( "GL_VERSION_1_0", "GL_VERSION_1_1",
45 "GL_VERSION_1_2", "GL_VERSION_1_3", "GL_VERSION_1_4", "GL_VERSION_1_5",
46 "GL_VERSION_2_0", "GL_VERSION_2_1", "GL_VERSION_3_0", "GL_VERSION_3_1",
47 "GL_VERSION_3_2", "GL_VERSION_3_3", "GL_VERSION_4_0", "GL_VERSION_4_1",
48 "GL_VERSION_4_2", "GL_VERSION_4_3", "GL_VERSION_4_4", "GL_VERSION_4_5",
49 )),
50 "glesv1" : frozenset(("GL_VERSION_ES_CM_1_0", "GL_OES_point_size_array")),
51 "glesv2" : frozenset(("GL_ES_VERSION_2_0", "GL_ES_VERSION_3_0",
52 "GL_ES_VERSION_3_1", "GL_ES_VERSION_3_2",
53 )),
54 }
55
56 def getFunctions(xmlFiles):
57 """
58 Reads an XML file and returns all of the functions defined in it.
59
60 xmlFile should be the path to Khronos's gl.xml file. The return value is a
61 sequence of FunctionDesc objects, ordered by slot number.
62 """
63 roots = [ etree.parse(xmlFile).getroot() for xmlFile in xmlFiles ]
64 return getFunctionsFromRoots(roots)
65
66 def getFunctionsFromRoots(roots):
67 functions = {}
68 for root in roots:
69 for func in _getFunctionList(root):
70 functions[func.name] = func
71 functions = functions.values()
72
73 # Sort the function list by name.
74 functions = sorted(functions, key=lambda f: f.name)
75
76 # Lookup for fixed offset/slot functions and use it if available.
77 # Assign a slot number to each function. This isn't strictly necessary,
78 # since you can just look at the index in the list, but it makes it easier
79 # to include the slot when formatting output.
80
81 next_slot = 0
82 for i in range(len(functions)):
83 name = functions[i].name[2:]
84
85 if name in static_data.offsets:
86 functions[i] = functions[i]._replace(slot=static_data.offsets[name])
87 elif not name.endswith("ARB") and name + "ARB" in static_data.offsets:
88 functions[i] = functions[i]._replace(slot=static_data.offsets[name + "ARB"])
89 elif not name.endswith("EXT") and name + "EXT" in static_data.offsets:
90 functions[i] = functions[i]._replace(slot=static_data.offsets[name + "EXT"])
91 else:
92 functions[i] = functions[i]._replace(slot=next_slot)
93 next_slot += 1
94
95 # Sort the function list by slot.... to simplify the diff
96 functions = sorted(functions, key=lambda f: f.slot)
97
98 return functions
99
100 def getExportNamesFromRoots(target, roots):
101 """
102 Goes through the <feature> tags from gl.xml and returns a set of OpenGL
103 functions that a library should export.
104
105 target should be one of "gl", "gldispatch", "opengl", "glesv1", or
106 "glesv2".
107 """
108 featureNames = _LIBRARY_FEATURE_NAMES[target]
109 if featureNames is None:
110 return set(func.name for func in getFunctionsFromRoots(roots))
111
112 names = set()
113 for root in roots:
114 features = []
115 for featElem in root.findall("feature"):
116 if featElem.get("name") in featureNames:
117 features.append(featElem)
118 for featElem in root.findall("extensions/extension"):
119 if featElem.get("name") in featureNames:
120 features.append(featElem)
121 for featElem in features:
122 for commandElem in featElem.findall("require/command"):
123 names.add(commandElem.get("name"))
124 return names
125
126 class FunctionArg(collections.namedtuple("FunctionArg", "type name")):
127 @property
128 def dec(self):
129 """
130 Returns a "TYPE NAME" string, suitable for a function prototype.
131 """
132 rv = str(self.type)
133 if not rv.endswith("*"):
134 rv += " "
135 rv += self.name
136 return rv
137
138 class FunctionDesc(collections.namedtuple("FunctionDesc", "name rt args slot")):
139 def hasReturn(self):
140 """
141 Returns true if the function returns a value.
142 """
143 return (self.rt != "void")
144
145 @property
146 def decArgs(self):
147 """
148 Returns a string with the types and names of the arguments, as you
149 would use in a function declaration.
150 """
151 if not self.args:
152 return "void"
153 else:
154 return ", ".join(arg.dec for arg in self.args)
155
156 @property
157 def callArgs(self):
158 """
159 Returns a string with the names of the arguments, as you would use in a
160 function call.
161 """
162 return ", ".join(arg.name for arg in self.args)
163
164 @property
165 def basename(self):
166 assert self.name.startswith("gl")
167 return self.name[2:]
168
169 def _getFunctionList(root):
170 for elem in root.findall("commands/command"):
171 yield _parseCommandElem(elem)
172
173 def _parseCommandElem(elem):
174 protoElem = elem.find("proto")
175 (rt, name) = _parseProtoElem(protoElem)
176
177 args = []
178 for ch in elem.findall("param"):
179 # <param> tags have the same format as a <proto> tag.
180 args.append(FunctionArg(*_parseProtoElem(ch)))
181 func = FunctionDesc(name, rt, tuple(args), slot=None)
182
183 return func
184
185 def _parseProtoElem(elem):
186 # If I just remove the tags and string the text together, I'll get valid C code.
187 text = _flattenText(elem)
188 text = text.strip()
189 m = re.match(r"^(.+)\b(\w+)(?:\s*\[\s*(\d*)\s*\])?$", text, re.S)
190 if m:
191 typename = _fixupTypeName(m.group(1))
192 name = m.group(2)
193 if m.group(3):
194 # HACK: glPathGlyphIndexRangeNV defines an argument like this:
195 # GLuint baseAndCount[2]
196 # Convert it to a pointer and hope for the best.
197 typename += "*"
198 return (typename, name)
199 else:
200 raise ValueError("Can't parse element %r -> %r" % (elem, text))
201
202 def _flattenText(elem):
203 """
204 Returns the text in an element and all child elements, with the tags
205 removed.
206 """
207 text = ""
208 if elem.text is not None:
209 text = elem.text
210 for ch in elem:
211 text += _flattenText(ch)
212 if ch.tail is not None:
213 text += ch.tail
214 return text
215
216 def _fixupTypeName(typeName):
217 """
218 Converts a typename into a more consistent format.
219 """
220
221 rv = typeName.strip()
222
223 # Replace "GLvoid" with just plain "void".
224 rv = re.sub(r"\bGLvoid\b", "void", rv)
225
226 # Remove the vendor suffixes from types that have a suffix-less version.
227 rv = re.sub(r"\b(GLhalf|GLintptr|GLsizeiptr|GLint64|GLuint64)(?:ARB|EXT|NV|ATI)\b", r"\1", rv)
228
229 rv = re.sub(r"\bGLvoid\b", "void", rv)
230
231 # Clear out any leading and trailing whitespace.
232 rv = rv.strip()
233
234 # Remove any whitespace before a '*'
235 rv = re.sub(r"\s+\*", r"*", rv)
236
237 # Change "foo*" to "foo *"
238 rv = re.sub(r"([^\*])\*", r"\1 *", rv)
239
240 # Condense all whitespace into a single space.
241 rv = re.sub(r"\s+", " ", rv)
242
243 return rv
244