#!/usr/bin/env python # # Copyright (c) 2013-2014 The Khronos Group Inc. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and/or associated documentation files (the # "Materials"), to deal in the Materials without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Materials, and to # permit persons to whom the Materials are furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Materials. # # THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. import sys, time, pdb, string, cProfile from reg import * # debug - start header generation in debugger # dump - dump registry after loading # profile - enable Python profiling # protect - whether to use #ifndef protections # registry - use specified XML registry instead of gl.xml # target - string name of target header, or all targets if None # timeit - time length of registry loading & header generation # validate - validate return & parameter group tags against debug = False dump = False profile = False protect = True target = None timeit = False validate= False # Default input / log files errFilename = None diagFilename = 'diag.txt' regFilename = 'gl.xml' outFilename = 'gen_gl_wrappers.c' dispatchheader = None prefix = "gl" preresolve = False staticwrappers = False WinGDI={key: 1 for key in [ "wglCopyContext" ,"wglCreateContext" ,"wglCreateLayerContext" ,"wglDeleteContext" ,"wglGetCurrentContext" ,"wglGetCurrentDC" ,"wglGetProcAddress" ,"wglMakeCurrent" ,"wglShareLists" ,"wglUseFontBitmapsA" ,"wglUseFontBitmapsW" ,"wglUseFontBitmaps" ,"SwapBuffers" ,"wglUseFontOutlinesA" ,"wglUseFontOutlinesW" ,"wglUseFontOutlines" ,"wglDescribeLayerPlane" ,"wglSetLayerPaletteEntries" ,"wglGetLayerPaletteEntries" ,"wglRealizeLayerPalette" ,"wglSwapLayerBuffers" ,"wglSwapMultipleBuffers" ,"ChoosePixelFormat" ,"DescribePixelFormat" ,"GetEnhMetaFilePixelFormat" ,"GetPixelFormat" ,"SetPixelFormat" ]} if __name__ == '__main__': i = 1 while (i < len(sys.argv)): arg = sys.argv[i] i = i + 1 if (arg == '-debug'): write('Enabling debug (-debug)', file=sys.stderr) debug = True elif (arg == '-dump'): write('Enabling dump (-dump)', file=sys.stderr) dump = True elif (arg == '-noprotect'): write('Disabling inclusion protection in output headers', file=sys.stderr) protect = False elif (arg == '-profile'): write('Enabling profiling (-profile)', file=sys.stderr) profile = True elif (arg == '-registry'): regFilename = sys.argv[i] i = i+1 write('Using registry ', regFilename, file=sys.stderr) elif (arg == '-time'): write('Enabling timing (-time)', file=sys.stderr) timeit = True elif (arg == '-validate'): write('Enabling group validation (-validate)', file=sys.stderr) validate = True elif (arg == '-outfile'): outFilename = sys.argv[i] i = i+1 write('Generating ', outFilename, file=sys.stderr) elif (arg == '-preresolve'): preresolve = True elif (arg == '-staticwrappers'): staticwrappers=True elif (arg == '-dispatchheader'): dispatchheader = sys.argv[i] i = i+1 elif (arg == '-prefix'): prefix = sys.argv[i] i = i+1 elif (arg[0:1] == '-'): write('Unrecognized argument:', arg, file=sys.stderr) exit(1) else: target = arg write('Using target', target, file=sys.stderr) # Simple timer functions startTime = None def startTimer(): global startTime startTime = time.clock() def endTimer(msg): global startTime endTime = time.clock() if (timeit): write(msg, endTime - startTime) startTime = None # Load & parse registry reg = Registry() startTimer() tree = etree.parse(regFilename) endTimer('Time to make ElementTree =') startTimer() reg.loadElementTree(tree) endTimer('Time to parse ElementTree =') if (validate): reg.validateGroups() if (dump): write('***************************************') write('Performing Registry dump to regdump.txt') write('***************************************') reg.dumpReg(filehandle = open('regdump.txt','w')) # Turn a list of strings into a regexp string matching exactly those strings def makeREstring(list): return '^(' + '|'.join(list) + ')$' # These are "mandatory" OpenGL ES 1 extensions, to # be included in the core GLES/gl.h header. es1CoreList = [ 'GL_OES_read_format', 'GL_OES_compressed_paletted_texture', 'GL_OES_point_size_array', 'GL_OES_point_sprite' ] # Descriptive names for various regexp patterns used to select # versions and extensions allVersions = allExtensions = '.*' noVersions = noExtensions = None gl12andLaterPat = '1\.[2-9]|[234]\.[0-9]' gles2onlyPat = '2\.[0-9]' gles2and30Pat = '2\.[0-9]|3.0' gles2and30and31Pat = '2.[0-9]|3.[01]' es1CorePat = makeREstring(es1CoreList) # Extensions in old glcorearb.h but not yet tagged accordingly in gl.xml glCoreARBPat = None glx13andLaterPat = '1\.[3-9]' # Copyright text prefixing all headers (list of strings). prefixStrings = [ '/*', '** Copyright (c) 2013-2014 The Khronos Group Inc.', '**', '** Permission is hereby granted, free of charge, to any person obtaining a', '** copy of this software and/or associated documentation files (the', '** "Materials"), to deal in the Materials without restriction, including', '** without limitation the rights to use, copy, modify, merge, publish,', '** distribute, sublicense, and/or sell copies of the Materials, and to', '** permit persons to whom the Materials are furnished to do so, subject to', '** the following conditions:', '**', '** The above copyright notice and this permission notice shall be included', '** in all copies or substantial portions of the Materials.', '**', '** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,', '** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF', '** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.', '** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY', '** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,', '** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE', '** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.', '*/', '/*', '** This header is generated from the Khronos OpenGL / OpenGL ES XML', '** API Registry. The current version of the Registry, generator scripts', '** used to make the header, and the header can be found at', '** http://www.opengl.org/registry/', '**', '** Khronos $' + 'Revision$ on $' + 'Date$', '*/', '' ] # glext.h / glcorearb.h define calling conventions inline (no GL *platform.h) glExtPlatformStrings = [ '#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)', '#ifndef WIN32_LEAN_AND_MEAN', '#define WIN32_LEAN_AND_MEAN 1', '#endif', '#include ', '#endif', '', '#ifndef APIENTRY', '#define APIENTRY', '#endif', '#ifndef APIENTRYP', '#define APIENTRYP APIENTRY *', '#endif', '#ifndef GLAPI', '#define GLAPI extern', '#endif', '' ] glCorearbPlatformStrings = glExtPlatformStrings + [ '/* glcorearb.h is for use with OpenGL core profile implementations.', '** It should should be placed in the same directory as gl.h and', '** included as .', '**', '** glcorearb.h includes only APIs in the latest OpenGL core profile', '** implementation together with APIs in newer ARB extensions which ', '** can be supported by the core profile. It does not, and never will', '** include functionality removed from the core profile, such as', '** fixed-function vertex and fragment processing.', '**', '** Do not #include both and either of or', '** in the same source file.', '*/', '' ] # wglext.h needs Windows include wglPlatformStrings = [ '#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)', '#define WIN32_LEAN_AND_MEAN 1', '#include ', '#endif', '', ] # GLES 1/2/3 core .h have separate *platform.h files to define calling conventions gles1PlatformStrings = [ '#include ', '' ] gles2PlatformStrings = [ '#include ', '' ] gles3PlatformStrings = [ '#include ', '' ] eglPlatformStrings = [ '#include ', '' ] # GLES 1/2 extension .h have small addition to calling convention headers gles1ExtPlatformStrings = gles2ExtPlatformStrings = [ '#ifndef GL_APIENTRYP', '#define GL_APIENTRYP GL_APIENTRY*', '#endif', '' ] # GL_GLEXT_VERSION is defined only in glext.h glextVersionStrings = [ format("#define GL_GLEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # WGL_WGLEXT_VERSION is defined only in wglext.h wglextVersionStrings = [ format("#define WGL_WGLEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # GLX_GLXEXT_VERSION is defined only in glxext.h glxextVersionStrings = [ format("#define GLX_GLXEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # EGL_EGLEXT_VERSION is defined only in eglext.h eglextVersionStrings = [ format("#define EGL_EGLEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # Defaults for generating re-inclusion protection wrappers (or not) protectFile = protect protectFeature = protect protectProto = protect genOpts = CGeneratorOptions( apiname = prefix, profile = 'compatibility', versions = allVersions, emitversions = allVersions, defaultExtensions = prefix, # Default extensions for GL ) # create error/warning & diagnostic files if (errFilename): errWarn = open(errFilename,'w') else: errWarn = sys.stderr diag = open(diagFilename, 'w') # # look for all the SET_ macros in dispatch.h, this is the set of functions # we need to generate # dispatch = {} if dispatchheader : fh = open(dispatchheader) dispatchh = fh.readlines() dispatch_regex = re.compile(r'^SET_(\S*)\(') for line in dispatchh : line = line.strip() m1 = dispatch_regex.search(line) if m1 : dispatch[prefix+m1.group(1)] = 1 del dispatch['glby_offset'] class PreResolveOutputGenerator(OutputGenerator): def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) self.wrappers={} def beginFile(self, genOpts): pass def endFile(self): self.outFile.write('\nvoid ' + prefix + 'ResolveExtensionProcs(void)\n{\n') for funcname in self.wrappers.keys(): self.outFile.write( ' PRERESOLVE(PFN' + funcname.upper() + 'PROC, "' + funcname + '");\n') self.outFile.write('}\n\n') def beginFeature(self, interface, emit): OutputGenerator.beginFeature(self, interface, emit) self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1') def endFeature(self): OutputGenerator.endFeature(self) def genType(self, typeinfo, name): OutputGenerator.genType(self, typeinfo, name) def genEnum(self, enuminfo, name): OutputGenerator.genEnum(self, enuminfo, name) def genCmd(self, cmd, name): OutputGenerator.genCmd(self, cmd, name) if name in WinGDI: return self.outFile.write('RESOLVE_DECL(PFN' + name.upper() + 'PROC);\n') self.wrappers[name]=1 class MyOutputGenerator(OutputGenerator): def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) self.wrappers={} def beginFile(self, genOpts): pass def endFile(self): pass def beginFeature(self, interface, emit): OutputGenerator.beginFeature(self, interface, emit) self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1') def endFeature(self): OutputGenerator.endFeature(self) def genType(self, typeinfo, name): OutputGenerator.genType(self, typeinfo, name) def genEnum(self, enuminfo, name): OutputGenerator.genEnum(self, enuminfo, name) def genCmd(self, cmd, name): OutputGenerator.genCmd(self, cmd, name) # Avoid generating wrappers which aren't referenced by the dispatch table if dispatchheader and not name in dispatch : self.outFile.write('/* No wrapper for ' + name + ', not in dispatch table */\n') return if name in WinGDI: return self.wrappers[name]=1 proto=noneStr(cmd.elem.find('proto')) rettype=noneStr(proto.text) if rettype.lower()!="void ": plist = ([t for t in proto.itertext()]) rettype = ''.join(plist[:-1]) params = cmd.elem.findall('param') plist=[] for param in params: paramlist = ([t for t in param.itertext()]) paramtype = ''.join(paramlist[:-1]) paramname = paramlist[-1] plist.append((paramtype, paramname)) if staticwrappers: self.outFile.write("static ") else: self.outFile.write("%s%sWrapper("%(rettype, name)) Comma="" if len(plist): for ptype, pname in plist: self.outFile.write("%s%s%s_"%(Comma, ptype, pname)) Comma=", " else: self.outFile.write("void") self.outFile.write(");\n") self.outFile.write("%s%sWrapper("%(rettype, name)) Comma="" if len(plist): for ptype, pname in plist: self.outFile.write("%s%s%s_"%(Comma, ptype, pname)) Comma=", " else: self.outFile.write("void") if self.OldVersion: self.outFile.write( """) { if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n"); glWinDirectProcCalls++; """%(prefix.upper(), name)) if rettype.lower()=="void ": self.outFile.write(" %s( "%(name)) else: self.outFile.write(" return %s( "%(name)) Comma="" for ptype, pname in plist: self.outFile.write("%s%s_"%(Comma, pname)) Comma=", " else: if rettype.lower()=="void ": self.outFile.write(""") { RESOLVE(PFN%sPROC, "%s");"""%(name.upper(), name)) self.outFile.write(""" if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n"); """%(prefix.upper(), name)) self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper())) else: self.outFile.write(""") { RESOLVE_RET(PFN%sPROC, "%s", FALSE);"""%(name.upper(), name)) self.outFile.write(""" if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n"); """%(prefix.upper(), name)) self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)( """%(name.upper())) Comma="" for ptype, pname in plist: self.outFile.write("%s%s_"%(Comma, pname)) Comma=", " self.outFile.write(" );\n}\n\n") def genHeaders(): startTimer() outFile = open(outFilename,"w") outFile.write("/* Automatically generated by ./gen_gl_wrappers.py DO NOT EDIT */\n\n") if preresolve: gen = PreResolveOutputGenerator(errFile=errWarn, warnFile=errWarn, diagFile=diag) gen.outFile=outFile reg.setGenerator(gen) reg.apiGen(genOpts) gen = MyOutputGenerator(errFile=errWarn, warnFile=errWarn, diagFile=diag) gen.outFile=outFile reg.setGenerator(gen) reg.apiGen(genOpts) # generate function to setup the dispatch table, which sets each # dispatch table entry to point to it's wrapper function # (assuming we were able to make one) if dispatchheader : outFile.write( 'void glWinSetupDispatchTable(void)\n') outFile.write( '{\n') outFile.write( ' static struct _glapi_table *disp = NULL;\n\n') outFile.write( ' if (!disp)\n') outFile.write( ' {\n') outFile.write( ' disp = calloc(sizeof(void *), _glapi_get_dispatch_table_size());\n') outFile.write( ' assert(disp);\n') for d in sorted(dispatch.keys()) : if d in gen.wrappers : outFile.write(' SET_'+ d[len(prefix):] + '(disp, (void *)' + d + 'Wrapper);\n') else : outFile.write('#warning No wrapper for ' + d + ' !\n') outFile.write( ' }\n\n') outFile.write( ' _glapi_set_dispatch(disp);\n') outFile.write( '}\n') outFile.close() write('** Generated', outFilename) if (debug): pdb.run('genHeaders()') elif (profile): import cProfile, pstats cProfile.run('genHeaders()', 'profile.txt') p = pstats.Stats('profile.txt') p.strip_dirs().sort_stats('time').print_stats(50) else: genHeaders()