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,
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
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)
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):
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):
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):
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)
### 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
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>
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
""")
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("""
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