| // Copyright (c) 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 "gpu/vulkan/vulkan_device_queue.h" |
| |
| #include <unordered_set> |
| #include <vector> |
| |
| #include "gpu/vulkan/vulkan_command_pool.h" |
| #include "gpu/vulkan/vulkan_function_pointers.h" |
| |
| namespace gpu { |
| |
| VulkanDeviceQueue::VulkanDeviceQueue(VkInstance vk_instance) |
| : vk_instance_(vk_instance) {} |
| |
| VulkanDeviceQueue::~VulkanDeviceQueue() { |
| DCHECK_EQ(static_cast<VkPhysicalDevice>(VK_NULL_HANDLE), vk_physical_device_); |
| DCHECK_EQ(static_cast<VkDevice>(VK_NULL_HANDLE), vk_device_); |
| DCHECK_EQ(static_cast<VkQueue>(VK_NULL_HANDLE), vk_queue_); |
| } |
| |
| bool VulkanDeviceQueue::Initialize( |
| uint32_t options, |
| const std::vector<const char*>& required_extensions, |
| const GetPresentationSupportCallback& get_presentation_support) { |
| if (VK_NULL_HANDLE == vk_instance_) |
| return false; |
| |
| VkResult result = VK_SUCCESS; |
| |
| uint32_t device_count = 0; |
| result = vkEnumeratePhysicalDevices(vk_instance_, &device_count, nullptr); |
| if (VK_SUCCESS != result || device_count == 0) |
| return false; |
| |
| std::vector<VkPhysicalDevice> devices(device_count); |
| result = |
| vkEnumeratePhysicalDevices(vk_instance_, &device_count, devices.data()); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkEnumeratePhysicalDevices() failed: " << result; |
| return false; |
| } |
| |
| VkQueueFlags queue_flags = 0; |
| if (options & DeviceQueueOption::GRAPHICS_QUEUE_FLAG) |
| queue_flags |= VK_QUEUE_GRAPHICS_BIT; |
| |
| int device_index = -1; |
| int queue_index = -1; |
| for (size_t i = 0; i < devices.size(); ++i) { |
| const VkPhysicalDevice& device = devices[i]; |
| uint32_t queue_count = 0; |
| vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, nullptr); |
| if (queue_count) { |
| std::vector<VkQueueFamilyProperties> queue_properties(queue_count); |
| vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, |
| queue_properties.data()); |
| for (size_t n = 0; n < queue_properties.size(); ++n) { |
| if ((queue_properties[n].queueFlags & queue_flags) != queue_flags) |
| continue; |
| |
| if (options & DeviceQueueOption::PRESENTATION_SUPPORT_QUEUE_FLAG && |
| !get_presentation_support.Run(device, queue_properties, n)) { |
| continue; |
| } |
| |
| queue_index = static_cast<int>(n); |
| break; |
| } |
| |
| if (-1 != queue_index) { |
| device_index = static_cast<int>(i); |
| break; |
| } |
| } |
| } |
| |
| if (queue_index == -1) |
| return false; |
| |
| vk_physical_device_ = devices[device_index]; |
| vk_queue_index_ = queue_index; |
| |
| float queue_priority = 0.0f; |
| VkDeviceQueueCreateInfo queue_create_info = {}; |
| queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; |
| queue_create_info.queueFamilyIndex = queue_index; |
| queue_create_info.queueCount = 1; |
| queue_create_info.pQueuePriorities = &queue_priority; |
| |
| std::vector<const char*> enabled_layer_names; |
| #if DCHECK_IS_ON() |
| uint32_t num_device_layers = 0; |
| result = vkEnumerateDeviceLayerProperties(vk_physical_device_, |
| &num_device_layers, nullptr); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkEnumerateDeviceLayerProperties(NULL) failed: " << result; |
| return false; |
| } |
| |
| std::vector<VkLayerProperties> device_layers(num_device_layers); |
| result = vkEnumerateDeviceLayerProperties( |
| vk_physical_device_, &num_device_layers, device_layers.data()); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkEnumerateDeviceLayerProperties() failed: " << result; |
| return false; |
| } |
| |
| std::unordered_set<std::string> desired_layers({ |
| "VK_LAYER_LUNARG_standard_validation", |
| }); |
| |
| for (const VkLayerProperties& layer_property : device_layers) { |
| if (desired_layers.find(layer_property.layerName) != desired_layers.end()) |
| enabled_layer_names.push_back(layer_property.layerName); |
| } |
| #endif |
| |
| std::vector<const char*> enabled_extensions; |
| enabled_extensions.insert(std::end(enabled_extensions), |
| std::begin(required_extensions), |
| std::end(required_extensions)); |
| |
| VkDeviceCreateInfo device_create_info = {}; |
| device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| device_create_info.queueCreateInfoCount = 1; |
| device_create_info.pQueueCreateInfos = &queue_create_info; |
| device_create_info.enabledLayerCount = enabled_layer_names.size(); |
| device_create_info.ppEnabledLayerNames = enabled_layer_names.data(); |
| device_create_info.enabledExtensionCount = enabled_extensions.size(); |
| device_create_info.ppEnabledExtensionNames = enabled_extensions.data(); |
| |
| result = vkCreateDevice(vk_physical_device_, &device_create_info, nullptr, |
| &vk_device_); |
| if (VK_SUCCESS != result) |
| return false; |
| |
| enabled_extensions_ = gfx::ExtensionSet(std::begin(enabled_extensions), |
| std::end(enabled_extensions)); |
| |
| gpu::GetVulkanFunctionPointers()->BindDeviceFunctionPointers(vk_device_); |
| |
| if (gfx::HasExtension(enabled_extensions_, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) |
| gpu::GetVulkanFunctionPointers()->BindSwapchainFunctionPointers(vk_device_); |
| |
| vkGetDeviceQueue(vk_device_, queue_index, 0, &vk_queue_); |
| |
| return true; |
| } |
| |
| void VulkanDeviceQueue::Destroy() { |
| if (VK_NULL_HANDLE != vk_device_) { |
| vkDestroyDevice(vk_device_, nullptr); |
| vk_device_ = VK_NULL_HANDLE; |
| } |
| |
| vk_queue_ = VK_NULL_HANDLE; |
| vk_queue_index_ = 0; |
| |
| vk_physical_device_ = VK_NULL_HANDLE; |
| } |
| |
| std::unique_ptr<VulkanCommandPool> VulkanDeviceQueue::CreateCommandPool() { |
| std::unique_ptr<VulkanCommandPool> command_pool(new VulkanCommandPool(this)); |
| if (!command_pool->Initialize()) |
| return nullptr; |
| |
| return command_pool; |
| } |
| |
| } // namespace gpu |