diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 31cb1573d3..9a36f3eaea 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -318,26 +318,18 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem return false; } -bool VulkanContext::InitObjects() { - if (!InitQueue()) { - return false; +void VulkanContext::DestroySwapchain() { + if (swapchain_ != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device_, swapchain_, nullptr); + swapchain_ = VK_NULL_HANDLE; } - - if (!InitSwapchain()) { - // Destroy queue? - return false; - } - return true; } -void VulkanContext::DestroyObjects() { - ILOG("VulkanContext::DestroyObjects (including swapchain)"); - if (swapchain_ != VK_NULL_HANDLE) - vkDestroySwapchainKHR(device_, swapchain_, nullptr); - swapchain_ = VK_NULL_HANDLE; - - vkDestroySurfaceKHR(instance_, surface_, nullptr); - surface_ = VK_NULL_HANDLE; +void VulkanContext::DestroySurface() { + if (surface_ != VK_NULL_HANDLE) { + vkDestroySurfaceKHR(instance_, surface_, nullptr); + surface_ = VK_NULL_HANDLE; + } } VkResult VulkanContext::GetInstanceLayerExtensionList(const char *layerName, std::vector &extensions) { @@ -716,7 +708,10 @@ VkResult VulkanContext::ReinitSurface() { surface_ = VK_NULL_HANDLE; } - ILOG("Creating Vulkan surface for window"); + ILOG("Creating Vulkan surface for window (%p %p)", winsysData1_, winsysData2_); + + VkResult retval = VK_SUCCESS; + switch (winsys_) { #ifdef _WIN32 case WINDOWSYSTEM_WIN32: @@ -725,7 +720,8 @@ VkResult VulkanContext::ReinitSurface() { win32.flags = 0; win32.hwnd = (HWND)winsysData2_; win32.hinstance = (HINSTANCE)winsysData1_; - return vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); + retval = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); + break; } #endif #if defined(__ANDROID__) @@ -735,7 +731,8 @@ VkResult VulkanContext::ReinitSurface() { VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; android.flags = 0; android.window = wnd; - return vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); + retval = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_METAL_EXT) @@ -745,7 +742,8 @@ VkResult VulkanContext::ReinitSurface() { metal.flags = 0; metal.pLayer = winsysData1_; metal.pNext = winsysData2_; - return vkCreateMetalSurfaceEXT(instance_, &metal, nullptr, &surface_); + retval = vkCreateMetalSurfaceEXT(instance_, &metal, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) @@ -755,7 +753,8 @@ VkResult VulkanContext::ReinitSurface() { xlib.flags = 0; xlib.dpy = (Display *)winsysData1_; xlib.window = (Window)winsysData2_; - return vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); + retval = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_XCB_KHR) @@ -765,7 +764,8 @@ VkResult VulkanContext::ReinitSurface() { xcb.flags = 0; xcb.connection = (Connection *)winsysData1_; xcb.window = (Window)(uintptr_t)winsysData2_; - return vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); + retval = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); + break; } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) @@ -775,7 +775,8 @@ VkResult VulkanContext::ReinitSurface() { wayland.flags = 0; wayland.display = (wl_display *)winsysData1_; wayland.surface = (wl_surface *)winsysData2_; - return vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); + retval = vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); + break; } #endif @@ -783,9 +784,19 @@ VkResult VulkanContext::ReinitSurface() { _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); return VK_ERROR_INITIALIZATION_FAILED; } + + if (retval != VK_SUCCESS) { + return retval; + } + + if (!ChooseQueue()) { + return VK_ERROR_INITIALIZATION_FAILED; + } + + return VK_SUCCESS; } -bool VulkanContext::InitQueue() { +bool VulkanContext::ChooseQueue() { // 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++) { @@ -869,7 +880,6 @@ bool VulkanContext::InitQueue() { } vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_); - ILOG("gfx_queue_: %p", gfx_queue_); return true; } @@ -906,21 +916,27 @@ bool VulkanContext::InitSwapchain() { res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, presentModes); assert(res == VK_SUCCESS); - ILOG("surfCapabilities_.currentExtent: %dx%d", surfCapabilities_.currentExtent.width, surfCapabilities_.currentExtent.height); - ILOG("surfCapabilities_.minImageExtent: %dx%d", surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height); - ILOG("surfCapabilities_.maxImageExtent: %dx%d", surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height); swapChainExtent_.width = clamp(surfCapabilities_.currentExtent.width, surfCapabilities_.minImageExtent.width, surfCapabilities_.maxImageExtent.width); swapChainExtent_.height = clamp(surfCapabilities_.currentExtent.height, surfCapabilities_.minImageExtent.height, surfCapabilities_.maxImageExtent.height); - ILOG("swapChainExtent: %dx%d", swapChainExtent_.width, swapChainExtent_.height); + ILOG("surfCapabilities_.current: %dx%d min: %dx%d max: %dx%d computed: %dx%d", + surfCapabilities_.currentExtent.width, surfCapabilities_.currentExtent.height, + surfCapabilities_.minImageExtent.width, surfCapabilities_.minImageExtent.height, + surfCapabilities_.maxImageExtent.width, surfCapabilities_.maxImageExtent.height, + swapChainExtent_.width, swapChainExtent_.height); // TODO: Find a better way to specify the prioritized present mode while being able // to fall back in a sensible way. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; + std::string modes = ""; for (size_t i = 0; i < presentModeCount; i++) { - ILOG("Supported present mode: %d (%s)", presentModes[i], PresentModeString(presentModes[i])); + modes += PresentModeString(presentModes[i]); + if (i != presentModeCount - 1) { + modes += ", "; + } } + ILOG("Supported present modes: %s", modes.c_str()); for (size_t i = 0; i < presentModeCount; i++) { bool match = false; match = match || ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR); @@ -940,13 +956,11 @@ bool VulkanContext::InitSwapchain() { // HACK swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; #endif - ILOG("Chosen present mode: %d (%s)", swapchainPresentMode, PresentModeString(swapchainPresentMode)); delete[] presentModes; // Determine the number of VkImage's to use in the swap chain (we desire to // own only 1 image at a time, besides the images being displayed and // queued for display): uint32_t desiredNumberOfSwapChainImages = surfCapabilities_.minImageCount + 1; - ILOG("numSwapChainImages: %d", desiredNumberOfSwapChainImages); if ((surfCapabilities_.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities_.maxImageCount)) { @@ -954,14 +968,16 @@ bool VulkanContext::InitSwapchain() { desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount; } + ILOG("Chosen present mode: %d (%s). numSwapChainImages: %d/%d", + swapchainPresentMode, PresentModeString(swapchainPresentMode), + desiredNumberOfSwapChainImages, surfCapabilities_.maxImageCount); + // We mostly follow the practices from // https://arm-software.github.io/vulkan_best_practice_for_mobile_developers/samples/surface_rotation/surface_rotation_tutorial.html // VkSurfaceTransformFlagBitsKHR preTransform; std::string supportedTransforms = surface_transforms_to_string(surfCapabilities_.supportedTransforms); std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform); - ILOG("Supported transforms: %s", supportedTransforms.c_str()); - ILOG("Current transform: %s", currentTransform.c_str()); g_display_rotation = DisplayRotation::ROTATE_0; g_display_rot_matrix.setIdentity(); bool swapChainExtentSwap = false; @@ -993,8 +1009,10 @@ bool VulkanContext::InitSwapchain() { // Let the OS rotate the image (potentially slow on many Android devices) preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } + std::string preTransformStr = surface_transforms_to_string(preTransform); - ILOG("Chosen pretransform transform: %s", preTransformStr.c_str()); + + ILOG("Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str()); if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) { ILOG("Applying PowerVR hack (rounding off the width!)"); @@ -1017,6 +1035,7 @@ bool VulkanContext::InitSwapchain() { swap_chain_info.oldSwapchain = VK_NULL_HANDLE; swap_chain_info.clipped = true; swap_chain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + // Don't ask for TRANSFER_DST for the swapchain image, we don't use that. // if (surfCapabilities_.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) // swap_chain_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 3a8e519381..db61f2e5b1 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -147,12 +147,11 @@ public: VkResult InitSurface(WindowSystem winsys, void *data1, void *data2); VkResult ReinitSurface(); - bool InitQueue(); - bool InitObjects(); bool InitSwapchain(); - // Also destroys the surface. - void DestroyObjects(); + void DestroySwapchain(); + void DestroySurface(); + void DestroyDevice(); void PerformPendingDeletes(); @@ -273,6 +272,8 @@ public: void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation); private: + bool ChooseQueue(); + VkResult InitDebugUtilsCallback(); // A layer can expose extensions, keep track of those extensions here. diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index a5928d45ba..ece0b81c96 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -114,11 +114,11 @@ static void InitSDLAudioDevice(const std::string &name = "") { } } if (audioDev <= 0) { - ILOG("SDL: Trying a different device"); + ILOG("SDL: Trying a different audio device"); audioDev = SDL_OpenAudioDevice(nullptr, 0, &fmt, &g_retFmt, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); } if (audioDev <= 0) { - ELOG("Failed to open audio: %s", SDL_GetError()); + ELOG("Failed to open audio device: %s", SDL_GetError()); } else { if (g_retFmt.samples != fmt.samples) // Notify, but still use it ELOG("Output audio samples: %d (requested: %d)", g_retFmt.samples, fmt.samples); diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp index 45898f3826..26a311394f 100644 --- a/SDL/SDLVulkanGraphicsContext.cpp +++ b/SDL/SDLVulkanGraphicsContext.cpp @@ -20,6 +20,15 @@ static const bool g_Validate = true; static const bool g_Validate = false; #endif +static uint32_t FlagsFromConfig() { + uint32_t flags = 0; + flags = g_Config.bVSync ? VULKAN_FLAG_PRESENT_FIFO : VULKAN_FLAG_PRESENT_MAILBOX; + if (g_Validate) { + flags |= VULKAN_FLAG_VALIDATE; + } + return flags; +} + bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode); if (!window) { @@ -41,10 +50,7 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, } vulkan_ = new VulkanContext(); - int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX; - if (g_Validate) { - vulkanFlags |= VULKAN_FLAG_VALIDATE; - } + int vulkanFlags = FlagsFromConfig(); VulkanContext::CreateInfo info{}; info.app_name = "PPSSPP"; @@ -102,7 +108,7 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, break; } - if (!vulkan_->InitObjects()) { + if (!vulkan_->InitSwapchain()) { *error_message = vulkan_->InitError(); Shutdown(); return false; @@ -126,7 +132,8 @@ void SDLVulkanGraphicsContext::Shutdown() { delete draw_; draw_ = nullptr; vulkan_->WaitUntilQueueIdle(); - vulkan_->DestroyObjects(); + vulkan_->DestroySwapchain(); + vulkan_->DestroySurface(); vulkan_->DestroyDevice(); vulkan_->DestroyInstance(); delete vulkan_; @@ -136,9 +143,11 @@ void SDLVulkanGraphicsContext::Shutdown() { void SDLVulkanGraphicsContext::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - vulkan_->DestroyObjects(); + vulkan_->DestroySwapchain(); + vulkan_->DestroySurface(); + vulkan_->UpdateFlags(FlagsFromConfig()); vulkan_->ReinitSurface(); - vulkan_->InitObjects(); + vulkan_->InitSwapchain(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 6c95bf7e91..1b353d8797 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -350,13 +350,14 @@ void GameSettingsScreen::CreateViews() { } #endif -#ifdef _WIN32 +#if !PPSSPP_PLATFORM(ANDROID) CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); vSync->OnClick.Add([=](EventParams &e) { NativeResized(); return UI::EVENT_CONTINUE; }); #endif + CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); frameDuplication->SetEnabledFunc([] { return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE || (g_Config.bSoftwareRendering && g_Config.iFrameSkip != 0); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 8f7249dbc5..33281640d4 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -173,12 +173,10 @@ void WindowsVulkanContext::Shutdown() { void WindowsVulkanContext::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - g_Vulkan->DestroyObjects(); - + g_Vulkan->DestroySwapchain(); g_Vulkan->UpdateFlags(FlagsFromConfig()); - g_Vulkan->ReinitSurface(); - - g_Vulkan->InitObjects(); + g_Vulkan_->ReinitSurface(); + g_Vulkan_->InitSwapchain(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); } diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 39fe573057..c5c2f0a02a 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -116,7 +116,8 @@ bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredB ILOG("AndroidVulkanContext::Init completed, %s", success ? "successfully" : "but failed"); if (!success) { - g_Vulkan->DestroyObjects(); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); g_Vulkan->DestroyDevice(); g_Vulkan->DestroyInstance(); } @@ -130,7 +131,8 @@ void AndroidVulkanContext::ShutdownFromRenderThread() { draw_ = nullptr; g_Vulkan->WaitUntilQueueIdle(); g_Vulkan->PerformPendingDeletes(); - g_Vulkan->DestroyObjects(); // Also destroys the surface, a bit asymmetric + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); ILOG("Done with ShutdownFromRenderThread"); } @@ -150,11 +152,12 @@ void AndroidVulkanContext::Resize() { ILOG("AndroidVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - g_Vulkan->DestroyObjects(); + g_Vulkan->DestroySwapchain(); + g_Vulkan->DestroySurface(); g_Vulkan->UpdateFlags(FlagsFromConfig()); g_Vulkan->ReinitSurface(); - g_Vulkan->InitObjects(); + g_Vulkan->InitSwapchain(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); ILOG("AndroidVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); }