fix(video): recreate swapchain after window minimization
This commit is contained in:
parent
46c799da67
commit
a7fb4cbf72
|
|
@ -54,6 +54,7 @@ add_library(libSceAgcDriver SHARED EXCLUDE_FROM_ALL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/BdaFeatures.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Pm4.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/VulkanDevice.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/SwapchainState.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/AspectFit.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/PresentationScaler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/Draw.cpp
|
||||
|
|
@ -281,6 +282,7 @@ if(AGC_BUILD_VISUAL_TEST)
|
|||
add_executable(agc_driver_visual_test EXCLUDE_FROM_ALL
|
||||
tests/Visual.cpp
|
||||
Execution/src/VulkanDevice.cpp
|
||||
Execution/src/SwapchainState.cpp
|
||||
Execution/src/AspectFit.cpp
|
||||
Execution/src/PresentationScaler.cpp
|
||||
Execution/src/GuestMemory.cpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_SWAPCHAINSTATE_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_SWAPCHAINSTATE_HPP
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace AgcDriver {
|
||||
|
||||
class SwapchainState {
|
||||
public:
|
||||
bool NeedsRecreation() const;
|
||||
void Recreated();
|
||||
bool ProcessResult(VkResult result, const char* operation);
|
||||
|
||||
private:
|
||||
bool outdated = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/SwapchainState.hpp"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace AgcDriver {
|
||||
|
||||
bool SwapchainState::NeedsRecreation() const {
|
||||
return outdated;
|
||||
}
|
||||
|
||||
void SwapchainState::Recreated() {
|
||||
outdated = false;
|
||||
}
|
||||
|
||||
bool SwapchainState::ProcessResult(VkResult result, const char* operation) {
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
outdated = true;
|
||||
return false;
|
||||
}
|
||||
if (result == VK_SUBOPTIMAL_KHR) {
|
||||
outdated = true;
|
||||
return true;
|
||||
}
|
||||
if (result != VK_SUCCESS) throw std::runtime_error(std::string(operation) + ": Vulkan result " + std::to_string(result));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/PerformanceTimer.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/BdaFeatures.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/PresentationScaler.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/SwapchainState.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/GpuColorTransfer.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/BufferPool.hpp"
|
||||
|
|
@ -52,6 +53,7 @@ struct VulkanDevice::State {
|
|||
void* window = nullptr;
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||
SwapchainState swapchainState;
|
||||
VkExtent2D extent{};
|
||||
std::vector<VkImage> images;
|
||||
VkFence acquireFence = VK_NULL_HANDLE;
|
||||
|
|
@ -520,11 +522,18 @@ void VulkanDevice::Resize(std::uint32_t width, std::uint32_t height) {
|
|||
state->extent = {0, 0};
|
||||
return;
|
||||
}
|
||||
if (state->extent.width == width && state->extent.height == height) return;
|
||||
WaitIdle();
|
||||
VkSurfaceCapabilitiesKHR surface{};
|
||||
check(state->InstanceFunction<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>("vkGetPhysicalDeviceSurfaceCapabilitiesKHR")(state->physical, state->surface, &surface), "vkGetPhysicalDeviceSurfaceCapabilitiesKHR resize");
|
||||
require(surface.currentExtent.width == std::numeric_limits<std::uint32_t>::max() || (surface.currentExtent.width == width && surface.currentExtent.height == height), "resized surface extent differs from output");
|
||||
if (surface.currentExtent.width != std::numeric_limits<std::uint32_t>::max()) {
|
||||
width = surface.currentExtent.width;
|
||||
height = surface.currentExtent.height;
|
||||
}
|
||||
if (width == 0 || height == 0) {
|
||||
state->extent = {0, 0};
|
||||
return;
|
||||
}
|
||||
if (!state->swapchainState.NeedsRecreation() && state->extent.width == width && state->extent.height == height) return;
|
||||
WaitIdle();
|
||||
require(width >= surface.minImageExtent.width && width <= surface.maxImageExtent.width && height >= surface.minImageExtent.height && height <= surface.maxImageExtent.height, "unsupported resized output extent");
|
||||
require((surface.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) != 0 && (surface.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) != 0 && (surface.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0, "resized surface capabilities are unsupported");
|
||||
VkSwapchainCreateInfoKHR create{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
|
||||
|
|
@ -553,6 +562,7 @@ void VulkanDevice::Resize(std::uint32_t width, std::uint32_t height) {
|
|||
check(getImages(state->device, replacement, &count, state->images.data()), "vkGetSwapchainImagesKHR resize");
|
||||
state->images.resize(count);
|
||||
state->rendered.assign(count, VK_NULL_HANDLE);
|
||||
state->swapchainState.Recreated();
|
||||
}
|
||||
|
||||
bool VulkanDevice::Presentable() const {
|
||||
|
|
@ -599,7 +609,7 @@ void VulkanDevice::present(std::uint32_t width, std::uint32_t height, bool opaqu
|
|||
check(reset(state->device, static_cast<std::uint32_t>(fences.size()), fences.data()), "vkResetFences");
|
||||
std::uint32_t index = 0;
|
||||
timing.Mark("fence_reset");
|
||||
check(state->DeviceFunction<PFN_vkAcquireNextImageKHR>("vkAcquireNextImageKHR")(state->device, state->swapchain, 5'000'000'000ULL, VK_NULL_HANDLE, state->acquireFence, &index), "vkAcquireNextImageKHR");
|
||||
if (!state->swapchainState.ProcessResult(state->DeviceFunction<PFN_vkAcquireNextImageKHR>("vkAcquireNextImageKHR")(state->device, state->swapchain, 5'000'000'000ULL, VK_NULL_HANDLE, state->acquireFence, &index), "vkAcquireNextImageKHR")) return;
|
||||
timing.Mark("acquire_image");
|
||||
check(wait(state->device, 1, &state->acquireFence, VK_TRUE, std::numeric_limits<std::uint64_t>::max()), "vkWaitForFences acquire");
|
||||
timing.Mark("acquire_fence_wait");
|
||||
|
|
@ -678,7 +688,7 @@ void VulkanDevice::present(std::uint32_t width, std::uint32_t height, bool opaqu
|
|||
present.swapchainCount = 1;
|
||||
present.pSwapchains = &state->swapchain;
|
||||
present.pImageIndices = &index;
|
||||
check(state->DeviceFunction<PFN_vkQueuePresentKHR>("vkQueuePresentKHR")(state->queue, &present), "vkQueuePresentKHR");
|
||||
state->swapchainState.ProcessResult(state->DeviceFunction<PFN_vkQueuePresentKHR>("vkQueuePresentKHR")(state->queue, &present), "vkQueuePresentKHR");
|
||||
timing.Mark("queue_present");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -349,6 +349,11 @@ void VideoOutDriver::processFlip(FlipRequest& req) {
|
|||
if (!SDL_Vulkan_CreateSurface(static_cast<SDL_Window*>(context), instance, &surface)) throw std::runtime_error(std::string("SDL_Vulkan_CreateSurface failed: ") + SDL_GetError());
|
||||
return surface;
|
||||
}, [](void* context, std::uint32_t* width, std::uint32_t* height) {
|
||||
if ((SDL_GetWindowFlags(static_cast<SDL_Window*>(context)) & SDL_WINDOW_MINIMIZED) != 0) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
return;
|
||||
}
|
||||
int drawableWidth = 0;
|
||||
int drawableHeight = 0;
|
||||
SDL_Vulkan_GetDrawableSize(static_cast<SDL_Window*>(context), &drawableWidth, &drawableHeight);
|
||||
|
|
@ -401,6 +406,12 @@ void VideoOutDriver::presentLoop(std::stop_token token) {
|
|||
PadInput padInput;
|
||||
try {
|
||||
while (!token.stop_requested()) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
require(event.type != SDL_QUIT, "window was closed");
|
||||
padInput.HandleEvent(event);
|
||||
}
|
||||
padInput.Update();
|
||||
{
|
||||
std::unique_lock lock(flipQueue->mutex);
|
||||
flipQueue->changed.wait_for(lock, std::chrono::milliseconds(10), [&] { return token.stop_requested() || flipQueue->failure || !flipQueue->requests.empty(); });
|
||||
|
|
@ -427,12 +438,6 @@ void VideoOutDriver::presentLoop(std::stop_token token) {
|
|||
current->timing->Print(current->outputHandle, current->index, current->flipArg, finished, interval);
|
||||
}
|
||||
current.reset();
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
require(event.type != SDL_QUIT, "window was closed");
|
||||
padInput.HandleEvent(event);
|
||||
}
|
||||
padInput.Update();
|
||||
}
|
||||
std::list<std::shared_ptr<FlipRequest>> cancelled;
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue