orca/scripts/gles_gen.py

316 lines
7.2 KiB
Python

from .reg_modified import *
import xml.etree.ElementTree as et
from argparse import ArgumentParser
# remove APIs that can't be sandboxed
removeProc = [
"glMapBuffer",
"glMapBufferRange",
"glUnmapBuffer",
"glFlushMappedBufferRange",
"glGetBufferPointerv"
]
def gen_gles_header(spec, filename):
# Generates the GLES header, wrapping gl functions
# prototypes in ORCA_IMPORT() macro
gles2through31Pat = '2\.[0-9]|3\.[01]'
allVersions = '.*'
genOpts = CGeneratorOptions(
filename=filename,
apiname='gles2',
profile='common',
versions=gles2through31Pat,
emitversions=allVersions,
protectProto=False,
procMacro='ORCA_IMPORT',
removeProc = removeProc)
reg = Registry()
tree = et.parse(spec)
reg.loadElementTree(tree)
logFile = open('./build/gles_gen.log', 'w')
gen = COutputGenerator(diagFile=logFile)
reg.setGenerator(gen)
reg.apiGen(genOpts)
logFile.close()
def get_bindgen_tag_for_type(typeName):
typeToTags = {
"void": "v",
"GLenum": "i",
"GLbitfield": "i",
"GLboolean": "i",
"GLbyte": "i",
"GLubyte": "i",
"GLchar": "i",
"GLshort": "i",
"GLushort": "i",
"GLhalf": "i",
"GLhalfARB": "i",
"GLuint": "i",
"GLint": "i",
"GLclampx": "i",
"GLsizei": "i",
"GLfixed": "i",
"GLintptr": "i",
"GLsizeiptr": "i",
"GLuint64": "I",
"GLint64": "I",
"GLfloat": "f",
"GLclampf": "f",
"GLdouble": "F",
"GLclampd": "F",
#NOTE: we treat sync objects as opaque 64bit values
#TODO we should _also_ make sure that Wasm code treat them as 64bit values
"GLsync": "I"
}
if typeName[len(typeName)-1] == '*':
return "p"
else:
tag = typeToTags.get(typeName)
return tag
def gen_compsize_len_entry(name, argName, compsizeArgs):
entry = '\t\t\t"len": {\n'
entry += '\t\t\t\t"proc": "orca_'+ name +'_'+argName+'_length",\n'
entry += '\t\t\t\t"args": ['
for i, compsizeArg in enumerate(compsizeArgs):
entry += '"' + compsizeArg + '"'
if i < len(compsizeArgs)-1:
entry += ', '
entry += ']\n'
entry += '\t\t\t}'
return entry
def gen_argcount_len_entry(name, argName, tokens):
entry = '\t\t\t"len": {'
if len(tokens) == 2:
if tokens[1].isnumeric() == False:
print("Warning: function " + name + ": couldn't parse parameter '" + argName + "' lenght attribute")
entry += '"count": "' + tokens[0] + '", "components": '+ tokens[1]
elif len(tokens) == 1:
if tokens[0].isnumeric():
entry += '"components":'+ tokens[0]
else:
entry += '"count": "'+ tokens[0] + '"'
else:
print("Warning: function " + name + ": couldn't parse parameter '" + argName + "' lenght attribute")
entry += '}'
return entry
def gen_gles_bindgen_json(spec, filename):
# Gather gles 3.1 required functions
tree = et.parse(spec)
api = []
for feature in tree.iterfind('feature[@api="gles2"]'):
if float(feature.get('number')) > 3.1:
break
for require in feature.iter('require'):
if require.get('profile') == 'compatibility':
continue
for command in require.iter('command'):
if command.get('name') not in removeProc:
api.append(command.get('name'))
for remove in feature.iter('remove'):
for command in remove.iter('command'):
api.remove(command.get('name'))
# put all GL commands in a dict
commands = dict()
commandsSpec = tree.find('./commands')
for command in commandsSpec.iter('command'):
name = command.find('proto/name')
commands[name.text] = command
# TODO: Generate json descriptions for commands in api
manualBind = [
"glShaderSource",
"glGetVertexAttribPointerv",
"glVertexAttribPointer",
"glVertexAttribIPointer",
"glGetString",
"glGetStringi",
"glGetUniformIndices"
]
json = '[\n'
for name in api:
if name in manualBind:
continue
command = commands.get(name)
if command == None:
print("Couldn't find definition for required command '" + name + "'")
exit(-1)
proto = command.find("proto")
ptype = proto.find("ptype")
retType = ''
if proto.text != None:
retType += proto.text
if ptype != None:
if ptype.text != None:
retType += ptype.text
if ptype.tail != None:
retType += ptype.tail
retType = retType.strip()
retTag = get_bindgen_tag_for_type(retType)
if retTag == None:
print("Couldn't find tag for GL type '" + retType + "'")
exit(-1)
entry = '{\n\t"name": "' + name + '",\n'
entry += '\t"cname": "' + name + '",\n'
entry += '\t"ret": { "name": "' + retType + '", "tag": "' + retTag + '"},\n'
entry += '\t"args": [ '
# iterate through params
for param in command.iter('param'):
argNode = param.find('name')
argName = argNode.text
typeNode = param.find('ptype')
typeName = ''
if param.text != None:
typeName += param.text
if typeNode != None:
if typeNode.text != None:
typeName += typeNode.text
if typeNode.tail != None:
typeName += typeNode.tail
typeName = typeName.strip()
if typeName.endswith('**'):
print("Warning: function " + name + ": parameter " + argName + " has 2 (or more) levels of indirection")
typeTag = get_bindgen_tag_for_type(typeName)
if typeTag == None:
print("Couldn't find tag for GL type '" + typeName + "' in function '"+ name +"'")
exit(-1)
entry += '\n'
entry += '\t\t{\n\t\t\t"name": "'+ argName +'",\n'
entry += '\t\t\t"type": {"name": "'+ typeName +'", "tag": "'+ typeTag +'"}'
lenString = param.get('len')
nullStringProcWithNoLen = [
"glBindAttribLocation",
"glGetAttribLocation",
"glGetUniformLocation"
]
drawIndirectProc = [
"glDrawArraysIndirect",
"glDrawElementsIndirect"
]
if typeTag == "p":
if lenString == None:
if name in drawIndirectProc:
entry += ',\n'
entry += gen_compsize_len_entry(name, argName, ['indirect'])
elif name in nullStringProcWithNoLen:
entry += ',\n'
entry += gen_compsize_len_entry(name, argName, ['name'])
else:
print("Warning: function " + name + ": parameter " + argName + " has no len attribute")
elif lenString != None:
entry += ',\n'
tokens = lenString.split('*')
if lenString.startswith("COMPSIZE"):
tmp = lenString
if tmp.startswith("COMPSIZE("):
tmp = tmp[len("COMPSIZE("):]
if tmp.endswith(")"):
tmp = tmp[:-1]
compsizeArgs = list(filter(None, tmp.split(",")))
if len(compsizeArgs) == 0:
# special case glGetUniformBlockIndex which isn't specified correctly in gl.xml
if name == 'glGetUniformBlockIndex':
compsizeArgs = ['uniformBlockName']
entry += gen_compsize_len_entry(name, argName, compsizeArgs)
else:
entry += gen_argcount_len_entry(name, argName, tokens)
entry += '\n\t\t},'
entry = entry[:-1]
entry += '\n\t]\n}'
json += entry
json += ',\n'
json = json[:-2]
json += '\n]'
# write json to jsonFile
f = open(filename, 'w')
f.write(json)
f.close()
def gles_gen(spec, json, header):
gen_gles_header(spec, header)
gen_gles_bindgen_json(spec, json)
#----------------------------------------
# driver
#----------------------------------------
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("-s", "--spec")
parser.add_argument("--header")
parser.add_argument("-j", "--json")
args = parser.parse_args()
glesHeader = args.header
jsonFile = args.json
gles_gen(args.spec, jsonFile, glesHeader)