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)