gen_egl_dispatch.py revision 01e04c3f
1#!/usr/bin/env python 2 3# (C) Copyright 2016, 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""" 29Generates dispatch functions for EGL. 30 31The list of functions and arguments is read from the Khronos's XML files, with 32additional information defined in the module eglFunctionList. 33""" 34 35import argparse 36import collections 37import imp 38import sys 39import textwrap 40 41import genCommon 42 43def main(): 44 parser = argparse.ArgumentParser() 45 parser.add_argument("target", choices=("header", "source"), 46 help="Whether to build the source or header file.") 47 parser.add_argument("func_list_file", help="The function list .py file.") 48 parser.add_argument("xml_files", nargs="+", help="The XML files with the EGL function lists.") 49 50 args = parser.parse_args() 51 52 # The function list is a Python module, but it's specified on the command 53 # line. 54 eglFunctionList = imp.load_source("eglFunctionList", args.func_list_file) 55 56 xmlFunctions = genCommon.getFunctions(args.xml_files) 57 xmlByName = dict((f.name, f) for f in xmlFunctions) 58 functions = [] 59 for (name, eglFunc) in eglFunctionList.EGL_FUNCTIONS: 60 func = xmlByName[name] 61 eglFunc = fixupEglFunc(func, eglFunc) 62 functions.append((func, eglFunc)) 63 64 # Sort the function list by name. 65 functions = sorted(functions, key=lambda f: f[0].name) 66 67 if args.target == "header": 68 text = generateHeader(functions) 69 elif args.target == "source": 70 text = generateSource(functions) 71 sys.stdout.write(text) 72 73def fixupEglFunc(func, eglFunc): 74 result = dict(eglFunc) 75 if result.get("prefix") is None: 76 result["prefix"] = "" 77 78 if result.get("extension") is not None: 79 text = "defined(" + result["extension"] + ")" 80 result["extension"] = text 81 82 if result["method"] in ("none", "custom"): 83 return result 84 85 if result["method"] not in ("display", "device", "current"): 86 raise ValueError("Invalid dispatch method %r for function %r" % (result["method"], func.name)) 87 88 if func.hasReturn(): 89 if result.get("retval") is None: 90 result["retval"] = getDefaultReturnValue(func.rt) 91 92 return result 93 94def generateHeader(functions): 95 text = textwrap.dedent(r""" 96 #ifndef G_EGLDISPATCH_STUBS_H 97 #define G_EGLDISPATCH_STUBS_H 98 99 #ifdef __cplusplus 100 extern "C" { 101 #endif 102 103 #include <EGL/egl.h> 104 #include <EGL/eglext.h> 105 #include "glvnd/libeglabi.h" 106 107 """.lstrip("\n")) 108 109 text += "enum {\n" 110 for (func, eglFunc) in functions: 111 text += generateGuardBegin(func, eglFunc) 112 text += " __EGL_DISPATCH_" + func.name + ",\n" 113 text += generateGuardEnd(func, eglFunc) 114 text += " __EGL_DISPATCH_COUNT\n" 115 text += "};\n" 116 117 for (func, eglFunc) in functions: 118 if eglFunc["inheader"]: 119 text += generateGuardBegin(func, eglFunc) 120 text += "{f.rt} EGLAPIENTRY {ex[prefix]}{f.name}({f.decArgs});\n".format(f=func, ex=eglFunc) 121 text += generateGuardEnd(func, eglFunc) 122 123 text += textwrap.dedent(r""" 124 #ifdef __cplusplus 125 } 126 #endif 127 #endif // G_EGLDISPATCH_STUBS_H 128 """) 129 return text 130 131def generateSource(functions): 132 # First, sort the function list by name. 133 text = "" 134 text += '#include "egldispatchstubs.h"\n' 135 text += '#include "g_egldispatchstubs.h"\n' 136 text += "\n" 137 138 for (func, eglFunc) in functions: 139 if eglFunc["method"] not in ("custom", "none"): 140 text += generateGuardBegin(func, eglFunc) 141 text += generateDispatchFunc(func, eglFunc) 142 text += generateGuardEnd(func, eglFunc) 143 144 text += "\n" 145 text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n" 146 for (func, eglFunc) in functions: 147 text += generateGuardBegin(func, eglFunc) 148 text += ' "' + func.name + '",\n' 149 text += generateGuardEnd(func, eglFunc) 150 text += " NULL\n" 151 text += "};\n" 152 153 text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n" 154 for (func, eglFunc) in functions: 155 text += generateGuardBegin(func, eglFunc) 156 if eglFunc["method"] != "none": 157 text += " (__eglMustCastToProperFunctionPointerType) " + eglFunc.get("prefix", "") + func.name + ",\n" 158 else: 159 text += " NULL, // " + func.name + "\n" 160 text += generateGuardEnd(func, eglFunc) 161 text += " NULL\n" 162 text += "};\n" 163 164 return text 165 166def generateGuardBegin(func, eglFunc): 167 ext = eglFunc.get("extension") 168 if ext is not None: 169 return "#if " + ext + "\n" 170 else: 171 return "" 172 173def generateGuardEnd(func, eglFunc): 174 if eglFunc.get("extension") is not None: 175 return "#endif\n" 176 else: 177 return "" 178 179def generateDispatchFunc(func, eglFunc): 180 text = "" 181 182 if eglFunc.get("static"): 183 text += "static " 184 elif eglFunc.get("public"): 185 text += "PUBLIC " 186 text += textwrap.dedent( 187 r""" 188 {f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs}) 189 {{ 190 typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs}); 191 """).lstrip("\n").format(f=func, ef=eglFunc) 192 193 if func.hasReturn(): 194 text += " {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc) 195 196 text += " _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func) 197 if eglFunc["method"] == "current": 198 text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(f=func) 199 200 elif eglFunc["method"] in ("display", "device"): 201 if eglFunc["method"] == "display": 202 lookupFunc = "__eglDispatchFetchByDisplay" 203 lookupType = "EGLDisplay" 204 else: 205 assert eglFunc["method"] == "device" 206 lookupFunc = "__eglDispatchFetchByDevice" 207 lookupType = "EGLDeviceEXT" 208 209 lookupArg = None 210 for arg in func.args: 211 if arg.type == lookupType: 212 lookupArg = arg.name 213 break 214 if lookupArg is None: 215 raise ValueError("Can't find %s argument for function %s" % (lookupType, func.name,)) 216 217 text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format( 218 f=func, lookupFunc=lookupFunc, lookupArg=lookupArg) 219 else: 220 raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],)) 221 222 text += " if(_ptr_{f.name} != NULL) {{\n".format(f=func) 223 text += " " 224 if func.hasReturn(): 225 text += "_ret = " 226 text += "_ptr_{f.name}({f.callArgs});\n".format(f=func) 227 text += " }\n" 228 229 if func.hasReturn(): 230 text += " return _ret;\n" 231 text += "}\n" 232 return text 233 234def getDefaultReturnValue(typename): 235 if typename.endswith("*"): 236 return "NULL" 237 elif typename == "EGLDisplay": 238 return "EGL_NO_DISPLAY" 239 elif typename == "EGLContext": 240 return "EGL_NO_CONTEXT" 241 elif typename == "EGLSurface": 242 return "EGL_NO_SURFACE" 243 elif typename == "EGLBoolean": 244 return "EGL_FALSE"; 245 246 return "0" 247 248if __name__ == "__main__": 249 main() 250 251