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)

Fixes: QTBUG-118568
Change-Id: I5f83999e86a9907efe08b38ca069bae20152a4e0
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
(cherry picked from commit 149f178d3fc01b84a92be63a7ba11529c7d769b5)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit daedbdbba7099479573e92ec555b309db41c7731)
(cherry picked from commit f42e846810b54724f06b67b8a6a83f18faeee65b)
This commit is contained in:
Laszlo Agocs 2023-10-26 18:13:38 +02:00 committed by Qt Cherry-pick Bot
parent 2b361aceb3
commit e132f55acb
2 changed files with 28 additions and 1 deletions

View File

@ -1834,13 +1834,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;
@ -2425,6 +2438,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().

View File

@ -72,6 +72,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,