3 # (C) Copyright 2015, NVIDIA CORPORATION.
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:
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
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
26 # Kyle Brenneman <kbrenneman@nvidia.com>
31 import xml
.etree
.cElementTree
as etree
33 MAPI_TABLE_NUM_DYNAMIC
= 4096
35 _LIBRARY_FEATURE_NAMES
= {
36 # libGL and libGLdiapatch both include every function.
39 "opengl" : frozenset(( "GL_VERSION_1_0", "GL_VERSION_1_1",
40 "GL_VERSION_1_2", "GL_VERSION_1_3", "GL_VERSION_1_4", "GL_VERSION_1_5",
41 "GL_VERSION_2_0", "GL_VERSION_2_1", "GL_VERSION_3_0", "GL_VERSION_3_1",
42 "GL_VERSION_3_2", "GL_VERSION_3_3", "GL_VERSION_4_0", "GL_VERSION_4_1",
43 "GL_VERSION_4_2", "GL_VERSION_4_3", "GL_VERSION_4_4", "GL_VERSION_4_5",
45 "glesv1" : frozenset(("GL_VERSION_ES_CM_1_0", "GL_OES_point_size_array")),
46 "glesv2" : frozenset(("GL_ES_VERSION_2_0", "GL_ES_VERSION_3_0",
47 "GL_ES_VERSION_3_1" "GL_ES_VERSION_3_2",
51 def getFunctions(xmlFiles
):
53 Reads an XML file and returns all of the functions defined in it.
55 xmlFile should be the path to Khronos's gl.xml file. The return value is a
56 sequence of FunctionDesc objects, ordered by slot number.
58 roots
= [ etree
.parse(xmlFile
).getroot() for xmlFile
in xmlFiles
]
59 return getFunctionsFromRoots(roots
)
61 def getFunctionsFromRoots(roots
):
64 for func
in _getFunctionList(root
):
65 functions
[func
.name
] = func
66 functions
= functions
.values()
68 # Sort the function list by name.
69 functions
= sorted(functions
, key
=lambda f
: f
.name
)
71 # Assign a slot number to each function. This isn't strictly necessary,
72 # since you can just look at the index in the list, but it makes it easier
73 # to include the slot when formatting output.
74 for i
in range(len(functions
)):
75 functions
[i
] = functions
[i
]._replace
(slot
=i
)
79 def getExportNamesFromRoots(target
, roots
):
81 Goes through the <feature> tags from gl.xml and returns a set of OpenGL
82 functions that a library should export.
84 target should be one of "gl", "gldispatch", "opengl", "glesv1", or
87 featureNames
= _LIBRARY_FEATURE_NAMES
[target
]
88 if featureNames
is None:
89 return set(func
.name
for func
in getFunctionsFromRoots(roots
))
94 for featElem
in root
.findall("feature"):
95 if featElem
.get("name") in featureNames
:
96 features
.append(featElem
)
97 for featElem
in root
.findall("extensions/extension"):
98 if featElem
.get("name") in featureNames
:
99 features
.append(featElem
)
100 for featElem
in features
:
101 for commandElem
in featElem
.findall("require/command"):
102 names
.add(commandElem
.get("name"))
105 class FunctionArg(collections
.namedtuple("FunctionArg", "type name")):
109 Returns a "TYPE NAME" string, suitable for a function prototype.
112 if not rv
.endswith("*"):
117 class FunctionDesc(collections
.namedtuple("FunctionDesc", "name rt args slot")):
120 Returns true if the function returns a value.
122 return (self
.rt
!= "void")
127 Returns a string with the types and names of the arguments, as you
128 would use in a function declaration.
133 return ", ".join(arg
.dec
for arg
in self
.args
)
138 Returns a string with the names of the arguments, as you would use in a
141 return ", ".join(arg
.name
for arg
in self
.args
)
145 assert self
.name
.startswith("gl")
148 def _getFunctionList(root
):
149 for elem
in root
.findall("commands/command"):
150 yield _parseCommandElem(elem
)
152 def _parseCommandElem(elem
):
153 protoElem
= elem
.find("proto")
154 (rt
, name
) = _parseProtoElem(protoElem
)
157 for ch
in elem
.findall("param"):
158 # <param> tags have the same format as a <proto> tag.
159 args
.append(FunctionArg(*_parseProtoElem(ch
)))
160 func
= FunctionDesc(name
, rt
, tuple(args
), slot
=None)
164 def _parseProtoElem(elem
):
165 # If I just remove the tags and string the text together, I'll get valid C code.
166 text
= _flattenText(elem
)
168 m
= re
.match(r
"^(.+)\b(\w+)(?:\s*\[\s*(\d*)\s*\])?$", text
, re
.S
)
170 typename
= _fixupTypeName(m
.group(1))
173 # HACK: glPathGlyphIndexRangeNV defines an argument like this:
174 # GLuint baseAndCount[2]
175 # Convert it to a pointer and hope for the best.
177 return (typename
, name
)
179 raise ValueError("Can't parse element %r -> %r" % (elem
, text
))
181 def _flattenText(elem
):
183 Returns the text in an element and all child elements, with the tags
187 if elem
.text
is not None:
190 text
+= _flattenText(ch
)
191 if ch
.tail
is not None:
195 def _fixupTypeName(typeName
):
197 Converts a typename into a more consistent format.
200 rv
= typeName
.strip()
202 # Replace "GLvoid" with just plain "void".
203 rv
= re
.sub(r
"\bGLvoid\b", "void", rv
)
205 # Remove the vendor suffixes from types that have a suffix-less version.
206 rv
= re
.sub(r
"\b(GLhalf|GLintptr|GLsizeiptr|GLint64|GLuint64)(?:ARB|EXT|NV|ATI)\b", r
"\1", rv
)
208 rv
= re
.sub(r
"\bGLvoid\b", "void", rv
)
210 # Clear out any leading and trailing whitespace.
213 # Remove any whitespace before a '*'
214 rv
= re
.sub(r
"\s+\*", r
"*", rv
)
216 # Change "foo*" to "foo *"
217 rv
= re
.sub(r
"([^\*])\*", r
"\1 *", rv
)
219 # Condense all whitespace into a single space.
220 rv
= re
.sub(r
"\s+", " ", rv
)