• 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"""Generates the driver_gen.h and driver_gen.cpp.
18"""
19
20import os
21import generator_common as gencom
22
23# Extensions intercepted at vulkan::driver level.
24_INTERCEPTED_EXTENSIONS = [
25    'VK_ANDROID_native_buffer',
26    'VK_EXT_debug_report',
27    'VK_EXT_hdr_metadata',
28    'VK_EXT_swapchain_colorspace',
29    'VK_GOOGLE_display_timing',
30    'VK_KHR_android_surface',
31    'VK_KHR_get_surface_capabilities2',
32    'VK_KHR_incremental_present',
33    'VK_KHR_shared_presentable_image',
34    'VK_KHR_surface',
35    'VK_KHR_swapchain',
36]
37
38# Extensions known to vulkan::driver level.
39_KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [
40    'VK_ANDROID_external_memory_android_hardware_buffer',
41    'VK_KHR_bind_memory2',
42    'VK_KHR_get_physical_device_properties2',
43]
44
45# Functions needed at vulkan::driver level.
46_NEEDED_COMMANDS = [
47    # Create functions of dispatchable objects
48    'vkCreateDevice',
49    'vkGetDeviceQueue',
50    'vkGetDeviceQueue2',
51    'vkAllocateCommandBuffers',
52
53    # Destroy functions of dispatchable objects
54    'vkDestroyInstance',
55    'vkDestroyDevice',
56
57    # Enumeration of extensions
58    'vkEnumerateDeviceExtensionProperties',
59
60    # We cache physical devices in loader.cpp
61    'vkEnumeratePhysicalDevices',
62    'vkEnumeratePhysicalDeviceGroups',
63
64    'vkGetInstanceProcAddr',
65    'vkGetDeviceProcAddr',
66
67    'vkQueueSubmit',
68
69    # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
70    'vkCreateImage',
71    'vkDestroyImage',
72
73    'vkGetPhysicalDeviceProperties',
74    'vkGetPhysicalDeviceProperties2',
75    'vkGetPhysicalDeviceProperties2KHR',
76
77    # VK_KHR_swapchain v69 requirement
78    'vkBindImageMemory2',
79    'vkBindImageMemory2KHR',
80]
81
82# Functions intercepted at vulkan::driver level.
83_INTERCEPTED_COMMANDS = [
84    # Create functions of dispatchable objects
85    'vkCreateInstance',
86    'vkCreateDevice',
87    'vkEnumeratePhysicalDevices',
88    'vkEnumeratePhysicalDeviceGroups',
89    'vkGetDeviceQueue',
90    'vkGetDeviceQueue2',
91    'vkAllocateCommandBuffers',
92
93    # Destroy functions of dispatchable objects
94    'vkDestroyInstance',
95    'vkDestroyDevice',
96
97    # Enumeration of extensions
98    'vkEnumerateInstanceExtensionProperties',
99    'vkEnumerateDeviceExtensionProperties',
100
101    'vkGetInstanceProcAddr',
102    'vkGetDeviceProcAddr',
103
104    'vkQueueSubmit',
105
106    # VK_KHR_swapchain v69 requirement
107    'vkBindImageMemory2',
108    'vkBindImageMemory2KHR',
109]
110
111
112def _is_driver_table_entry(cmd):
113  """Returns true if a function is needed by vulkan::driver.
114
115  Args:
116    cmd: Vulkan function name.
117  """
118  if gencom.is_function_supported(cmd):
119    if cmd in _NEEDED_COMMANDS:
120      return True
121    if cmd in gencom.extension_dict:
122      if (gencom.extension_dict[cmd] == 'VK_ANDROID_native_buffer' or
123          gencom.extension_dict[cmd] == 'VK_EXT_debug_report'):
124        return True
125  return False
126
127
128def _is_instance_driver_table_entry(cmd):
129  """Returns true if a instance-dispatched function is needed by vulkan::driver.
130
131  Args:
132    cmd: Vulkan function name.
133  """
134  return (_is_driver_table_entry(cmd) and
135          gencom.is_instance_dispatched(cmd))
136
137
138def _is_device_driver_table_entry(cmd):
139  """Returns true if a device-dispatched function is needed by vulkan::driver.
140
141  Args:
142    cmd: Vulkan function name.
143  """
144  return (_is_driver_table_entry(cmd) and
145          gencom.is_device_dispatched(cmd))
146
147
148def gen_h():
149  """Generates the driver_gen.h file.
150  """
151  genfile = os.path.join(os.path.dirname(__file__),
152                         '..', 'libvulkan', 'driver_gen.h')
153
154  with open(genfile, 'w') as f:
155    f.write(gencom.copyright_and_warning(2016))
156
157    f.write("""\
158#ifndef LIBVULKAN_DRIVER_GEN_H
159#define LIBVULKAN_DRIVER_GEN_H
160
161#include <vulkan/vk_android_native_buffer.h>
162#include <vulkan/vulkan.h>
163
164#include <bitset>
165
166namespace vulkan {
167namespace driver {
168
169struct ProcHook {
170    enum Type {
171        GLOBAL,
172        INSTANCE,
173        DEVICE,
174    };
175    enum Extension {\n""")
176
177    for ext in _KNOWN_EXTENSIONS:
178      f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n')
179
180    f.write('\n')
181    for version in gencom.version_code_list:
182      f.write(gencom.indent(2) + 'EXTENSION_CORE_' + version + ',\n')
183
184    # EXTENSION_COUNT must be the next enum after the highest API version.
185    f.write("""\
186        EXTENSION_COUNT,
187        EXTENSION_UNKNOWN,
188    };
189
190    const char* name;
191    Type type;
192    Extension extension;
193
194    PFN_vkVoidFunction proc;
195    PFN_vkVoidFunction checked_proc;  // always nullptr for non-device hooks
196};
197
198struct InstanceDriverTable {
199    // clang-format off\n""")
200
201    for cmd in gencom.command_list:
202      if _is_instance_driver_table_entry(cmd):
203        f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' +
204                gencom.base_name(cmd) + ';\n')
205
206    f.write("""\
207    // clang-format on
208};
209
210struct DeviceDriverTable {
211    // clang-format off\n""")
212
213    for cmd in gencom.command_list:
214      if _is_device_driver_table_entry(cmd):
215        f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' +
216                gencom.base_name(cmd) + ';\n')
217
218    f.write("""\
219    // clang-format on
220};
221
222const ProcHook* GetProcHook(const char* name);
223ProcHook::Extension GetProcHookExtension(const char* name);
224
225bool InitDriverTable(VkInstance instance,
226                     PFN_vkGetInstanceProcAddr get_proc,
227                     const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
228bool InitDriverTable(VkDevice dev,
229                     PFN_vkGetDeviceProcAddr get_proc,
230                     const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
231
232}  // namespace driver
233}  // namespace vulkan
234
235#endif  // LIBVULKAN_DRIVER_TABLE_H\n""")
236
237    f.close()
238  gencom.run_clang_format(genfile)
239
240
241def _is_intercepted(cmd):
242  """Returns true if a function is intercepted by vulkan::driver.
243
244  Args:
245    cmd: Vulkan function name.
246  """
247  if gencom.is_function_supported(cmd):
248    if cmd in _INTERCEPTED_COMMANDS:
249      return True
250
251    if cmd in gencom.extension_dict:
252      return gencom.extension_dict[cmd] in _INTERCEPTED_EXTENSIONS
253  return False
254
255
256def _get_proc_hook_enum(cmd):
257  """Returns the ProcHook enumeration for the corresponding core function.
258
259  Args:
260    cmd: Vulkan function name.
261  """
262  assert cmd in gencom.version_dict
263  for version in gencom.version_code_list:
264    if gencom.version_dict[cmd] == 'VK_VERSION_' + version:
265      return 'ProcHook::EXTENSION_CORE_' + version
266
267
268def _need_proc_hook_stub(cmd):
269  """Returns true if a function needs a ProcHook stub.
270
271  Args:
272    cmd: Vulkan function name.
273  """
274  if _is_intercepted(cmd) and gencom.is_device_dispatched(cmd):
275    if cmd in gencom.extension_dict:
276      if not gencom.is_extension_internal(gencom.extension_dict[cmd]):
277        return True
278    elif gencom.version_dict[cmd] != 'VK_VERSION_1_0':
279      return True
280  return False
281
282
283def _define_proc_hook_stub(cmd, f):
284  """Emits a stub for ProcHook::checked_proc.
285
286  Args:
287    cmd: Vulkan function name.
288    f: Output file handle.
289  """
290  if _need_proc_hook_stub(cmd):
291    return_type = gencom.return_type_dict[cmd]
292
293    ext_name = ''
294    ext_hook = ''
295    if cmd in gencom.extension_dict:
296      ext_name = gencom.extension_dict[cmd]
297      ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
298    else:
299      ext_name = gencom.version_dict[cmd]
300      ext_hook = _get_proc_hook_enum(cmd)
301
302    handle = gencom.param_dict[cmd][0][1]
303    param_types = ', '.join([''.join(i) for i in gencom.param_dict[cmd]])
304    param_names = ', '.join([''.join(i[1]) for i in gencom.param_dict[cmd]])
305
306    f.write('VKAPI_ATTR ' + return_type + ' checked' + gencom.base_name(cmd) +
307            '(' + param_types + ') {\n')
308    f.write(gencom.indent(1) + 'if (GetData(' + handle + ').hook_extensions[' +
309            ext_hook + ']) {\n')
310
311    f.write(gencom.indent(2))
312    if gencom.return_type_dict[cmd] != 'void':
313      f.write('return ')
314    f.write(gencom.base_name(cmd) + '(' + param_names + ');\n')
315
316    f.write(gencom.indent(1) + '} else {\n')
317    f.write(gencom.indent(2) + 'Logger(' + handle + ').Err(' + handle + ', \"' +
318            ext_name + ' not enabled. ' + cmd + ' not executed.\");\n')
319    if gencom.return_type_dict[cmd] != 'void':
320      f.write(gencom.indent(2) + 'return VK_SUCCESS;\n')
321    f.write(gencom.indent(1) + '}\n}\n\n')
322
323
324def _define_global_proc_hook(cmd, f):
325  """Emits definition of a global ProcHook.
326
327  Args:
328    cmd: Vulkan function name.
329    f: Output file handle.
330  """
331  assert cmd not in gencom.extension_dict
332
333  f.write(gencom.indent(1) + '{\n')
334  f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
335  f.write(gencom.indent(2) + 'ProcHook::GLOBAL,\n')
336  f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
337  f.write(gencom.indent(2) + 'reinterpret_cast<PFN_vkVoidFunction>(' +
338          gencom.base_name(cmd) + '),\n')
339  f.write(gencom.indent(2) + 'nullptr,\n')
340  f.write(gencom.indent(1) + '},\n')
341
342
343def _define_instance_proc_hook(cmd, f):
344  """Emits definition of a instance ProcHook.
345
346  Args:
347    cmd: Vulkan function name.
348    f: Output file handle.
349  """
350  f.write(gencom.indent(1) + '{\n')
351  f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
352  f.write(gencom.indent(2) + 'ProcHook::INSTANCE,\n')
353
354  if cmd in gencom.extension_dict:
355    ext_name = gencom.extension_dict[cmd]
356    f.write(gencom.indent(2) + 'ProcHook::' +
357            gencom.base_ext_name(ext_name) + ',\n')
358
359    if gencom.is_extension_internal(ext_name):
360      f.write("""\
361        nullptr,
362        nullptr,\n""")
363    else:
364      f.write("""\
365        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
366        nullptr,\n""")
367  else:
368    f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
369    f.write("""\
370        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
371        nullptr,\n""")
372
373  f.write(gencom.indent(1) + '},\n')
374
375
376def _define_device_proc_hook(cmd, f):
377  """Emits definition of a device ProcHook.
378
379  Args:
380    cmd: Vulkan function name.
381    f: Output file handle.
382  """
383  f.write(gencom.indent(1) + '{\n')
384  f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
385  f.write(gencom.indent(2) + 'ProcHook::DEVICE,\n')
386
387  if (cmd in gencom.extension_dict or
388      gencom.version_dict[cmd] != 'VK_VERSION_1_0'):
389    ext_name = ''
390    ext_hook = ''
391    if cmd in gencom.extension_dict:
392      ext_name = gencom.extension_dict[cmd]
393      ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
394    else:
395      ext_name = gencom.version_dict[cmd]
396      ext_hook = _get_proc_hook_enum(cmd)
397    f.write(gencom.indent(2) + ext_hook + ',\n')
398
399    if gencom.is_extension_internal(ext_name):
400      f.write("""\
401        nullptr,
402        nullptr,\n""")
403    else:
404      f.write("""\
405        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
406        reinterpret_cast<PFN_vkVoidFunction>(checked""" +
407              gencom.base_name(cmd) + '),\n')
408
409  else:
410    f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
411    f.write("""\
412        reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
413        nullptr,\n""")
414
415  f.write(gencom.indent(1) + '},\n')
416
417
418def gen_cpp():
419  """Generates the driver_gen.cpp file.
420  """
421  genfile = os.path.join(os.path.dirname(__file__),
422                         '..', 'libvulkan', 'driver_gen.cpp')
423
424  with open(genfile, 'w') as f:
425    f.write(gencom.copyright_and_warning(2016))
426    f.write("""\
427#include <log/log.h>
428#include <string.h>
429
430#include <algorithm>
431
432#include "driver.h"
433
434namespace vulkan {
435namespace driver {
436
437namespace {
438
439// clang-format off\n\n""")
440
441    for cmd in gencom.command_list:
442      _define_proc_hook_stub(cmd, f)
443
444    f.write("""\
445// clang-format on
446
447const ProcHook g_proc_hooks[] = {
448    // clang-format off\n""")
449
450    sorted_command_list = sorted(gencom.command_list)
451    for cmd in sorted_command_list:
452      if _is_intercepted(cmd):
453        if gencom.is_globally_dispatched(cmd):
454          _define_global_proc_hook(cmd, f)
455        elif gencom.is_instance_dispatched(cmd):
456          _define_instance_proc_hook(cmd, f)
457        elif gencom.is_device_dispatched(cmd):
458          _define_device_proc_hook(cmd, f)
459
460    f.write("""\
461    // clang-format on
462};
463
464}  // namespace
465
466const ProcHook* GetProcHook(const char* name) {
467    const auto& begin = g_proc_hooks;
468    const auto& end =
469        g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
470    const auto hook = std::lower_bound(
471        begin, end, name,
472        [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
473    return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
474}
475
476ProcHook::Extension GetProcHookExtension(const char* name) {
477    // clang-format off\n""")
478
479    for ext in _KNOWN_EXTENSIONS:
480      f.write(gencom.indent(1) + 'if (strcmp(name, \"' + ext +
481              '\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n')
482
483    f.write("""\
484    // clang-format on
485    return ProcHook::EXTENSION_UNKNOWN;
486}
487
488#define UNLIKELY(expr) __builtin_expect((expr), 0)
489
490#define INIT_PROC(required, obj, proc)                                 \\
491    do {                                                               \\
492        data.driver.proc =                                             \\
493            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
494        if (UNLIKELY(required && !data.driver.proc)) {                 \\
495            ALOGE("missing " #obj " proc: vk" #proc);                  \\
496            success = false;                                           \\
497        }                                                              \\
498    } while (0)
499
500#define INIT_PROC_EXT(ext, required, obj, proc) \\
501    do {                                        \\
502        if (extensions[ProcHook::ext])          \\
503            INIT_PROC(required, obj, proc);     \\
504    } while (0)
505
506bool InitDriverTable(VkInstance instance,
507                     PFN_vkGetInstanceProcAddr get_proc,
508                     const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
509    auto& data = GetData(instance);
510    bool success = true;
511
512    // clang-format off\n""")
513
514    for cmd in gencom.command_list:
515      if _is_instance_driver_table_entry(cmd):
516        gencom.init_proc(cmd, f)
517
518    f.write("""\
519    // clang-format on
520
521    return success;
522}
523
524bool InitDriverTable(VkDevice dev,
525                     PFN_vkGetDeviceProcAddr get_proc,
526                     const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
527    auto& data = GetData(dev);
528    bool success = true;
529
530    // clang-format off\n""")
531
532    for cmd in gencom.command_list:
533      if _is_device_driver_table_entry(cmd):
534        gencom.init_proc(cmd, f)
535
536    f.write("""\
537    // clang-format on
538
539    return success;
540}
541
542}  // namespace driver
543}  // namespace vulkan\n""")
544
545    f.close()
546  gencom.run_clang_format(genfile)
547