blob: db253e222db2c7266012d416ba34c31c5de181c7 [file] [log] [blame]
Corentin Wallez59382b72020-04-17 20:43:07 +00001#!/usr/bin/env python3
Corentin Wallezdf69f242019-06-13 10:22:32 +00002# Copyright 2019 The Dawn Authors
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Jiawei Shao9d9d76c2019-08-22 08:19:13 +000016import os, json, sys
Corentin Wallezdf69f242019-06-13 10:22:32 +000017from collections import namedtuple
18import xml.etree.ElementTree as etree
19
20from generator_lib import Generator, run_generator, FileRender
21
Kai Ninomiya01aeca22020-07-15 19:51:17 +000022
Corentin Wallez8f4046b2019-06-17 09:17:29 +000023class ProcName:
Corentin Wallezdf69f242019-06-13 10:22:32 +000024 def __init__(self, gl_name, proc_name=None):
Kai Ninomiya01aeca22020-07-15 19:51:17 +000025 assert gl_name.startswith('gl')
Corentin Wallezdf69f242019-06-13 10:22:32 +000026 if proc_name == None:
27 proc_name = gl_name[2:]
28
29 self.gl_name = gl_name
30 self.proc_name = proc_name
31
32 def glProcName(self):
33 return self.gl_name
34
35 def ProcName(self):
36 return self.proc_name
37
38 def PFNPROCNAME(self):
39 return 'PFN' + self.gl_name.upper() + 'PROC'
40
41 def __repr__(self):
42 return 'Proc("{}", "{}")'.format(self.gl_name, self.proc_name)
43
Kai Ninomiya01aeca22020-07-15 19:51:17 +000044
Corentin Wallez8f4046b2019-06-17 09:17:29 +000045ProcParam = namedtuple('ProcParam', ['name', 'type'])
Kai Ninomiya01aeca22020-07-15 19:51:17 +000046
47
Corentin Wallez8f4046b2019-06-17 09:17:29 +000048class Proc:
49 def __init__(self, element):
50 # Type declaration for return values and arguments all have the same
51 # (weird) format.
52 # <element>[A][<ptype>B</ptype>][C]<other stuff.../></element>
53 #
54 # Some examples are:
55 # <proto>void <name>glFinish</name></proto>
56 # <proto><ptype>GLenum</ptype><name>glFenceSync</name></proto>
57 # <proto>const <ptype>GLubyte</ptype> *<name>glGetString</name></proto>
58 #
59 # This handles all the shapes found in gl.xml except for this one that
60 # has an array specifier after </name>:
61 # <param><ptype>GLuint</ptype> <name>baseAndCount</name>[2]</param>
62 def parse_type_declaration(element):
63 result = ''
64 if element.text != None:
65 result += element.text
66 ptype = element.find('ptype')
67 if ptype != None:
68 result += ptype.text
69 if ptype.tail != None:
70 result += ptype.tail
71 return result.strip()
72
73 proto = element.find('proto')
74
75 self.return_type = parse_type_declaration(proto)
76
77 self.params = []
78 for param in element.findall('./param'):
Kai Ninomiya01aeca22020-07-15 19:51:17 +000079 self.params.append(
80 ProcParam(
81 param.find('name').text, parse_type_declaration(param)))
Corentin Wallez8f4046b2019-06-17 09:17:29 +000082
83 self.gl_name = proto.find('name').text
84 self.alias = None
85 if element.find('alias') != None:
86 self.alias = element.find('alias').attrib['name']
87
88 def glProcName(self):
89 return self.gl_name
90
91 def ProcName(self):
Kai Ninomiya01aeca22020-07-15 19:51:17 +000092 assert self.gl_name.startswith('gl')
Corentin Wallez8f4046b2019-06-17 09:17:29 +000093 return self.gl_name[2:]
94
95 def PFNGLPROCNAME(self):
96 return 'PFN' + self.gl_name.upper() + 'PROC'
97
98 def __repr__(self):
99 return 'Proc("{}")'.format(self.gl_name)
100
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000101
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000102EnumDefine = namedtuple('EnumDefine', ['name', 'value'])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000103Version = namedtuple('Version', ['major', 'minor'])
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000104VersionBlock = namedtuple('VersionBlock', ['version', 'procs', 'enums'])
105HeaderBlock = namedtuple('HeaderBlock', ['description', 'procs', 'enums'])
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000106ExtensionBlock = namedtuple('ExtensionBlock',
107 ['extension', 'procs', 'enums', 'supported_specs'])
108
Corentin Wallezdf69f242019-06-13 10:22:32 +0000109
110def parse_version(version):
111 return Version(*map(int, version.split('.')))
112
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000113
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000114def compute_params(root, supported_extensions):
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000115 # Parse all the commands and enums
116 all_procs = {}
117 for command in root.findall('''commands[@namespace='GL']/command'''):
118 proc = Proc(command)
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000119 assert proc.gl_name not in all_procs
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000120 all_procs[proc.gl_name] = proc
121
122 all_enums = {}
123 for enum in root.findall('''enums[@namespace='GL']/enum'''):
124 enum_name = enum.attrib['name']
125 # Special case an enum we'll never use that has different values in GL and GLES
126 if enum_name == 'GL_ACTIVE_PROGRAM_EXT':
127 continue
128
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000129 assert enum_name not in all_enums
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000130 all_enums[enum_name] = EnumDefine(enum_name, enum.attrib['value'])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000131
132 # Get the list of all Desktop OpenGL function removed by the Core Profile.
133 core_removed_procs = set()
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000134 for proc in root.findall('''feature/remove[@profile='core']/command'''):
135 core_removed_procs.add(proc.attrib['name'])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000136
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000137 # Get list of enums and procs per OpenGL ES/Desktop OpenGL version
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000138 def parse_version_blocks(api, removed_procs=set()):
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000139 blocks = []
140 for section in root.findall('''feature[@api='{}']'''.format(api)):
141 section_procs = []
142 for command in section.findall('./require/command'):
143 proc_name = command.attrib['name']
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000144 assert all_procs[proc_name].alias == None
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000145 if proc_name not in removed_procs:
146 section_procs.append(all_procs[proc_name])
Corentin Wallezdf69f242019-06-13 10:22:32 +0000147
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000148 section_enums = []
149 for enum in section.findall('./require/enum'):
150 section_enums.append(all_enums[enum.attrib['name']])
151
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000152 blocks.append(
153 VersionBlock(parse_version(section.attrib['number']),
154 section_procs, section_enums))
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000155
156 return blocks
157
158 gles_blocks = parse_version_blocks('gles2')
159 desktop_gl_blocks = parse_version_blocks('gl', core_removed_procs)
160
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000161 def parse_extension_block(extension):
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000162 section = root.find(
163 '''extensions/extension[@name='{}']'''.format(extension))
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000164 supported_specs = section.attrib['supported'].split('|')
165 section_procs = []
166 for command in section.findall('./require/command'):
167 proc_name = command.attrib['name']
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000168 assert all_procs[proc_name].alias == None
Stephen Whited0ebcba2021-05-06 18:34:14 +0000169 section_procs.append(all_procs[proc_name])
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000170
171 section_enums = []
172 for enum in section.findall('./require/enum'):
173 section_enums.append(all_enums[enum.attrib['name']])
174
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000175 return ExtensionBlock(extension, section_procs, section_enums,
176 supported_specs)
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000177
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000178 extension_desktop_gl_blocks = []
179 extension_gles_blocks = []
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000180 for extension in supported_extensions:
181 extension_block = parse_extension_block(extension)
182 if 'gl' in extension_block.supported_specs:
183 extension_desktop_gl_blocks.append(extension_block)
184 if 'gles2' in extension_block.supported_specs:
185 extension_gles_blocks.append(extension_block)
186
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000187 # Compute the blocks for headers such that there is no duplicate definition
Corentin Wallezdf69f242019-06-13 10:22:32 +0000188 already_added_header_procs = set()
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000189 already_added_header_enums = set()
Corentin Wallezdf69f242019-06-13 10:22:32 +0000190 header_blocks = []
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000191
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000192 def add_header_block(description, block):
Corentin Wallezdf69f242019-06-13 10:22:32 +0000193 block_procs = []
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000194 for proc in block.procs:
Corentin Wallezdf69f242019-06-13 10:22:32 +0000195 if not proc.glProcName() in already_added_header_procs:
196 already_added_header_procs.add(proc.glProcName())
197 block_procs.append(proc)
Corentin Wallez8f4046b2019-06-17 09:17:29 +0000198
199 block_enums = []
200 for enum in block.enums:
201 if not enum.name in already_added_header_enums:
202 already_added_header_enums.add(enum.name)
203 block_enums.append(enum)
204
205 if len(block_procs) > 0 or len(block_enums) > 0:
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000206 header_blocks.append(
207 HeaderBlock(description, block_procs, block_enums))
Corentin Wallezdf69f242019-06-13 10:22:32 +0000208
209 for block in gles_blocks:
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000210 add_header_block(
211 'OpenGL ES {}.{}'.format(block.version.major, block.version.minor),
212 block)
Corentin Wallezdf69f242019-06-13 10:22:32 +0000213
214 for block in desktop_gl_blocks:
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000215 add_header_block(
216 'Desktop OpenGL {}.{}'.format(block.version.major,
217 block.version.minor), block)
Corentin Wallezdf69f242019-06-13 10:22:32 +0000218
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000219 for block in extension_desktop_gl_blocks:
220 add_header_block(block.extension, block)
221
222 for block in extension_gles_blocks:
223 add_header_block(block.extension, block)
224
Corentin Wallezdf69f242019-06-13 10:22:32 +0000225 return {
226 'gles_blocks': gles_blocks,
227 'desktop_gl_blocks': desktop_gl_blocks,
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000228 'extension_desktop_gl_blocks': extension_desktop_gl_blocks,
229 'extension_gles_blocks': extension_gles_blocks,
Corentin Wallezdf69f242019-06-13 10:22:32 +0000230 'header_blocks': header_blocks,
231 }
232
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000233
Corentin Wallezdf69f242019-06-13 10:22:32 +0000234class OpenGLLoaderGenerator(Generator):
235 def get_description(self):
236 return 'Generates code to load OpenGL function pointers'
237
238 def add_commandline_arguments(self, parser):
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000239 parser.add_argument('--gl-xml',
240 required=True,
241 type=str,
242 help='The Khronos gl.xml to use.')
243 parser.add_argument(
244 '--supported-extensions',
245 required=True,
246 type=str,
247 help=
248 'The JSON file that defines the OpenGL and GLES extensions to use.'
249 )
Corentin Wallezdf69f242019-06-13 10:22:32 +0000250
251 def get_file_renders(self, args):
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000252 supported_extensions = []
253 with open(args.supported_extensions) as f:
254 supported_extensions_json = json.loads(f.read())
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000255 supported_extensions = supported_extensions_json[
256 'supported_extensions']
Jiawei Shao9d9d76c2019-08-22 08:19:13 +0000257
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000258 params = compute_params(
259 etree.parse(args.gl_xml).getroot(), supported_extensions)
Corentin Wallezdf69f242019-06-13 10:22:32 +0000260
261 return [
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000262 FileRender(
263 'opengl/OpenGLFunctionsBase.cpp',
Ben Clayton818001d2022-02-04 17:07:46 +0000264 'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.cpp',
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000265 [params]),
266 FileRender('opengl/OpenGLFunctionsBase.h',
Ben Clayton818001d2022-02-04 17:07:46 +0000267 'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.h',
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000268 [params]),
269 FileRender('opengl/opengl_platform.h',
Ben Clayton818001d2022-02-04 17:07:46 +0000270 'src/dawn/native/opengl/opengl_platform_autogen.h',
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000271 [params]),
Corentin Wallezdf69f242019-06-13 10:22:32 +0000272 ]
273
274 def get_dependencies(self, args):
Corentin Wallez615d6ea2021-05-05 16:06:23 +0000275 return [
276 os.path.abspath(args.gl_xml),
277 os.path.abspath(args.supported_extensions)
278 ]
Corentin Wallezdf69f242019-06-13 10:22:32 +0000279
Kai Ninomiya01aeca22020-07-15 19:51:17 +0000280
Corentin Wallezdf69f242019-06-13 10:22:32 +0000281if __name__ == '__main__':
282 sys.exit(run_generator(OpenGLLoaderGenerator()))