blob: 8fa35010a9d2b481cbcca3c9bee2e1b7b6e449f9 [file] [log] [blame]
// Copyright 2013 The Flutter 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 "flutter/vulkan/procs/vulkan_proc_table.h"
#include <utility>
#include "flutter/fml/logging.h"
#define ACQUIRE_PROC(name, context) \
if (!(name = AcquireProc("vk" #name, context))) { \
return false; \
}
#define ACQUIRE_PROC_EITHER(name, name2, context) \
if (!(name = AcquireProc("vk" #name, context)) && \
!(name2 = AcquireProc("vk" #name2, context))) { \
return false; \
}
namespace vulkan {
VulkanProcTable::VulkanProcTable() : VulkanProcTable("libvulkan.so"){};
VulkanProcTable::VulkanProcTable(const char* so_path)
: handle_(nullptr), acquired_mandatory_proc_addresses_(false) {
acquired_mandatory_proc_addresses_ = OpenLibraryHandle(so_path) &&
SetupGetInstanceProcAddress() &&
SetupLoaderProcAddresses();
}
VulkanProcTable::VulkanProcTable(
PFN_vkGetInstanceProcAddr get_instance_proc_addr)
: handle_(nullptr), acquired_mandatory_proc_addresses_(false) {
GetInstanceProcAddr = get_instance_proc_addr;
acquired_mandatory_proc_addresses_ = SetupLoaderProcAddresses();
}
VulkanProcTable::~VulkanProcTable() {
CloseLibraryHandle();
}
bool VulkanProcTable::HasAcquiredMandatoryProcAddresses() const {
return acquired_mandatory_proc_addresses_;
}
bool VulkanProcTable::IsValid() const {
return instance_ && device_;
}
bool VulkanProcTable::AreInstanceProcsSetup() const {
return instance_;
}
bool VulkanProcTable::AreDeviceProcsSetup() const {
return device_;
}
bool VulkanProcTable::SetupGetInstanceProcAddress() {
if (!handle_) {
return true;
}
GetInstanceProcAddr = NativeGetInstanceProcAddr();
if (!GetInstanceProcAddr) {
FML_DLOG(WARNING) << "Could not acquire vkGetInstanceProcAddr.";
return false;
}
return true;
}
PFN_vkGetInstanceProcAddr VulkanProcTable::NativeGetInstanceProcAddr() const {
if (GetInstanceProcAddr) {
return GetInstanceProcAddr;
}
#if VULKAN_LINK_STATICALLY
return &vkGetInstanceProcAddr;
#else // VULKAN_LINK_STATICALLY
auto instance_proc =
const_cast<uint8_t*>(handle_->ResolveSymbol("vkGetInstanceProcAddr"));
return reinterpret_cast<PFN_vkGetInstanceProcAddr>(instance_proc);
#endif // VULKAN_LINK_STATICALLY
}
bool VulkanProcTable::SetupLoaderProcAddresses() {
VulkanHandle<VkInstance> null_instance(VK_NULL_HANDLE, nullptr);
ACQUIRE_PROC(CreateInstance, null_instance);
ACQUIRE_PROC(EnumerateInstanceExtensionProperties, null_instance);
ACQUIRE_PROC(EnumerateInstanceLayerProperties, null_instance);
return true;
}
bool VulkanProcTable::SetupInstanceProcAddresses(
const VulkanHandle<VkInstance>& handle) {
ACQUIRE_PROC(CreateDevice, handle);
ACQUIRE_PROC(DestroyDevice, handle);
ACQUIRE_PROC(DestroyInstance, handle);
ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle);
ACQUIRE_PROC(EnumeratePhysicalDevices, handle);
ACQUIRE_PROC(GetDeviceProcAddr, handle);
ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle);
ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle);
ACQUIRE_PROC(GetPhysicalDeviceProperties, handle);
ACQUIRE_PROC(GetPhysicalDeviceMemoryProperties, handle);
ACQUIRE_PROC_EITHER(GetPhysicalDeviceMemoryProperties2,
GetPhysicalDeviceMemoryProperties2KHR, handle);
#if FML_OS_ANDROID
ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle);
ACQUIRE_PROC(DestroySurfaceKHR, handle);
ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle);
#endif // FML_OS_ANDROID
// The debug report functions are optional. We don't want proc acquisition to
// fail here because the optional methods were not present (since ACQUIRE_PROC
// returns false on failure). Wrap the optional proc acquisitions in an
// anonymous lambda and invoke it. We don't really care about the result since
// users of Debug reporting functions check for their presence explicitly.
[this, &handle]() -> bool {
ACQUIRE_PROC(CreateDebugReportCallbackEXT, handle);
ACQUIRE_PROC(DestroyDebugReportCallbackEXT, handle);
return true;
}();
instance_ = VulkanHandle<VkInstance>{handle, nullptr};
return true;
}
bool VulkanProcTable::SetupDeviceProcAddresses(
const VulkanHandle<VkDevice>& handle) {
ACQUIRE_PROC(AllocateCommandBuffers, handle);
ACQUIRE_PROC(AllocateMemory, handle);
ACQUIRE_PROC(BeginCommandBuffer, handle);
ACQUIRE_PROC(BindImageMemory, handle);
ACQUIRE_PROC(CmdPipelineBarrier, handle);
ACQUIRE_PROC(CreateCommandPool, handle);
ACQUIRE_PROC(CreateFence, handle);
ACQUIRE_PROC(CreateImage, handle);
ACQUIRE_PROC(CreateSemaphore, handle);
ACQUIRE_PROC(DestroyCommandPool, handle);
ACQUIRE_PROC(DestroyFence, handle);
ACQUIRE_PROC(DestroyImage, handle);
ACQUIRE_PROC(DestroySemaphore, handle);
ACQUIRE_PROC(DeviceWaitIdle, handle);
ACQUIRE_PROC(EndCommandBuffer, handle);
ACQUIRE_PROC(FreeCommandBuffers, handle);
ACQUIRE_PROC(FreeMemory, handle);
ACQUIRE_PROC(GetDeviceQueue, handle);
ACQUIRE_PROC(GetImageMemoryRequirements, handle);
ACQUIRE_PROC(QueueSubmit, handle);
ACQUIRE_PROC(QueueWaitIdle, handle);
ACQUIRE_PROC(ResetCommandBuffer, handle);
ACQUIRE_PROC(ResetFences, handle);
ACQUIRE_PROC(WaitForFences, handle);
ACQUIRE_PROC(MapMemory, handle);
ACQUIRE_PROC(UnmapMemory, handle);
ACQUIRE_PROC(FlushMappedMemoryRanges, handle);
ACQUIRE_PROC(InvalidateMappedMemoryRanges, handle);
ACQUIRE_PROC(BindBufferMemory, handle);
ACQUIRE_PROC(GetBufferMemoryRequirements, handle);
ACQUIRE_PROC(CreateBuffer, handle);
ACQUIRE_PROC(DestroyBuffer, handle);
ACQUIRE_PROC(CmdCopyBuffer, handle);
ACQUIRE_PROC_EITHER(GetBufferMemoryRequirements2,
GetBufferMemoryRequirements2KHR, handle);
ACQUIRE_PROC_EITHER(GetImageMemoryRequirements2,
GetImageMemoryRequirements2KHR, handle);
ACQUIRE_PROC_EITHER(BindBufferMemory2, BindBufferMemory2KHR, handle);
ACQUIRE_PROC_EITHER(BindImageMemory2, BindImageMemory2KHR, handle);
#ifndef TEST_VULKAN_PROCS
#if FML_OS_ANDROID
ACQUIRE_PROC(AcquireNextImageKHR, handle);
ACQUIRE_PROC(CreateSwapchainKHR, handle);
ACQUIRE_PROC(DestroySwapchainKHR, handle);
ACQUIRE_PROC(GetSwapchainImagesKHR, handle);
ACQUIRE_PROC(QueuePresentKHR, handle);
#endif // FML_OS_ANDROID
#if OS_FUCHSIA
ACQUIRE_PROC(ImportSemaphoreZirconHandleFUCHSIA, handle);
ACQUIRE_PROC(GetSemaphoreZirconHandleFUCHSIA, handle);
ACQUIRE_PROC(GetMemoryZirconHandleFUCHSIA, handle);
ACQUIRE_PROC(CreateBufferCollectionFUCHSIA, handle);
ACQUIRE_PROC(DestroyBufferCollectionFUCHSIA, handle);
ACQUIRE_PROC(SetBufferCollectionImageConstraintsFUCHSIA, handle);
ACQUIRE_PROC(GetBufferCollectionPropertiesFUCHSIA, handle);
#endif // OS_FUCHSIA
#endif // TEST_VULKAN_PROCS
device_ = VulkanHandle<VkDevice>{handle, nullptr};
return true;
}
bool VulkanProcTable::OpenLibraryHandle(const char* path) {
#if VULKAN_LINK_STATICALLY
handle_ = fml::NativeLibrary::CreateForCurrentProcess();
#else // VULKAN_LINK_STATICALLY
handle_ = fml::NativeLibrary::Create(path);
#endif // VULKAN_LINK_STATICALLY
if (!handle_) {
FML_DLOG(ERROR) << "Could not open Vulkan library handle: " << path;
return false;
}
return true;
}
bool VulkanProcTable::CloseLibraryHandle() {
handle_ = nullptr;
return true;
}
PFN_vkVoidFunction VulkanProcTable::AcquireProc(
const char* proc_name,
const VulkanHandle<VkInstance>& instance) const {
if (proc_name == nullptr || !GetInstanceProcAddr) {
return nullptr;
}
// A VK_NULL_HANDLE as the instance is an acceptable parameter.
return reinterpret_cast<PFN_vkVoidFunction>(
GetInstanceProcAddr(instance, proc_name));
}
PFN_vkVoidFunction VulkanProcTable::AcquireProc(
const char* proc_name,
const VulkanHandle<VkDevice>& device) const {
if (proc_name == nullptr || !device || !GetDeviceProcAddr) {
return nullptr;
}
return GetDeviceProcAddr(device, proc_name);
}
} // namespace vulkan