forked from bullno1/cosmo-sokol
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgen-gl
executable file
·119 lines (95 loc) · 3.29 KB
/
gen-gl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python
import xml.etree.ElementTree as ET
import textwrap
MIN_VERSION = (4, 0)
def main():
tree = ET.parse("gl.xml")
root = tree.getroot()
# Iterate versions to find required commands
required_commands = set()
for feature in root.findall(f'./feature[@api="gl"]'):
version = tuple(map(int, feature.get('number').split('.')))
if version > MIN_VERSION:
break
required_commands.update([
node.get('name')
for node in feature.findall('./require/command')
])
# Gather specs for required commands
command_specs = []
for command in root.findall('./commands[@namespace="GL"]/command'):
proto = command.find('./proto')
name = proto.find('./name')
if name.text not in required_commands:
continue
params = []
for param in command.findall('./param'):
param_element = param.find('./name')
param_type = innertext(param, param_element)
params.append({
'name': param_element.text.strip(),
'type': param_type.strip(),
})
command_specs.append({
'name': name.text.strip(),
'return': innertext(proto, name).strip(),
'params': params,
})
# Shim generation
with open("gl.c", "w") as f:
f.write(textwrap.dedent("""
#include <GL/gl.h>
#include <stddef.h>
#include <threads.h>
#include <dlfcn.h>
#pragma GCC diagnostic ignored "-Warray-parameter"
static once_flag libgl_init = {0};
""").lstrip())
# Function pointers
for command_spec in command_specs:
f.write(
f"static {command_spec['return']} "
f"(*proc_{command_spec['name']})("
f"{arg_list(command_spec['params'])}"
") = NULL;\n"
)
# Loader
f.write(textwrap.dedent("""
static void load_gl_shims(void) {
void* libgl = cosmo_dlopen("libgl.so", RTLD_NOW | RTLD_GLOBAL);
"""))
for command_spec in command_specs:
name = command_spec['name']
f.write(f' proc_{name} = cosmo_dltramp(cosmo_dlsym(libgl, "{name}"));\n')
f.write("}\n")
# Shim
for command_spec in command_specs:
name = command_spec['name']
return_type = command_spec['return']
params = command_spec['params']
f.write(textwrap.dedent(f"""
{return_type} {name}({arg_list(params)}) {{
call_once(&libgl_init, load_gl_shims);
{ 'return ' if return_type != 'void' else '' }proc_{name}({forward_list(params)});
}}
"""))
def innertext(tag, exclude):
return (tag.text or '') + ''.join(innertext(e, exclude) for e in tag if e != exclude) + (tag.tail or '')
def arg_list(params):
if len(params) > 0:
return ', '.join([
f"{param['type']} {param['name']}"
for param in params
])
else:
return 'void'
def forward_list(params):
if len(params) > 0:
return ', '.join([
f"{param['name']}"
for param in params
])
else:
return ''
if __name__ == "__main__":
main()