Support rendering windowless (tested on the Vulkan backend)
This commit is contained in:
parent
8fc71f6f7c
commit
09b3a07e3c
|
@ -191,11 +191,13 @@ X_STATUS Emulator::Setup(
|
|||
// Initialize emulator fallback exception handling last.
|
||||
ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this);
|
||||
|
||||
// Finish initializing the display.
|
||||
display_window_->loop()->PostSynchronous([this]() {
|
||||
xe::ui::GraphicsContextLock context_lock(display_window_->context());
|
||||
Profiler::set_window(display_window_);
|
||||
});
|
||||
if (display_window_) {
|
||||
// Finish initializing the display.
|
||||
display_window_->loop()->PostSynchronous([this]() {
|
||||
xe::ui::GraphicsContextLock context_lock(display_window_->context());
|
||||
Profiler::set_window(display_window_);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -51,16 +51,21 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
|
|||
// This must happen on the UI thread.
|
||||
std::unique_ptr<xe::ui::GraphicsContext> processor_context = nullptr;
|
||||
if (provider_) {
|
||||
target_window_->loop()->PostSynchronous([&]() {
|
||||
// Create the context used for presentation.
|
||||
assert_null(target_window->context());
|
||||
target_window_->set_context(provider_->CreateContext(target_window_));
|
||||
if (target_window_) {
|
||||
target_window_->loop()->PostSynchronous([&]() {
|
||||
// Create the context used for presentation.
|
||||
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.
|
||||
// It's shared with the display context so that we can resolve
|
||||
// framebuffers from it.
|
||||
// Setup the context the command processor will do all its drawing in.
|
||||
// It's shared with the display context so that we can resolve
|
||||
// framebuffers from it.
|
||||
processor_context = provider()->CreateOffscreenContext();
|
||||
});
|
||||
} else {
|
||||
processor_context = provider()->CreateOffscreenContext();
|
||||
});
|
||||
}
|
||||
|
||||
if (!processor_context) {
|
||||
xe::FatalError(
|
||||
"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");
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
command_processor_->set_swap_request_handler(
|
||||
[this]() { target_window_->Invalidate(); });
|
||||
|
||||
// Watch for paint requests to do our swap.
|
||||
target_window->on_painting.AddListener(
|
||||
[this](xe::ui::UIEvent* e) { Swap(e); });
|
||||
if (target_window) {
|
||||
command_processor_->set_swap_request_handler(
|
||||
[this]() { target_window_->Invalidate(); });
|
||||
|
||||
// Watch for context lost events.
|
||||
target_window->on_context_lost.AddListener(
|
||||
[this](xe::ui::UIEvent* e) { Reset(); });
|
||||
// Watch for paint requests to do our swap.
|
||||
target_window->on_painting.AddListener(
|
||||
[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.
|
||||
memory_->AddVirtualMappedRange(
|
||||
|
|
|
@ -212,13 +212,13 @@ VkResult TextureCache::Initialize() {
|
|||
invalidated_textures_sets_[1].reserve(64);
|
||||
invalidated_textures_ = &invalidated_textures_sets_[0];
|
||||
|
||||
device_queue_ = device_->AcquireQueue();
|
||||
device_queue_ = device_->AcquireQueue(device_->queue_family_index());
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void TextureCache::Shutdown() {
|
||||
if (device_queue_) {
|
||||
device_->ReleaseQueue(device_queue_);
|
||||
device_->ReleaseQueue(device_queue_, device_->queue_family_index());
|
||||
}
|
||||
|
||||
// Free all textures allocated.
|
||||
|
|
|
@ -62,7 +62,7 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
// Acquire our device and queue.
|
||||
auto context = static_cast<xe::ui::vulkan::VulkanContext*>(context_.get());
|
||||
device_ = context->device();
|
||||
queue_ = device_->AcquireQueue();
|
||||
queue_ = device_->AcquireQueue(device_->queue_family_index());
|
||||
if (!queue_) {
|
||||
// Need to reuse primary queue (with locks).
|
||||
queue_ = device_->primary_queue();
|
||||
|
@ -159,7 +159,7 @@ void VulkanCommandProcessor::ShutdownContext() {
|
|||
|
||||
// Release queue, if we were using an acquired one.
|
||||
if (!queue_mutex_) {
|
||||
device_->ReleaseQueue(queue_);
|
||||
device_->ReleaseQueue(queue_, device_->queue_family_index());
|
||||
queue_ = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,16 +37,19 @@ X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
|
|||
kernel::KernelState* kernel_state,
|
||||
ui::Window* target_window) {
|
||||
// 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);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
|
||||
target_window->context());
|
||||
device_ = display_context_->device();
|
||||
if (target_window) {
|
||||
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
|
||||
target_window->context());
|
||||
}
|
||||
|
||||
// Create our own command pool we can use for captures.
|
||||
VkCommandPoolCreateInfo create_info = {
|
||||
|
|
|
@ -124,12 +124,9 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
|||
uint32_t queue_count = 1;
|
||||
for (size_t i = 0; i < device_info.queue_family_properties.size(); ++i) {
|
||||
auto queue_flags = device_info.queue_family_properties[i].queueFlags;
|
||||
if (!device_info.queue_family_supports_present[i]) {
|
||||
// Can't present from this queue, so ignore it.
|
||||
continue;
|
||||
}
|
||||
if (queue_flags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
// Can do graphics and present - good!
|
||||
if (queue_flags & VK_QUEUE_GRAPHICS_BIT &&
|
||||
queue_flags & VK_QUEUE_TRANSFER_BIT) {
|
||||
// Can do graphics and transfer - good!
|
||||
ideal_queue_family_index = static_cast<uint32_t>(i);
|
||||
// Grab all the queues we can.
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -147,23 +144,36 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
|||
queue_count = 1;
|
||||
}
|
||||
|
||||
VkDeviceQueueCreateInfo queue_info;
|
||||
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_info.pNext = nullptr;
|
||||
queue_info.flags = 0;
|
||||
queue_info.queueFamilyIndex = ideal_queue_family_index;
|
||||
queue_info.queueCount = queue_count;
|
||||
std::vector<float> queue_priorities(queue_count);
|
||||
// Prioritize the primary queue.
|
||||
queue_priorities[0] = 1.0f;
|
||||
queue_info.pQueuePriorities = queue_priorities.data();
|
||||
std::vector<VkDeviceQueueCreateInfo> queue_infos;
|
||||
queue_infos.resize(device_info.queue_family_properties.size());
|
||||
for (int i = 0; i < queue_infos.size(); i++) {
|
||||
VkDeviceQueueCreateInfo& queue_info = queue_infos[i];
|
||||
VkQueueFamilyProperties& family_props =
|
||||
device_info.queue_family_properties[i];
|
||||
|
||||
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_info.pNext = nullptr;
|
||||
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;
|
||||
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
create_info.pNext = nullptr;
|
||||
create_info.flags = 0;
|
||||
create_info.queueCreateInfoCount = 1;
|
||||
create_info.pQueueCreateInfos = &queue_info;
|
||||
create_info.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size());
|
||||
create_info.pQueueCreateInfos = queue_infos.data();
|
||||
create_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
|
||||
create_info.ppEnabledLayerNames = enabled_layers.data();
|
||||
create_info.enabledExtensionCount =
|
||||
|
@ -205,31 +215,49 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
|||
|
||||
// Get the primary queue used for most submissions/etc.
|
||||
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.
|
||||
for (uint32_t i = 0; i < queue_count - 1; ++i) {
|
||||
VkQueue queue;
|
||||
vkGetDeviceQueue(handle, queue_family_index_, i, &queue);
|
||||
free_queues_.push_back(queue);
|
||||
free_queues_.resize(device_info_.queue_family_properties.size());
|
||||
for (uint32_t i = 0; i < device_info_.queue_family_properties.size(); i++) {
|
||||
VkQueueFamilyProperties& family_props =
|
||||
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!");
|
||||
return true;
|
||||
}
|
||||
|
||||
VkQueue VulkanDevice::AcquireQueue() {
|
||||
VkQueue VulkanDevice::AcquireQueue(uint32_t queue_family_index) {
|
||||
std::lock_guard<std::mutex> lock(queue_mutex_);
|
||||
if (free_queues_.empty()) {
|
||||
if (free_queues_[queue_family_index].empty()) {
|
||||
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;
|
||||
}
|
||||
|
||||
void VulkanDevice::ReleaseQueue(VkQueue queue) {
|
||||
void VulkanDevice::ReleaseQueue(VkQueue queue, uint32_t queue_family_index) {
|
||||
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,
|
||||
|
|
|
@ -70,10 +70,10 @@ class VulkanDevice {
|
|||
// returns null the primary_queue should be used with the
|
||||
// primary_queue_mutex.
|
||||
// This method is thread safe.
|
||||
VkQueue AcquireQueue();
|
||||
VkQueue AcquireQueue(uint32_t queue_family_index);
|
||||
// Releases a queue back to the device pool.
|
||||
// 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,
|
||||
VkDebugReportObjectTypeEXT object_type,
|
||||
|
@ -108,7 +108,7 @@ class VulkanDevice {
|
|||
uint32_t queue_family_index_ = 0;
|
||||
std::mutex queue_mutex_;
|
||||
VkQueue primary_queue_ = nullptr;
|
||||
std::vector<VkQueue> free_queues_;
|
||||
std::vector<std::vector<VkQueue>> free_queues_;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
|
|
|
@ -69,7 +69,7 @@ VulkanInstance::VulkanInstance() {
|
|||
|
||||
VulkanInstance::~VulkanInstance() { DestroyInstance(); }
|
||||
|
||||
bool VulkanInstance::Initialize(Window* any_target_window) {
|
||||
bool VulkanInstance::Initialize() {
|
||||
auto version = Version::Parse(VK_API_VERSION);
|
||||
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.
|
||||
if (!QueryDevices(any_target_window)) {
|
||||
if (!QueryDevices()) {
|
||||
XELOGE("Failed to query devices");
|
||||
return false;
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ void VulkanInstance::DisableDebugValidation() {
|
|||
dbg_report_callback_ = nullptr;
|
||||
}
|
||||
|
||||
bool VulkanInstance::QueryDevices(Window* any_target_window) {
|
||||
bool VulkanInstance::QueryDevices() {
|
||||
// Get handles to all devices.
|
||||
uint32_t count = 0;
|
||||
std::vector<VkPhysicalDevice> device_handles;
|
||||
|
@ -376,56 +376,6 @@ bool VulkanInstance::QueryDevices(Window* any_target_window) {
|
|||
vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
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.
|
||||
std::vector<VkLayerProperties> layer_properties;
|
||||
err = vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr);
|
||||
|
@ -552,8 +502,6 @@ void VulkanInstance::DumpDeviceInfo(const DeviceInfo& device_info) {
|
|||
: "");
|
||||
XELOGVK(" queueCount = %u", queue_props.queueCount);
|
||||
XELOGVK(" timestampValidBits = %u", queue_props.timestampValidBits);
|
||||
XELOGVK(" supportsPresent = %s",
|
||||
device_info.queue_family_supports_present[j] ? "true" : "false");
|
||||
}
|
||||
|
||||
XELOGVK(" Layers:");
|
||||
|
|
|
@ -50,8 +50,7 @@ class VulkanInstance {
|
|||
// preparing the instance for general use.
|
||||
// If initialization succeeds it's likely that no more failures beyond runtime
|
||||
// issues will occur.
|
||||
// TODO(benvanik): remove need for any_target_window - it's just for queries.
|
||||
bool Initialize(Window* any_target_window);
|
||||
bool Initialize();
|
||||
|
||||
// Returns a list of all available devices as detected during initialization.
|
||||
const std::vector<DeviceInfo>& available_devices() const {
|
||||
|
@ -79,7 +78,7 @@ class VulkanInstance {
|
|||
void DisableDebugValidation();
|
||||
|
||||
// Queries all available physical devices.
|
||||
bool QueryDevices(Window* any_target_window);
|
||||
bool QueryDevices();
|
||||
|
||||
void DumpLayers(const std::vector<LayerInfo>& layers, const char* indent);
|
||||
void DumpExtensions(const std::vector<VkExtensionProperties>& extensions,
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace xe {
|
|||
namespace ui {
|
||||
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));
|
||||
if (!provider->Initialize()) {
|
||||
xe::FatalError(
|
||||
|
@ -35,7 +35,7 @@ std::unique_ptr<GraphicsProvider> VulkanProvider::Create(Window* main_window) {
|
|||
"list of supported GPUs.");
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GraphicsProvider>(provider.release());
|
||||
return provider;
|
||||
}
|
||||
|
||||
VulkanProvider::VulkanProvider(Window* main_window)
|
||||
|
@ -56,7 +56,7 @@ bool VulkanProvider::Initialize() {
|
|||
Version::Make(0, 0, 0), false);
|
||||
|
||||
// Attempt initialization and device query.
|
||||
if (!instance_->Initialize(main_window_)) {
|
||||
if (!instance_->Initialize()) {
|
||||
XELOGE("Failed to initialize vulkan instance");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class VulkanProvider : public GraphicsProvider {
|
|||
public:
|
||||
~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(); }
|
||||
VulkanDevice* device() const { return device_.get(); }
|
||||
|
|
|
@ -36,14 +36,40 @@ VulkanSwapChain::~VulkanSwapChain() { Shutdown(); }
|
|||
|
||||
VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
surface_ = surface;
|
||||
VkResult status;
|
||||
|
||||
// Find a queue family that supports presentation.
|
||||
VkBool32 surface_supported = false;
|
||||
auto status = vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
*device_, device_->queue_family_index(), surface, &surface_supported);
|
||||
assert_true(surface_supported);
|
||||
CheckResult(status, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
uint32_t queue_family_index = -1;
|
||||
for (uint32_t i = 0;
|
||||
i < device_->device_info().queue_family_properties.size(); i++) {
|
||||
const VkQueueFamilyProperties& family_props =
|
||||
device_->device_info().queue_family_properties[i];
|
||||
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.
|
||||
|
@ -190,7 +216,7 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
|||
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
cmd_pool_info.pNext = nullptr;
|
||||
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_);
|
||||
CheckResult(status, "vkCreateCommandPool");
|
||||
if (status != VK_SUCCESS) {
|
||||
|
@ -432,6 +458,11 @@ void VulkanSwapChain::Shutdown() {
|
|||
vkDestroyCommandPool(*device_, 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.
|
||||
if (handle) {
|
||||
vkDestroySwapchainKHR(*device_, handle, nullptr);
|
||||
|
@ -471,11 +502,7 @@ VkResult VulkanSwapChain::Begin() {
|
|||
wait_submit_info.pCommandBuffers = nullptr;
|
||||
wait_submit_info.signalSemaphoreCount = 1;
|
||||
wait_submit_info.pSignalSemaphores = &image_usage_semaphore_;
|
||||
{
|
||||
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||
status =
|
||||
vkQueueSubmit(device_->primary_queue(), 1, &wait_submit_info, nullptr);
|
||||
}
|
||||
status = vkQueueSubmit(presentation_queue_, 1, &wait_submit_info, nullptr);
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
@ -687,12 +714,7 @@ VkResult VulkanSwapChain::End() {
|
|||
render_submit_info.pCommandBuffers = &cmd_buffer_;
|
||||
render_submit_info.signalSemaphoreCount = uint32_t(semaphores.size()) - 1;
|
||||
render_submit_info.pSignalSemaphores = semaphores.data();
|
||||
{
|
||||
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||
status = vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
status = vkQueueSubmit(presentation_queue_, 1, &render_submit_info, nullptr);
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
@ -709,10 +731,7 @@ VkResult VulkanSwapChain::End() {
|
|||
present_info.pSwapchains = swap_chains;
|
||||
present_info.pImageIndices = swap_chain_image_indices;
|
||||
present_info.pResults = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> queue_lock(device_->primary_queue_mutex());
|
||||
status = vkQueuePresentKHR(device_->primary_queue(), &present_info);
|
||||
}
|
||||
status = vkQueuePresentKHR(presentation_queue_, &present_info);
|
||||
switch (status) {
|
||||
case VK_SUCCESS:
|
||||
break;
|
||||
|
|
|
@ -78,6 +78,8 @@ class VulkanSwapChain {
|
|||
VulkanInstance* instance_ = nullptr;
|
||||
VulkanDevice* device_ = nullptr;
|
||||
|
||||
VkQueue presentation_queue_ = nullptr;
|
||||
uint32_t presentation_queue_family_ = -1;
|
||||
VkSurfaceKHR surface_ = nullptr;
|
||||
uint32_t surface_width_ = 0;
|
||||
uint32_t surface_height_ = 0;
|
||||
|
|
|
@ -95,7 +95,6 @@ struct DeviceInfo {
|
|||
VkPhysicalDeviceFeatures features;
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
std::vector<VkQueueFamilyProperties> queue_family_properties;
|
||||
std::vector<VkBool32> queue_family_supports_present;
|
||||
std::vector<LayerInfo> layers;
|
||||
std::vector<VkExtensionProperties> extensions;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue