You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

653 lines
19 KiB

#!/usr/bin/env python3
#
# Copyright 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Generates the driver_gen.h and driver_gen.cpp.
"""
import os
import generator_common as gencom
# Extensions intercepted at vulkan::driver level.
_INTERCEPTED_EXTENSIONS = [
'VK_ANDROID_native_buffer',
'VK_EXT_debug_report',
'VK_EXT_hdr_metadata',
'VK_EXT_swapchain_colorspace',
'VK_GOOGLE_display_timing',
'VK_KHR_android_surface',
'VK_KHR_get_surface_capabilities2',
'VK_KHR_incremental_present',
'VK_KHR_shared_presentable_image',
'VK_KHR_surface',
'VK_KHR_swapchain',
]
# Extensions known to vulkan::driver level.
_KNOWN_EXTENSIONS = _INTERCEPTED_EXTENSIONS + [
'VK_ANDROID_external_memory_android_hardware_buffer',
'VK_KHR_bind_memory2',
'VK_KHR_get_physical_device_properties2',
'VK_KHR_device_group_creation',
'VK_KHR_external_memory_capabilities',
'VK_KHR_external_semaphore_capabilities',
'VK_KHR_external_fence_capabilities',
]
# Functions needed at vulkan::driver level.
_NEEDED_COMMANDS = [
# Create functions of dispatchable objects
'vkCreateDevice',
'vkGetDeviceQueue',
'vkGetDeviceQueue2',
'vkAllocateCommandBuffers',
# Destroy functions of dispatchable objects
'vkDestroyInstance',
'vkDestroyDevice',
# Enumeration of extensions
'vkEnumerateDeviceExtensionProperties',
# We cache physical devices in loader.cpp
'vkEnumeratePhysicalDevices',
'vkEnumeratePhysicalDeviceGroups',
'vkGetInstanceProcAddr',
'vkGetDeviceProcAddr',
'vkQueueSubmit',
# VK_KHR_swapchain->VK_ANDROID_native_buffer translation
'vkCreateImage',
'vkDestroyImage',
'vkGetPhysicalDeviceProperties',
# VK_KHR_swapchain v69 requirement
'vkBindImageMemory2',
'vkBindImageMemory2KHR',
# For promoted VK_KHR_device_group_creation
'vkEnumeratePhysicalDeviceGroupsKHR',
# For promoted VK_KHR_get_physical_device_properties2
'vkGetPhysicalDeviceFeatures2',
'vkGetPhysicalDeviceFeatures2KHR',
'vkGetPhysicalDeviceProperties2',
'vkGetPhysicalDeviceProperties2KHR',
'vkGetPhysicalDeviceFormatProperties2',
'vkGetPhysicalDeviceFormatProperties2KHR',
'vkGetPhysicalDeviceImageFormatProperties2',
'vkGetPhysicalDeviceImageFormatProperties2KHR',
'vkGetPhysicalDeviceQueueFamilyProperties2',
'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
'vkGetPhysicalDeviceMemoryProperties2',
'vkGetPhysicalDeviceMemoryProperties2KHR',
'vkGetPhysicalDeviceSparseImageFormatProperties2',
'vkGetPhysicalDeviceSparseImageFormatProperties2KHR',
# For promoted VK_KHR_external_memory_capabilities
'vkGetPhysicalDeviceExternalBufferProperties',
'vkGetPhysicalDeviceExternalBufferPropertiesKHR',
# For promoted VK_KHR_external_semaphore_capabilities
'vkGetPhysicalDeviceExternalSemaphoreProperties',
'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR',
# For promoted VK_KHR_external_fence_capabilities
'vkGetPhysicalDeviceExternalFenceProperties',
'vkGetPhysicalDeviceExternalFencePropertiesKHR',
]
# Functions intercepted at vulkan::driver level.
_INTERCEPTED_COMMANDS = [
# Create functions of dispatchable objects
'vkCreateInstance',
'vkCreateDevice',
'vkEnumeratePhysicalDevices',
'vkEnumeratePhysicalDeviceGroups',
'vkGetDeviceQueue',
'vkGetDeviceQueue2',
'vkAllocateCommandBuffers',
# Destroy functions of dispatchable objects
'vkDestroyInstance',
'vkDestroyDevice',
# Enumeration of extensions
'vkEnumerateInstanceExtensionProperties',
'vkEnumerateDeviceExtensionProperties',
'vkGetInstanceProcAddr',
'vkGetDeviceProcAddr',
'vkQueueSubmit',
# VK_KHR_swapchain v69 requirement
'vkBindImageMemory2',
'vkBindImageMemory2KHR',
# For promoted VK_KHR_get_physical_device_properties2
'vkGetPhysicalDeviceFeatures2',
'vkGetPhysicalDeviceProperties2',
'vkGetPhysicalDeviceFormatProperties2',
'vkGetPhysicalDeviceImageFormatProperties2',
'vkGetPhysicalDeviceQueueFamilyProperties2',
'vkGetPhysicalDeviceMemoryProperties2',
'vkGetPhysicalDeviceSparseImageFormatProperties2',
# For promoted VK_KHR_external_memory_capabilities
'vkGetPhysicalDeviceExternalBufferProperties',
# For promoted VK_KHR_external_semaphore_capabilities
'vkGetPhysicalDeviceExternalSemaphoreProperties',
# For promoted VK_KHR_external_fence_capabilities
'vkGetPhysicalDeviceExternalFenceProperties',
]
def _is_driver_table_entry(cmd):
"""Returns true if a function is needed by vulkan::driver.
Args:
cmd: Vulkan function name.
"""
if gencom.is_function_supported(cmd):
if cmd in _NEEDED_COMMANDS:
return True
if cmd in gencom.extension_dict:
if (gencom.extension_dict[cmd] == 'VK_ANDROID_native_buffer' or
gencom.extension_dict[cmd] == 'VK_EXT_debug_report'):
return True
return False
def _is_instance_driver_table_entry(cmd):
"""Returns true if a instance-dispatched function is needed by vulkan::driver.
Args:
cmd: Vulkan function name.
"""
return (_is_driver_table_entry(cmd) and
gencom.is_instance_dispatched(cmd))
def _is_device_driver_table_entry(cmd):
"""Returns true if a device-dispatched function is needed by vulkan::driver.
Args:
cmd: Vulkan function name.
"""
return (_is_driver_table_entry(cmd) and
gencom.is_device_dispatched(cmd))
def gen_h():
"""Generates the driver_gen.h file.
"""
genfile = os.path.join(os.path.dirname(__file__),
'..', 'libvulkan', 'driver_gen.h')
with open(genfile, 'w') as f:
f.write(gencom.copyright_and_warning(2016))
f.write("""\
#ifndef LIBVULKAN_DRIVER_GEN_H
#define LIBVULKAN_DRIVER_GEN_H
#include <vulkan/vk_android_native_buffer.h>
#include <vulkan/vulkan.h>
#include <bitset>
#include <optional>
#include <vector>
namespace vulkan {
namespace driver {
struct ProcHook {
enum Type {
GLOBAL,
INSTANCE,
DEVICE,
};
enum Extension {\n""")
for ext in _KNOWN_EXTENSIONS:
f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n')
f.write('\n')
for version in gencom.version_code_list:
f.write(gencom.indent(2) + 'EXTENSION_CORE_' + version + ',\n')
# EXTENSION_COUNT must be the next enum after the highest API version.
f.write("""\
EXTENSION_COUNT,
EXTENSION_UNKNOWN,
};
const char* name;
Type type;
Extension extension;
PFN_vkVoidFunction proc;
PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks
};
struct InstanceDriverTable {
// clang-format off\n""")
for cmd in gencom.command_list:
if _is_instance_driver_table_entry(cmd):
f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' +
gencom.base_name(cmd) + ';\n')
f.write("""\
// clang-format on
};
struct DeviceDriverTable {
// clang-format off\n""")
for cmd in gencom.command_list:
if _is_device_driver_table_entry(cmd):
f.write(gencom.indent(1) + 'PFN_' + cmd + ' ' +
gencom.base_name(cmd) + ';\n')
f.write("""\
// clang-format on
};
const ProcHook* GetProcHook(const char* name);
ProcHook::Extension GetProcHookExtension(const char* name);
bool InitDriverTable(VkInstance instance,
PFN_vkGetInstanceProcAddr get_proc,
const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
bool InitDriverTable(VkDevice dev,
PFN_vkGetDeviceProcAddr get_proc,
const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name);
uint32_t CountPromotedInstanceExtensions(uint32_t begin_version,
uint32_t end_version);
std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version,
uint32_t end_version);
} // namespace driver
} // namespace vulkan
#endif // LIBVULKAN_DRIVER_TABLE_H\n""")
f.close()
gencom.run_clang_format(genfile)
def _is_intercepted(cmd):
"""Returns true if a function is intercepted by vulkan::driver.
Args:
cmd: Vulkan function name.
"""
if gencom.is_function_supported(cmd):
if cmd in _INTERCEPTED_COMMANDS:
return True
if cmd in gencom.extension_dict:
return gencom.extension_dict[cmd] in _INTERCEPTED_EXTENSIONS
return False
def _get_proc_hook_enum(cmd):
"""Returns the ProcHook enumeration for the corresponding core function.
Args:
cmd: Vulkan function name.
"""
assert cmd in gencom.version_dict
for version in gencom.version_code_list:
if gencom.version_dict[cmd] == 'VK_VERSION_' + version:
return 'ProcHook::EXTENSION_CORE_' + version
def _need_proc_hook_stub(cmd):
"""Returns true if a function needs a ProcHook stub.
Args:
cmd: Vulkan function name.
"""
if _is_intercepted(cmd) and gencom.is_device_dispatched(cmd):
if cmd in gencom.extension_dict:
if not gencom.is_extension_internal(gencom.extension_dict[cmd]):
return True
elif gencom.version_dict[cmd] != 'VK_VERSION_1_0':
return True
return False
def _define_proc_hook_stub(cmd, f):
"""Emits a stub for ProcHook::checked_proc.
Args:
cmd: Vulkan function name.
f: Output file handle.
"""
if _need_proc_hook_stub(cmd):
return_type = gencom.return_type_dict[cmd]
ext_name = ''
ext_hook = ''
if cmd in gencom.extension_dict:
ext_name = gencom.extension_dict[cmd]
ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
else:
ext_name = gencom.version_dict[cmd]
ext_hook = _get_proc_hook_enum(cmd)
handle = gencom.param_dict[cmd][0][1]
param_types = ', '.join([''.join(i) for i in gencom.param_dict[cmd]])
param_names = ', '.join([''.join(i[1]) for i in gencom.param_dict[cmd]])
f.write('VKAPI_ATTR ' + return_type + ' checked' + gencom.base_name(cmd) +
'(' + param_types + ') {\n')
f.write(gencom.indent(1) + 'if (GetData(' + handle + ').hook_extensions[' +
ext_hook + ']) {\n')
f.write(gencom.indent(2))
if gencom.return_type_dict[cmd] != 'void':
f.write('return ')
f.write(gencom.base_name(cmd) + '(' + param_names + ');\n')
f.write(gencom.indent(1) + '} else {\n')
f.write(gencom.indent(2) + 'Logger(' + handle + ').Err(' + handle + ', \"' +
ext_name + ' not enabled. ' + cmd + ' not executed.\");\n')
if gencom.return_type_dict[cmd] != 'void':
f.write(gencom.indent(2) + 'return VK_SUCCESS;\n')
f.write(gencom.indent(1) + '}\n}\n\n')
def _define_global_proc_hook(cmd, f):
"""Emits definition of a global ProcHook.
Args:
cmd: Vulkan function name.
f: Output file handle.
"""
assert cmd not in gencom.extension_dict
f.write(gencom.indent(1) + '{\n')
f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
f.write(gencom.indent(2) + 'ProcHook::GLOBAL,\n')
f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
f.write(gencom.indent(2) + 'reinterpret_cast<PFN_vkVoidFunction>(' +
gencom.base_name(cmd) + '),\n')
f.write(gencom.indent(2) + 'nullptr,\n')
f.write(gencom.indent(1) + '},\n')
def _define_instance_proc_hook(cmd, f):
"""Emits definition of a instance ProcHook.
Args:
cmd: Vulkan function name.
f: Output file handle.
"""
f.write(gencom.indent(1) + '{\n')
f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
f.write(gencom.indent(2) + 'ProcHook::INSTANCE,\n')
if cmd in gencom.extension_dict:
ext_name = gencom.extension_dict[cmd]
f.write(gencom.indent(2) + 'ProcHook::' +
gencom.base_ext_name(ext_name) + ',\n')
if gencom.is_extension_internal(ext_name):
f.write("""\
nullptr,
nullptr,\n""")
else:
f.write("""\
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
nullptr,\n""")
else:
f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
f.write("""\
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
nullptr,\n""")
f.write(gencom.indent(1) + '},\n')
def _define_device_proc_hook(cmd, f):
"""Emits definition of a device ProcHook.
Args:
cmd: Vulkan function name.
f: Output file handle.
"""
f.write(gencom.indent(1) + '{\n')
f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
f.write(gencom.indent(2) + 'ProcHook::DEVICE,\n')
if (cmd in gencom.extension_dict or
gencom.version_dict[cmd] != 'VK_VERSION_1_0'):
ext_name = ''
ext_hook = ''
if cmd in gencom.extension_dict:
ext_name = gencom.extension_dict[cmd]
ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
else:
ext_name = gencom.version_dict[cmd]
ext_hook = _get_proc_hook_enum(cmd)
f.write(gencom.indent(2) + ext_hook + ',\n')
if gencom.is_extension_internal(ext_name):
f.write("""\
nullptr,
nullptr,\n""")
else:
f.write("""\
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
reinterpret_cast<PFN_vkVoidFunction>(checked""" +
gencom.base_name(cmd) + '),\n')
else:
f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
f.write("""\
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
nullptr,\n""")
f.write(gencom.indent(1) + '},\n')
def gen_cpp():
"""Generates the driver_gen.cpp file.
"""
genfile = os.path.join(os.path.dirname(__file__),
'..', 'libvulkan', 'driver_gen.cpp')
with open(genfile, 'w') as f:
f.write(gencom.copyright_and_warning(2016))
f.write("""\
#include <log/log.h>
#include <string.h>
#include <algorithm>
#include "driver.h"
namespace vulkan {
namespace driver {
namespace {
// clang-format off\n\n""")
for cmd in gencom.command_list:
_define_proc_hook_stub(cmd, f)
f.write("""\
// clang-format on
const ProcHook g_proc_hooks[] = {
// clang-format off\n""")
sorted_command_list = sorted(gencom.command_list)
for cmd in sorted_command_list:
if _is_intercepted(cmd):
if gencom.is_globally_dispatched(cmd):
_define_global_proc_hook(cmd, f)
elif gencom.is_instance_dispatched(cmd):
_define_instance_proc_hook(cmd, f)
elif gencom.is_device_dispatched(cmd):
_define_device_proc_hook(cmd, f)
f.write("""\
// clang-format on
};
} // namespace
const ProcHook* GetProcHook(const char* name) {
auto begin = std::cbegin(g_proc_hooks);
auto end = std::cend(g_proc_hooks);
auto hook = std::lower_bound(
begin, end, name,
[](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
}
ProcHook::Extension GetProcHookExtension(const char* name) {
// clang-format off\n""")
for ext in _KNOWN_EXTENSIONS:
f.write(gencom.indent(1) + 'if (strcmp(name, \"' + ext +
'\") == 0) return ProcHook::' + gencom.base_ext_name(ext) + ';\n')
f.write("""\
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
}
#define UNLIKELY(expr) __builtin_expect((expr), 0)
#define INIT_PROC(required, obj, proc) \\
do { \\
data.driver.proc = \\
reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
if (UNLIKELY(required && !data.driver.proc)) { \\
ALOGE("missing " #obj " proc: vk" #proc); \\
success = false; \\
} \\
} while (0)
#define INIT_PROC_EXT(ext, required, obj, proc) \\
do { \\
if (extensions[ProcHook::ext]) \\
INIT_PROC(required, obj, proc); \\
} while (0)
bool InitDriverTable(VkInstance instance,
PFN_vkGetInstanceProcAddr get_proc,
const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
auto& data = GetData(instance);
bool success = true;
// clang-format off\n""")
for cmd in gencom.command_list:
if _is_instance_driver_table_entry(cmd):
gencom.init_proc(cmd, f)
f.write("""\
// clang-format on
return success;
}
bool InitDriverTable(VkDevice dev,
PFN_vkGetDeviceProcAddr get_proc,
const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
auto& data = GetData(dev);
bool success = true;
// clang-format off\n""")
for cmd in gencom.command_list:
if _is_device_driver_table_entry(cmd):
gencom.init_proc(cmd, f)
f.write("""\
// clang-format on
return success;
}
const std::pair<const char*, uint32_t> g_promoted_instance_extensions[] = {
// clang-format off\n""")
for key, value in sorted(gencom.promoted_inst_ext_dict.items()):
f.write(gencom.indent(1) + 'std::make_pair("' + key + '", ' + value + '),\n')
f.write("""\
// clang-format on
};
std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name) {
auto begin = std::cbegin(g_promoted_instance_extensions);
auto end = std::cend(g_promoted_instance_extensions);
auto iter =
std::lower_bound(begin, end, name,
[](const std::pair<const char*, uint32_t>& e,
const char* n) { return strcmp(e.first, n) < 0; });
return (iter < end && strcmp(iter->first, name) == 0)
? std::optional<uint32_t>(iter->second)
: std::nullopt;
}
uint32_t CountPromotedInstanceExtensions(uint32_t begin_version,
uint32_t end_version) {
auto begin = std::cbegin(g_promoted_instance_extensions);
auto end = std::cend(g_promoted_instance_extensions);
uint32_t count = 0;
for (auto iter = begin; iter != end; iter++)
if (iter->second > begin_version && iter->second <= end_version)
count++;
return count;
}
std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version,
uint32_t end_version) {
auto begin = std::cbegin(g_promoted_instance_extensions);
auto end = std::cend(g_promoted_instance_extensions);
std::vector<const char*> extensions;
for (auto iter = begin; iter != end; iter++)
if (iter->second > begin_version && iter->second <= end_version)
extensions.emplace_back(iter->first);
return extensions;
}
} // namespace driver
} // namespace vulkan\n""")
f.close()
gencom.run_clang_format(genfile)