]> git.tdb.fi Git - libs/gl.git/commitdiff
Enhance the extension generator to support different APIs
authorMikko Rasa <tdb@tdb.fi>
Wed, 15 Oct 2014 15:54:16 +0000 (18:54 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 15 Oct 2014 16:13:44 +0000 (19:13 +0300)
extensions/arb_fragment_shader.glext
extensions/arb_pixel_buffer_object.glext
extensions/arb_texture_cube_map.glext
extensions/arb_texture_float.glext
extensions/arb_uniform_buffer_object.glext
extensions/ext_bgra.glext
extensions/ext_blend_subtract.glext
scripts/extgen.py

index ac02f71f5a0bbaa61404b040e4ce30ae579c8a46..30961f5617329c97c8fd2d96612d7528832f3e3e 100644 (file)
@@ -1,2 +1,2 @@
 extension ARB_fragment_shader
-core_version 2.0
+core_version gl 2.0
index c11586d85d646d31c015260caf689c2c501450eb..b36e7f128497297701177ccd3a5b8c0c0c8b0204 100644 (file)
@@ -1,2 +1,2 @@
 extension ARB_pixel_buffer_object
-core_version 2.1
+core_version gl 2.1
index 16a6a929f51e635abcc295e9c365d915bec2eb54..8874530792c325284002b04c72880ce0532edf54 100644 (file)
@@ -1,2 +1,2 @@
 extension ARB_texture_cube_map
-core_version 1.3
+core_version gl 1.3
index bb379fdf1cbce06273522b94b858d5eea6560837..24f42c2f70e3a39fdaf447d1ead14abb970db393 100644 (file)
@@ -1,2 +1,2 @@
 extension ARB_texture_float
-core_version 3.0
+core_version gl 3.0
index c6b1b443ab22be314dea7b3e1b4de3ab1d4802f0..8e0e93105c802e237eecf43e634d215822bdb48c 100644 (file)
@@ -1,2 +1,2 @@
 extension ARB_uniform_buffer_object
-core_version 3.0
+core_version gl 3.0
index b449b888d9a6a9aadb16a76f7a891159e7c2400a..2ba56750b8102856bbfbac44e7adb5e6bcc6a0a1 100644 (file)
@@ -1,2 +1,2 @@
 extension EXT_bgra
-core_version 1.2
+core_version gl 1.2
index 312119daa990d81bb2c7fe0b2f55b2b70b1d8d47..0e89f4d247964ffa7b70a36085e7e5579f5c80df 100644 (file)
@@ -1,2 +1,2 @@
 extension EXT_blend_subtract
-core_version 1.2
+core_version gl 1.2
index c8f87c3bf79278bb98e5e1342912f66570752cab..fbb66815ae1de93102485065bace98bde781b05f 100755 (executable)
@@ -10,8 +10,8 @@ import itertools
 
 if len(sys.argv)<2:
        print """Usage:
-  extgen.py <extension> [<core_version>] [<secondary> ...]
-  extgen.py <extfile> [<outfile>]
+  extgen.py [api] <extension> [<core_version>] [<secondary> ...]
+  extgen.py [api] <extfile> [<outfile>]
 
 Reads gl.xml and generates files to use <extension>.  Any promoted functions
 are exposed with their promoted names.  If <secondary> extensions are given,
@@ -23,7 +23,14 @@ absent, the extension's lowercased name is used.  Anything after the last dot
 in <outfile> is removed and replaced with cpp and h."""
        sys.exit(0)
 
-target_ext = sys.argv[1]
+target_api = "gl"
+
+i = 1
+if sys.argv[i].startswith("gl"):
+       target_api = sys.argv[i]
+       i += 1
+
+target_ext = sys.argv[i]
 out_base = None
 if target_ext.endswith(".glext"):
        fn = target_ext
@@ -35,13 +42,14 @@ if target_ext.endswith(".glext"):
                if parts[0]=="extension":
                        target_ext = parts[1]
                elif parts[0]=="core_version":
-                       core_version = parts[1]
+                       if parts[1]==target_api:
+                               core_version = parts[2]
                elif parts[0]=="secondary":
                        secondary.append(parts[1])
-       if len(sys.argv)>=3:
-               out_base = os.path.splitext(sys.argv[2])[0]
+       if i+1<len(sys.argv):
+               out_base = os.path.splitext(sys.argv[i+1])[0]
 else:
-       secondary = sys.argv[2:]
+       secondary = sys.argv[i+1:]
        core_version = None
        if secondary and secondary[0][0].isdigit():
                core_version = secondary.pop(0)
@@ -66,8 +74,9 @@ class Thing:
                self.kind = kind
                self.version = None
                self.extension = None
+               self.supported_apis = {}
                self.aliases = []
-               self.source = None
+               self.sources = []
 
 class Function(Thing):
        def __init__(self, name):
@@ -80,7 +89,15 @@ class Enum(Thing):
        def __init__(self, name):
                Thing.__init__(self, name, Thing.ENUM)
                self.value = 0
+               self.bitmask = (name.endswith("_BIT") or "_BIT_" in name)
 
+class Extension:
+       def __init__(self, name):
+               self.name = name
+               self.supported_apis = []
+               self.ext_type = name[0:name.find('_')]
+
+extensions = {}
 things = {}
 
 def get_nested_elements(elem, path):
@@ -144,27 +161,32 @@ def parse_enum(en):
 
 def parse_feature(feat):
        api = feat.getAttribute("api")
-       if api=="gl":
-               version = feat.getAttribute("number")
-               if version:
-                       version = map(int, version.split('.'))
-               else:
-                       version = None
+       version = feat.getAttribute("number")
+       if version:
+               version = map(int, version.split('.'))
+       else:
+               version = None
 
-               commands = get_nested_elements(feat, "require/command")
-               enums = get_nested_elements(feat, "require/enum")
+       requires = get_nested_elements(feat, "require")
+       for req in requires:
+               commands = get_nested_elements(req, "command")
+               enums = get_nested_elements(req, "enum")
                for t in itertools.chain(commands, enums):
                        name = t.getAttribute("name")
                        thing = things.get(name)
                        if thing:
-                               thing.version = version
+                               thing.supported_apis.setdefault(api, version)
+
+       if not api or api==target_api:
+               removes = get_nested_elements(feat, "remove")
+               for rem in removes:
+                       profile = rem.getAttribute("profile")
+                       commands = get_nested_elements(rem, "command")
+                       enums = get_nested_elements(rem, "enum")
 
-               if feat.getAttribute("name")=="MSPGL_REMOVE":
-                       commands = get_nested_elements(feat, "remove/command")
-                       enums = get_nested_elements(feat, "remove/enum")
                        for t in itertools.chain(commands, enums):
                                name = t.getAttribute("name")
-                               if name in things:
+                               if profile!="core" and name in things:
                                        del things[name]
 
 def parse_extension(ext):
@@ -173,14 +195,39 @@ def parse_extension(ext):
                ext_name = ext_name[3:]
 
        supported = ext.getAttribute("supported").split('|')
-       if "gl" in supported:
-               commands = get_nested_elements(ext, "require/command")
-               enums = get_nested_elements(ext, "require/enum")
+       if target_api not in supported and ext_name!=target_ext:
+               return
+
+       extension = extensions.get(ext_name)
+       if not extension:
+               extension = Extension(ext_name)
+               extensions[ext_name] = extension
+
+       extension.supported_apis = supported
+
+       requires = get_nested_elements(ext, "require")
+       for req in requires:
+               api = req.getAttribute("api")
+               if api:
+                       supported = [api]
+               else:
+                       supported = extension.supported_apis
+
+               commands = get_nested_elements(req, "command")
+               enums = get_nested_elements(req, "enum")
                for t in itertools.chain(commands, enums):
                        name = t.getAttribute("name")
                        thing = things.get(name)
                        if thing:
-                               thing.extension = ext_name
+                               if thing.extension and extension.name!=target_ext:
+                                       if thing.extension.ext_type=="ARB" or thing.extension.name==target_ext:
+                                               continue
+                                       if thing.extension.ext_type=="EXT" and extension.ext_type!="ARB":
+                                               continue
+
+                               thing.extension = extension
+                               for a in supported:
+                                       thing.supported_apis.setdefault(a, "ext")
 
 def parse_file(fn):
        doc = xml.dom.minidom.parse(fn)
@@ -207,33 +254,57 @@ parse_file("gl.fixes.xml")
 
 ### Additional processing ###
 
+if target_ext in extensions:
+       target_ext = extensions[target_ext]
+else:
+       print "Extension %s not found"%target_ext
+       sys.exit(1)
+
 # 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)
+core_enums = [e for e in enums if any(v!="ext" for v in e.supported_apis.itervalues())]
+core_enums_by_value = dict((e.value, None) for e in core_enums)
+
+def get_key_api(things):
+       common_apis = set(target_ext.supported_apis)
+       for t in things:
+               common_apis.intersection_update(t.supported_apis.keys())
+       if common_apis:
+               return common_apis.pop()
+       else:
+               return target_api
 
 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)
