]> git.tdb.fi Git - libs/gl.git/commitdiff
Deal with extensions that are not present at compile time
authorMikko Rasa <tdb@tdb.fi>
Wed, 2 Oct 2013 17:43:24 +0000 (20:43 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 2 Oct 2013 17:43:24 +0000 (20:43 +0300)
scripts/extgen.py

index 0bf6bd67aa19ad5bfd96a574c39147063e7e06e1..4333cf37345f176d06fdf52abe2e6f30d8cc1f0c 100755 (executable)
@@ -4,6 +4,7 @@ import sys
 import os
 import xml.dom
 import xml.dom.minidom
+import itertools
 
 ### Command line processing ###
 
@@ -53,17 +54,30 @@ if not out_base:
 
 ### XML file parsing ###
 
-class Function:
-       def __init__(self, name):
+class Thing:
+       FUNCTION = 1
+       ENUM = 2
+
+       def __init__(self, name, kind):
                self.name = name
-               self.typedef = None
+               self.kind = kind
                self.version = None
                self.extension = None
-               self.vectorequiv = None
                self.aliases = []
-               self.extfunc = None
+               self.source = None
+
+class Function(Thing):
+       def __init__(self, name):
+               Thing.__init__(self, name, Thing.FUNCTION)
+               self.typedef = None
+               self.vectorequiv = None
+
+class Enum(Thing):
+       def __init__(self, name):
+               Thing.__init__(self, name, Thing.ENUM)
+               self.value = 0
 
-funcs = {}
+things = {}
 
 def get_nested_elements(elem, path):
        if '/' in path:
@@ -90,10 +104,10 @@ def parse_file(fn):
        commands = get_nested_elements(root, "commands/command")
        for cmd in commands:
                name = get_text_contents(get_nested_elements(cmd, "proto/name")[0])
-               func = funcs.get(name)
+               func = things.get(name)
                if not func:
                        func = Function(name)
-                       funcs[name] = func
+                       things[name] = func
 
                aliases = cmd.getElementsByTagName("alias")
                for a in aliases:
@@ -103,6 +117,16 @@ def parse_file(fn):
                if vec:
                        func.vectorequiv = vec[0].getAttribute("name")
 
+       enums = get_nested_elements(root, "enums/enum")
+       for en in enums:
+               name = en.getAttribute("name")
+               enum = things.get(name)
+               if not enum:
+                       enum = Enum(name)
+                       things[name] = enum
+
+               enum.value = int(en.getAttribute("value"), 16)
+
        features = root.getElementsByTagName("feature")
        for feat in features:
                api = feat.getAttribute("api")
@@ -110,18 +134,20 @@ def parse_file(fn):
                        version = feat.getAttribute("number")
 
                        commands = get_nested_elements(feat, "require/command")
-                       for c in commands:
-                               name = c.getAttribute("name")
-                               func = funcs.get(name)
-                               if func:
-                                       func.version = version
+                       enums = get_nested_elements(feat, "require/enum")
+                       for t in itertools.chain(commands, enums):
+                               name = t.getAttribute("name")
+                               thing = things.get(name)
+                               if thing:
+                                       thing.version = version
 
                        if feat.getAttribute("name")=="MSPGL_REMOVE":
                                commands = get_nested_elements(feat, "remove/command")
-                               for c in commands:
-                                       name = c.getAttribute("name")
-                                       if name in funcs:
-                                               del funcs[name]
+                               enums = get_nested_elements(feat, "require/enum")
+                               for t in itertools.chain(commands, enums):
+                                       name = t.getAttribute("name")
+                                       if name in things:
+                                               del things[name]
 
        extensions = get_nested_elements(root, "extensions/extension")
        for ext in extensions:
@@ -131,53 +157,67 @@ def parse_file(fn):
                supported = ext.getAttribute("supported").split('|')
                if "gl" in supported:
                        commands = get_nested_elements(ext, "require/command")
-                       for c in commands:
-                               name = c.getAttribute("name")
-                               func = funcs.get(name)
-                               if func:
-                                       func.extension = ext_name
+                       enums = get_nested_elements(ext, "require/enum")
+                       for t in itertools.chain(commands, enums):
+                               name = t.getAttribute("name")
+                               thing = things.get(name)
+                               if thing:
+                                       thing.extension = ext_name
 
 parse_file("gl.xml")
 parse_file("gl.fixes.xml")
 
 ### Additional processing ###
 
-# Create references from core functions to their extension counterparts
-for f in funcs.itervalues():
-       if f.extension==ext or f.extension in secondary:
-               for a in f.aliases:
-                       aliasfunc = funcs.get(a)
-                       if aliasfunc:
-                               aliasfunc.extfunc = f
-
-def is_relevant(f):
-       # Unpromoted extension functions are relevant
-       if f.extension==ext and not f.aliases:
+# Find aliases for enums
+enums = [t for t in things.itervalues() if t.kind==Thing.ENUM]
+core_enums_by_value = dict((e.value, e) for e in enums if e.version)
+
+for e in enums:
+       if e.kind==t.ENUM and e.extension:
+               ce = core_enums_by_value.get(e.value)
+               if ce and ce!=e:
+                       e.aliases.append(ce.name)
+
+# Create references from core things to their extension counterparts
+for t in things.itervalues():
+       if t.extension==ext or t.extension in secondary:
+               for a in t.aliases:
+                       alias = things.get(a)
+                       if alias:
+                               alias.source = t
+
+def is_relevant(t):
+       # Unpromoted extension things are relevant
+       if t.extension==ext and not t.aliases:
                return True
 
-       # Core functions promoted from the extension are also relevant
-       if f.extfunc:
-               e = f.extfunc
+       # Core things promoted from the extension are also relevant
+       if t.source:
+               e = t.source
                if e.extension==ext or e.extension in secondary:
                        return True
 
        return False
 
-funcs = [f for f in funcs.itervalues() if is_relevant(f)]
+funcs = [t for t in things.itervalues() if t.kind==Thing.FUNCTION and is_relevant(t)]
 funcs.sort(key=(lambda f: f.name))
+enums = [e for e in enums if is_relevant(e)]
+enums.sort(key=(lambda e: e.value))
 
-for f in funcs:
+for t in itertools.chain(funcs, enums):
        if not ver:
-               ver = f.version
+               ver = t.version
 
-       # Functions in backport extensions don't acquire an extension suffix
-       if f.extension and not f.name.endswith(exttype):
-               backport_ext = f.extension
+       # Things in backport extensions don't acquire an extension suffix
+       if t.extension and not t.name.endswith(exttype):
+               backport_ext = t.extension
 
-       if f.extfunc:
+for f in funcs:
+       if f.source:
                # Typedefs for early core functions are not available in all
                # implementations
-               f.typedef = "PFN%sPROC"%f.extfunc.name.upper()
+               f.typedef = "PFN%sPROC"%f.source.name.upper()
        else:
                f.typedef = "PFN%sPROC"%f.name.upper()
 
@@ -198,10 +238,17 @@ namespace Msp {
 namespace GL {
 """)
 
-if funcs:
-       out.write("\n")
-for f in funcs:
-       out.write("extern %s %s;\n"%(f.typedef, f.name))
+if funcs or enums:
+       out.write("\n#ifndef GL_%s\n"%ext)
+       for f in funcs:
+               out.write("typedef int (*%s)(...);\n"%f.typedef)
+       if funcs and enums:
+               out.write("\n")
+       for e in enums:
+               out.write("#define %s 0x%04X\n"%(e.name, e.value))
+       out.write("#endif\n\n")
+       for f in funcs:
+               out.write("extern %s %s;\n"%(f.typedef, f.name))
 
 out.write("\nextern Extension %s;\n"%ext)
 
@@ -226,6 +273,7 @@ for f in funcs:
        out.write("%s %s = 0;\n"%(f.typedef, f.name))
 
 out.write("\nExtension::SupportLevel init_%s()\n{\n"%ext.lower())
+out.write("#ifdef GL_%s\n"%ext)
 if ver:
        out.write("\tif(is_version_at_least(%d, %d)"%tuple(ver))
        if backport_ext:
@@ -239,11 +287,12 @@ if ext!=backport_ext:
        out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(ext))
        for f in funcs:
                n = f.name
-               if f.extfunc:
-                       n = f.extfunc.name
+               if f.source:
+                       n = f.source.name
                out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, n))
        out.write("\t\treturn Extension::EXTENSION;\n")
        out.write("\t}\n")
+out.write("#endif\n")
 out.write("\treturn Extension::UNSUPPORTED;\n")
 out.write("}\n")