mirror of
https://github.com/astromaddie/HaloCE-VR.git
synced 2026-10-19 07:00:13 +02:00
184 lines
7.3 KiB
Python
184 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate the Android guest's OpenGL ES entry points.
|
|
|
|
The guest (ILP32 code, see port/android/README.md) cannot link against the
|
|
host's libGLESv3, but it can call it: a host function receives the guest's
|
|
pointer arguments zero-extended, and 32-bit integers and floats go in the
|
|
same registers under both ABIs. What differs is
|
|
|
|
- GLsizeiptr and GLintptr, 32-bit in the guest and 64-bit in the host;
|
|
- arguments passed on the stack (beyond the eighth integer argument), which
|
|
the guest packs by size while the host expects 8-byte slots;
|
|
- returned pointers, which point at host memory.
|
|
|
|
For each function in the Android list in port/linux/src/gl.h this writes a
|
|
guest wrapper that widens such arguments and calls an import named
|
|
hostgl_<function>, which the host resolves to the real entry point. Functions
|
|
returning a string go through host_gl_get_string instead.
|
|
|
|
Usage: android_gl_stubs.py gl.h gl32.h gl2ext.h output.c imports.list
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
|
|
INTEGER_REGISTER_COUNT = 8
|
|
WIDE_TYPES = {"GLsizeiptr", "GLintptr", "GLint64", "GLuint64", "GLint64EXT", "GLuint64EXT"}
|
|
FLOAT_TYPES = {"GLfloat", "GLclampf", "GLdouble", "GLclampd", "float", "double"}
|
|
|
|
|
|
def android_functions(gl_header: str):
|
|
text = open(gl_header, encoding="utf-8").read()
|
|
start = text.index("/* ANDROID_GL_FUNCTIONS_BEGIN */")
|
|
end = text.index("/* ANDROID_GL_FUNCTIONS_END */")
|
|
return re.findall(r"X\((\w+)\)", text[start:end])
|
|
|
|
|
|
def prototypes(*headers):
|
|
result = {}
|
|
pattern = re.compile(r"GL_APICALL\s+(.+?)\s*GL_APIENTRY\s+(\w+)\s*\((.*?)\);", re.S)
|
|
for header in headers:
|
|
text = open(header, encoding="utf-8").read()
|
|
for ret, name, params in pattern.findall(text):
|
|
params = " ".join(params.split())
|
|
result.setdefault(name, (ret.strip(), params))
|
|
return result
|
|
|
|
|
|
def split_parameter(param: str):
|
|
param = param.strip()
|
|
m = re.match(r"(.*?)(\w+)\s*$", param)
|
|
ptype, pname = m.group(1).strip(), m.group(2)
|
|
if not ptype: # unnamed
|
|
ptype, pname = param, None
|
|
return ptype, pname
|
|
|
|
|
|
def main():
|
|
gl_header, gl32, gl2ext, output, imports = sys.argv[1:6]
|
|
functions = android_functions(gl_header)
|
|
protos = prototypes(gl32, gl2ext)
|
|
out = [
|
|
"/* generated by tools/android_gl_stubs.py from port/linux/src/gl.h; do not edit */",
|
|
"#include <GLES3/gl32.h>",
|
|
"#include <GLES2/gl2ext.h>",
|
|
"#include <string.h>",
|
|
"",
|
|
"void host_gl_get_string(unsigned int name, int index, char *buffer, unsigned int size);",
|
|
"",
|
|
]
|
|
table = []
|
|
import_names = []
|
|
for name in functions:
|
|
if name not in protos:
|
|
raise SystemExit(f"{name}: no prototype in the GLES headers")
|
|
ret, params = protos[name]
|
|
if params in ("void", ""):
|
|
plist = []
|
|
else:
|
|
plist = [split_parameter(p) for p in params.split(",")]
|
|
if name == "glGetString":
|
|
out += [
|
|
"static const GLubyte *GL_APIENTRY guest_glGetString(GLenum name)",
|
|
"{",
|
|
"\tstatic __thread char buffer[4][4096];",
|
|
"\tstatic __thread int next;",
|
|
"\tchar *result = buffer[next++ & 3];",
|
|
"",
|
|
"\thost_gl_get_string(name, -1, result, sizeof(buffer[0]));",
|
|
"\treturn (const GLubyte *)result;",
|
|
"}",
|
|
"",
|
|
]
|
|
table.append(name)
|
|
continue
|
|
if name == "glShaderSource":
|
|
# an array of pointers: widen each to a host pointer
|
|
import_names.append("hostgl_glShaderSource")
|
|
out += [
|
|
"void hostgl_glShaderSource(GLuint shader, GLsizei count, const unsigned long long *strings, "
|
|
"const GLint *lengths);",
|
|
"static void GL_APIENTRY guest_glShaderSource(GLuint shader, GLsizei count, "
|
|
"const GLchar *const *strings, const GLint *lengths)",
|
|
"{",
|
|
"\tunsigned long long wide[16];",
|
|
"\tGLsizei index;",
|
|
"",
|
|
"\tif (count > 16)",
|
|
"\t\tcount = 16;",
|
|
"\tfor (index = 0; index < count; index++)",
|
|
"\t\twide[index] = (unsigned long long)(unsigned int)strings[index];",
|
|
"\thostgl_glShaderSource(shader, count, wide, lengths);",
|
|
"}",
|
|
"",
|
|
]
|
|
table.append(name)
|
|
continue
|
|
if "*" in ret:
|
|
raise SystemExit(f"{name}: returns a pointer; add a special case")
|
|
if any(p.count("*") > 1 for p, _ in plist):
|
|
raise SystemExit(f"{name}: takes an array of pointers; add a special case")
|
|
decl_params, host_params, call_args = [], [], []
|
|
integer_index = 0
|
|
for index, (ptype, pname) in enumerate(plist):
|
|
arg = f"a{index}"
|
|
decl_params.append(f"{ptype} {arg}")
|
|
is_pointer = "*" in ptype
|
|
base = ptype.replace("const", "").strip()
|
|
if base in FLOAT_TYPES and not is_pointer:
|
|
host_params.append(ptype)
|
|
call_args.append(arg)
|
|
continue
|
|
wide = base in WIDE_TYPES and not is_pointer
|
|
on_stack = integer_index >= INTEGER_REGISTER_COUNT
|
|
integer_index += 1
|
|
if is_pointer:
|
|
if on_stack:
|
|
host_params.append("unsigned long long")
|
|
call_args.append(f"(unsigned long long)(unsigned int){arg}")
|
|
else:
|
|
host_params.append(ptype)
|
|
call_args.append(arg)
|
|
elif wide or on_stack:
|
|
host_params.append("long long")
|
|
call_args.append(f"(long long){arg}")
|
|
else:
|
|
host_params.append(ptype)
|
|
call_args.append(arg)
|
|
host_name = "hostgl_" + name
|
|
import_names.append(host_name)
|
|
out.append(f"{ret} {host_name}({', '.join(host_params) or 'void'});")
|
|
out.append(f"static {ret} GL_APIENTRY guest_{name}({', '.join(decl_params) or 'void'})")
|
|
out.append("{")
|
|
call = f"{host_name}({', '.join(call_args)})"
|
|
out.append(f"\t{'return ' if ret != 'void' else ''}{call};")
|
|
out.append("}")
|
|
out.append("")
|
|
table.append(name)
|
|
out.append("static const struct { const char *name; void *function; } guest_gl_functions[] =")
|
|
out.append("{")
|
|
for name in table:
|
|
out.append(f'\t{{ "{name}", (void *)guest_{name} }},')
|
|
out.append("};")
|
|
out.append("")
|
|
out.append("typedef void (*guest_gl_function)(void);")
|
|
out.append("guest_gl_function guest_gl_get_proc_address(const char *name)")
|
|
out.append("{")
|
|
out.append("\tunsigned long index;")
|
|
out.append("")
|
|
out.append("\tfor (index = 0; index < sizeof(guest_gl_functions) / sizeof(guest_gl_functions[0]); index++)")
|
|
out.append("\t{")
|
|
out.append("\t\tif (!strcmp(guest_gl_functions[index].name, name))")
|
|
out.append("\t\t\treturn (guest_gl_function)guest_gl_functions[index].function;")
|
|
out.append("\t}")
|
|
out.append("\treturn 0;")
|
|
out.append("}")
|
|
with open(output, "w", encoding="utf-8") as f:
|
|
f.write("\n".join(out) + "\n")
|
|
with open(imports, "w", encoding="utf-8") as f:
|
|
f.write("\n".join(import_names) + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|