Support rendering windowless (tested on the Vulkan backend)

This commit is contained in:
DrChat 2017-12-19 16:02:09 -06:00
parent 8fc71f6f7c
commit 09b3a07e3c
14 changed files with 156 additions and 146 deletions

View File

@ -191,11 +191,13 @@ X_STATUS Emulator::Setup(
// Initialize emulator fallback exception handling last. // Initialize emulator fallback exception handling last.
ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this); ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this);
// Finish initializing the display. if (display_window_) {
display_window_->loop()->PostSynchronous([this]() { // Finish initializing the display.
xe::ui::GraphicsContextLock context_lock(display_window_->context()); display_window_->loop()->PostSynchronous([this]() {
Profiler::set_window(display_window_); xe::ui::GraphicsContextLock context_lock(display_window_->context());
}); Profiler::set_window(display_window_);
});
}
return result; return result;
} }

View File

@ -51,16 +51,21 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
// This must happen on the UI thread. // This must happen on the UI thread.
std::unique_ptr<xe::ui::GraphicsContext> processor_context = nullptr; std::unique_ptr<xe::ui::GraphicsContext> processor_context = nullptr;
if (provider_) { if (provider_) {
target_window_->loop()->PostSynchronous([&]() { if (target_window_) {
// Create the context used for presentation. target_window_->loop()->PostSynchronous([&]() {
assert_null(target_window->context()); // Create the context used for presentation.
target_window_->set_context(provider_->CreateContext(target_window_)); assert_null(target_window->context());
target_window_->set_context(provider_->CreateContext(target_window_));
// Setup the context the command processor will do all its drawing in. // Setup the context the command processor will do all its drawing in.
// It's shared with the display context so that we can resolve // It's shared with the display context so that we can resolve
// framebuffers from it. // framebuffers from it.
processor_context = provider()->CreateOffscreenContext();
});
} else {
processor_context = provider()->CreateOffscreenContext(); processor_context = provider()->CreateOffscreenContext();
}); }
if (!processor_context) { if (!processor_context) {
xe::FatalError( xe::FatalError(
"Unable to initialize graphics context. Xenia requires OpenGL 4.5 or " "Unable to initialize graphics context. Xenia requires OpenGL 4.5 or "
@ -78,16 +83,21 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
XELOGE("Unable to initialize command processor"); XELOGE("Unable to initialize command processor");
return X_STATUS_UNSUCCESSFUL; return X_STATUS_UNSUCCESSFUL;
} }
command_processor_->set_swap_request_handler(
[this]() { target_window_->Invalidate(); });
// Watch for paint requests to do our swap. if (target_window) {
target_window->on_painting.AddListener( command_processor_->set_swap_request_handler(
[this](xe::ui::UIEvent* e) { Swap(e); }); [this]() { target_window_->Invalidate(); });
// Watch for context lost events. // Watch for paint requests to do our swap.
target_window->on_context_lost.AddListener( target_window->on_painting.AddListener(
[this](xe::ui::UIEvent* e) { Reset(); }); [this](xe::ui::UIEvent* e) { Swap(e); });
// Watch for context lost events.
target_window->on_context_lost.AddListener(
[this](xe::ui::UIEvent* e) { Reset(); });
} else {
command_processor_->set_swap_request_handler([]() {});
}
// Let the processor know we want register access callbacks. // Let the processor know we want register access callbacks.
memory_->AddVirtualMappedRange( memory_->AddVirtualMappedRange(

View File

@ -212,13 +212,13 @@ VkResult TextureCache::Initialize() {
invalidated_textures_sets_[1].reserve(64); invalidated_textures_sets_[1].reserve(64);
invalidated_textures_ = &invalidated_textures_sets_[0]; invalidated_textures_ = &invalidated_textures_sets_[0];
device_queue_ = device_->AcquireQueue(); device_queue_ = device_->AcquireQueue(device_->queue_family_index());
return VK_SUCCESS; return VK_SUCCESS;
} }
void TextureCache::Shutdown() { void TextureCache::Shutdown() {
if (device_queue_) { if (device_queue_) {
device_->ReleaseQueue(device_queue_); device_->ReleaseQueue(device_queue_, device_->queue_family_index());
} }
// Free all textures allocated. // Free all textures allocated.

View File

@ -62,7 +62,7 @@ bool VulkanCommandProcessor::SetupContext() {
// Acquire our device and queue. // Acquire our device and queue.
auto context = static_cast<xe::ui::vulkan::VulkanContext*>(context_.get()); auto context = static_cast<xe::ui::vulkan::VulkanContext*>(context_.get());
device_ = context->device(); device_ = context->device();
queue_ = device_->AcquireQueue(); queue_ = device_->AcquireQueue(device_->queue_family_index());
if (!queue_) { if (!queue_) {
// Need to reuse primary queue (with locks). // Need to reuse primary queue (with locks).
queue_ = device_->primary_queue(); queue_ = device_->primary_queue();
@ -159,7 +159,7 @@ void VulkanCommandProcessor::ShutdownContext() {
// Release queue, if we were using an acquired one. // Release queue, if we were using an acquired one.
if (!queue_mutex_) { if (!queue_mutex_) {
device_->ReleaseQueue(queue_); device_->ReleaseQueue(queue_, device_->queue_family_index());
queue_ = nullptr; queue_ = nullptr;
} }

View File

@ -37,16 +37,19 @@ X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state, kernel::KernelState* kernel_state,
ui::Window* target_window) { ui::Window* target_window) {
// Must create the provider so we can create contexts. // Must create the provider so we can create contexts.
provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window); auto provider = xe::ui::vulkan::VulkanProvider::Create(target_window);
device_ = provider->device();
provider_ = std::move(provider);
auto result = GraphicsSystem::Setup(processor, kernel_state, target_window); auto result = GraphicsSystem::Setup(processor, kernel_state, target_window);
if (result) { if (result) {
return result; return result;
} }
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>( if (target_window) {
target_window->context()); display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
device_ = display_context_->device(); target_window->context());
}
// Create our own command pool we can use for captures. // Create our own command pool we can use for captures.
VkCommandPoolCreateInfo create_info = { VkCommandPoolCreateInfo create_info = {

View File

@ -124,12 +124,9 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
uint32_t queue_count = 1; uint32_t queue_count = 1;
for (size_t i = 0; i < device_info.queue_family_properties.size(); ++i) { for (size_t i = 0; i < device_info.queue_family_properties.size(); ++i) {
auto queue_flags = device_info.queue_family_properties[i].queueFlags; auto queue_flags = device_info.queue_family_properties[i].queueFlags;
if (!device_info.queue_family_supports_present[i]) { if (queue_flags & VK_QUEUE_GRAPHICS_BIT &&
// Can't present from this queue, so ignore it. queue_flags & VK_QUEUE_TRANSFER_BIT) {
continue; // Can do graphics and transfer - good!
}
if (queue_flags & VK_QUEUE_GRAPHICS_BIT) {
// Can do graphics and present - good!
ideal_queue_family_index = static_cast<uint32_t>(i); ideal_queue_family_index = static_cast<uint32_t>(i);
// Grab all the queues we can. // Grab all the queues we can.
queue_count = device_info.queue_family_properties[i].queueCount; queue_count = device_info.queue_family_properties[i].queueCount;
@ -138,7 +135,7 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
} }
if (ideal_queue_family_index == UINT_MAX) { if (ideal_queue_family_index == UINT_MAX) {
FatalVulkanError( FatalVulkanError(
"No queue families available that can both do graphics and present"); "No queue families available that can both do graphics and transfer");
return false; return false;
} }
@ -147,23 +144,36 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
queue_count = 1; queue_count = 1;
} }
VkDeviceQueueCreateInfo queue_info; std::vector<VkDeviceQueueCreateInfo> queue_infos;
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_infos.resize(device_info.queue_family_properties.size());
queue_info.pNext = nullptr; for (int i = 0; i < queue_infos.size(); i++) {
queue_info.flags = 0; VkDeviceQueueCreateInfo& queue_info = queue_infos[i];
queue_info.queueFamilyIndex = ideal_queue_family_index; VkQueueFamilyProperties& family_props =
queue_info.queueCount = queue_count; device_info.queue_family_properties[i];
std::vector<float> queue_priorities(queue_count);
// Prioritize the primary queue. queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_priorities[0] = 1.0f; queue_info.pNext = nullptr;
queue_info.pQueuePriorities = queue_priorities.data(); queue_info.flags = 0;
queue_info.queueFamilyIndex = i;
queue_info.queueCount = family_props.queueCount;
std::vector<float> queue_priorities(queue_count);
if (i == ideal_queue_family_index) {
// Prioritize the first queue on the primary queue family.
queue_priorities[0] = 1.0f;
} else {
queue_priorities[0] = 0.f;
}
queue_info.pQueuePriorities = queue_priorities.data();
}
VkDeviceCreateInfo create_info; VkDeviceCreateInfo create_info;
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.pNext = nullptr; create_info.pNext = nullptr;
create_info.flags = 0; create_info.flags = 0;
create_info.queueCreateInfoCount = 1; create_info.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size());
create_info.pQueueCreateInfos = &queue_info; create_info.pQueueCreateInfos = queue_infos.data();
create_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()); create_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
create_info.ppEnabledLayerNames = enabled_layers.data(); create_info.ppEnabledLayerNames = enabled_layers.data();
create_info.enabledExtensionCount = create_info.enabledExtensionCount =
@ -205,31 +215,49 @@ 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_);
if (!primary_queue_) {
XELOGE("vkGetDeviceQueue returned nullptr!");
return false;
}
// Get all additional queues, if we got any. // Get all additional queues, if we got any.
for (uint32_t i = 0; i < queue_count - 1; ++i) { free_queues_.resize(device_info_.queue_family_properties.size());
VkQueue queue; for (uint32_t i = 0; i < device_info_.queue_family_properties.size(); i++) {
vkGetDeviceQueue(handle, queue_family_index_, i, &queue); VkQueueFamilyProperties& family_props =
free_queues_.push_back(queue); device_info_.queue_family_properties[i];
for (uint32_t j = 0; j < family_props.queueCount; j++) {
VkQueue queue = nullptr;
if (i == queue_family_index_ && j == 0) {
// Already retrieved the primary queue index.
continue;
}
vkGetDeviceQueue(handle, i, j, &queue);
if (queue) {
free_queues_[i].push_back(queue);
}
}
} }
XELOGVK("Device initialized successfully!"); XELOGVK("Device initialized successfully!");
return true; return true;
} }
VkQueue VulkanDevice::AcquireQueue() { VkQueue VulkanDevice::AcquireQueue(uint32_t queue_family_index) {
std::lock_guard<std::mutex> lock(queue_mutex_); std::lock_guard<std::mutex> lock(queue_mutex_);
if (free_queues_.empty()) { if (free_queues_[queue_family_index].empty()) {
return nullptr; return nullptr;
} }
auto queue = free_queues_.back();
free_queues_.pop_back(); auto queue = free_queues_[queue_family_index].back();
free_queues_[queue_family_index].pop_back();
return queue; return queue;
} }
void VulkanDevice::ReleaseQueue(VkQueue queue) { void VulkanDevice::ReleaseQueue(VkQueue queue, uint32_t queue_family_index) {
std::lock_guard<std::mutex> lock(queue_mutex_); std::lock_guard<std::mutex> lock(queue_mutex_);
free_queues_.push_back(queue); free_queues_[queue_family_index].push_back(queue);
} }
void VulkanDevice::DbgSetObjectName(VkDevice device, uint64_t object, void VulkanDevice::DbgSetObjectName(VkDevice device, uint64_t object,

View File

@ -70,10 +70,10 @@ class VulkanDevice {
// returns null the primary_queue should be used with the // returns null the primary_queue should be used with the
// primary_queue_mutex. // primary_queue_mutex.
// This method is thread safe. // This method is thread safe.
VkQueue AcquireQueue(); VkQueue AcquireQueue(uint32_t queue_family_index);
// Releases a queue back to the device pool. // Releases a queue back to the device pool.
// This method is thread safe. // This method is thread safe.
void ReleaseQueue(VkQueue queue); void ReleaseQueue(VkQueue queue, uint32_t queue_family_index);
static void DbgSetObjectName(VkDevice device, uint64_t object, static void DbgSetObjectName(VkDevice device, uint64_t object,
VkDebugReportObjectTypeEXT object_type, VkDebugReportObjectTypeEXT object_type,
@ -108,7 +108,7 @@ class VulkanDevice {
uint32_t queue_family_index_ = 0; uint32_t queue_family_index_ = 0;
std::mutex queue_mutex_; std::mutex queue_mutex_;
VkQueue primary_queue_ = nullptr; VkQueue primary_queue_ = nullptr;
std::vector<VkQueue> free_queues_; std::vector<std::vector<VkQueue>> free_queues_;
}; };
} // namespace vulkan } // namespace vulkan

View File

@ -69,7 +69,7 @@ VulkanInstance::VulkanInstance() {
VulkanInstance::~VulkanInstance() { DestroyInstance(); } VulkanInstance::~VulkanInstance() { DestroyInstance(); }
bool VulkanInstance::Initialize(Window* any_target_window) { bool VulkanInstance::Initialize() {
auto version = Version::Parse(VK_API_VERSION); auto version = Version::Parse(VK_API_VERSION);
XELOGVK("Initializing Vulkan %s...", version.pretty_string.c_str()); XELOGVK("Initializing Vulkan %s...", version.pretty_string.c_str());
@ -87,7 +87,7 @@ bool VulkanInstance::Initialize(Window* any_target_window) {
} }
// Query available devices so that we can pick one. // Query available devices so that we can pick one.
if (!QueryDevices(any_target_window)) { if (!QueryDevices()) {
XELOGE("Failed to query devices"); XELOGE("Failed to query devices");
return false; return false;
} }
@ -347,7 +347,7 @@ void VulkanInstance::DisableDebugValidation() {
dbg_report_callback_ = nullptr; dbg_report_callback_ = nullptr;
} }
bool VulkanInstance::QueryDevices(Window* any_target_window) { bool VulkanInstance::QueryDevices() {
// Get handles to all devices. // Get handles to all devices.
uint32_t count = 0; uint32_t count = 0;
std::vector<VkPhysicalDevice> device_handles; std::vector<VkPhysicalDevice> device_handles;
@ -376,56 +376,6 @@ bool VulkanInstance::QueryDevices(Window* any_target_window) {
vkGetPhysicalDeviceQueueFamilyProperties( vkGetPhysicalDeviceQueueFamilyProperties(
device_handle, &count, device_info.queue_family_properties.data()); device_handle, &count, device_info.queue_family_properties.data());
// Gather queue family presentation support.
// TODO(benvanik): move to swap chain?
VkSurfaceKHR any_surface = nullptr;
#if XE_PLATFORM_WIN32
VkWin32SurfaceCreateInfoKHR create_info;
create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.hinstance =
static_cast<HINSTANCE>(any_target_window->native_platform_handle());
create_info.hwnd = static_cast<HWND>(any_target_window->native_handle());
err = vkCreateWin32SurfaceKHR(handle, &create_info, nullptr, &any_surface);
CheckResult(err, "vkCreateWin32SurfaceKHR");
#elif XE_PLATFORM_LINUX
#ifdef GDK_WINDOWING_X11
GtkWidget* window_handle =
static_cast<GtkWidget*>(any_target_window->native_handle());
GdkDisplay* gdk_display = gtk_widget_get_display(window_handle);
assert(GDK_IS_X11_DISPLAY(gdk_display));
xcb_connection_t* connection =
XGetXCBConnection(gdk_x11_display_get_xdisplay(gdk_display));
xcb_window_t window =
gdk_x11_window_get_xid(gtk_widget_get_window(window_handle));
VkXcbSurfaceCreateInfoKHR create_info;
create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
create_info.pNext = nullptr;
create_info.flags = 0;
create_info.connection = static_cast<xcb_connection_t*>(
any_target_window->native_platform_handle());
create_info.window = static_cast<xcb_window_t>(window);
auto err =
vkCreateXcbSurfaceKHR(handle, &create_info, nullptr, &any_surface);
CheckResult(err, "vkCreateXcbSurfaceKHR");
#else
#error Unsupported GDK Backend on Linux.
#endif // GDK_WINDOWING_X11
#else
#error Platform not yet implemented.
#endif // XE_PLATFORM_WIN32
device_info.queue_family_supports_present.resize(
device_info.queue_family_properties.size());
for (size_t j = 0; j < device_info.queue_family_supports_present.size();
++j) {
err = vkGetPhysicalDeviceSurfaceSupportKHR(
device_handle, static_cast<uint32_t>(j), any_surface,
&device_info.queue_family_supports_present[j]);
CheckResult(err, "vkGetPhysicalDeviceSurfaceSupportKHR");
}
vkDestroySurfaceKHR(handle, any_surface, nullptr);
// Gather layers. // Gather layers.
std::vector<VkLayerProperties> layer_properties; std::vector<VkLayerProperties> layer_properties;
err = vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr); err = vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr);
@ -552,8 +502,6 @@ void VulkanInstance::DumpDeviceInfo(const DeviceInfo& device_info) {
: ""); : "");
XELOGVK(" queueCount = %u", queue_props.queueCount); XELOGVK(" queueCount = %u", queue_props.queueCount);
XELOGVK(" timestampValidBits = %u", queue_props.timestampValidBits); XELOGVK(" timestampValidBits = %u", queue_props.timestampValidBits);
XELOGVK(" supportsPresent = %s",
device_info.queue_family_supports_present[j] ? "true" : "false");
} }
XELOGVK(" Layers:"); XELOGVK(" Layers:");

View File

@ -50,8 +50,7 @@ class VulkanInstance {
// preparing the instance for general use. // preparing the instance for general use.
// If initialization succeeds it's likely that no more failures beyond runtime // If initialization succeeds it's likely that no more failures beyond runtime
// issues will occur. // issues will occur.
// TODO(benvanik): remove need for any_target_window - it's just for queries. bool Initialize();
bool Initialize(Window* any_target_window);
// Returns a list of all available devices as detected during initialization. // Returns a list of all available devices as detected during initialization.
const std::vector<DeviceInfo>& available_devices() const { const std::vector<DeviceInfo>& available_devices() const {
@ -79,7 +78,7 @@ class VulkanInstance {
void DisableDebugValidation(); void DisableDebugValidation();
// Queries all available physical devices. // Queries all available physical devices.
bool QueryDevices(Window* any_target_window); bool QueryDevices();
void DumpLayers(const std::vector<LayerInfo>& layers, const char* indent); void DumpLayers(const std::vector<LayerInfo>& layers, const char* indent);
void DumpExtensions(const std::vector<VkExtensionProperties>& extensions, void DumpExtensions(const std::vector<VkExtensionProperties>& extensions,

View File

@ -25,7 +25,7 @@ namespace xe {
namespace ui { namespace ui {
namespace vulkan { namespace vulkan {
std::unique_ptr<GraphicsProvider> VulkanProvider::Create(Window* main_window) { std::unique_ptr<VulkanProvider> VulkanProvider::Create(Window* main_window) {
std::unique_ptr<VulkanProvider> provider(new VulkanProvider(main_window)); std::unique_ptr<VulkanProvider> provider(new VulkanProvider(main_window));
if (!provider->Initialize()) { if (!provider->Initialize()) {
xe::FatalError( xe::FatalError(
@ -35,7 +35,7 @@ std::unique_ptr<GraphicsProvider> VulkanProvider::Create(Window* main_window) {
"list of supported GPUs."); "list of supported GPUs.");
return nullptr; return nullptr;
} }
return std::unique_ptr<GraphicsProvider>(provider.release()); return provider;
} }
VulkanProvider::VulkanProvider(Window* main_window) VulkanProvider::VulkanProvider(Window* main_window)
@ -56,7 +56,7 @@ bool VulkanProvider::Initialize() {
Version::Make(0, 0, 0), false); Version::Make(0, 0, 0), false);
// Attempt initialization and device query. // Attempt initialization and device query.
if (!instance_->Initialize(main_window_)) { if (!instance_->Initialize()) {
XELOGE("Failed to initialize vulkan instance"); XELOGE("Failed to initialize vulkan instance");
return false; return false;
} }

View File

@ -25,7 +25,7 @@ class VulkanProvider : public GraphicsProvider {
public: public:
~VulkanProvider() override; ~VulkanProvider() override;
static std::unique_ptr<GraphicsProvider> Create(Window* main_window); static std::unique_ptr<VulkanProvider> Create(Window* main_window);
VulkanInstance* instance() const { return instance_.get(); } VulkanInstance* instance() const { return instance_.get(); }
VulkanDevice* device() const { return device_.get(); } VulkanDevice* device() const { return device_.get(); }

View File

@ -36,14 +36,40 @@ VulkanSwapChain::~VulkanSwapChain() { Shutdown(); }
VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) { VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
surface_ = surface; surface_ = surface;
VkResult status;
// Find a queue family that supports presentation.
VkBool32 surface_supported = false; VkBool32 surface_supported = false;
auto status = vkGetPhysicalDeviceSurfaceSupportKHR( uint32_t queue_family_index = -1;
*device_, device_->queue_family_index(), surface, &surface_supported); for (uint32_t i = 0;
assert_true(surface_supported); i < device_->device_info().queue_family_properties.size(); i++) {
CheckResult(status, "vkGetPhysicalDeviceSurfaceSupportKHR"); const VkQueueFamilyProperties& family_props =
if (status != VK_SUCCESS) { device_->device_info().queue_family_properties[i];
return status; if (!(family_props.queueFlags & VK_QUEUE_GRAPHICS_BIT) ||
!(family_props.queueFlags & VK_QUEUE_TRANSFER_BIT)) {
continue;
}
status = vkGetPhysicalDeviceSurfaceSupportKHR(*device_, i, surface,
&surface_supported);
if (status == VK_SUCCESS && surface_supported == VK_TRUE) {
queue_family_index = i;
break;
}
}
if (!surface_supported) {
XELOGE(
"Physical device does not have a queue that supports "
"graphics/transfer/presentation!");
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
presentation_queue_family_ = queue_family_index;
presentation_queue_ = device_->AcquireQueue(queue_family_index);
if (!presentation_queue_) {
XELOGE("Failed to acquire swap chain presentation queue!");
return VK_ERROR_INITIALIZATION_FAILED;
} }
// Query supported target formats. // Query supported target formats.
@ -190,7 +216,7 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmd_pool_info.pNext = nullptr; cmd_pool_info.pNext = nullptr;
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
cmd_pool_info.queueFamilyIndex = device_->queue_family_index(); cmd_pool_info.queueFamilyIndex = presentation_queue_family_;
status = vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_); status = vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_);
CheckResult(status, "vkCreateCommandPool"); CheckResult(status, "vkCreateCommandPool");
if (status != VK_SUCCESS) { if (status != VK_SUCCESS) {
@ -432,6 +458,11 @@ void VulkanSwapChain::Shutdown() {
vkDestroyCommandPool(*device_, cmd_pool_, nullptr); vkDestroyCommandPool(*device_, cmd_pool_, nullptr);
cmd_pool_ = nullptr; cmd_pool_ = nullptr;
} }
if (presentation_queue_) {
device_->ReleaseQueue(presentation_queue_, presentation_queue_family_);
presentation_queue_ = nullptr;
presentation_queue_family_ = -1;
}
// images_ doesn't need to be cleaned up as the swapchain does it implicitly. // images_ doesn't need to be cleaned up as the swapchain does it implicitly.
if (handle) { if (handle) {
vkDestroySwapchainKHR(*device_, handle, nullptr); vkDestroySwapchainKHR(*device_, handle, nullptr);
@ -471,11 +502,7 @@ VkResult VulkanSwapChain::Begin() {
wait_submit_info.pCommandBuffers = nullptr; wait_submit_info.pCommandBuffers = nullptr;
wait_submit_info.signalSemaphoreCount = 1; wait_submit_info.signalSemaphoreCount = 1;
wait_submit_info.pSignalSemaphores = &image_usage_semaphore_; wait_submit_info.pSignalSemaphores = &image_usage_semaphore_;
{ status = vkQueueSubmit(presentation_queue_, 1, &wait_submit_info, nullptr);
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
status =
vkQueueSubmit(device_->primary_queue(), 1, &wait_submit_info, nullptr);
}
if (status != VK_SUCCESS) { if (status != VK_SUCCESS) {
return status; return status;
} }
@ -687,12 +714,7 @@ VkResult VulkanSwapChain::End() {
render_submit_info.pCommandBuffers = &cmd_buffer_; render_submit_info.pCommandBuffers = &cmd_buffer_;
render_submit_info.signalSemaphoreCount = uint32_t(semaphores.size()) - 1; render_submit_info.signalSemaphoreCount = uint32_t(semaphores.size()) - 1;
render_submit_info.pSignalSemaphores = semaphores.data(); render_submit_info.pSignalSemaphores = semaphores.data();
{ status = vkQueueSubmit(presentation_queue_, 1, &render_submit_info, nullptr);
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
status = vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info,
nullptr);
}
if (status != VK_SUCCESS) { if (status != VK_SUCCESS) {
return status; return status;
} }
@ -709,10 +731,7 @@ VkResult 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;
{ status = vkQueuePresentKHR(presentation_queue_, &present_info);
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
status = vkQueuePresentKHR(device_->primary_queue(), &present_info);
}
switch (status) { switch (status) {
case VK_SUCCESS: case VK_SUCCESS:
break; break;

View File

@ -78,6 +78,8 @@ class VulkanSwapChain {
VulkanInstance* instance_ = nullptr; VulkanInstance* instance_ = nullptr;
VulkanDevice* device_ = nullptr; VulkanDevice* device_ = nullptr;
VkQueue presentation_queue_ = nullptr;
uint32_t presentation_queue_family_ = -1;
VkSurfaceKHR surface_ = nullptr; VkSurfaceKHR surface_ = nullptr;
uint32_t surface_width_ = 0; uint32_t surface_width_ = 0;
uint32_t surface_height_ = 0; uint32_t surface_height_ = 0;

View File

@ -95,7 +95,6 @@ struct DeviceInfo {
VkPhysicalDeviceFeatures features; VkPhysicalDeviceFeatures features;
VkPhysicalDeviceMemoryProperties memory_properties; VkPhysicalDeviceMemoryProperties memory_properties;
std::vector<VkQueueFamilyProperties> queue_family_properties; std::vector<VkQueueFamilyProperties> queue_family_properties;
std::vector<VkBool32> queue_family_supports_present;
std::vector<LayerInfo> layers; std::vector<LayerInfo> layers;
std::vector<VkExtensionProperties> extensions; std::vector<VkExtensionProperties> extensions;
}; };