Adding mutliple queue/shared queue support.
This commit is contained in:
parent
ea959b52fd
commit
00594da417
|
@ -35,28 +35,18 @@ VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window)
|
||||||
VulkanContext::~VulkanContext() {
|
VulkanContext::~VulkanContext() {
|
||||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||||
auto device = provider->device();
|
auto device = provider->device();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||||
vkQueueWaitIdle(device->primary_queue());
|
vkQueueWaitIdle(device->primary_queue());
|
||||||
|
}
|
||||||
immediate_drawer_.reset();
|
immediate_drawer_.reset();
|
||||||
swap_chain_.reset();
|
swap_chain_.reset();
|
||||||
if (cmd_pool_) {
|
|
||||||
vkDestroyCommandPool(*device, cmd_pool_, nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanContext::Initialize() {
|
bool VulkanContext::Initialize() {
|
||||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||||
auto device = provider->device();
|
auto device = provider->device();
|
||||||
|
|
||||||
// All context-specific commands will be allocated from this.
|
|
||||||
// We may want to have additional pools for different rendering subsystems.
|
|
||||||
VkCommandPoolCreateInfo cmd_pool_info;
|
|
||||||
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
||||||
cmd_pool_info.pNext = nullptr;
|
|
||||||
cmd_pool_info.queueFamilyIndex = device->queue_family_index();
|
|
||||||
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
|
||||||
auto err = vkCreateCommandPool(*device, &cmd_pool_info, nullptr, &cmd_pool_);
|
|
||||||
CheckResult(err, "vkCreateCommandPool");
|
|
||||||
|
|
||||||
if (target_window_) {
|
if (target_window_) {
|
||||||
// Create swap chain used to present to the window.
|
// Create swap chain used to present to the window.
|
||||||
VkSurfaceKHR surface = nullptr;
|
VkSurfaceKHR surface = nullptr;
|
||||||
|
@ -68,8 +58,8 @@ bool VulkanContext::Initialize() {
|
||||||
create_info.hinstance =
|
create_info.hinstance =
|
||||||
static_cast<HINSTANCE>(target_window_->native_platform_handle());
|
static_cast<HINSTANCE>(target_window_->native_platform_handle());
|
||||||
create_info.hwnd = static_cast<HWND>(target_window_->native_handle());
|
create_info.hwnd = static_cast<HWND>(target_window_->native_handle());
|
||||||
err = vkCreateWin32SurfaceKHR(*provider->instance(), &create_info, nullptr,
|
auto err = vkCreateWin32SurfaceKHR(*provider->instance(), &create_info,
|
||||||
&surface);
|
nullptr, &surface);
|
||||||
CheckResult(err, "vkCreateWin32SurfaceKHR");
|
CheckResult(err, "vkCreateWin32SurfaceKHR");
|
||||||
#else
|
#else
|
||||||
#error Platform not yet implemented.
|
#error Platform not yet implemented.
|
||||||
|
@ -130,6 +120,7 @@ void VulkanContext::BeginSwap() {
|
||||||
swap_chain_->Begin();
|
swap_chain_->Begin();
|
||||||
|
|
||||||
// TODO(benvanik): use a fence instead? May not be possible with target image.
|
// TODO(benvanik): use a fence instead? May not be possible with target image.
|
||||||
|
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||||
auto err = vkQueueWaitIdle(device->primary_queue());
|
auto err = vkQueueWaitIdle(device->primary_queue());
|
||||||
CheckResult(err, "vkQueueWaitIdle");
|
CheckResult(err, "vkQueueWaitIdle");
|
||||||
}
|
}
|
||||||
|
@ -145,6 +136,7 @@ void VulkanContext::EndSwap() {
|
||||||
|
|
||||||
// Wait until the queue is idle.
|
// Wait until the queue is idle.
|
||||||
// TODO(benvanik): is this required?
|
// TODO(benvanik): is this required?
|
||||||
|
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||||
auto err = vkQueueWaitIdle(device->primary_queue());
|
auto err = vkQueueWaitIdle(device->primary_queue());
|
||||||
CheckResult(err, "vkQueueWaitIdle");
|
CheckResult(err, "vkQueueWaitIdle");
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,6 @@ class VulkanContext : public GraphicsContext {
|
||||||
|
|
||||||
std::unique_ptr<VulkanSwapChain> swap_chain_;
|
std::unique_ptr<VulkanSwapChain> swap_chain_;
|
||||||
std::unique_ptr<VulkanImmediateDrawer> immediate_drawer_;
|
std::unique_ptr<VulkanImmediateDrawer> immediate_drawer_;
|
||||||
VkCommandPool cmd_pool_ = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vulkan
|
} // namespace vulkan
|
||||||
|
|
|
@ -118,8 +118,8 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||||
if (queue_flags & VK_QUEUE_GRAPHICS_BIT) {
|
if (queue_flags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
// Can do graphics and present - good!
|
// Can do graphics and present - good!
|
||||||
ideal_queue_family_index = static_cast<uint32_t>(i);
|
ideal_queue_family_index = static_cast<uint32_t>(i);
|
||||||
// TODO(benvanik): pick a higher queue count?
|
// Grab all the queues we can.
|
||||||
queue_count = 1;
|
queue_count = device_info.queue_family_properties[i].queueCount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,6 +136,8 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||||
queue_info.queueFamilyIndex = ideal_queue_family_index;
|
queue_info.queueFamilyIndex = ideal_queue_family_index;
|
||||||
queue_info.queueCount = queue_count;
|
queue_info.queueCount = queue_count;
|
||||||
std::vector<float> queue_priorities(queue_count);
|
std::vector<float> queue_priorities(queue_count);
|
||||||
|
// Prioritize the primary queue.
|
||||||
|
queue_priorities[0] = 1.0f;
|
||||||
queue_info.pQueuePriorities = queue_priorities.data();
|
queue_info.pQueuePriorities = queue_priorities.data();
|
||||||
|
|
||||||
VkDeviceCreateInfo create_info;
|
VkDeviceCreateInfo create_info;
|
||||||
|
@ -179,10 +181,32 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||||
// Get the primary queue used for most submissions/etc.
|
// Get the primary queue used for most submissions/etc.
|
||||||
vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_);
|
vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_);
|
||||||
|
|
||||||
|
// Get all additional queues, if we got any.
|
||||||
|
for (uint32_t i = 0; i < queue_count - 1; ++i) {
|
||||||
|
VkQueue queue;
|
||||||
|
vkGetDeviceQueue(handle, queue_family_index_, i, &queue);
|
||||||
|
free_queues_.push_back(queue);
|
||||||
|
}
|
||||||
|
|
||||||
XELOGVK("Device initialized successfully!");
|
XELOGVK("Device initialized successfully!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkQueue VulkanDevice::AcquireQueue() {
|
||||||
|
std::lock_guard<std::mutex> lock(queue_mutex_);
|
||||||
|
if (free_queues_.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto queue = free_queues_.back();
|
||||||
|
free_queues_.pop_back();
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::ReleaseQueue(VkQueue queue) {
|
||||||
|
std::lock_guard<std::mutex> lock(queue_mutex_);
|
||||||
|
free_queues_.push_back(queue);
|
||||||
|
}
|
||||||
|
|
||||||
VkDeviceMemory VulkanDevice::AllocateMemory(
|
VkDeviceMemory VulkanDevice::AllocateMemory(
|
||||||
const VkMemoryRequirements& requirements, VkFlags required_properties) {
|
const VkMemoryRequirements& requirements, VkFlags required_properties) {
|
||||||
// Search memory types to find one matching our requirements and our
|
// Search memory types to find one matching our requirements and our
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define XENIA_UI_VULKAN_VULKAN_DEVICE_H_
|
#define XENIA_UI_VULKAN_VULKAN_DEVICE_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -57,9 +58,23 @@ class VulkanDevice {
|
||||||
bool Initialize(DeviceInfo device_info);
|
bool Initialize(DeviceInfo device_info);
|
||||||
|
|
||||||
uint32_t queue_family_index() const { return queue_family_index_; }
|
uint32_t queue_family_index() const { return queue_family_index_; }
|
||||||
|
std::mutex& primary_queue_mutex() { return queue_mutex_; }
|
||||||
|
// Access to the primary queue must be synchronized with primary_queue_mutex.
|
||||||
VkQueue primary_queue() const { return primary_queue_; }
|
VkQueue primary_queue() const { return primary_queue_; }
|
||||||
const DeviceInfo& device_info() const { return device_info_; }
|
const DeviceInfo& device_info() const { return device_info_; }
|
||||||
|
|
||||||
|
// Acquires a queue for exclusive use by the caller.
|
||||||
|
// The queue will not be touched by any other code until it's returned with
|
||||||
|
// ReleaseQueue.
|
||||||
|
// Not all devices support queues or only support a limited number. If this
|
||||||
|
// returns null the primary_queue should be used with the
|
||||||
|
// primary_queue_mutex.
|
||||||
|
// This method is thread safe.
|
||||||
|
VkQueue AcquireQueue();
|
||||||
|
// Releases a queue back to the device pool.
|
||||||
|
// This method is thread safe.
|
||||||
|
void ReleaseQueue(VkQueue queue);
|
||||||
|
|
||||||
// Allocates memory of the given size matching the required properties.
|
// Allocates memory of the given size matching the required properties.
|
||||||
VkDeviceMemory AllocateMemory(
|
VkDeviceMemory AllocateMemory(
|
||||||
const VkMemoryRequirements& requirements,
|
const VkMemoryRequirements& requirements,
|
||||||
|
@ -73,7 +88,9 @@ class VulkanDevice {
|
||||||
|
|
||||||
DeviceInfo device_info_;
|
DeviceInfo device_info_;
|
||||||
uint32_t queue_family_index_ = 0;
|
uint32_t queue_family_index_ = 0;
|
||||||
|
std::mutex queue_mutex_;
|
||||||
VkQueue primary_queue_ = nullptr;
|
VkQueue primary_queue_ = nullptr;
|
||||||
|
std::vector<VkQueue> free_queues_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vulkan
|
} // namespace vulkan
|
||||||
|
|
|
@ -373,12 +373,15 @@ bool VulkanSwapChain::Begin() {
|
||||||
wait_submit_info.pCommandBuffers = nullptr;
|
wait_submit_info.pCommandBuffers = nullptr;
|
||||||
wait_submit_info.signalSemaphoreCount = 0;
|
wait_submit_info.signalSemaphoreCount = 0;
|
||||||
wait_submit_info.pSignalSemaphores = nullptr;
|
wait_submit_info.pSignalSemaphores = nullptr;
|
||||||
err = vkQueueSubmit(device_->primary_queue(), 1, &wait_submit_info, nullptr);
|
{
|
||||||
|
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||||
|
err =
|
||||||
|
vkQueueSubmit(device_->primary_queue(), 1, &wait_submit_info, nullptr);
|
||||||
|
}
|
||||||
CheckResult(err, "vkQueueSubmit");
|
CheckResult(err, "vkQueueSubmit");
|
||||||
|
|
||||||
// Reset all command buffers.
|
// Reset all command buffers.
|
||||||
vkResetCommandBuffer(render_cmd_buffer_,
|
vkResetCommandBuffer(render_cmd_buffer_, 0);
|
||||||
VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
|
|
||||||
auto& current_buffer = buffers_[current_buffer_index_];
|
auto& current_buffer = buffers_[current_buffer_index_];
|
||||||
|
|
||||||
// Build the command buffer that will execute all queued rendering buffers.
|
// Build the command buffer that will execute all queued rendering buffers.
|
||||||
|
@ -484,8 +487,11 @@ bool VulkanSwapChain::End() {
|
||||||
render_submit_info.pCommandBuffers = &render_cmd_buffer_;
|
render_submit_info.pCommandBuffers = &render_cmd_buffer_;
|
||||||
render_submit_info.signalSemaphoreCount = 0;
|
render_submit_info.signalSemaphoreCount = 0;
|
||||||
render_submit_info.pSignalSemaphores = nullptr;
|
render_submit_info.pSignalSemaphores = nullptr;
|
||||||
err =
|
{
|
||||||
vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info, nullptr);
|
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||||
|
err = vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
CheckResult(err, "vkQueueSubmit");
|
CheckResult(err, "vkQueueSubmit");
|
||||||
|
|
||||||
// Queue the present of our current image.
|
// Queue the present of our current image.
|
||||||
|
@ -500,7 +506,10 @@ bool VulkanSwapChain::End() {
|
||||||
present_info.pSwapchains = swap_chains;
|
present_info.pSwapchains = swap_chains;
|
||||||
present_info.pImageIndices = swap_chain_image_indices;
|
present_info.pImageIndices = swap_chain_image_indices;
|
||||||
present_info.pResults = nullptr;
|
present_info.pResults = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||||
err = vkQueuePresentKHR(device_->primary_queue(), &present_info);
|
err = vkQueuePresentKHR(device_->primary_queue(), &present_info);
|
||||||
|
}
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case VK_SUCCESS:
|
case VK_SUCCESS:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue