Corentin Wallez | 59382b7 | 2020-04-17 20:43:07 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 2 | # 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 Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 16 | import os, json, sys |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 17 | from collections import namedtuple |
| 18 | import xml.etree.ElementTree as etree |
| 19 | |
| 20 | from generator_lib import Generator, run_generator, FileRender |
| 21 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 22 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 23 | class ProcName: |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 24 | def __init__(self, gl_name, proc_name=None): |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 25 | assert gl_name.startswith('gl') |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 26 | 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 44 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 45 | ProcParam = namedtuple('ProcParam', ['name', 'type']) |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 46 | |
| 47 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 48 | class 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 79 | self.params.append( |
| 80 | ProcParam( |
| 81 | param.find('name').text, parse_type_declaration(param))) |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 82 | |
| 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 92 | assert self.gl_name.startswith('gl') |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 93 | 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 101 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 102 | EnumDefine = namedtuple('EnumDefine', ['name', 'value']) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 103 | Version = namedtuple('Version', ['major', 'minor']) |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 104 | VersionBlock = namedtuple('VersionBlock', ['version', 'procs', 'enums']) |
| 105 | HeaderBlock = namedtuple('HeaderBlock', ['description', 'procs', 'enums']) |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 106 | ExtensionBlock = namedtuple('ExtensionBlock', |
| 107 | ['extension', 'procs', 'enums', 'supported_specs']) |
| 108 | |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 109 | |
| 110 | def parse_version(version): |
| 111 | return Version(*map(int, version.split('.'))) |
| 112 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 113 | |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 114 | def compute_params(root, supported_extensions): |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 115 | # Parse all the commands and enums |
| 116 | all_procs = {} |
| 117 | for command in root.findall('''commands[@namespace='GL']/command'''): |
| 118 | proc = Proc(command) |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 119 | assert proc.gl_name not in all_procs |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 120 | 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 129 | assert enum_name not in all_enums |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 130 | all_enums[enum_name] = EnumDefine(enum_name, enum.attrib['value']) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 131 | |
| 132 | # Get the list of all Desktop OpenGL function removed by the Core Profile. |
| 133 | core_removed_procs = set() |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 134 | for proc in root.findall('''feature/remove[@profile='core']/command'''): |
| 135 | core_removed_procs.add(proc.attrib['name']) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 136 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 137 | # Get list of enums and procs per OpenGL ES/Desktop OpenGL version |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 138 | def parse_version_blocks(api, removed_procs=set()): |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 139 | 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 144 | assert all_procs[proc_name].alias == None |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 145 | if proc_name not in removed_procs: |
| 146 | section_procs.append(all_procs[proc_name]) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 147 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 148 | section_enums = [] |
| 149 | for enum in section.findall('./require/enum'): |
| 150 | section_enums.append(all_enums[enum.attrib['name']]) |
| 151 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 152 | blocks.append( |
| 153 | VersionBlock(parse_version(section.attrib['number']), |
| 154 | section_procs, section_enums)) |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 155 | |
| 156 | return blocks |
| 157 | |
| 158 | gles_blocks = parse_version_blocks('gles2') |
| 159 | desktop_gl_blocks = parse_version_blocks('gl', core_removed_procs) |
| 160 | |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 161 | def parse_extension_block(extension): |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 162 | section = root.find( |
| 163 | '''extensions/extension[@name='{}']'''.format(extension)) |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 164 | supported_specs = section.attrib['supported'].split('|') |
| 165 | section_procs = [] |
| 166 | for command in section.findall('./require/command'): |
| 167 | proc_name = command.attrib['name'] |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 168 | assert all_procs[proc_name].alias == None |
Stephen White | d0ebcba | 2021-05-06 18:34:14 +0000 | [diff] [blame] | 169 | section_procs.append(all_procs[proc_name]) |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 170 | |
| 171 | section_enums = [] |
| 172 | for enum in section.findall('./require/enum'): |
| 173 | section_enums.append(all_enums[enum.attrib['name']]) |
| 174 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 175 | return ExtensionBlock(extension, section_procs, section_enums, |
| 176 | supported_specs) |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 177 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 178 | extension_desktop_gl_blocks = [] |
| 179 | extension_gles_blocks = [] |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 180 | 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 Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 187 | # Compute the blocks for headers such that there is no duplicate definition |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 188 | already_added_header_procs = set() |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 189 | already_added_header_enums = set() |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 190 | header_blocks = [] |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 191 | |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 192 | def add_header_block(description, block): |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 193 | block_procs = [] |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 194 | for proc in block.procs: |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 195 | if not proc.glProcName() in already_added_header_procs: |
| 196 | already_added_header_procs.add(proc.glProcName()) |
| 197 | block_procs.append(proc) |
Corentin Wallez | 8f4046b | 2019-06-17 09:17:29 +0000 | [diff] [blame] | 198 | |
| 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 206 | header_blocks.append( |
| 207 | HeaderBlock(description, block_procs, block_enums)) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 208 | |
| 209 | for block in gles_blocks: |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 210 | add_header_block( |
| 211 | 'OpenGL ES {}.{}'.format(block.version.major, block.version.minor), |
| 212 | block) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 213 | |
| 214 | for block in desktop_gl_blocks: |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 215 | add_header_block( |
| 216 | 'Desktop OpenGL {}.{}'.format(block.version.major, |
| 217 | block.version.minor), block) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 218 | |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 219 | 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 Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 225 | return { |
| 226 | 'gles_blocks': gles_blocks, |
| 227 | 'desktop_gl_blocks': desktop_gl_blocks, |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 228 | 'extension_desktop_gl_blocks': extension_desktop_gl_blocks, |
| 229 | 'extension_gles_blocks': extension_gles_blocks, |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 230 | 'header_blocks': header_blocks, |
| 231 | } |
| 232 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 233 | |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 234 | class 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 Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 239 | 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 Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 250 | |
| 251 | def get_file_renders(self, args): |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 252 | supported_extensions = [] |
| 253 | with open(args.supported_extensions) as f: |
| 254 | supported_extensions_json = json.loads(f.read()) |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 255 | supported_extensions = supported_extensions_json[ |
| 256 | 'supported_extensions'] |
Jiawei Shao | 9d9d76c | 2019-08-22 08:19:13 +0000 | [diff] [blame] | 257 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 258 | params = compute_params( |
| 259 | etree.parse(args.gl_xml).getroot(), supported_extensions) |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 260 | |
| 261 | return [ |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 262 | FileRender( |
| 263 | 'opengl/OpenGLFunctionsBase.cpp', |
Ben Clayton | 818001d | 2022-02-04 17:07:46 +0000 | [diff] [blame] | 264 | 'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.cpp', |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 265 | [params]), |
| 266 | FileRender('opengl/OpenGLFunctionsBase.h', |
Ben Clayton | 818001d | 2022-02-04 17:07:46 +0000 | [diff] [blame] | 267 | 'src/dawn/native/opengl/OpenGLFunctionsBase_autogen.h', |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 268 | [params]), |
| 269 | FileRender('opengl/opengl_platform.h', |
Ben Clayton | 818001d | 2022-02-04 17:07:46 +0000 | [diff] [blame] | 270 | 'src/dawn/native/opengl/opengl_platform_autogen.h', |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 271 | [params]), |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 272 | ] |
| 273 | |
| 274 | def get_dependencies(self, args): |
Corentin Wallez | 615d6ea | 2021-05-05 16:06:23 +0000 | [diff] [blame] | 275 | return [ |
| 276 | os.path.abspath(args.gl_xml), |
| 277 | os.path.abspath(args.supported_extensions) |
| 278 | ] |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 279 | |
Kai Ninomiya | 01aeca2 | 2020-07-15 19:51:17 +0000 | [diff] [blame] | 280 | |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 281 | if __name__ == '__main__': |
| 282 | sys.exit(run_generator(OpenGLLoaderGenerator())) |