+       if all(v=="ext" for v in e.supported_apis.values()) and e.value in core_enums_by_value:
+               if core_enums_by_value[e.value] is None:
+                       candidates = [ce for ce in core_enums if ce.value==e.value]
+                       key_api = get_key_api(candidates)
+                       core_enums_by_value[e.value] = list(sorted(candidates, key=(lambda x: x.supported_apis.get(key_api, "ext"))))
+               for ce in core_enums_by_value[e.value]:
+                       if ce.bitmask==e.bitmask:
+                               e.aliases.append(ce.name)
+                               break
 
 # Create references from core things to their extension counterparts
 for t in things.itervalues():
-       if t.extension==target_ext or t.extension in secondary:
+       if t.extension:
                for a in t.aliases:
                        alias = things.get(a)
                        if alias:
-                               alias.source = t
+                               if target_api in t.supported_apis:
+                                       alias.sources.insert(0, t)
+                               else:
+                                       alias.sources.append(t)
 
+# Find the things we want to include in this extension
 def is_relevant(t):
        # Unpromoted extension things are relevant
-       if t.extension==target_ext and not t.aliases:
+       if t.extension and t.extension==target_ext and not t.aliases:
                return True
 
        # Core things promoted from the extension are also relevant
-       if t.source:
-               e = t.source
-               if e.extension==target_ext or e.extension in secondary:
+       for s in t.sources:
+               if s.extension==target_ext or s.extension.name in secondary:
                        return True
 
        return False
