diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2023-10-26 18:13:38 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2023-12-04 16:04:18 +0100 |
commit | 149f178d3fc01b84a92be63a7ba11529c7d769b5 (patch) | |
tree | 52489e54e103f772c283f2261cf41d09d2e23a22 | |
parent | 21eeef83f642d8c34f7ab3bbcd3171c267cff09f (diff) |
QVulkanWindow: sync surface size logic with QRhi
The legacy QWindow convenience subclass does not have the
robust logic that was later implemented for the Vulkan backend of
QRhi. (i.e., never trust the QWindow; problem with QVulkanWindow
is that it half-trusts those values still, which leads to the
classic pixel-size-differs-by-one problem)
Pick-to: 6.6 6.5 6.2
Fixes: QTBUG-118568
Change-Id: I5f83999e86a9907efe08b38ca069bae20152a4e0
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r-- | src/gui/vulkan/qvulkanwindow.cpp | 28 | ||||
-rw-r--r-- | src/gui/vulkan/qvulkanwindow_p.h | 1 |
2 files changed, 28 insertions, 1 deletions
diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index e383bebb74..a2d3e49880 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -1897,13 +1897,26 @@ void QVulkanWindowRenderer::logicalDeviceLost() { } +QSize QVulkanWindowPrivate::surfacePixelSize() const +{ + Q_Q(const QVulkanWindow); + VkSurfaceCapabilitiesKHR surfaceCaps = {}; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps); + VkExtent2D bufferSize = surfaceCaps.currentExtent; + if (bufferSize.width == uint32_t(-1)) { + Q_ASSERT(bufferSize.height == uint32_t(-1)); + return q->size() * q->devicePixelRatio(); + } + return QSize(int(bufferSize.width), int(bufferSize.height)); +} + void QVulkanWindowPrivate::beginFrame() { if (!swapChain || framePending) return; Q_Q(QVulkanWindow); - if (q->size() * q->devicePixelRatio() != swapChainImageSize) { + if (swapChainImageSize != surfacePixelSize()) { recreateSwapChain(); if (!swapChain) return; @@ -2488,6 +2501,19 @@ VkFormat QVulkanWindow::depthStencilFormat() const This usually matches the size of the window, but may also differ in case \c vkGetPhysicalDeviceSurfaceCapabilitiesKHR reports a fixed size. + In addition, it has been observed on some platforms that the + Vulkan-reported surface size is different with high DPI scaling active, + meaning the QWindow-reported + \l{QWindow::}{size()} multiplied with the \l{QWindow::}{devicePixelRatio()} + was 1 pixel less or more when compared to the value returned from here, + presumably due to differences in rounding. Rendering code should be aware + of this, and any related rendering logic must be based in the value returned + from here, never on the QWindow-reported size. Regardless of which pixel size + is correct in theory, Vulkan rendering must only ever rely on the Vulkan + API-reported surface size. Otherwise validation errors may occur, e.g. when + setting the viewport, because the application-provided values may become + out-of-bounds from Vulkan's perspective. + \note Calling this function is only valid from the invocation of QVulkanWindowRenderer::initSwapChainResources() up until QVulkanWindowRenderer::releaseSwapChainResources(). diff --git a/src/gui/vulkan/qvulkanwindow_p.h b/src/gui/vulkan/qvulkanwindow_p.h index a2f4d4d678..7a0ee091e6 100644 --- a/src/gui/vulkan/qvulkanwindow_p.h +++ b/src/gui/vulkan/qvulkanwindow_p.h @@ -36,6 +36,7 @@ public: void init(); void reset(); bool createDefaultRenderPass(); + QSize surfacePixelSize() const; void recreateSwapChain(); uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex); bool createTransientImage(VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectMask, |