mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
231 lines
7.1 KiB
C++
231 lines
7.1 KiB
C++
// Copyright 2016 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 "flutter/vulkan/vulkan_proc_table.h"
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include "lib/fxl/logging.h"
|
|
|
|
#define ACQUIRE_PROC(name, context) \
|
|
if (!(name = AcquireProc("vk" #name, context))) { \
|
|
FXL_DLOG(INFO) << "Could not acquire proc: vk" << #name; \
|
|
return false; \
|
|
}
|
|
|
|
namespace vulkan {
|
|
|
|
VulkanProcTable::VulkanProcTable()
|
|
: handle_(nullptr), acquired_mandatory_proc_addresses_(false) {
|
|
acquired_mandatory_proc_addresses_ =
|
|
OpenLibraryHandle() && 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::SetupLoaderProcAddresses() {
|
|
if (handle_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
GetInstanceProcAddr =
|
|
#if VULKAN_LINK_STATICALLY
|
|
GetInstanceProcAddr = &vkGetInstanceProcAddr;
|
|
#else // VULKAN_LINK_STATICALLY
|
|
reinterpret_cast<PFN_vkGetInstanceProcAddr>(
|
|
dlsym(handle_, "vkGetInstanceProcAddr"));
|
|
#endif // VULKAN_LINK_STATICALLY
|
|
|
|
if (!GetInstanceProcAddr) {
|
|
FXL_DLOG(WARNING) << "Could not acquire vkGetInstanceProcAddr.";
|
|
return false;
|
|
}
|
|
|
|
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(DestroySurfaceKHR, handle);
|
|
ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle);
|
|
ACQUIRE_PROC(EnumeratePhysicalDevices, handle);
|
|
ACQUIRE_PROC(GetDeviceProcAddr, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle);
|
|
|
|
#if OS_ANDROID
|
|
ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle);
|
|
#endif // OS_ANDROID
|
|
|
|
#if OS_FUCHSIA
|
|
[this, &handle]() -> bool {
|
|
ACQUIRE_PROC(CreateMagmaSurfaceKHR, handle);
|
|
ACQUIRE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR, handle);
|
|
return true;
|
|
}();
|
|
#endif // OS_FUCHSIA
|
|
|
|
// 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_ = {handle, nullptr};
|
|
return true;
|
|
}
|
|
|
|
bool VulkanProcTable::SetupDeviceProcAddresses(
|
|
const VulkanHandle<VkDevice>& handle) {
|
|
ACQUIRE_PROC(AcquireNextImageKHR, 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(CreateSwapchainKHR, handle);
|
|
ACQUIRE_PROC(DestroyCommandPool, handle);
|
|
ACQUIRE_PROC(DestroyFence, handle);
|
|
ACQUIRE_PROC(DestroyImage, handle);
|
|
ACQUIRE_PROC(DestroySemaphore, handle);
|
|
ACQUIRE_PROC(DestroySwapchainKHR, 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(GetSwapchainImagesKHR, handle);
|
|
ACQUIRE_PROC(QueuePresentKHR, handle);
|
|
ACQUIRE_PROC(QueueSubmit, handle);
|
|
ACQUIRE_PROC(QueueWaitIdle, handle);
|
|
ACQUIRE_PROC(ResetCommandBuffer, handle);
|
|
ACQUIRE_PROC(ResetFences, handle);
|
|
ACQUIRE_PROC(WaitForFences, handle);
|
|
#if OS_FUCHSIA
|
|
ACQUIRE_PROC(GetMemoryFuchsiaHandleKHR, handle);
|
|
ACQUIRE_PROC(ImportSemaphoreFuchsiaHandleKHR, handle);
|
|
#endif // OS_FUCHSIA
|
|
device_ = {handle, nullptr};
|
|
return true;
|
|
}
|
|
|
|
bool VulkanProcTable::OpenLibraryHandle() {
|
|
#if VULKAN_LINK_STATICALLY
|
|
static char kDummyLibraryHandle = '\0';
|
|
handle_ = reinterpret_cast<decltype(handle_)>(&kDummyLibraryHandle);
|
|
return true;
|
|
#else // VULKAN_LINK_STATICALLY
|
|
dlerror(); // clear existing errors on thread.
|
|
handle_ = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
|
if (handle_ == nullptr) {
|
|
FXL_DLOG(WARNING) << "Could not open the vulkan library: " << dlerror();
|
|
return false;
|
|
}
|
|
return true;
|
|
#endif // VULKAN_LINK_STATICALLY
|
|
}
|
|
|
|
bool VulkanProcTable::CloseLibraryHandle() {
|
|
#if VULKAN_LINK_STATICALLY
|
|
handle_ = nullptr;
|
|
return true;
|
|
#else
|
|
if (handle_ != nullptr) {
|
|
dlerror(); // clear existing errors on thread.
|
|
if (dlclose(handle_) != 0) {
|
|
FXL_DLOG(ERROR) << "Could not close the vulkan library handle. This "
|
|
"indicates a leak.";
|
|
FXL_DLOG(ERROR) << dlerror();
|
|
}
|
|
handle_ = nullptr;
|
|
}
|
|
return handle_ == nullptr;
|
|
#endif
|
|
}
|
|
|
|
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 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);
|
|
}
|
|
|
|
sk_sp<GrVkInterface> VulkanProcTable::CreateSkiaInterface() const {
|
|
if (!IsValid()) {
|
|
return nullptr;
|
|
}
|
|
|
|
GrVkInterface::GetProc proc = [this](const char* proc_name,
|
|
VkInstance instance, VkDevice device) {
|
|
if (device != VK_NULL_HANDLE) {
|
|
auto result = AcquireProc(proc_name, {device, nullptr});
|
|
if (result != nullptr) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return AcquireProc(proc_name, {instance, nullptr});
|
|
};
|
|
|
|
return sk_make_sp<GrVkInterface>(proc, instance_, device_,
|
|
0 /* extensions */);
|
|
}
|
|
|
|
} // namespace vulkan
|