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