allow suboptimal rendering with fewer than required swapchain images

fixes #61
This commit is contained in:
PancakeTAS 2025-07-11 18:39:23 +02:00
parent 896a205e8e
commit d4e4ec8df6
No known key found for this signature in database
5 changed files with 50 additions and 2 deletions

View file

@ -53,6 +53,11 @@ namespace Layer {
void ovkGetPhysicalDeviceProperties( void ovkGetPhysicalDeviceProperties(
VkPhysicalDevice physicalDevice, VkPhysicalDevice physicalDevice,
VkPhysicalDeviceProperties* pProperties); VkPhysicalDeviceProperties* pProperties);
/// Call to the original vkGetPhysicalDeviceSurfaceCapabilitiesKHR function.
VkResult ovkGetPhysicalDeviceSurfaceCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
/// Call to the original vkCreateSwapchainKHR function. /// Call to the original vkCreateSwapchainKHR function.
VkResult ovkCreateSwapchainKHR( VkResult ovkCreateSwapchainKHR(

View file

@ -31,6 +31,15 @@ namespace Utils {
/// ///
uint64_t getDeviceUUID(VkPhysicalDevice physicalDevice); uint64_t getDeviceUUID(VkPhysicalDevice physicalDevice);
///
/// Get the max image count for a swapchain.
///
/// @param physicalDevice The physical device to query.
/// @param surface The surface to query the capabilities for.
/// @return The maximum image count for the swapchain.
///
uint32_t getMaxImageCount(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface);
/// ///
/// Ensure a list of extensions is present in the given array. /// Ensure a list of extensions is present in the given array.
/// ///

View file

@ -151,13 +151,21 @@ namespace {
// update swapchain create info // update swapchain create info
VkSwapchainCreateInfoKHR createInfo = *pCreateInfo; VkSwapchainCreateInfoKHR createInfo = *pCreateInfo;
createInfo.minImageCount += 1 + deviceInfo.frameGen; // 1 deferred + N framegen, FIXME: check hardware max const uint32_t maxImageCount = Utils::getMaxImageCount(deviceInfo.physicalDevice, pCreateInfo->surface);
const uint32_t imageCount = createInfo.minImageCount + 1 + static_cast<uint32_t>(deviceInfo.frameGen);
Log::debug("hooks", "Creating swapchain with max image count: {}/{}", imageCount, maxImageCount);
if (imageCount > maxImageCount) {
Log::warn("hooks", "LSFG_MULTIPLIER is set very high. This might lead to performance degradation");
createInfo.minImageCount = maxImageCount; // limit to max possible
} else {
createInfo.minImageCount = imageCount; // set to frameGen + 1
}
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; // allow copy from/to images createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; // allow copy from/to images
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; // force vsync createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; // force vsync
auto res = Layer::ovkCreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain); auto res = Layer::ovkCreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
Log::error("hooks", "Failed to create swapchain: {:x}", static_cast<uint32_t>(res)); Log::error("hooks", "Failed to create swapchain: {}", static_cast<uint32_t>(res));
return res; return res;
} }
Log::info("hooks", "Swapchain created successfully: {:x}", Log::info("hooks", "Swapchain created successfully: {:x}",
@ -235,6 +243,8 @@ namespace {
auto& swapchain = it3->second; auto& swapchain = it3->second;
// patch vsync NOLINTBEGIN // patch vsync NOLINTBEGIN
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
const VkSwapchainPresentModeInfoEXT* presentModeInfo = const VkSwapchainPresentModeInfoEXT* presentModeInfo =
reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(pPresentInfo->pNext); reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(pPresentInfo->pNext);
while (presentModeInfo) { while (presentModeInfo) {
@ -246,6 +256,7 @@ namespace {
presentModeInfo = presentModeInfo =
reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(presentModeInfo->pNext); reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(presentModeInfo->pNext);
} // NOLINTEND } // NOLINTEND
#pragma clang diagnostic pop
// present the next frame // present the next frame
Log::debug("hooks2", "Presenting swapchain: {:x} on queue: {:x}", Log::debug("hooks2", "Presenting swapchain: {:x} on queue: {:x}",

View file

@ -23,6 +23,7 @@ namespace {
PFN_vkGetPhysicalDeviceQueueFamilyProperties next_vkGetPhysicalDeviceQueueFamilyProperties{}; PFN_vkGetPhysicalDeviceQueueFamilyProperties next_vkGetPhysicalDeviceQueueFamilyProperties{};
PFN_vkGetPhysicalDeviceMemoryProperties next_vkGetPhysicalDeviceMemoryProperties{}; PFN_vkGetPhysicalDeviceMemoryProperties next_vkGetPhysicalDeviceMemoryProperties{};
PFN_vkGetPhysicalDeviceProperties next_vkGetPhysicalDeviceProperties{}; PFN_vkGetPhysicalDeviceProperties next_vkGetPhysicalDeviceProperties{};
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR next_vkGetPhysicalDeviceSurfaceCapabilitiesKHR{};
PFN_vkCreateSwapchainKHR next_vkCreateSwapchainKHR{}; PFN_vkCreateSwapchainKHR next_vkCreateSwapchainKHR{};
PFN_vkQueuePresentKHR next_vkQueuePresentKHR{}; PFN_vkQueuePresentKHR next_vkQueuePresentKHR{};
@ -122,6 +123,8 @@ namespace {
"vkGetPhysicalDeviceMemoryProperties", &next_vkGetPhysicalDeviceMemoryProperties); "vkGetPhysicalDeviceMemoryProperties", &next_vkGetPhysicalDeviceMemoryProperties);
success &= initInstanceFunc(*pInstance, success &= initInstanceFunc(*pInstance,
"vkGetPhysicalDeviceProperties", &next_vkGetPhysicalDeviceProperties); "vkGetPhysicalDeviceProperties", &next_vkGetPhysicalDeviceProperties);
success &= initInstanceFunc(*pInstance,
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", &next_vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
if (!success) { if (!success) {
Log::error("layer", "Failed to get instance function pointers"); Log::error("layer", "Failed to get instance function pointers");
return VK_ERROR_INITIALIZATION_FAILED; return VK_ERROR_INITIALIZATION_FAILED;
@ -374,6 +377,15 @@ void Layer::ovkGetPhysicalDeviceProperties(
reinterpret_cast<uintptr_t>(physicalDevice)); reinterpret_cast<uintptr_t>(physicalDevice));
next_vkGetPhysicalDeviceProperties(physicalDevice, pProperties); next_vkGetPhysicalDeviceProperties(physicalDevice, pProperties);
} }
VkResult Layer::ovkGetPhysicalDeviceSurfaceCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) {
Log::debug("vulkan", "vkGetPhysicalDeviceSurfaceCapabilitiesKHR called for physical device {:x} and surface {:x}",
reinterpret_cast<uintptr_t>(physicalDevice),
reinterpret_cast<uintptr_t>(surface));
return next_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
}
VkResult Layer::ovkCreateSwapchainKHR( VkResult Layer::ovkCreateSwapchainKHR(
VkDevice device, VkDevice device,

View file

@ -53,6 +53,17 @@ uint64_t Utils::getDeviceUUID(VkPhysicalDevice physicalDevice) {
return static_cast<uint64_t>(properties.vendorID) << 32 | properties.deviceID; return static_cast<uint64_t>(properties.vendorID) << 32 | properties.deviceID;
} }
uint32_t Utils::getMaxImageCount(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
VkSurfaceCapabilitiesKHR capabilities{};
auto res = Layer::ovkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,
surface, &capabilities);
if (res != VK_SUCCESS)
throw LSFG::vulkan_error(res, "Failed to get surface capabilities");
if (capabilities.maxImageCount == 0)
return 999; // :3
return capabilities.maxImageCount;
}
std::vector<const char*> Utils::addExtensions(const char* const* extensions, size_t count, std::vector<const char*> Utils::addExtensions(const char* const* extensions, size_t count,
const std::vector<const char*>& requiredExtensions) { const std::vector<const char*>& requiredExtensions) {
std::vector<const char*> ext(count); std::vector<const char*> ext(count);