From 941b2de2ee6dec81d2f8fa2a6d46ff0ab5ca6f8d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 28 Aug 2023 10:43:53 +0200 Subject: [PATCH] Use linear filtering again when QT_WIDGETS_HIGHDPI_DOWNSCALE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ec27b99c2a16994127f77d76eb1fb466c390aee9 the filtering mode is changed from Linear to Nearest since users encountered obscure cases, in particular when multisampling with large sample counts got enabled, where the different filtering mode becomes noticeable. (Qt 5 and Qt 6 up until 6.4 uses Nearest, whereas the OpenGL -> QRhi migration introduced using Linear in 6.4) Meanwhile, the as of now undocumented high DPI downscaling feature got introduced, and that prefers linear filtering. (since that's definitely not a 1:1 mapping when it comes to texture size and the on-screen quad) To reconcile the differences, add support for both kind of samplers, and choose based on the sizes. This should have no effect when not running with the env.var. QT_WIDGETS_RHI=1 QT_WIDGETS_HIGHDPI_DOWNSCALE=1 set, but should restore the pre-6.5.2 look when they are set. Fixes: QTBUG-115461 Change-Id: I42eb8526cb7f74236b5550e26c4570771d2fbfb4 Reviewed-by: Qt CI Bot Reviewed-by: Morten Johan Sørvig (cherry picked from commit 9505305c403423f58e70471aaf55994bb734a0bd) Reviewed-by: Qt Cherry-pick Bot --- .../qbackingstoredefaultcompositor.cpp | 71 +++++++++++++------ .../qbackingstoredefaultcompositor_p.h | 21 ++++-- 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp index 96df95c7f98..c60ed604997 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor.cpp +++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp @@ -24,8 +24,10 @@ void QBackingStoreDefaultCompositor::reset() m_psBlend = nullptr; delete m_psPremulBlend; m_psPremulBlend = nullptr; - delete m_sampler; - m_sampler = nullptr; + delete m_samplerNearest; + m_samplerNearest = nullptr; + delete m_samplerLinear; + m_samplerLinear = nullptr; delete m_vbuf; m_vbuf = nullptr; delete m_texture; @@ -347,7 +349,7 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea d.srb = m_rhi->newShaderResourceBindings(); d.srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE), - QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_sampler) + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_samplerNearest) }); if (!d.srb->create()) qWarning("QBackingStoreDefaultCompositor: Failed to create srb"); @@ -357,7 +359,7 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea d.srbExtra = m_rhi->newShaderResourceBindings(); d.srbExtra->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE), - QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_sampler) + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_samplerNearest) }); if (!d.srbExtra->create()) qWarning("QBackingStoreDefaultCompositor: Failed to create srb"); @@ -368,27 +370,31 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea return d; } -void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra) +void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra, + UpdateQuadDataOptions options) { // This whole check-if-texture-ptr-is-different is needed because there is // nothing saying a QPlatformTextureList cannot return a different // QRhiTexture* from the same index in a subsequent flush. - if (d->lastUsedTexture == texture || !d->srb) + const QRhiSampler::Filter filter = options.testFlag(NeedsLinearFiltering) ? QRhiSampler::Linear : QRhiSampler::Nearest; + if ((d->lastUsedTexture == texture && d->lastUsedFilter == filter) || !d->srb) return; + QRhiSampler *sampler = filter == QRhiSampler::Linear ? m_samplerLinear : m_samplerNearest; d->srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE), - QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_sampler) + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler) }); d->srb->updateResources(QRhiShaderResourceBindings::BindingsAreSorted); d->lastUsedTexture = texture; + d->lastUsedFilter = filter; if (textureExtra) { d->srbExtra->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE), - QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_sampler) + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, sampler) }); d->srbExtra->updateResources(QRhiShaderResourceBindings::BindingsAreSorted); @@ -397,13 +403,14 @@ void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTextu } void QBackingStoreDefaultCompositor::updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates, - const QMatrix4x4 &target, const QMatrix3x3 &source, UpdateUniformOption option) + const QMatrix4x4 &target, const QMatrix3x3 &source, + UpdateUniformOptions options) { resourceUpdates->updateDynamicBuffer(d->ubuf, 0, 64, target.constData()); updateMatrix3x3(resourceUpdates, d->ubuf, source); float opacity = 1.0f; resourceUpdates->updateDynamicBuffer(d->ubuf, 112, 4, &opacity); - qint32 textureSwizzle = static_cast(option); + qint32 textureSwizzle = options; resourceUpdates->updateDynamicBuffer(d->ubuf, 116, 4, &textureSwizzle); } @@ -426,11 +433,18 @@ void QBackingStoreDefaultCompositor::ensureResources(QRhiSwapChain *swapchain, Q qWarning("QBackingStoreDefaultCompositor: Failed to create vertex buffer"); } - if (!m_sampler) { - m_sampler = m_rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None, - QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); - if (!m_sampler->create()) - qWarning("QBackingStoreDefaultCompositor: Failed to create sampler"); + if (!m_samplerNearest) { + m_samplerNearest = m_rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + if (!m_samplerNearest->create()) + qWarning("QBackingStoreDefaultCompositor: Failed to create sampler (Nearest filtering)"); + } + + if (!m_samplerLinear) { + m_samplerLinear = m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + if (!m_samplerLinear->create()) + qWarning("QBackingStoreDefaultCompositor: Failed to create sampler (Linear filtering)"); } if (!m_widgetQuadData.isValid()) @@ -513,10 +527,13 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo ensureResources(swapchain, resourceUpdates); + UpdateUniformOptions uniformOptions; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - const UpdateUniformOption uniformOption = (flags & QPlatformBackingStore::TextureSwizzle) != 0? NeedsRedBlueSwap : NoOption; + if (flags & QPlatformBackingStore::TextureSwizzle) + uniformOptions |= NeedsRedBlueSwap; #else - const UpdateUniformOption uniformOption = (flags & QPlatformBackingStore::TextureSwizzle) != 0? NeedsAlphaRotate : NoOption; + if (flags & QPlatformBackingStore::TextureSwizzle) + uniformOptions |= NeedsAlphaRotate; #endif const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0; SourceTransformOrigin origin = SourceTransformOrigin::TopLeft; @@ -539,7 +556,17 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo QMatrix4x4 target; // identity if (invertTargetY) target.data()[5] = -1.0f; - updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOption); + updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions); + + // If sourceWindowRect is larger than deviceWindowRect, we are doing + // high DPI downscaling. In that case Linear filtering is a must, + // whereas for the 1:1 case Nearest must be used for Qt 5 visual + // compatibility. + if (sourceWindowRect.width() > deviceWindowRect.width() + && sourceWindowRect.height() > deviceWindowRect.height()) + { + updatePerQuadData(&m_widgetQuadData, m_texture, nullptr, NeedsLinearFiltering); + } } const int textureWidgetCount = textures->count(); @@ -562,13 +589,11 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo QRhiTexture *t = textures->texture(i); QRhiTexture *tExtra = textures->textureExtra(i); if (t) { - if (!m_textureQuadData[i].isValid()) { + if (!m_textureQuadData[i].isValid()) m_textureQuadData[i] = createPerQuadData(t, tExtra); - } - else { + else updatePerQuadData(&m_textureQuadData[i], t, tExtra); - } - updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source, NoOption); + updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source); } else { m_textureQuadData[i].reset(); } diff --git a/src/gui/painting/qbackingstoredefaultcompositor_p.h b/src/gui/painting/qbackingstoredefaultcompositor_p.h index 839fa61c73f..2f835e5d358 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor_p.h +++ b/src/gui/painting/qbackingstoredefaultcompositor_p.h @@ -45,10 +45,14 @@ public: private: enum UpdateUniformOption { - NoOption = 0x00, - NeedsRedBlueSwap = 0x01, - NeedsAlphaRotate = 0x02, + NeedsRedBlueSwap = 1 << 0, + NeedsAlphaRotate = 1 << 1 }; + Q_DECLARE_FLAGS(UpdateUniformOptions, UpdateUniformOption) + enum UpdateQuadDataOption { + NeedsLinearFiltering = 1 << 0 + }; + Q_DECLARE_FLAGS(UpdateQuadDataOptions, UpdateQuadDataOption) void ensureResources(QRhiSwapChain *swapchain, QRhiResourceUpdateBatch *resourceUpdates); QRhiTexture *toTexture(const QImage &image, @@ -61,7 +65,8 @@ private: mutable QRhiTexture *m_texture = nullptr; QRhiBuffer *m_vbuf = nullptr; - QRhiSampler *m_sampler = nullptr; + QRhiSampler *m_samplerNearest = nullptr; + QRhiSampler *m_samplerLinear = nullptr; QRhiGraphicsPipeline *m_psNoBlend = nullptr; QRhiGraphicsPipeline *m_psBlend = nullptr; QRhiGraphicsPipeline *m_psPremulBlend = nullptr; @@ -73,6 +78,7 @@ private: QRhiShaderResourceBindings *srbExtra = nullptr; // may be null (used for stereo) QRhiTexture *lastUsedTexture = nullptr; QRhiTexture *lastUsedTextureExtra = nullptr; // may be null (used for stereo) + QRhiSampler::Filter lastUsedFilter = QRhiSampler::None; bool isValid() const { return ubuf && srb; } void reset() { delete ubuf; @@ -85,15 +91,18 @@ private: } lastUsedTexture = nullptr; lastUsedTextureExtra = nullptr; + lastUsedFilter = QRhiSampler::None; } }; PerQuadData m_widgetQuadData; QVarLengthArray m_textureQuadData; PerQuadData createPerQuadData(QRhiTexture *texture, QRhiTexture *textureExtra = nullptr); - void updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra = nullptr); + void updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra = nullptr, + UpdateQuadDataOptions options = {}); void updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates, - const QMatrix4x4 &target, const QMatrix3x3 &source, UpdateUniformOption option); + const QMatrix4x4 &target, const QMatrix3x3 &source, + UpdateUniformOptions options = {}); }; QT_END_NAMESPACE