fix(agc): ask the swapchain for one image beyond the surface minimum

On Wayland with the NVIDIA driver the surface reports minImageCount 2.
The presenter acquires with a zero timeout, so once both images were
queued no image was ever free again: PPSA29340 flipped at 60 per second
but presented 0 frames per 10 s (599 dropped: no free swapchain image)
and its window stayed black. Ask for minImageCount + 1, capped by
maxImageCount when the surface has one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
This commit is contained in:
hypermistandClaude Opus 5.5 committed 2026-10-23 01:52:59 +13:00
1 parent 8b3a6ba88d
commit df70917ccc
3 files changed
+32 -2

No files matched your search

@@ -0,0 +1,17 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_SWAPCHAINIMAGES_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_SWAPCHAINIMAGES_HPP
#include <vulkan/vulkan.h>
#include <algorithm>
#include <cstdint>
namespace AgcDriver {
inline std::uint32_t SwapchainImageCount(const VkSurfaceCapabilitiesKHR& surface) {
const std::uint32_t count = surface.minImageCount + 1;
return surface.maxImageCount != 0 ? std::min(count, surface.maxImageCount) : count;
}
}
#endif
@@ -22,6 +22,7 @@
#include "prx/libSceAgcDriver/Execution/include/SubgroupClock.hpp"
#include "prx/libSceAgcDriver/Execution/include/ShaderDeviceProfile.hpp"
#include "prx/libSceAgcDriver/Execution/include/PresentMode.hpp"
#include "prx/libSceAgcDriver/Execution/include/SwapchainImages.hpp"
#include "prx/libSceAgcDriver/Execution/include/PerformanceOverlay.hpp"
#include "prx/libSceAgcDriver/Execution/include/PresentationPass.hpp"
#include "prx/libSceAgcDriver/Execution/include/PresentationScaler.hpp"
@@ -2069,7 +2070,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
require((surface.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0, "surface does not support color attachment images");
VkSwapchainCreateInfoKHR swapchain{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
swapchain.surface = state->surface;
swapchain.minImageCount = surface.minImageCount;
swapchain.minImageCount = AgcDriver::SwapchainImageCount(surface);
swapchain.imageFormat = state->surfaceFormat;
swapchain.imageColorSpace = state->surfaceColorSpace;
swapchain.imageExtent = state->extent;
@@ -2883,7 +2884,7 @@ void VulkanDevice::recreateSwapchain(std::uint32_t width, std::uint32_t height,
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};
create.surface = state->surface;
create.minImageCount = surface.minImageCount;
create.minImageCount = AgcDriver::SwapchainImageCount(surface);
create.imageFormat = state->surfaceFormat;
create.imageColorSpace = state->surfaceColorSpace;
create.imageExtent = {width, height};
@@ -1,5 +1,6 @@
#include "prx/libSceAgcDriver/Execution/include/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/PresentMode.hpp"
#include "prx/libSceAgcDriver/Execution/include/SwapchainImages.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "prx/libSceAgcDriver/Execution/include/VideoOutput.hpp"
#include "prx/libSceAgcDriver/Submit/include/Dcb.hpp"
@@ -402,6 +403,17 @@ void testReset(bool compute) {
void testPresentMode() {
using AgcDriver::SelectPresentMode;
VkSurfaceCapabilitiesKHR surface{};
surface.minImageCount = 2;
surface.maxImageCount = 8;
check(AgcDriver::SwapchainImageCount(surface) == 3, "the swapchain has no image beyond the surface minimum");
surface.minImageCount = 3;
check(AgcDriver::SwapchainImageCount(surface) == 4, "the swapchain does not follow a larger surface minimum");
surface.maxImageCount = 3;
check(AgcDriver::SwapchainImageCount(surface) == 3, "the swapchain exceeds the surface maximum");
surface.minImageCount = 2;
surface.maxImageCount = 0;
check(AgcDriver::SwapchainImageCount(surface) == 3, "an unlimited surface maximum capped the swapchain");
const std::array wayland{VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR};
const std::array all{VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR};
check(SelectPresentMode(nullptr, wayland) == VK_PRESENT_MODE_FIFO_KHR, "the default present mode is not FIFO");