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