• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Provide the utilities for framework generation.
18"""
19
20import os
21import subprocess
22import xml.etree.ElementTree as element_tree
23
24# Extensions unsupported on Android.
25_BLOCKED_EXTENSIONS = [
26    'VK_EXT_acquire_xlib_display',
27    'VK_EXT_direct_mode_display',
28    'VK_EXT_directfb_surface',
29    'VK_EXT_display_control',
30    'VK_EXT_display_surface_counter',
31    'VK_EXT_full_screen_exclusive',
32    'VK_EXT_headless_surface',
33    'VK_EXT_metal_surface',
34    'VK_FUCHSIA_imagepipe_surface',
35    'VK_GGP_stream_descriptor_surface',
36    'VK_HUAWEI_subpass_shading',
37    'VK_KHR_display',
38    'VK_KHR_display_swapchain',
39    'VK_KHR_external_fence_win32',
40    'VK_KHR_external_memory_win32',
41    'VK_KHR_external_semaphore_win32',
42    'VK_KHR_mir_surface',
43    'VK_KHR_wayland_surface',
44    'VK_KHR_win32_keyed_mutex',
45    'VK_KHR_win32_surface',
46    'VK_KHR_xcb_surface',
47    'VK_KHR_xlib_surface',
48    'VK_MVK_ios_surface',
49    'VK_MVK_macos_surface',
50    'VK_NN_vi_surface',
51    'VK_NV_acquire_winrt_display',
52    'VK_NV_cooperative_matrix',
53    'VK_NV_coverage_reduction_mode',
54    'VK_NV_external_memory_win32',
55    'VK_NV_win32_keyed_mutex',
56    'VK_NVX_image_view_handle',
57    'VK_QNX_screen_surface',
58]
59
60# Extensions having functions exported by the loader.
61_EXPORTED_EXTENSIONS = [
62    'VK_ANDROID_external_memory_android_hardware_buffer',
63    'VK_KHR_android_surface',
64    'VK_KHR_surface',
65    'VK_KHR_swapchain',
66]
67
68# Functions optional on Android even if extension is advertised.
69_OPTIONAL_COMMANDS = [
70    'vkGetSwapchainGrallocUsageANDROID',
71    'vkGetSwapchainGrallocUsage2ANDROID',
72]
73
74# Dict for mapping dispatch table to a type.
75_DISPATCH_TYPE_DICT = {
76    'VkInstance ': 'Instance',
77    'VkPhysicalDevice ': 'Instance',
78    'VkDevice ': 'Device',
79    'VkQueue ': 'Device',
80    'VkCommandBuffer ': 'Device'
81}
82
83# Dict for mapping a function to its alias.
84alias_dict = {}
85
86# List of all the Vulkan functions.
87command_list = []
88
89# Dict for mapping a function to an extension.
90extension_dict = {}
91
92# Dict for mapping a function to all its parameters.
93param_dict = {}
94
95# Dict for mapping a function to its return type.
96return_type_dict = {}
97
98# List of the sorted Vulkan version codes. e.g. '1_0', '1_1'.
99version_code_list = []
100
101# Dict for mapping a function to the core Vulkan API version.
102version_dict = {}
103
104# Dict for mapping a promoted instance extension to the core Vulkan API version.
105promoted_inst_ext_dict = {}
106
107
108def indent(num):
109  """Returns the requested indents.
110
111  Args:
112    num: Number of the 4-space indents.
113  """
114  return '    ' * num
115
116
117def copyright_and_warning(year):
118  """Returns the standard copyright and warning codes.
119
120  Args:
121    year: An integer year for the copyright.
122  """
123  return """\
124/*
125 * Copyright """ + str(year) + """ The Android Open Source Project
126 *
127 * Licensed under the Apache License, Version 2.0 (the "License");
128 * you may not use this file except in compliance with the License.
129 * You may obtain a copy of the License at
130 *
131 *      http://www.apache.org/licenses/LICENSE-2.0
132 *
133 * Unless required by applicable law or agreed to in writing, software
134 * distributed under the License is distributed on an "AS IS" BASIS,
135 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136 * See the License for the specific language governing permissions and
137 * limitations under the License.
138 */
139
140// WARNING: This file is generated. See ../README.md for instructions.
141
142"""
143
144
145def run_clang_format(args):
146  """Run clang format on the file.
147
148  Args:
149    args: The file to be formatted.
150  """
151  clang_call = ['clang-format', '--style', 'file', '-i', args]
152  subprocess.check_call(clang_call)
153
154
155def is_extension_internal(ext):
156  """Returns true if an extension is internal to the loader and drivers.
157
158  The loader should not enumerate this extension.
159
160  Args:
161    ext: Vulkan extension name.
162  """
163  return ext == 'VK_ANDROID_native_buffer'
164
165
166def base_name(cmd):
167  """Returns a function name without the 'vk' prefix.
168
169  Args:
170    cmd: Vulkan function name.
171  """
172  return cmd[2:]
173
174
175def base_ext_name(ext):
176  """Returns an extension name without the 'VK_' prefix.
177
178  Args:
179    ext: Vulkan extension name.
180  """
181  return ext[3:]
182
183
184def version_code(version):
185  """Returns the version code from a version string.
186
187  Args:
188    version: Vulkan version string.
189  """
190  return version[11:]
191
192
193def version_2_api_version(version):
194  """Returns the api version from a version string.
195
196  Args:
197    version: Vulkan version string.
198  """
199  return 'VK_API' + version[2:]
200
201
202def is_function_supported(cmd):
203  """Returns true if a function is core or from a supportable extension.
204
205  Args:
206    cmd: Vulkan function name.
207  """
208  if cmd not in extension_dict:
209    return True
210  else:
211    if extension_dict[cmd] not in _BLOCKED_EXTENSIONS:
212      return True
213  return False
214
215
216def get_dispatch_table_type(cmd):
217  """Returns the dispatch table type for a function.
218
219  Args:
220    cmd: Vulkan function name.
221  """
222  if cmd not in param_dict:
223    return None
224
225  if param_dict[cmd]:
226    return _DISPATCH_TYPE_DICT.get(param_dict[cmd][0][0], 'Global')
227  return 'Global'
228
229
230def is_globally_dispatched(cmd):
231  """Returns true if the function is global, which is not dispatched.
232
233  Only global functions and functions handled in the loader top without calling
234  into lower layers are not dispatched.
235
236  Args:
237    cmd: Vulkan function name.
238  """
239  return is_function_supported(cmd) and get_dispatch_table_type(cmd) == 'Global'
240
241
242def is_instance_dispatched(cmd):
243  """Returns true for functions that can have instance-specific dispatch.
244
245  Args:
246    cmd: Vulkan function name.
247  """
248  return (is_function_supported(cmd) and
249          get_dispatch_table_type(cmd) == 'Instance')
250
251
252def is_device_dispatched(cmd):
253  """Returns true for functions that can have device-specific dispatch.
254
255  Args:
256    cmd: Vulkan function name.
257  """
258  return is_function_supported(cmd) and get_dispatch_table_type(cmd) == 'Device'
259
260
261def is_extension_exported(ext):
262  """Returns true if an extension has functions exported by the loader.
263
264  E.g. applications can directly link to an extension function.
265
266  Args:
267    ext: Vulkan extension name.
268  """
269  return ext in _EXPORTED_EXTENSIONS
270
271
272def is_function_exported(cmd):
273  """Returns true if a function is exported from the Android Vulkan library.
274
275  Functions in the core API and in loader extensions are exported.
276
277  Args:
278    cmd: Vulkan function name.
279  """
280  if is_function_supported(cmd):
281    if cmd in extension_dict:
282      return is_extension_exported(extension_dict[cmd])
283    return True
284  return False
285
286
287def is_instance_dispatch_table_entry(cmd):
288  """Returns true if a function is exported and instance-dispatched.
289
290  Args:
291    cmd: Vulkan function name.
292  """
293  if cmd == 'vkEnumerateDeviceLayerProperties':
294    # deprecated, unused internally - @dbd33bc
295    return False
296  return is_function_exported(cmd) and is_instance_dispatched(cmd)
297
298
299def is_device_dispatch_table_entry(cmd):
300  """Returns true if a function is exported and device-dispatched.
301
302  Args:
303    cmd: Vulkan function name.
304  """
305  return is_function_exported(cmd) and is_device_dispatched(cmd)
306
307
308def init_proc(name, f):
309  """Emits code to invoke INIT_PROC or INIT_PROC_EXT.
310
311  Args:
312    name: Vulkan function name.
313    f: Output file handle.
314  """
315  f.write(indent(1))
316  if name in extension_dict:
317    f.write('INIT_PROC_EXT(' + base_ext_name(extension_dict[name]) + ', ')
318  else:
319    f.write('INIT_PROC(')
320
321  if name in _OPTIONAL_COMMANDS:
322    f.write('false, ')
323  elif version_dict[name] == 'VK_VERSION_1_0':
324    f.write('true, ')
325  else:
326    f.write('false, ')
327
328  if is_instance_dispatched(name):
329    f.write('instance, ')
330  else:
331    f.write('dev, ')
332
333  f.write(base_name(name) + ');\n')
334
335
336def parse_vulkan_registry():
337  """Parses Vulkan registry into the below global variables.
338
339  alias_dict
340  command_list
341  extension_dict
342  param_dict
343  return_type_dict
344  version_code_list
345  version_dict
346  promoted_inst_ext_dict
347  """
348  registry = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
349                          'external', 'vulkan-headers', 'registry', 'vk.xml')
350  tree = element_tree.parse(registry)
351  root = tree.getroot()
352  for commands in root.iter('commands'):
353    for command in commands:
354      if command.tag == 'command':
355        parameter_list = []
356        protoset = False
357        cmd_name = ''
358        cmd_type = ''
359        if command.get('alias') is not None:
360          alias = command.get('alias')
361          cmd_name = command.get('name')
362          alias_dict[cmd_name] = alias
363          command_list.append(cmd_name)
364          param_dict[cmd_name] = param_dict[alias].copy()
365          return_type_dict[cmd_name] = return_type_dict[alias]
366        for params in command:
367          if params.tag == 'param':
368            param_type = ''
369            if params.text is not None and params.text.strip():
370              param_type = params.text.strip() + ' '
371            type_val = params.find('type')
372            param_type = param_type + type_val.text
373            if type_val.tail is not None:
374              param_type += type_val.tail.strip() + ' '
375            pname = params.find('name')
376            param_name = pname.text
377            if pname.tail is not None and pname.tail.strip():
378              parameter_list.append(
379                  (param_type, param_name, pname.tail.strip()))
380            else:
381              parameter_list.append((param_type, param_name))
382          if params.tag == 'proto':
383            for c in params:
384              if c.tag == 'type':
385                cmd_type = c.text
386              if c.tag == 'name':
387                cmd_name = c.text
388                protoset = True
389                command_list.append(cmd_name)
390                return_type_dict[cmd_name] = cmd_type
391        if protoset:
392          param_dict[cmd_name] = parameter_list.copy()
393
394  for exts in root.iter('extensions'):
395    for extension in exts:
396      apiversion = 'VK_VERSION_1_0'
397      if extension.tag == 'extension':
398        extname = extension.get('name')
399        if (extension.get('type') == 'instance' and
400            extension.get('promotedto') is not None):
401          promoted_inst_ext_dict[extname] = \
402              version_2_api_version(extension.get('promotedto'))
403        for req in extension:
404          if req.get('feature') is not None:
405            apiversion = req.get('feature')
406          for commands in req:
407            if commands.tag == 'command':
408              cmd_name = commands.get('name')
409              if cmd_name not in extension_dict:
410                extension_dict[cmd_name] = extname
411                version_dict[cmd_name] = apiversion
412
413  for feature in root.iter('feature'):
414    apiversion = feature.get('name')
415    for req in feature:
416      for command in req:
417        if command.tag == 'command':
418          cmd_name = command.get('name')
419          if cmd_name in command_list:
420            version_dict[cmd_name] = apiversion
421
422  version_code_set = set()
423  for version in version_dict.values():
424    version_code_set.add(version_code(version))
425  for code in sorted(version_code_set):
426    version_code_list.append(code)
427