// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h"
#include <memory>
#include "base/files/file_path.h"
#include "base/logging.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_image.h"
#include "gpu/vulkan/vulkan_instance.h"
#include "gpu/vulkan/vulkan_surface.h"
#include "gpu/vulkan/vulkan_util.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_memory_buffer.h"
namespace ui {
VulkanImplementationGbm::VulkanImplementationGbm(bool allow_protected_memory)
: VulkanImplementation(/*use_switfshader=*/false, allow_protected_memory) {}
VulkanImplementationGbm::~VulkanImplementationGbm() = default;
bool VulkanImplementationGbm::InitializeVulkanInstance(bool using_surface) {
DLOG_IF(ERROR, using_surface) << "VK_KHR_surface is not supported.";
std::vector<const char*> required_extensions = {
"VK_KHR_get_physical_device_properties2",
};
if (!vulkan_instance_.Initialize(base::FilePath("libvulkan.so.1"),
required_extensions, {})) {
return false;
}
vkGetPhysicalDeviceExternalFenceProperties_ =
reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
vkGetInstanceProcAddr(vulkan_instance_.vk_instance(),
"vkGetPhysicalDeviceExternalFenceProperties"));
if (!vkGetPhysicalDeviceExternalFenceProperties_) {
return false;
}
vkGetFenceFdKHR_ = reinterpret_cast<PFN_vkGetFenceFdKHR>(
vkGetInstanceProcAddr(vulkan_instance_.vk_instance(), "vkGetFenceFdKHR"));
if (!vkGetFenceFdKHR_) {
return false;
}
return true;
}
gpu::VulkanInstance* VulkanImplementationGbm::GetVulkanInstance() {
return &vulkan_instance_;
}
std::unique_ptr<gpu::VulkanSurface> VulkanImplementationGbm::CreateViewSurface(
gfx::AcceleratedWidget window) {
return nullptr;
}
bool VulkanImplementationGbm::GetPhysicalDevicePresentationSupport(
VkPhysicalDevice physical_device,
const std::vector<VkQueueFamilyProperties>& queue_family_properties,
uint32_t queue_family_index) {
VkPhysicalDeviceExternalFenceInfo external_fence_info = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO,
.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT};
VkExternalFenceProperties external_fence_properties;
vkGetPhysicalDeviceExternalFenceProperties_(
physical_device, &external_fence_info, &external_fence_properties);
if (!(external_fence_properties.externalFenceFeatures &
VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT)) {
return false;
}
return true;
}
std::vector<const char*>
VulkanImplementationGbm::GetRequiredDeviceExtensions() {
return {VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME,
VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME};
}
std::vector<const char*>
VulkanImplementationGbm::GetOptionalDeviceExtensions() {
return {
VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
};
}
VkFence VulkanImplementationGbm::CreateVkFenceForGpuFence(VkDevice vk_device) {
VkFenceCreateInfo fence_create_info = {};
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkExportFenceCreateInfo fence_export_create_info = {};
fence_create_info.pNext = &fence_export_create_info;
fence_export_create_info.sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO;
fence_export_create_info.handleTypes =
VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
VkFence fence;
VkResult result =
vkCreateFence(vk_device, &fence_create_info, nullptr, &fence);
if (result != VK_SUCCESS) {
DLOG(ERROR) << "vkCreateFence failed: " << result;
return VK_NULL_HANDLE;
}
return fence;
}
std::unique_ptr<gfx::GpuFence> VulkanImplementationGbm::ExportVkFenceToGpuFence(
VkDevice vk_device,
VkFence vk_fence) {
VkFenceGetFdInfoKHR fence_get_fd_info = {};
fence_get_fd_info.sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR;
fence_get_fd_info.fence = vk_fence;
fence_get_fd_info.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
int fence_fd = -1;
VkResult result = vkGetFenceFdKHR_(vk_device, &fence_get_fd_info, &fence_fd);
if (result != VK_SUCCESS) {
DLOG(ERROR) << "vkGetFenceFdKHR failed: " << result;
return nullptr;
}
gfx::GpuFenceHandle gpu_fence_handle;
gpu_fence_handle.Adopt(base::ScopedFD(fence_fd));
return std::make_unique<gfx::GpuFence>(std::move(gpu_fence_handle));
}
VkExternalSemaphoreHandleTypeFlagBits
VulkanImplementationGbm::GetExternalSemaphoreHandleType() {
return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
}
bool VulkanImplementationGbm::CanImportGpuMemoryBuffer(
gpu::VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferType memory_buffer_type) {
const auto& enabled_extensions = device_queue->enabled_extensions();
return gfx::HasExtension(enabled_extensions,
VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME) &&
gfx::HasExtension(enabled_extensions,
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) &&
memory_buffer_type == gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
}
std::unique_ptr<gpu::VulkanImage>
VulkanImplementationGbm::CreateImageFromGpuMemoryHandle(
gpu::VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferHandle gmb_handle,
gfx::Size size,
VkFormat vk_format,
const gfx::ColorSpace& color_space) {
constexpr auto kUsage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
auto tiling = gmb_handle.native_pixmap_handle.modifier ==
gfx::NativePixmapHandle::kNoModifier
? VK_IMAGE_TILING_OPTIMAL
: VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
return gpu::VulkanImage::CreateFromGpuMemoryBufferHandle(
device_queue, std::move(gmb_handle), size, vk_format, kUsage,
allow_protected_memory() ? VK_IMAGE_CREATE_PROTECTED_BIT : 0, tiling,
VK_QUEUE_FAMILY_FOREIGN_EXT);
}
} // namespace ui