@@ -243,27 +314,38 @@ funcs.sort(key=(lambda f: f.name))
 enums = filter(is_relevant, enums)
 enums.sort(key=(lambda e: e.value))
 
+# Some final preparations for creating the files
 for t in itertools.chain(funcs, enums):
+       if target_api in t.supported_apis and t.supported_apis[target_api]!="ext":
+               t.version = t.supported_apis[target_api]
        if not core_version:
                core_version = t.version
 
        # Things in backport extensions don't acquire an extension suffix
-       if t.extension and not t.name.endswith(ext_type):
+       if t.extension and not t.name.endswith(ext_type) and target_api in t.supported_apis:
                backport_ext = t.extension
 
 for f in funcs:
-       if f.source:
-               # Typedefs for early core functions are not available in all
-               # implementations
-               f.typedef = "PFN%sPROC"%f.source.name.upper()
+       f.typedef = "FPtr_%s"%f.name
+
+if target_api in target_ext.supported_apis:
+       source_ext = target_ext
+else:
+       candidates = {}
+       for t in itertools.chain(funcs, enums):
+               for s in t.sources:
+                       if target_api in s.supported_apis:
+                               candidates[s.extension.name] = candidates.get(s.extension.name, 0)+1
+       if candidates:
+               source_ext = extensions[max(candidates.iteritems(), key=(lambda x: x[1]))[0]]
        else:
-               f.typedef = "PFN%sPROC"%f.name.upper()
+               source_ext = None
 
 ### Output ###
 
 out = file(out_base+".h", "w")
