Commit 8cff2cd0 authored by Peng Huang's avatar Peng Huang Committed by Commit Bot

vulkan: enable the possibility of using vulkan c++ binding

The vulkan.hpp is included in the upstream Khronos vulkan headers
package. It is a vulkan c++ binding generated from vulkan registry.
It is implemented with c++ template in a single header file.

This change updates gpu::VulkanFunctionPointers to make it compatible
with vulkan.hpp, and adds vulkan_cxx.h which setups several necessary
macros before including <vulkan/vulkan.hpp>. So any code wants to use
vulkan c++ binding just needs to include vulkan_cxx.h.

This change also adds a test for the vulkan c++ binding.

Change-Id: I74c7003008082686984b559c729bdecac1b08efd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2198140
Commit-Queue: Peng Huang <penghuang@chromium.org>
Reviewed-by: default avatarVasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770361}
parent eaf102da
...@@ -85,6 +85,7 @@ if (enable_vulkan) { ...@@ -85,6 +85,7 @@ if (enable_vulkan) {
"vulkan_command_pool.h", "vulkan_command_pool.h",
"vulkan_crash_keys.cc", "vulkan_crash_keys.cc",
"vulkan_crash_keys.h", "vulkan_crash_keys.h",
"vulkan_cxx.h",
"vulkan_device_queue.cc", "vulkan_device_queue.cc",
"vulkan_device_queue.h", "vulkan_device_queue.h",
"vulkan_fence_helper.cc", "vulkan_fence_helper.cc",
...@@ -203,6 +204,7 @@ if (enable_vulkan) { ...@@ -203,6 +204,7 @@ if (enable_vulkan) {
"tests/basic_vulkan_test.h", "tests/basic_vulkan_test.h",
"tests/vulkan_test.cc", "tests/vulkan_test.cc",
"tests/vulkan_tests_main.cc", "tests/vulkan_tests_main.cc",
"vulkan_cxx_unittest.cc",
"vulkan_fence_helper_unittest.cc", "vulkan_fence_helper_unittest.cc",
"vulkan_image_unittest.cc", "vulkan_image_unittest.cc",
] ]
......
...@@ -26,7 +26,7 @@ VULKAN_UNASSOCIATED_FUNCTIONS = [ ...@@ -26,7 +26,7 @@ VULKAN_UNASSOCIATED_FUNCTIONS = [
{ {
'functions': [ 'functions': [
# vkGetInstanceProcAddr belongs here but is handled specially. # vkGetInstanceProcAddr belongs here but is handled specially.
# vkEnumerateInstanceVersion belongs here but is handled specially. 'vkEnumerateInstanceVersion',
'vkCreateInstance', 'vkCreateInstance',
'vkEnumerateInstanceExtensionProperties', 'vkEnumerateInstanceExtensionProperties',
'vkEnumerateInstanceLayerProperties', 'vkEnumerateInstanceLayerProperties',
...@@ -326,7 +326,7 @@ def WriteFunctions(file, functions, template, check_extension=False): ...@@ -326,7 +326,7 @@ def WriteFunctions(file, functions, template, check_extension=False):
WriteFunctionsInternal(file, functions, gen_content, check_extension) WriteFunctionsInternal(file, functions, gen_content, check_extension)
def WriteFunctionDeclarations(file, functions): def WriteFunctionDeclarations(file, functions):
template = Template(' VulkanFunction<PFN_${name}> ${name}Fn;\n') template = Template(' VulkanFunction<PFN_${name}> ${name};\n')
WriteFunctions(file, functions, template) WriteFunctions(file, functions, template)
def WriteMacros(file, functions): def WriteMacros(file, functions):
...@@ -335,7 +335,7 @@ def WriteMacros(file, functions): ...@@ -335,7 +335,7 @@ def WriteMacros(file, functions):
# Some fuchsia functions are not in the vulkan registry, so use macro for # Some fuchsia functions are not in the vulkan registry, so use macro for
# them. # them.
template = Template( template = Template(
'#define $name gpu::GetVulkanFunctionPointers()->${name}Fn\n') '#define $name gpu::GetVulkanFunctionPointers()->${name}\n')
return template.substitute({'name': func, 'extension_suffix' : suffix}) return template.substitute({'name': func, 'extension_suffix' : suffix})
none_str = lambda s: s if s else '' none_str = lambda s: s if s else ''
cmd = registry.cmddict[func].elem cmd = registry.cmddict[func].elem
...@@ -348,7 +348,7 @@ def WriteMacros(file, functions): ...@@ -348,7 +348,7 @@ def WriteMacros(file, functions):
pdecl += text + tail pdecl += text + tail
n = len(params) n = len(params)
callstat = 'return gpu::GetVulkanFunctionPointers()->%sFn(' % func callstat = 'return gpu::GetVulkanFunctionPointers()->%s(' % func
paramdecl = '(' paramdecl = '('
if n > 0: if n > 0:
paramnames = (''.join(t for t in p.itertext()) paramnames = (''.join(t for t in p.itertext())
...@@ -437,12 +437,12 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers { ...@@ -437,12 +437,12 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers {
public: public:
using Fn = R(VKAPI_PTR*)(Args...); using Fn = R(VKAPI_PTR*)(Args...);
explicit operator bool() { explicit operator bool() const {
return !!fn_; return !!fn_;
} }
NO_SANITIZE("cfi-icall") NO_SANITIZE("cfi-icall")
R operator()(Args... args) { R operator()(Args... args) const {
return fn_(args...); return fn_(args...);
} }
...@@ -460,8 +460,7 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers { ...@@ -460,8 +460,7 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers {
}; };
// Unassociated functions // Unassociated functions
VulkanFunction<PFN_vkEnumerateInstanceVersion> vkEnumerateInstanceVersionFn; VulkanFunction<PFN_vkGetInstanceProcAddr> vkGetInstanceProcAddr;
VulkanFunction<PFN_vkGetInstanceProcAddr> vkGetInstanceProcAddrFn;
""") """)
...@@ -489,8 +488,7 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers { ...@@ -489,8 +488,7 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers {
// Unassociated functions // Unassociated functions
""") """)
WriteMacros(file, [{'functions': [ 'vkGetInstanceProcAddr' , WriteMacros(file, [{'functions': [ 'vkGetInstanceProcAddr']}])
'vkEnumerateInstanceVersion']}])
WriteMacros(file, VULKAN_UNASSOCIATED_FUNCTIONS) WriteMacros(file, VULKAN_UNASSOCIATED_FUNCTIONS)
file.write("""\ file.write("""\
...@@ -513,9 +511,9 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers { ...@@ -513,9 +511,9 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers {
def WriteFunctionPointerInitialization(file, proc_addr_function, parent, def WriteFunctionPointerInitialization(file, proc_addr_function, parent,
functions): functions):
template = Template(""" ${name}Fn = reinterpret_cast<PFN_${name}>( template = Template(""" ${name} = reinterpret_cast<PFN_${name}>(
${get_proc_addr}(${parent}, "${name}${extension_suffix}")); ${get_proc_addr}(${parent}, "${name}${extension_suffix}"));
if (!${name}Fn) { if (!${name}) {
DLOG(WARNING) << "Failed to bind vulkan entrypoint: " DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
<< "${name}${extension_suffix}"; << "${name}${extension_suffix}";
return false; return false;
...@@ -568,17 +566,11 @@ bool VulkanFunctionPointers::BindUnassociatedFunctionPointers() { ...@@ -568,17 +566,11 @@ bool VulkanFunctionPointers::BindUnassociatedFunctionPointers() {
// vkGetInstanceProcAddr must be handled specially since it gets its function // vkGetInstanceProcAddr must be handled specially since it gets its function
// pointer through base::GetFunctionPOinterFromNativeLibrary(). Other Vulkan // pointer through base::GetFunctionPOinterFromNativeLibrary(). Other Vulkan
// functions don't do this. // functions don't do this.
vkGetInstanceProcAddrFn = reinterpret_cast<PFN_vkGetInstanceProcAddr>( vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
base::GetFunctionPointerFromNativeLibrary(vulkan_loader_library, base::GetFunctionPointerFromNativeLibrary(vulkan_loader_library,
"vkGetInstanceProcAddr")); "vkGetInstanceProcAddr"));
if (!vkGetInstanceProcAddrFn) if (!vkGetInstanceProcAddr)
return false; return false;
vkEnumerateInstanceVersionFn =
reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"));
// vkEnumerateInstanceVersion didn't exist in Vulkan 1.0, so we should
// proceed even if we fail to get vkEnumerateInstanceVersion pointer.
""") """)
WriteUnassociatedFunctionPointerInitialization( WriteUnassociatedFunctionPointerInitialization(
......
...@@ -18,25 +18,25 @@ VkResult CreateAllocator(VkPhysicalDevice physical_device, ...@@ -18,25 +18,25 @@ VkResult CreateAllocator(VkPhysicalDevice physical_device,
VmaAllocator* pAllocator) { VmaAllocator* pAllocator) {
auto* function_pointers = gpu::GetVulkanFunctionPointers(); auto* function_pointers = gpu::GetVulkanFunctionPointers();
VmaVulkanFunctions functions = { VmaVulkanFunctions functions = {
function_pointers->vkGetPhysicalDevicePropertiesFn.get(), function_pointers->vkGetPhysicalDeviceProperties.get(),
function_pointers->vkGetPhysicalDeviceMemoryPropertiesFn.get(), function_pointers->vkGetPhysicalDeviceMemoryProperties.get(),
function_pointers->vkAllocateMemoryFn.get(), function_pointers->vkAllocateMemory.get(),
function_pointers->vkFreeMemoryFn.get(), function_pointers->vkFreeMemory.get(),
function_pointers->vkMapMemoryFn.get(), function_pointers->vkMapMemory.get(),
function_pointers->vkUnmapMemoryFn.get(), function_pointers->vkUnmapMemory.get(),
function_pointers->vkFlushMappedMemoryRangesFn.get(), function_pointers->vkFlushMappedMemoryRanges.get(),
function_pointers->vkInvalidateMappedMemoryRangesFn.get(), function_pointers->vkInvalidateMappedMemoryRanges.get(),
function_pointers->vkBindBufferMemoryFn.get(), function_pointers->vkBindBufferMemory.get(),
function_pointers->vkBindImageMemoryFn.get(), function_pointers->vkBindImageMemory.get(),
function_pointers->vkGetBufferMemoryRequirementsFn.get(), function_pointers->vkGetBufferMemoryRequirements.get(),
function_pointers->vkGetImageMemoryRequirementsFn.get(), function_pointers->vkGetImageMemoryRequirements.get(),
function_pointers->vkCreateBufferFn.get(), function_pointers->vkCreateBuffer.get(),
function_pointers->vkDestroyBufferFn.get(), function_pointers->vkDestroyBuffer.get(),
function_pointers->vkCreateImageFn.get(), function_pointers->vkCreateImage.get(),
function_pointers->vkDestroyImageFn.get(), function_pointers->vkDestroyImage.get(),
function_pointers->vkCmdCopyBufferFn.get(), function_pointers->vkCmdCopyBuffer.get(),
function_pointers->vkGetBufferMemoryRequirements2Fn.get(), function_pointers->vkGetBufferMemoryRequirements2.get(),
function_pointers->vkGetImageMemoryRequirements2Fn.get(), function_pointers->vkGetImageMemoryRequirements2.get(),
}; };
VmaAllocatorCreateInfo allocator_info = { VmaAllocatorCreateInfo allocator_info = {
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_VULKAN_VULKAN_CXX_H_
#define GPU_VULKAN_VULKAN_CXX_H_
#include <ostream>
#include "base/compiler_specific.h"
// Disable vulkan prototypes.
#if !defined(VK_NO_PROTOTYPES)
#define VK_NO_PROTOTYPES 1
#endif
// Disable dynamic loader tool.
#define VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL 0
// Disable c++ exceptions.
#define VULKAN_HPP_NO_EXCEPTIONS 1
// Disable dynamic dispatch loader.
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 0
// Set gpu::VulkanFunctionPointers as the default dispatcher.
#define VULKAN_HPP_DEFAULT_DISPATCHER (*gpu::GetVulkanFunctionPointers())
#define VULKAN_HPP_DEFAULT_DISPATCHER_TYPE gpu::VulkanFunctionPointers
#include "gpu/vulkan/vulkan_function_pointers.h"
#include <vulkan/vulkan.hpp>
// operator for LOG() << result
ALWAYS_INLINE std::ostream& operator<<(std::ostream& out, vk::Result result) {
out << static_cast<VkResult>(result);
return out;
}
#endif // GPU_VULKAN_VULKAN_CXX_H_
\ No newline at end of file
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "testing/gtest/include/gtest/gtest.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "build/build_config.h"
#include "gpu/vulkan/vulkan_cxx.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
namespace gpu {
class VulkanCXXTest : public testing::Test {
public:
VulkanCXXTest() = default;
~VulkanCXXTest() override = default;
void SetUp() override {
use_swiftshader_ =
base::CommandLine::ForCurrentProcess()->HasSwitch("use-swiftshader");
base::FilePath path;
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) || \
defined(OS_FUCHSIA)
if (use_swiftshader_) {
#if defined(OS_LINUX)
EXPECT_TRUE(base::PathService::Get(base::DIR_MODULE, &path));
path = path.Append("libvk_swiftshader.so");
#else
return;
#endif
} else {
path = base::FilePath("libvulkan.so.1");
}
#elif defined(OS_WIN)
if (use_swiftshader_) {
EXPECT_TRUE(base::PathService::Get(base::DIR_MODULE, &path));
path = path.Append(L"vk_swiftshader.dll");
} else {
path = base::FilePath(L"vulkan-1.dll");
}
#else
#error "Not supported platform"
#endif
auto* vulkan_function_pointers = GetVulkanFunctionPointers();
base::NativeLibraryLoadError native_library_load_error;
vulkan_function_pointers->vulkan_loader_library =
base::LoadNativeLibrary(path, &native_library_load_error);
EXPECT_TRUE(vulkan_function_pointers->vulkan_loader_library);
}
void TearDown() override {
auto* vulkan_function_pointers = GetVulkanFunctionPointers();
base::UnloadNativeLibrary(vulkan_function_pointers->vulkan_loader_library);
}
private:
bool use_swiftshader_ = false;
};
TEST_F(VulkanCXXTest, CreateInstanceUnique) {
auto* vulkan_function_pointers = GetVulkanFunctionPointers();
EXPECT_TRUE(vulkan_function_pointers->BindUnassociatedFunctionPointers());
constexpr uint32_t kRequiredApiVersion = VK_MAKE_VERSION(1, 1, 0);
vk::Result result;
uint32_t api_version;
std::tie(result, api_version) = vk::enumerateInstanceVersion();
EXPECT_EQ(result, vk::Result::eSuccess);
EXPECT_GE(api_version, kRequiredApiVersion);
vk::ApplicationInfo app_info("VulkanCXXTest", 0, nullptr, 0,
kRequiredApiVersion);
vk::InstanceCreateInfo instance_create_info({}, &app_info);
auto result_value = vk::createInstanceUnique(instance_create_info);
EXPECT_EQ(result_value.result, vk::Result::eSuccess);
vk::UniqueInstance instance = std::move(result_value.value);
EXPECT_TRUE(instance);
EXPECT_TRUE(vulkan_function_pointers->BindInstanceFunctionPointers(
instance.get(), kRequiredApiVersion, gfx::ExtensionSet()));
instance.reset();
}
} // namespace gpu
This diff is collapsed.
This diff is collapsed.
...@@ -60,6 +60,8 @@ VulkanWarningCallback(VkDebugReportFlagsEXT flags, ...@@ -60,6 +60,8 @@ VulkanWarningCallback(VkDebugReportFlagsEXT flags,
} }
#endif // DCHECK_IS_ON() #endif // DCHECK_IS_ON()
constexpr uint32_t kRequiredApiVersion = VK_MAKE_VERSION(1, 1, 0);
} // namespace } // namespace
VulkanInstance::VulkanInstance() = default; VulkanInstance::VulkanInstance() = default;
...@@ -79,19 +81,19 @@ bool VulkanInstance::Initialize( ...@@ -79,19 +81,19 @@ bool VulkanInstance::Initialize(
if (!vulkan_function_pointers->BindUnassociatedFunctionPointers()) if (!vulkan_function_pointers->BindUnassociatedFunctionPointers())
return false; return false;
if (vulkan_function_pointers->vkEnumerateInstanceVersionFn) VkResult result = vkEnumerateInstanceVersion(&vulkan_info_.api_version);
vkEnumerateInstanceVersion(&vulkan_info_.api_version); if (result != VK_SUCCESS) {
DLOG(ERROR) << "vkEnumerateInstanceVersion() failed: " << result;
return false;
}
if (vulkan_info_.api_version < VK_MAKE_VERSION(1, 1, 0)) if (vulkan_info_.api_version < kRequiredApiVersion)
return false; return false;
gpu::crash_keys::vulkan_api_version.Set( gpu::crash_keys::vulkan_api_version.Set(
VkVersionToString(vulkan_info_.api_version)); VkVersionToString(vulkan_info_.api_version));
// Use Vulkan 1.1 if it's available. vulkan_info_.used_api_version = kRequiredApiVersion;
vulkan_info_.used_api_version = VK_MAKE_VERSION(1, 1, 0);
VkResult result = VK_SUCCESS;
VkApplicationInfo app_info = {}; VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment