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