From b1554ef0615ddb7a1e4803ab59374f27c5b1a62e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 Nov 2017 21:50:54 -0800 Subject: [PATCH 1/2] Vulkan: Cut down on asserts during init. In case something is horribly wrong, or our desired settings aren't compatible, let's try to stumble our way out. More things can fail, but the goal is to detect failure or at least be able to render UI settings to swap out of Vulkan. --- Common/Vulkan/VulkanContext.cpp | 17 ++++++-- Common/Vulkan/VulkanContext.h | 2 +- Windows/GPU/WindowsVulkanContext.cpp | 7 ++++ android/jni/app-android.cpp | 31 +++++++++++---- ext/native/thin3d/VulkanRenderManager.cpp | 48 +++++++++++++++++------ ext/native/thin3d/VulkanRenderManager.h | 8 +++- 6 files changed, 88 insertions(+), 25 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index a0f17daaf2..e75719e53a 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -220,7 +220,9 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem } bool VulkanContext::InitObjects() { - InitQueue(); + if (!InitQueue()) { + return false; + } if (!InitSwapchain()) { return false; @@ -616,7 +618,7 @@ void VulkanContext::ReinitSurfaceAndroid(int width, int height) { } #endif -void VulkanContext::InitQueue() { +bool VulkanContext::InitQueue() { // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = new VkBool32[queue_count]; for (uint32_t i = 0; i < queue_count; i++) { @@ -654,8 +656,8 @@ void VulkanContext::InitQueue() { // Generate error if could not find both a graphics and a present queue if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { - std::cout << "Could not find a graphics and a present queue"; - exit(-1); + ELOG("Could not find a graphics and a present queue"); + return false; } graphics_queue_family_index_ = graphicsQueueNodeIndex; @@ -664,9 +666,15 @@ void VulkanContext::InitQueue() { uint32_t formatCount; VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, nullptr); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) + return false; VkSurfaceFormatKHR *surfFormats = new VkSurfaceFormatKHR[formatCount]; res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, surfFormats); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) { + delete[] surfFormats; + return false; + } // If the format list includes just one entry of VK_FORMAT_UNDEFINED, // the surface has no preferred format. Otherwise, at least one // supported format will be returned. @@ -695,6 +703,7 @@ void VulkanContext::InitQueue() { vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_); ILOG("gfx_queue_: %p", gfx_queue_); + return true; } bool VulkanContext::InitSwapchain() { diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 6dbef6e33b..476edfcf10 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -141,7 +141,7 @@ public: void InitSurfaceAndroid(ANativeWindow *native_window, int width, int height); void ReinitSurfaceAndroid(int width, int height); #endif - void InitQueue(); + bool InitQueue(); bool InitObjects(); bool InitSwapchain(); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 01a353cec8..c120e5cd1d 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -56,6 +56,7 @@ #include "base/stringutil.h" #include "thin3d/thin3d.h" +#include "thin3d/VulkanRenderManager.h" #include "util/text/parsers.h" #include "Windows/GPU/WindowsVulkanContext.h" @@ -204,6 +205,12 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m bool success = draw_->CreatePresets(); assert(success); // Doesn't fail, we include the compiler. draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + if (!renderManager->HasBackbuffers()) { + Shutdown(); + return false; + } return true; } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index d1260fce3c..76a499bf51 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -38,6 +38,7 @@ #include "gfx_es2/gpu_features.h" #include "thin3d/thin3d.h" +#include "thin3d/VulkanRenderManager.h" #include "Core/Config.h" #include "Core/Loaders.h" #include "Core/System.h" @@ -326,13 +327,29 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); } - g_Vulkan->InitObjects(); - draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); - bool success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. - assert(success); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - ILOG("AndroidVulkanContext::Init completed"); - return true; + + bool success = true; + if (g_Vulkan->InitObjects()) { + draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); + success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. + assert(success); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + success = renderManager->HasBackbuffers(); + } else { + success = false; + } + + ILOG("AndroidVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); + if (!success) { + g_Vulkan->DestroyObjects(); + g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugMsgCallback(); + + g_Vulkan->DestroyInstance(); + } + return success; } void AndroidVulkanContext::Shutdown() { diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index c29b3294e8..4f265e8f81 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -133,9 +133,13 @@ void VulkanRenderManager::CreateBackbuffers() { VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr); assert(res == VK_SUCCESS); - VkImage* swapchainImages = new VkImage[swapchainImageCount_]; + VkImage *swapchainImages = new VkImage[swapchainImageCount_]; res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) { + delete[] swapchainImages; + return; + } VkCommandBuffer cmdInit = GetInitCmd(); @@ -172,15 +176,19 @@ void VulkanRenderManager::CreateBackbuffers() { } delete[] swapchainImages; - InitDepthStencilBuffer(cmdInit); // Must be before InitBackbufferRenderPass. - InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + // Must be before InitBackbufferRenderPass. + if (InitDepthStencilBuffer(cmdInit)) { + InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + } curWidth_ = -1; curHeight_ = -1; - VLOG("Backbuffers Created"); + if (HasBackbuffers()) { + VLOG("Backbuffers Created"); + } // Start the thread. - if (useThread) { + if (useThread && HasBackbuffers()) { run_ = true; // Won't necessarily be 0. threadInitFrame_ = vulkan_->GetCurFrame(); @@ -453,8 +461,8 @@ void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int queueRunner_.CopyReadbackBuffer(w, h, destFormat, destFormat, pixelStride, pixels); } -void VulkanRenderManager::InitBackbufferFramebuffers(int width, int height) { - VkResult U_ASSERT_ONLY res; +bool VulkanRenderManager::InitBackbufferFramebuffers(int width, int height) { + VkResult res; // We share the same depth buffer but have multiple color buffers, see the loop below. VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view }; @@ -473,12 +481,18 @@ void VulkanRenderManager::InitBackbufferFramebuffers(int width, int height) { attachments[0] = swapchainImages_[i].view; res = vkCreateFramebuffer(vulkan_->GetDevice(), &fb_info, nullptr, &framebuffers_[i]); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) { + framebuffers_.clear(); + return false; + } } + + return true; } -void VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { - VkResult U_ASSERT_ONLY res; - bool U_ASSERT_ONLY pass; +bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { + VkResult res; + bool pass; const VkFormat depth_format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat; int aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; @@ -506,8 +520,10 @@ void VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { depth_.format = depth_format; VkDevice device = vulkan_->GetDevice(); - res = vkCreateImage(device, &image_info, NULL, &depth_.image); + res = vkCreateImage(device, &image_info, nullptr, &depth_.image); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) + return false; vkGetImageMemoryRequirements(device, depth_.image, &mem_reqs); @@ -517,12 +533,18 @@ void VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { 0, /* No requirements */ &mem_alloc.memoryTypeIndex); assert(pass); + if (!pass) + return false; res = vkAllocateMemory(device, &mem_alloc, NULL, &depth_.mem); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) + return false; res = vkBindImageMemory(device, depth_.image, depth_.mem, 0); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) + return false; TransitionImageLayout2(cmd, depth_.image, aspectMask, @@ -547,6 +569,10 @@ void VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { res = vkCreateImageView(device, &depth_view_info, NULL, &depth_.view); assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) + return false; + + return true; } void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) { diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 818a44f41b..0f9995771c 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -204,9 +204,13 @@ public: void CreateBackbuffers(); void DestroyBackbuffers(); + bool HasBackbuffers() { + return !framebuffers_.empty(); + } + private: - void InitBackbufferFramebuffers(int width, int height); - void InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. + bool InitBackbufferFramebuffers(int width, int height); + bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. void BeginSubmitFrame(int frame); void EndSubmitFrame(int frame); void Submit(int frame, bool triggerFence); From d2d5b8ee4e1ed52c01d0401c5265d476dfa0c5ee Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 Nov 2017 21:57:01 -0800 Subject: [PATCH 2/2] Vulkan: Remove experimental warning. --- UI/GameSettingsScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 7579c65aaa..68cb2d71bf 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -177,7 +177,7 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab(ms->T("Graphics"), graphicsSettingsScroll); graphicsSettings->Add(new ItemHeader(gr->T("Rendering Mode"))); - static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan (experimental)" }; + static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" }; PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, GPU_BACKEND_OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager())); renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend); #if !PPSSPP_PLATFORM(WINDOWS)