1#!/usr/bin/python 2# 3# Comedy python script to generate cdecl to stdcall wrappers for GL functions 4# 5# This is designed to operate on OpenGL spec files from 6# http://www.opengl.org/registry/api/ 7# 8# 9# Copyright (c) Jon TURNEY 2009 10# 11# Permission is hereby granted, free of charge, to any person obtaining a 12# copy of this software and associated documentation files (the "Software"), 13# to deal in the Software without restriction, including without limitation 14# the rights to use, copy, modify, merge, publish, distribute, sublicense, 15# and/or sell copies of the Software, and to permit persons to whom the 16# Software is furnished to do so, subject to the following conditions: 17# 18# The above copyright notice and this permission notice shall be included in 19# all copies or substantial portions of the Software. 20# 21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24# THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 25# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27# DEALINGS IN THE SOFTWARE. 28# 29# Except as contained in this notice, the name(s) of the above copyright 30# holders shall not be used in advertising or otherwise to promote the sale, 31# use or other dealings in this Software without prior written authorization. 32# 33 34import sys 35import re 36import getopt 37 38dispatchheader = '' 39prefix = 'gl' 40preresolve = False 41staticwrappers = False 42 43opts, args = getopt.getopt(sys.argv[1:], "", ['spec=', 'typemap=', 'dispatch-header=', 'prefix=', 'preresolve', 'staticwrappers' ]) 44 45for o,a in opts: 46 if o == '--typemap' : 47 typemapfile = a 48 elif o == '--dispatch-header' : 49 dispatchheader = a 50 elif o == '--spec' : 51 specfile = a 52 elif o == '--prefix' : 53 prefix = a 54 elif o == '--preresolve' : 55 preresolve = True 56 elif o == '--staticwrappers' : 57 staticwrappers = True 58 59# 60# look for all the SET_ macros in dispatch.h, this is the set of functions 61# we need to generate 62# 63 64dispatch = {} 65 66if dispatchheader : 67 fh = open(dispatchheader) 68 dispatchh = fh.readlines() 69 70 dispatch_regex = re.compile(r'#define\sSET_(\S*)\(') 71 72 for line in dispatchh : 73 line = line.strip() 74 m1 = dispatch_regex.search(line) 75 76 if m1 : 77 dispatch[m1.group(1)] = 1 78 79 del dispatch['by_offset'] 80 81# 82# read the typemap .tm file 83# 84 85typemap = {} 86 87fh = open(typemapfile) 88tm = fh.readlines() 89 90typemap_regex = re.compile(r'#define\sSET_(\S*)\(') 91 92for line in tm : 93 # ignore everything after a '#' as a comment 94 hash = line.find('#') 95 if hash != -1 : 96 line = line[:hash-1] 97 98 # ignore blank lines 99 if line.startswith('#') or len(line) == 0 : 100 continue 101 102 l = line.split(',') 103 typemap[l[0]] = l[3].strip() 104 105# interestingly, * is not a C type 106if typemap['void'] == '*' : 107 typemap['void'] = 'void' 108 109# 110# crudely parse the .spec file 111# 112 113r1 = re.compile(r'\t(\S*)\s+(\S*.*)') 114r2 = re.compile(r'(.*)\((.*)\)') 115r3 = re.compile(r'glWindowPos.*MESA') 116r4 = re.compile(r'gl.*Program(s|)NV') 117r5 = re.compile(r'glGetVertexAttribfvNV') 118 119wrappers = {} 120 121fh = open(specfile) 122glspec = fh.readlines() 123param_count = 0 124 125for line in glspec : 126 line = line.rstrip() 127 128 # ignore everything after a '#' as a comment 129 hash = line.find('#') 130 if hash != -1 : 131 line = line[:hash-1] 132 133 # ignore blank lines 134 if line.startswith('#') or len(line) == 0 : 135 continue 136 137 # lines containing ':' aren't intersting to us 138 if line.count(':') != 0 : 139 continue 140 141 # attributes of each function follow the name, indented by a tab 142 if not line.startswith('\t') : 143 m1 = r2.search(line) 144 if m1 : 145 function = m1.group(1) 146 arglist_use = m1.group(2) 147 wrappers[function] = {} 148 149 # near and far might be reserved words or macros so can't be used as formal parameter names 150 arglist_use = arglist_use.replace('near','zNear') 151 arglist_use = arglist_use.replace('far','zFar') 152 153 wrappers[function]['arglist_use'] = arglist_use 154 param_count = 0 155 else : 156 m1 = r1.search(line) 157 if m1 : 158 attribute = m1.group(1) 159 value = m1.group(2) 160 161 # make param attributes unique and ordered 162 if attribute == 'param' : 163 attribute = 'param' + '%02d' % param_count 164 param_count += 1 165 166 wrappers[function][attribute] = value 167 168# 169# now emit code 170# 171 172print '/* Automatically generated by ' + sys.argv[0] + ' DO NOT EDIT */' 173print '/* from ' + specfile + ' and typemap ' + typemapfile + ' */' 174print '' 175 176# 177# if required, emit code for non-lazy function resolving 178# 179 180if preresolve : 181 for w in sorted(wrappers.keys()) : 182 funcname = prefix + w 183 print 'RESOLVE_DECL(PFN' + funcname.upper() + 'PROC);' 184 185 print '' 186 print 'void ' + prefix + 'ResolveExtensionProcs(void)' 187 print '{' 188 189 for w in sorted(wrappers.keys()) : 190 funcname = prefix + w 191 print ' PRERESOLVE(PFN' + funcname.upper() + 'PROC, "' + funcname + '");' 192 193 print '}\n' 194 195# 196# now emit the wrappers 197# for GL 1.0 and 1.1 functions, generate stdcall wrappers which call the function directly 198# for GL 1.2+ functions, generate wrappers which use wglGetProcAddress() 199# 200 201for w in sorted(wrappers.keys()) : 202 203 funcname = prefix + w 204 returntype = wrappers[w]['return'] 205 if returntype != 'void' : 206 returntype = typemap[returntype] 207 208 # Avoid generating wrappers which aren't referenced by the dispatch table 209 if dispatchheader and not dispatch.has_key(w) : 210 print '/* No wrapper for ' + funcname + ', not in dispatch table */' 211 continue 212 213 # manufacture arglist 214 # if no param attributes were found, it should be 'void' 215 al = [] 216 for k in sorted(wrappers[w].keys()) : 217 if k.startswith('param') : 218 l = wrappers[w][k].split() 219 220 # near and far might be reserved words or macros so can't be used as formal parameter names 221 l[0] = l[0].replace('near','zNear') 222 l[0] = l[0].replace('far','zFar') 223 224 if l[2] == 'in' : 225 if l[3] == 'array' : 226 arg = 'const ' + typemap[l[1]] + ' *' + l[0] 227 else : 228 arg = typemap[l[1]] + ' ' + l[0] 229 elif l[2] == 'out' : 230 arg = typemap[l[1]] + ' *' + l[0] 231 232 al.append(arg) 233 234 if len(al) == 0 : 235 arglist = 'void' 236 else: 237 arglist = ', '.join(al) 238 239 if wrappers[w]['category'].startswith('VERSION_1_0') or wrappers[w]['category'].startswith('VERSION_1_1') : 240 if staticwrappers : 241 print 'static', 242 print returntype + ' ' + funcname + 'Wrapper(' + arglist + ')' 243 print '{' 244 print ' if (glxWinDebugSettings.enable' + prefix.upper() + 'callTrace) ErrorF("'+ funcname + '\\n");' 245 print ' glWinDirectProcCalls++;' 246 if returntype.lower() == 'void' : 247 print ' ' + funcname + '(', 248 else : 249 print ' /* returntype was ' + returntype.lower() + '*/' 250 print ' return ' + funcname + '(', 251 252 if arglist != 'void' : 253 print wrappers[w]['arglist_use'], 254 255 print ');' 256 print "}\n" 257 else: 258 if staticwrappers : 259 print 'static', 260 print returntype + ' ' + funcname + 'Wrapper(' + arglist + ')' 261 print '{' 262 263 stringname = funcname 264 265# 266# special case: Windows OpenGL implementations are far more likely to have GL_ARB_window_pos than GL_MESA_window_pos, 267# so arrange for the wrapper to use the ARB strings to find functions... 268# 269 270 m2 = r3.search(funcname) 271 if m2 : 272 stringname = stringname.replace('MESA','ARB') 273 274# 275# special case: likewise, implementations are more likely to have GL_ARB_vertex_program than GL_NV_vertex_program, 276# especially if they are not NV implementations, so arrange for the wrapper to use ARB strings to find functions 277# 278 279 m3 = r4.search(funcname) 280 if m3 : 281 stringname = stringname.replace('NV','ARB') 282 m4 = r5.search(funcname) 283 if m4 : 284 stringname = stringname.replace('NV','ARB') 285 286 pfntypename = 'PFN' + funcname.upper() + 'PROC' 287 288 if returntype.lower() == 'void' : 289 print ' RESOLVE(' + pfntypename + ', "' + stringname + '");' 290 print ' if (glxWinDebugSettings.enable' + prefix.upper() + 'callTrace) ErrorF("'+ funcname + '\\n");' 291 print ' RESOLVED_PROC(' + pfntypename + ')(', 292 else : 293 print ' RESOLVE_RET(' + pfntypename + ', "' + stringname + '", FALSE);' 294 print ' if (glxWinDebugSettings.enable' + prefix.upper() + 'callTrace) ErrorF("'+ funcname + '\\n");' 295 print ' return RESOLVED_PROC(' + pfntypename + ')(', 296 297 if arglist != 'void' : 298 print wrappers[w]['arglist_use'], 299 300 print ');' 301 print "}\n" 302 303 304# generate function to setup the dispatch table, which sets each 305# dispatch table entry to point to it's wrapper function 306# (assuming we were able to make one) 307 308if dispatchheader : 309 print 'void glWinSetupDispatchTable(void)' 310 print '{' 311 print ' struct _glapi_table *disp = _glapi_get_dispatch();' 312 313 for d in sorted(dispatch.keys()) : 314 if wrappers.has_key(d) : 315 print ' SET_'+ d + '(disp, ' + prefix + d + 'Wrapper);' 316 else : 317 print '#warning No wrapper for ' + prefix + d + ' !' 318 319 print '}' 320