1#!/usr/bin/env python
2#
3# Copyright (c) 2013-2014 The Khronos Group Inc.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and/or associated documentation files (the
7# "Materials"), to deal in the Materials without restriction, including
8# without limitation the rights to use, copy, modify, merge, publish,
9# distribute, sublicense, and/or sell copies of the Materials, and to
10# permit persons to whom the Materials are furnished to do so, subject to
11# the following conditions:
12#
13# The above copyright notice and this permission notice shall be included
14# in all copies or substantial portions of the Materials.
15#
16# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
23
24import sys, time, pdb, string, cProfile
25from reg import *
26
27# debug - start header generation in debugger
28# dump - dump registry after loading
29# profile - enable Python profiling
30# protect - whether to use #ifndef protections
31# registry <filename> - use specified XML registry instead of gl.xml
32# target - string name of target header, or all targets if None
33# timeit - time length of registry loading & header generation
34# validate - validate return & parameter group tags against <group>
35debug   = False
36dump    = False
37profile = False
38protect = True
39target  = None
40timeit  = False
41validate= False
42# Default input / log files
43errFilename = None
44diagFilename = 'diag.txt'
45regFilename = 'gl.xml'
46
47if __name__ == '__main__':
48    i = 1
49    while (i < len(sys.argv)):
50        arg = sys.argv[i]
51        i = i + 1
52        if (arg == '-debug'):
53            write('Enabling debug (-debug)', file=sys.stderr)
54            debug = True
55        elif (arg == '-dump'):
56            write('Enabling dump (-dump)', file=sys.stderr)
57            dump = True
58        elif (arg == '-noprotect'):
59            write('Disabling inclusion protection in output headers', file=sys.stderr)
60            protect = False
61        elif (arg == '-profile'):
62            write('Enabling profiling (-profile)', file=sys.stderr)
63            profile = True
64        elif (arg == '-registry'):
65            regFilename = sys.argv[i]
66            i = i+1
67            write('Using registry ', regFilename, file=sys.stderr)
68        elif (arg == '-time'):
69            write('Enabling timing (-time)', file=sys.stderr)
70            timeit = True
71        elif (arg == '-validate'):
72            write('Enabling group validation (-validate)', file=sys.stderr)
73            validate = True
74        elif (arg[0:1] == '-'):
75            write('Unrecognized argument:', arg, file=sys.stderr)
76            exit(1)
77        else:
78            target = arg
79            write('Using target', target, file=sys.stderr)
80
81# Simple timer functions
82startTime = None
83def startTimer():
84    global startTime
85    startTime = time.clock()
86def endTimer(msg):
87    global startTime
88    endTime = time.clock()
89    if (timeit):
90        write(msg, endTime - startTime)
91        startTime = None
92
93# Load & parse registry
94reg = Registry()
95
96startTimer()
97tree = etree.parse(regFilename)
98endTimer('Time to make ElementTree =')
99
100startTimer()
101reg.loadElementTree(tree)
102endTimer('Time to parse ElementTree =')
103
104if (validate):
105    reg.validateGroups()
106
107if (dump):
108    write('***************************************')
109    write('Performing Registry dump to regdump.txt')
110    write('***************************************')
111    reg.dumpReg(filehandle = open('regdump.txt','w'))
112
113# Turn a list of strings into a regexp string matching exactly those strings
114def makeREstring(list):
115    return '^(' + '|'.join(list) + ')$'
116
117# These are "mandatory" OpenGL ES 1 extensions, to
118# be included in the core GLES/gl.h header.
119es1CoreList = [
120    'GL_OES_read_format',
121    'GL_OES_compressed_paletted_texture',
122    'GL_OES_point_size_array',
123    'GL_OES_point_sprite'
124]
125
126# Descriptive names for various regexp patterns used to select
127# versions and extensions
128
129allVersions     = allExtensions = '.*'
130noVersions      = noExtensions = None
131gl12andLaterPat = '1\.[2-9]|[234]\.[0-9]'
132gles2onlyPat    = '2\.[0-9]'
133gles2and30Pat   = '2\.[0-9]|3.0'
134gles2and30and31Pat    = '2.[0-9]|3.[01]'
135es1CorePat      = makeREstring(es1CoreList)
136# Extensions in old glcorearb.h but not yet tagged accordingly in gl.xml
137glCoreARBPat    = None
138glx13andLaterPat = '1\.[3-9]'
139
140# Copyright text prefixing all headers (list of strings).
141prefixStrings = [
142    '/*',
143    '** Copyright (c) 2013-2014 The Khronos Group Inc.',
144    '**',
145    '** Permission is hereby granted, free of charge, to any person obtaining a',
146    '** copy of this software and/or associated documentation files (the',
147    '** "Materials"), to deal in the Materials without restriction, including',
148    '** without limitation the rights to use, copy, modify, merge, publish,',
149    '** distribute, sublicense, and/or sell copies of the Materials, and to',
150    '** permit persons to whom the Materials are furnished to do so, subject to',
151    '** the following conditions:',
152    '**',
153    '** The above copyright notice and this permission notice shall be included',
154    '** in all copies or substantial portions of the Materials.',
155    '**',
156    '** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,',
157    '** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF',
158    '** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.',
159    '** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY',
160    '** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,',
161    '** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE',
162    '** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.',
163    '*/',
164    '/*',
165    '** This header is generated from the Khronos OpenGL / OpenGL ES XML',
166    '** API Registry. The current version of the Registry, generator scripts',
167    '** used to make the header, and the header can be found at',
168    '**   http://www.opengl.org/registry/',
169    '**',
170    '** Khronos $' + 'Revision$ on $' + 'Date$',
171    '*/',
172    ''
173]
174
175# glext.h / glcorearb.h define calling conventions inline (no GL *platform.h)
176glExtPlatformStrings = [
177    '#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)',
178    '#ifndef WIN32_LEAN_AND_MEAN',
179    '#define WIN32_LEAN_AND_MEAN 1',
180    '#endif',
181    '#include <windows.h>',
182    '#endif',
183    '',
184    '#ifndef APIENTRY',
185    '#define APIENTRY',
186    '#endif',
187    '#ifndef APIENTRYP',
188    '#define APIENTRYP APIENTRY *',
189    '#endif',
190    '#ifndef GLAPI',
191    '#define GLAPI extern',
192    '#endif',
193    ''
194]
195
196glCorearbPlatformStrings = glExtPlatformStrings + [
197    '/* glcorearb.h is for use with OpenGL core profile implementations.',
198    '** It should should be placed in the same directory as gl.h and',
199    '** included as <GL/glcorearb.h>.',
200    '**',
201    '** glcorearb.h includes only APIs in the latest OpenGL core profile',
202    '** implementation together with APIs in newer ARB extensions which ',
203    '** can be supported by the core profile. It does not, and never will',
204    '** include functionality removed from the core profile, such as',
205    '** fixed-function vertex and fragment processing.',
206    '**',
207    '** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or',
208    '** <GL/glext.h> in the same source file.',
209    '*/',
210    ''
211]
212
213# wglext.h needs Windows include
214wglPlatformStrings = [
215    '#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)',
216    '#define WIN32_LEAN_AND_MEAN 1',
217    '#include <windows.h>',
218    '#endif',
219    '',
220]
221
222# GLES 1/2/3 core .h have separate *platform.h files to define calling conventions
223gles1PlatformStrings = [ '#include <GLES/glplatform.h>', '' ]
224gles2PlatformStrings = [ '#include <GLES2/gl2platform.h>', '' ]
225gles3PlatformStrings = [ '#include <GLES3/gl3platform.h>', '' ]
226eglPlatformStrings   = [ '#include <EGL/eglplatform.h>', '' ]
227
228# GLES 1/2 extension .h have small addition to calling convention headers
229gles1ExtPlatformStrings = gles2ExtPlatformStrings = [
230    '#ifndef GL_APIENTRYP',
231    '#define GL_APIENTRYP GL_APIENTRY*',
232    '#endif',
233    ''
234]
235
236# Insert generation date in a comment for headers not having *GLEXT_VERSION macros
237genDateCommentString = [
238    format("/* Generated on date %s */" % time.strftime("%Y%m%d")),
239    ''
240]
241
242# GL_GLEXT_VERSION is defined only in glext.h
243glextVersionStrings = [
244    format("#define GL_GLEXT_VERSION %s" % time.strftime("%Y%m%d")),
245    ''
246]
247# WGL_WGLEXT_VERSION is defined only in wglext.h
248wglextVersionStrings = [
249    format("#define WGL_WGLEXT_VERSION %s" % time.strftime("%Y%m%d")),
250    ''
251]
252# GLX_GLXEXT_VERSION is defined only in glxext.h
253glxextVersionStrings = [
254    format("#define GLX_GLXEXT_VERSION %s" % time.strftime("%Y%m%d")),
255    ''
256]
257# EGL_EGLEXT_VERSION is defined only in eglext.h
258eglextVersionStrings = [
259    format("#define EGL_EGLEXT_VERSION %s" % time.strftime("%Y%m%d")),
260    ''
261]
262
263# Defaults for generating re-inclusion protection wrappers (or not)
264protectFile = protect
265protectFeature = protect
266protectProto = protect
267
268buildList = [
269    # GL API 1.2+ + extensions - GL/glext.h
270    CGeneratorOptions(
271        filename          = 'GL/glext.h',
272        apiname           = 'gl',
273        profile           = 'compatibility',
274        versions          = allVersions,
275        emitversions      = gl12andLaterPat,
276        defaultExtensions = 'gl',                   # Default extensions for GL
277        addExtensions     = None,
278        removeExtensions  = None,
279        prefixText        = prefixStrings + glExtPlatformStrings + glextVersionStrings,
280        genFuncPointers   = True,
281        protectFile       = protectFile,
282        protectFeature    = protectFeature,
283        protectProto      = protectProto,
284        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
285        apicall           = 'GLAPI ',
286        apientry          = 'APIENTRY ',
287        apientryp         = 'APIENTRYP '),
288    # GL core profile + extensions - GL/glcorearb.h
289    CGeneratorOptions(
290        filename          = 'GL/glcorearb.h',
291        apiname           = 'gl',
292        profile           = 'core',
293        versions          = allVersions,
294        emitversions      = allVersions,
295        defaultExtensions = 'glcore',               # Default extensions for GL core profile (only)
296        addExtensions     = glCoreARBPat,
297        removeExtensions  = None,
298        prefixText        = prefixStrings + glCorearbPlatformStrings,
299        genFuncPointers   = True,
300        protectFile       = protectFile,
301        protectFeature    = protectFeature,
302        protectProto      = protectProto,
303        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
304        apicall           = 'GLAPI ',
305        apientry          = 'APIENTRY ',
306        apientryp         = 'APIENTRYP '),
307    # GLES 1.x API + mandatory extensions - GLES/gl.h (no function pointers)
308    CGeneratorOptions(
309        filename          = 'GLES/gl.h',
310        apiname           = 'gles1',
311        profile           = 'common',
312        versions          = allVersions,
313        emitversions      = allVersions,
314        defaultExtensions = None,                   # No default extensions
315        addExtensions     = es1CorePat,             # Add mandatory ES1 extensions in GLES1/gl.h
316        removeExtensions  = None,
317        prefixText        = prefixStrings + gles1PlatformStrings + genDateCommentString,
318        genFuncPointers   = False,
319        protectFile       = protectFile,
320        protectFeature    = protectFeature,
321        protectProto      = False,                  # Core ES API functions are in the static link libraries
322        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
323        apicall           = 'GL_API ',
324        apientry          = 'GL_APIENTRY ',
325        apientryp         = 'GL_APIENTRYP '),
326    # GLES 1.x extensions - GLES/glext.h
327    CGeneratorOptions(
328        filename          = 'GLES/glext.h',
329        apiname           = 'gles1',
330        profile           = 'common',
331        versions          = allVersions,
332        emitversions      = noVersions,
333        defaultExtensions = 'gles1',                # Default extensions for GLES 1
334        addExtensions     = None,
335        removeExtensions  = es1CorePat,             # Remove mandatory ES1 extensions in GLES1/glext.h
336        prefixText        = prefixStrings + gles1ExtPlatformStrings + genDateCommentString,
337        genFuncPointers   = True,
338        protectFile       = protectFile,
339        protectFeature    = protectFeature,
340        protectProto      = protectProto,
341        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
342        apicall           = 'GL_API ',
343        apientry          = 'GL_APIENTRY ',
344        apientryp         = 'GL_APIENTRYP '),
345    # GLES 2.0 API - GLES2/gl2.h (no function pointers)
346    CGeneratorOptions(
347        filename          = 'GLES2/gl2.h',
348        apiname           = 'gles2',
349        profile           = 'common',
350        versions          = gles2onlyPat,
351        emitversions      = allVersions,
352        defaultExtensions = None,                   # No default extensions
353        addExtensions     = None,
354        removeExtensions  = None,
355        prefixText        = prefixStrings + gles2PlatformStrings + genDateCommentString,
356        genFuncPointers   = False,
357        protectFile       = protectFile,
358        protectFeature    = protectFeature,
359        protectProto      = False,                  # Core ES API functions are in the static link libraries
360        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
361        apicall           = 'GL_APICALL ',
362        apientry          = 'GL_APIENTRY ',
363        apientryp         = 'GL_APIENTRYP '),
364    # GLES 3.1 / 3.0 / 2.0 extensions - GLES2/gl2ext.h
365    CGeneratorOptions(
366        filename          = 'GLES2/gl2ext.h',
367        apiname           = 'gles2',
368        profile           = 'common',
369        versions          = gles2onlyPat,
370        emitversions      = None,
371        defaultExtensions = 'gles2',                # Default extensions for GLES 2
372        addExtensions     = None,
373        removeExtensions  = None,
374        prefixText        = prefixStrings + gles2ExtPlatformStrings + genDateCommentString,
375        genFuncPointers   = True,
376        protectFile       = protectFile,
377        protectFeature    = protectFeature,
378        protectProto      = protectProto,
379        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
380        apicall           = 'GL_APICALL ',
381        apientry          = 'GL_APIENTRY ',
382        apientryp         = 'GL_APIENTRYP '),
383    # GLES 3.1 API - GLES3/gl31.h (no function pointers)
384    CGeneratorOptions(
385        filename          = 'GLES3/gl31.h',
386        apiname           = 'gles2',
387        profile           = 'common',
388        versions          = gles2and30and31Pat,
389        emitversions      = allVersions,
390        defaultExtensions = None,                   # No default extensions
391        addExtensions     = None,
392        removeExtensions  = None,
393        prefixText        = prefixStrings + gles3PlatformStrings + genDateCommentString,
394        genFuncPointers   = False,
395        protectFile       = protectFile,
396        protectFeature    = protectFeature,
397        protectProto      = False,                  # Core ES API functions are in the static link libraries
398        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
399        apicall           = 'GL_APICALL ',
400        apientry          = 'GL_APIENTRY ',
401        apientryp         = 'GL_APIENTRYP '),
402    # GLES 3.0 API - GLES3/gl3.h (no function pointers)
403    CGeneratorOptions(
404        filename          = 'GLES3/gl3.h',
405        apiname           = 'gles2',
406        profile           = 'common',
407        versions          = gles2and30Pat,
408        emitversions      = allVersions,
409        defaultExtensions = None,                   # No default extensions
410        addExtensions     = None,
411        removeExtensions  = None,
412        prefixText        = prefixStrings + gles3PlatformStrings + genDateCommentString,
413        genFuncPointers   = False,
414        protectFile       = protectFile,
415        protectFeature    = protectFeature,
416        protectProto      = False,                  # Core ES API functions are in the static link libraries
417        protectProtoStr   = 'GL_GLEXT_PROTOTYPES',
418        apicall           = 'GL_APICALL ',
419        apientry          = 'GL_APIENTRY ',
420        apientryp         = 'GL_APIENTRYP '),
421    # EGL API - EGL/egl.h (no function pointers, yet @@@)
422    CGeneratorOptions(
423        filename          = 'EGL/egl.h',
424        apiname           = 'egl',
425        profile           = None,
426        versions          = allVersions,
427        emitversions      = allVersions,
428        defaultExtensions = None,                   # No default extensions
429        addExtensions     = None,
430        removeExtensions  = None,
431        prefixText        = prefixStrings + eglPlatformStrings + genDateCommentString,
432        genFuncPointers   = False,
433        protectFile       = protectFile,
434        protectFeature    = protectFeature,
435        protectProto      = False,
436        protectProtoStr   = 'EGL_EGLEXT_PROTOTYPES',
437        apicall           = 'EGLAPI ',
438        apientry          = 'EGLAPIENTRY ',
439        apientryp         = 'EGLAPIENTRYP '),
440    # EGL extensions - EGL/eglext.h (no function pointers, yet @@@)
441    CGeneratorOptions(
442        filename          = 'EGL/eglext.h',
443        apiname           = 'egl',
444        profile           = None,
445        versions          = allVersions,
446        emitversions      = None,
447        defaultExtensions = 'egl',                  # Default extensions for EGL
448        addExtensions     = None,
449        removeExtensions  = None,
450        prefixText        = prefixStrings + eglPlatformStrings + eglextVersionStrings,
451        genFuncPointers   = True,
452        protectFile       = protectFile,
453        protectFeature    = protectFeature,
454        protectProto      = protectProto,
455        protectProtoStr   = 'EGL_EGLEXT_PROTOTYPES',
456        apicall           = 'EGLAPI ',
457        apientry          = 'EGLAPIENTRY ',
458        apientryp         = 'EGLAPIENTRYP '),
459    # GLX 1.* API - GL/glx.h
460    CGeneratorOptions(
461        filename          = 'GL/glx.h',
462        apiname           = 'glx',
463        profile           = None,
464        versions          = allVersions,
465        emitversions      = allVersions,
466        defaultExtensions = None,                   # No default extensions
467        addExtensions     = None,
468        removeExtensions  = None,
469        # add glXPlatformStrings?
470        prefixText        = prefixStrings + genDateCommentString,
471        genFuncPointers   = True,
472        protectFile       = protectFile,
473        protectFeature    = protectFeature,
474        protectProto      = protectProto,
475        protectProtoStr   = 'GLX_GLXEXT_PROTOTYPES',
476        apicall           = '',
477        apientry          = '',
478        apientryp         = ' *'),
479    # GLX 1.3+ API + extensions - GL/glxext.h (no function pointers, yet @@@)
480    CGeneratorOptions(
481        filename          = 'GL/glxext.h',
482        apiname           = 'glx',
483        profile           = None,
484        versions          = allVersions,
485        emitversions      = glx13andLaterPat,
486        defaultExtensions = 'glx',                  # Default extensions for GLX
487        addExtensions     = None,
488        removeExtensions  = None,
489        # add glXPlatformStrings?
490        prefixText        = prefixStrings + glxextVersionStrings,
491        genFuncPointers   = True,
492        protectFile       = protectFile,
493        protectFeature    = protectFeature,
494        protectProto      = protectProto,
495        protectProtoStr   = 'GLX_GLXEXT_PROTOTYPES',
496        apicall           = '',
497        apientry          = '',
498        apientryp         = ' *'),
499    # WGL API + extensions - GL/wgl.h (no function pointers, yet @@@)
500    CGeneratorOptions(
501        filename          = 'GL/wgl.h',
502        apiname           = 'wgl',
503        profile           = None,
504        versions          = allVersions,
505        emitversions      = allVersions,
506        defaultExtensions = 'wgl',                  # Default extensions for WGL
507        addExtensions     = None,
508        removeExtensions  = None,
509        prefixText        = prefixStrings + wglPlatformStrings + genDateCommentString,
510        genFuncPointers   = True,
511        protectFile       = protectFile,
512        protectFeature    = protectFeature,
513        protectProto      = protectProto,
514        protectProtoStr   = 'WGL_WGLEXT_PROTOTYPES',
515        apicall           = '',
516        apientry          = 'WINAPI ',
517        apientryp         = 'WINAPI * '),
518    # WGL extensions - GL/wglext.h (no function pointers, yet @@@)
519    CGeneratorOptions(
520        filename          = 'GL/wglext.h',
521        apiname           = 'wgl',
522        profile           = None,
523        versions          = allVersions,
524        emitversions      = None,
525        defaultExtensions = 'wgl',                  # Default extensions for WGL
526        addExtensions     = None,
527        removeExtensions  = None,
528        prefixText        = prefixStrings + wglPlatformStrings + wglextVersionStrings,
529        genFuncPointers   = True,
530        protectFile       = protectFile,
531        protectFeature    = protectFeature,
532        protectProto      = protectProto,
533        protectProtoStr   = 'WGL_WGLEXT_PROTOTYPES',
534        apicall           = '',
535        apientry          = 'WINAPI ',
536        apientryp         = 'WINAPI * '),
537    # End of list
538    None
539]
540
541# create error/warning & diagnostic files
542if (errFilename):
543    errWarn = open(errFilename,'w')
544else:
545    errWarn = sys.stderr
546diag = open(diagFilename, 'w')
547
548def genHeaders():
549    # Loop over targets, building each
550    generated = 0
551    for genOpts in buildList:
552        if (genOpts == None):
553            break
554        if (target and target != genOpts.filename):
555            # write('*** Skipping', genOpts.filename)
556            continue
557        write('*** Building', genOpts.filename)
558        generated = generated + 1
559        startTimer()
560        gen = COutputGenerator(errFile=errWarn,
561                               warnFile=errWarn,
562                               diagFile=diag)
563        reg.setGenerator(gen)
564        reg.apiGen(genOpts)
565        write('** Generated', genOpts.filename)
566        endTimer('Time to generate ' + genOpts.filename + ' =')
567    if (target and generated == 0):
568        write('Failed to generate target:', target)
569
570if (debug):
571    pdb.run('genHeaders()')
572elif (profile):
573    import cProfile, pstats
574    cProfile.run('genHeaders()', 'profile.txt')
575    p = pstats.Stats('profile.txt')
576    p.strip_dirs().sort_stats('time').print_stats(50)
577else:
578    genHeaders()
579