blob: 671e0069a8394bb1e9b95bbb044d3a35fcc6be78 [file] [log] [blame]
Corentin Wallez59382b72020-04-17 20:43:07 +00001#!/usr/bin/env python3
Austin Engcc2516a2023-10-17 20:57:54 +00002# Copyright 2019 The Dawn & Tint Authors
Corentin Wallezdf69f242019-06-13 10:22:32 +00003#
Austin Engcc2516a2023-10-17 20:57:54 +00004# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
Corentin Wallezdf69f242019-06-13 10:22:32 +00006#
Austin Engcc2516a2023-10-17 20:57:54 +00007# 1. Redistributions of source code must retain the above copyright notice, this
8# list of conditions and the following disclaimer.
Corentin Wallezdf69f242019-06-13 10:22:32 +00009#
Austin Engcc2516a2023-10-17 20:57:54 +000010# 2. Redistributions in binary form must reproduce the above copyright notice,
11# this list of conditions and the following disclaimer in the documentation
12# and/or other materials provided with the distribution.
13#
14# 3. Neither the name of the copyright holder nor the names of its
15# contributors may be used to endorse or promote products derived from
16# this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Corentin Wallezdf69f242019-06-13 10:22:32 +000028
Jiawei Shao9d9d76c2019-08-22 08:19:13 +000029import os, json, sys
Corentin Wallezdf69f242019-06-13 10:22:32 +000030from collections import namedtuple
31import xml.etree.ElementTree as etree
32
Corentin Wallezf4a01c92024-07-16 11:18:42 +000033from generator_lib import Generator, run_generator, FileRender, GeneratorOutput
Corentin Wallezdf69f242019-06-13 10:22:32 +000034
Kai Ninomiya01aeca22020-07-15 19:51:17 +000035
Corentin Wallez8f4046b2019-06-17 09:17:29 +000036class ProcName:
Corentin Wallezdf69f242019-06-13 10:22:32 +000037 def __init__(self, gl_name, proc_name=None):
Kai Ninomiya01aeca22020-07-15 19:51:17 +000038 assert gl_name.startswith('gl')
Corentin Wallezdf69f242019-06-13 10:22:32 +000039 if proc_name == None:
40 proc_name = gl_name[2:]
41
42 self.gl_name = gl_name
43 self.proc_name = proc_name
44
45 def glProcName(self):
46 return self.gl_name
47
48 def ProcName(self):
49 return self.proc_name
50
51 def PFNPROCNAME(self):
52 return 'PFN' + self.gl_name.upper() + 'PROC'
53
54 def __repr__(self):
55 return 'Proc("{}", "{}")'.format(self.gl_name, self.proc_name)
56
Kai Ninomiya01aeca22020-07-15 19:51:17 +000057
Corentin Wallez8f4046b2019-06-17 09:17:29 +000058ProcParam = namedtuple('ProcParam', ['name', 'type'])
Kai Ninomiya01aeca22020-07-15 19:51:17 +000059
60
Corentin Wallez8f4046b2019-06-17 09:17:29 +000061class Proc:
62 def __init__(self, element):
63 # Type declaration for return values and arguments all have the same
64 # (weird) format.
65 # <element>[A][<ptype>B</ptype>][C]<other stuff.../></element>
66 #
67 # Some examples are:
68 # <proto>void <name>glFinish</name></proto>
69 # <proto><ptype>GLenum</ptype><name>glFenceSync</name></proto>
70 # <proto>const <ptype>GLubyte</ptype> *<name>glGetString</name></proto>
71 #
72 # This handles all the shapes found in gl.xml except for this one that
73 # has an array specifier after </name>:
74 # <param><ptype>GLuint</ptype> <name>baseAndCount</name>[2]</param>
75 def parse_type_declaration(element):
76 result = ''
77 if element.text != None:
78 result += element.text
79 ptype = element.find('ptype')
80 if ptype != None:
81 result += ptype.text
82 if ptype.tail != None:
83 result += ptype.tail
84 return result.strip()
85
86 proto = element.find('proto')
87
88 self.return_type = parse_type_declaration(proto)
89
90 self.params = []
91 for param in element.findall('./param'):
Kai Ninomiya01aeca22020-07-15 19:51:17 +000092 self.params.append(
93 ProcParam(
94 param.find('name').text, parse_type_declaration(param)))
Corentin Wallez8f4046b2019-06-17 09:17:29 +000095
96 self.gl_name = proto.find('name').text
97 self.alias = None
98 if element.find('alias') != None:
99 self.alias = element.find('alias').attrib['name']
100
101 def glProcName(self):
102 return self.gl_name
103
104 def ProcName(self):
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000105 assert self.gl_name.startswith('gl')
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000106 return self.gl_name[2:]
107
108 def PFNGLPROCNAME(self):
109 return 'PFN' + self.gl_name.upper() + 'PROC'
110
111 def __repr__(self):
112 return 'Proc("{}")'.format(self.gl_name)
113
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000114
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000115EnumDefine = namedtuple('EnumDefine', ['name', 'value'])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000116Version = namedtuple('Version', ['major', 'minor'])
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000117VersionBlock = namedtuple('VersionBlock', ['version', 'procs', 'enums'])
118HeaderBlock = namedtuple('HeaderBlock', ['description', 'procs', 'enums'])
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000119ExtensionBlock = namedtuple('ExtensionBlock',
120 ['extension', 'procs', 'enums', 'supported_specs'])
121
Corentin Wallezdf69f242019-06-13 10:22:32 +0000122
123def parse_version(version):
124 return Version(*map(int, version.split('.')))
125
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000126
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000127def compute_params(root, supported_extensions):
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000128 # Parse all the commands and enums
129 all_procs = {}
130 for command in root.findall('''commands[@namespace='GL']/command'''):
131 proc = Proc(command)
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000132 assert proc.gl_name not in all_procs
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000133 all_procs[proc.gl_name] = proc
134
135 all_enums = {}
136 for enum in root.findall('''enums[@namespace='GL']/enum'''):
137 enum_name = enum.attrib['name']
138 # Special case an enum we'll never use that has different values in GL and GLES
139 if enum_name == 'GL_ACTIVE_PROGRAM_EXT':
140 continue
141
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000142 assert enum_name not in all_enums
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000143 all_enums[enum_name] = EnumDefine(enum_name, enum.attrib['value'])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000144
145 # Get the list of all Desktop OpenGL function removed by the Core Profile.
146 core_removed_procs = set()
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000147 for proc in root.findall('''feature/remove[@profile='core']/command'''):
148 core_removed_procs.add(proc.attrib['name'])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000149
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000150 # Get list of enums and procs per OpenGL ES/Desktop OpenGL version
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000151 def parse_version_blocks(api, removed_procs=set()):
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000152 blocks = []
153 for section in root.findall('''feature[@api='{}']'''.format(api)):
154 section_procs = []
155 for command in section.findall('./require/command'):
156 proc_name = command.attrib['name']
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000157 assert all_procs[proc_name].alias == None
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000158 if proc_name not in removed_procs:
159 section_procs.append(all_procs[proc_name])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000160
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000161 section_enums = []
162 for enum in section.findall('./require/enum'):
163 section_enums.append(all_enums[enum.attrib['name']])
164
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000165 blocks.append(
166 VersionBlock(parse_version(section.attrib['number']),
167 section_procs, section_enums))
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000168
169 return blocks
170
171 gles_blocks = parse_version_blocks('gles2')
172 desktop_gl_blocks = parse_version_blocks('gl', core_removed_procs)
173
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000174 def parse_extension_block(extension):
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000175 section = root.find(
176 '''extensions/extension[@name='{}']'''.format(extension))
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000177 supported_specs = section.attrib['supported'].split('|')
178 section_procs = []
179 for command in section.findall('./require/command'):
180 proc_name = command.attrib['name']
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000181 assert all_procs[proc_name].alias == None
Stephen Whited0ebcba2021-05-06 18:34:14 +0000182 section_procs.append(all_procs[proc_name])
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000183
184 section_enums = []
185 for enum in section.findall('./require/enum'):
186 section_enums.append(all_enums[enum.attrib['name']])
187
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000188 return ExtensionBlock(extension, section_procs, section_enums,
189 supported_specs)
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000190
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000191 extension_desktop_gl_blocks = []
192 extension_gles_blocks = []
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000193 for extension in supported_extensions:
194 extension_block = parse_extension_block(extension)
195 if 'gl' in extension_block.supported_specs:
196 extension_desktop_gl_blocks.append(extension_block)
197 if 'gles2' in extension_block.supported_specs:
198 extension_gles_blocks.append(extension_block)
199
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000200 # Compute the blocks for headers such that there is no duplicate definition
Corentin Wallezdf69f242019-06-13 10:22:32 +0000201 already_added_header_procs = set()
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000202 already_added_header_enums = set()
Corentin Wallezdf69f242019-06-13 10:22:32 +0000203 header_blocks = []
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000204
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000205 def add_header_block(description, block):
Corentin Wallezdf69f242019-06-13 10:22:32 +0000206 block_procs = []
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000207 for proc in block.procs:
Corentin Wallezdf69f242019-06-13 10:22:32 +0000208 if not proc.glProcName() in already_added_header_procs:
209 already_added_header_procs.add(proc.glProcName())
210 block_procs.append(proc)
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000211
212 block_enums = []
213 for enum in block.enums:
214 if not enum.name in already_added_header_enums:
215 already_added_header_enums.add(enum.name)
216 block_enums.append(enum)
217
218 if len(block_procs) > 0 or len(block_enums) > 0:
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000219 header_blocks.append(
220 HeaderBlock(description, block_procs, block_enums))
Corentin Wallezdf69f242019-06-13 10:22:32 +0000221
222 for block in gles_blocks:
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000223 add_header_block(
224 'OpenGL ES {}.{}'.format(block.version.major, block.version.minor),
225 block)
Corentin Wallezdf69f242019-06-13 10:22:32 +0000226
227 for block in desktop_gl_blocks:
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000228 add_header_block(
229 'Desktop OpenGL {}.{}'.format(block.version.major,
230 block.version.minor), block)
Corentin Wallezdf69f242019-06-13 10:22:32 +0000231
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000232 for block in extension_desktop_gl_blocks:
233 add_header_block(block.extension, block)
234
235 for block in extension_gles_blocks:
236 add_header_block(block.extension, block)
237
Corentin Wallezdf69f242019-06-13 10:22:32 +0000238 return {
239 'gles_blocks': gles_blocks,
240 'desktop_gl_blocks': desktop_gl_blocks,
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000241 'extension_desktop_gl_blocks': extension_desktop_gl_blocks,
242 'extension_gles_blocks': extension_gles_blocks,
Corentin Wallezdf69f242019-06-13 10:22:32 +0000243 'header_blocks': header_blocks,
244 }
245
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000246
Corentin Wallezdf69f242019-06-13 10:22:32 +0000247class OpenGLLoaderGenerator(Generator):
248 def get_description(self):
249 return 'Generates code to load OpenGL function pointers'
250
251 def add_commandline_arguments(self, parser):
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000252 parser.add_argument('--gl-xml',
253 required=True,
254 type=str,
255 help='The Khronos gl.xml to use.')
256 parser.add_argument(
257 '--supported-extensions',
258 required=True,
259 type=str,
260 help=
261 'The JSON file that defines the OpenGL and GLES extensions to use.'
262 )
Corentin Wallezdf69f242019-06-13 10:22:32 +0000263
Corentin Wallezf4a01c92024-07-16 11:18:42 +0000264 def get_outputs(self, args):
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000265 supported_extensions = []
266 with open(args.supported_extensions) as f:
267 supported_extensions_json = json.loads(f.read())
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000268 supported_extensions = supported_extensions_json[
269 'supported_extensions']
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000270
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000271 params = compute_params(
272 etree.parse(args.gl_xml).getroot(), supported_extensions)
Corentin Wallezdf69f242019-06-13 10:22:32 +0000273
Corentin Wallezf4a01c92024-07-16 11:18:42 +0000274 renders = [
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000275 FileRender(
276 'opengl/OpenGLFunctionsBase.cpp',
Ben Clayton818001d2022-02-04 17:07:46 +0000277 'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.cpp',
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000278 [params]),
279 FileRender('opengl/OpenGLFunctionsBase.h',
Ben Clayton818001d2022-02-04 17:07:46 +0000280 'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.h',
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000281 [params]),
282 FileRender('opengl/opengl_platform.h',
Ben Clayton818001d2022-02-04 17:07:46 +0000283 'src/dawn/native/opengl/opengl_platform_autogen.h',
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000284 [params]),
Corentin Wallezdf69f242019-06-13 10:22:32 +0000285 ]
Corentin Wallezf4a01c92024-07-16 11:18:42 +0000286 return GeneratorOutput(renders=renders, imported_templates=[])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000287
288 def get_dependencies(self, args):
Corentin Wallez615d6ea2021-05-05 16:06:23 +0000289 return [
290 os.path.abspath(args.gl_xml),
291 os.path.abspath(args.supported_extensions)
292 ]
Corentin Wallezdf69f242019-06-13 10:22:32 +0000293
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000294
Corentin Wallezdf69f242019-06-13 10:22:32 +0000295if __name__ == '__main__':
296 sys.exit(run_generator(OpenGLLoaderGenerator()))