-out.write("#ifndef MSP_GL_%s_\n"%target_ext.upper())
-out.write("#define MSP_GL_%s_\n"%target_ext.upper())
+out.write("#ifndef MSP_GL_%s_\n"%target_ext.name.upper())
+out.write("#define MSP_GL_%s_\n"%target_ext.name.upper())
 
 out.write("""
 #include <msp/gl/extension.h>
@@ -276,24 +358,37 @@ namespace GL {
 
 if funcs or enums:
        if funcs:
-               out.write("#if defined(__APPLE__) || !defined(GL_%s)\n"%target_ext)
                for f in funcs:
                        out.write("typedef %s (*%s)(%s);\n"%(f.return_type, f.typedef, ", ".join(f.params)))
-               out.write("#endif\n\n")
+               out.write("\n")
 
        if enums:
-               if core_version:
-                       out.write("#ifndef GL_VERSION_%s\n"%"_".join(map(str, core_version)))
-               else:
-                       out.write("#ifndef GL_%s\n"%target_ext)
+               api_prefix = "GL"
+               if target_api=="gles2":
+                       api_prefix = "GL_ES"
+
+               enums_by_category = {}
                for e in enums:
-                       out.write("#define %s 0x%04X\n"%(e.name, e.value))
-               out.write("#endif\n\n")
+                       cat = None
+                       if e.version:
+                               cat = api_prefix+"_VERSION_"+"_".join(map(str, e.version))
+                       elif e.extension:
+                               cat = "GL_"+e.extension.name
+                       enums_by_category.setdefault(cat, []).append(e)
+
+               for cat in sorted(enums_by_category.keys()):
+                       if cat:
+                               out.write("#ifndef %s\n"%cat)
+                       for e in enums_by_category[cat]:
+                               out.write("#define %s 0x%04X\n"%(e.name, e.value))
+                       if cat:
+                               out.write("#endif\n")
+                       out.write("\n")
 
        for f in funcs:
                out.write("extern %s %s;\n"%(f.typedef, f.name))
 
-out.write("extern Extension %s;\n"%target_ext)
+out.write("extern Extension %s;\n"%target_ext.name)
 
 out.write("""
 } // namespace GL
@@ -303,7 +398,7 @@ out.write("""
 """)
 
 out = file(out_base+".cpp", "w")
-out.write("#include \"%s.h\"\n"%target_ext.lower())
+out.write("#include \"%s.h\"\n"%target_ext.name.lower())
 
 if funcs:
        out.write("""
@@ -322,33 +417,31 @@ namespace GL {
 for f in funcs:
        out.write("%s %s = 0;\n"%(f.typedef, f.name))
 
-out.write("\nExtension::SupportLevel init_%s()\n{\n"%target_ext.lower())
-out.write("#ifdef GL_%s\n"%target_ext)
+out.write("\nExtension::SupportLevel init_%s()\n{\n"%target_ext.name.lower())
 if core_version:
        out.write("\tif(is_version_at_least(%d, %d)"%tuple(core_version))
        if backport_ext:
-               out.write(" || is_supported(\"GL_%s\")"%backport_ext)
+               out.write(" || is_supported(\"GL_%s\")"%backport_ext.name)
        out.write(")\n\t{\n")
-       if funcs:
-               for f in funcs:
+       for f in funcs:
+               if f.version or target_api in f.supported_apis:
                        out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, f.name))
        out.write("\t\treturn Extension::CORE;\n")
        out.write("\t}\n")
-if target_ext!=backport_ext:
-       out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(target_ext))
-       if funcs:
-               for f in funcs:
-                       n = f.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))
+if source_ext and source_ext!=backport_ext:
+       out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(source_ext.name))
+       for f in funcs:
+               s = f
+               if f.sources:
+                       s = f.sources[0]
+               if s.version or target_api in s.supported_apis:
+                       out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, s.name))
        out.write("\t\treturn Extension::EXTENSION;\n")
        out.write("\t}\n")
-out.write("#endif\n")
 out.write("\treturn Extension::UNSUPPORTED;\n")
 out.write("}\n")
 
-out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(target_ext, target_ext, target_ext.lower()))
+out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(target_ext.name, target_ext.name, target_ext.name.lower()))
 
 out.write("""
 } // namespace GL