From af3cf63e5fb5c23dc38f4f365316ab2c0cf56c01 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 17 Aug 2023 14:22:04 +0200 Subject: [PATCH] Fix OpenGL rendering with precise HighDPI. --- .../calls/calls_video_incoming.cpp | 8 +++-- .../group/calls_group_viewport_opengl.cpp | 34 +++++++++++-------- .../calls/group/calls_group_viewport_opengl.h | 1 + .../media/view/media_view_overlay_opengl.cpp | 27 ++++++++------- .../media/view/media_view_overlay_opengl.h | 1 + .../media/view/media_view_pip_opengl.cpp | 17 +++++----- .../media/view/media_view_pip_opengl.h | 1 + 7 files changed, 50 insertions(+), 39 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_video_incoming.cpp b/Telegram/SourceFiles/calls/calls_video_incoming.cpp index 916a058dd..9ea9fe41c 100644 --- a/Telegram/SourceFiles/calls/calls_video_incoming.cpp +++ b/Telegram/SourceFiles/calls/calls_video_incoming.cpp @@ -73,6 +73,7 @@ private: QSize _viewport; float _factor = 1.; + int _ifactor = 1; QVector2D _uniformViewport; std::optional _contentBuffer; @@ -189,9 +190,10 @@ void Panel::Incoming::RendererGL::paint( return; } - const auto factor = widget->devicePixelRatio(); + const auto factor = widget->devicePixelRatioF(); if (_factor != factor) { _factor = factor; + _ifactor = int(std::ceil(_factor)); _controlsShadowImage.invalidate(); } _viewport = widget->size(); @@ -375,9 +377,9 @@ void Panel::Incoming::RendererGL::validateShadowImage() { return; } const auto size = st::callTitleShadowLeft.size(); - const auto full = QSize(size.width(), 2 * size.height()) * int(_factor); + const auto full = QSize(size.width(), 2 * size.height()) * _ifactor; auto image = QImage(full, QImage::Format_ARGB32_Premultiplied); - image.setDevicePixelRatio(_factor); + image.setDevicePixelRatio(_ifactor); image.fill(Qt::transparent); { auto p = QPainter(&image); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index e4a04f7c5..26a9cbed0 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -414,16 +414,20 @@ void Viewport::RendererGL::deinit( } void Viewport::RendererGL::setDefaultViewport(QOpenGLFunctions &f) { - const auto size = _viewport * _factor; - f.glViewport(0, 0, size.width(), size.height()); + f.glViewport( + 0, + 0, + _viewport.width() * _factor, + _viewport.height() * _factor); } void Viewport::RendererGL::paint( not_null widget, QOpenGLFunctions &f) { - const auto factor = widget->devicePixelRatio(); + const auto factor = widget->devicePixelRatioF(); if (_factor != factor) { _factor = factor; + _ifactor = int(std::ceil(_factor)); _buttons.invalidate(); } _viewport = widget->size(); @@ -773,7 +777,7 @@ void Viewport::RendererGL::paintTile( const auto program = _rgbaFrame ? &*_frameProgram.argb32 : &*_frameProgram.yuv420; - const auto uniformViewport = QSizeF(_viewport * _factor); + const auto uniformViewport = QSizeF(_viewport) * _factor; program->setUniformValue("viewport", uniformViewport); program->setUniformValue( @@ -1122,18 +1126,18 @@ void Viewport::RendererGL::ensureButtonsImage() { + backSize.height() + muteSize.height() + pausedSize.height())); - const auto imageSize = fullSize * _factor; + const auto imageSize = fullSize * _ifactor; auto image = _buttons.takeImage(); if (image.size() != imageSize) { image = QImage(imageSize, QImage::Format_ARGB32_Premultiplied); } image.fill(Qt::transparent); - image.setDevicePixelRatio(_factor); + image.setDevicePixelRatio(_ifactor); { auto p = Painter(&image); auto hq = PainterHighQualityEnabler(p); - _pinOn = QRect(QPoint(), pinOnSize * _factor); + _pinOn = QRect(QPoint(), pinOnSize * _ifactor); VideoTile::PaintPinButton( p, true, @@ -1145,8 +1149,8 @@ void Viewport::RendererGL::ensureButtonsImage() { const auto pinOffTop = pinOnSize.height(); _pinOff = QRect( - QPoint(0, pinOffTop) * _factor, - pinOffSize * _factor); + QPoint(0, pinOffTop) * _ifactor, + pinOffSize * _ifactor); VideoTile::PaintPinButton( p, false, @@ -1157,7 +1161,7 @@ void Viewport::RendererGL::ensureButtonsImage() { &_pinIcon); const auto backTop = pinOffTop + pinOffSize.height(); - _back = QRect(QPoint(0, backTop) * _factor, backSize * _factor); + _back = QRect(QPoint(0, backTop) * _ifactor, backSize * _ifactor); VideoTile::PaintBackButton( p, 0, @@ -1166,18 +1170,18 @@ void Viewport::RendererGL::ensureButtonsImage() { &_pinBackground); const auto muteTop = backTop + backSize.height(); - _muteOn = QRect(QPoint(0, muteTop) * _factor, muteSize * _factor); + _muteOn = QRect(QPoint(0, muteTop) * _ifactor, muteSize * _ifactor); _muteIcon.paint(p, { 0, muteTop }, 1.); _muteOff = QRect( - QPoint(muteSize.width(), muteTop) * _factor, - muteSize * _factor); + QPoint(muteSize.width(), muteTop) * _ifactor, + muteSize * _ifactor); _muteIcon.paint(p, { muteSize.width(), muteTop }, 0.); const auto pausedTop = muteTop + muteSize.height(); _paused = QRect( - QPoint(0, pausedTop) * _factor, - pausedSize * _factor); + QPoint(0, pausedTop) * _ifactor, + pausedSize * _ifactor); st::groupCallPaused.paint(p, 0, pausedTop, fullSize.width()); } _buttons.setImage(std::move(image)); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h index aab98c6fd..848174f86 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h @@ -130,6 +130,7 @@ private: const not_null _owner; GLfloat _factor = 1.; + int _ifactor = 1; QSize _viewport; bool _rgbaFrame = false; bool _userpicFrame; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index 570eed0af..97b59fc72 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -263,9 +263,10 @@ void OverlayWidget::RendererGL::paint( if (handleHideWorkaround(f)) { return; } - const auto factor = widget->devicePixelRatio(); + const auto factor = widget->devicePixelRatioF(); if (_factor != factor) { _factor = factor; + _ifactor = int(std::ceil(factor)); _controlsImage.invalidate(); // We use the fact that fade texture atlas @@ -763,10 +764,10 @@ void OverlayWidget::RendererGL::validateControls() { maxWidth = std::max(st::mediaviewIconOver, maxWidth); fullHeight += st::mediaviewIconOver; auto image = QImage( - QSize(maxWidth, fullHeight) * _factor, + QSize(maxWidth, fullHeight) * _ifactor, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); - image.setDevicePixelRatio(_factor); + image.setDevicePixelRatio(_ifactor); { auto p = QPainter(&image); auto index = 0; @@ -774,8 +775,8 @@ void OverlayWidget::RendererGL::validateControls() { for (const auto &meta : metas) { meta.icon->paint(p, 0, height, maxWidth); _controlsTextures[index++] = QRect( - QPoint(0, height) * _factor, - meta.icon->size() * _factor); + QPoint(0, height) * _ifactor, + meta.icon->size() * _ifactor); height += meta.icon->height(); } auto hq = PainterHighQualityEnabler(p); @@ -784,8 +785,8 @@ void OverlayWidget::RendererGL::validateControls() { p.drawEllipse( QRect(0, height, st::mediaviewIconOver, st::mediaviewIconOver)); _controlsTextures[index++] = QRect( - QPoint(0, height) * _factor, - QSize(st::mediaviewIconOver, st::mediaviewIconOver) * _factor); + QPoint(0, height) * _ifactor, + QSize(st::mediaviewIconOver, st::mediaviewIconOver) * _ifactor); height += st::mediaviewIconOver; } _controlsImage.setImage(std::move(image)); @@ -817,10 +818,10 @@ void OverlayWidget::RendererGL::validateControlsFade() { const auto height = bottomTop + bottom.height(); auto image = QImage( - QSize(width, height) * _factor, + QSize(width, height) * _ifactor, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); - image.setDevicePixelRatio(_factor); + image.setDevicePixelRatio(_ifactor); auto p = QPainter(&image); top.paint(p, 0, 0, width); @@ -1007,18 +1008,18 @@ void OverlayWidget::RendererGL::paintUsingRaster( int bufferOffset, bool transparent) { auto raster = image.takeImage(); - const auto size = rect.size() * _factor; + const auto size = rect.size() * _ifactor; if (raster.width() < size.width() || raster.height() < size.height()) { raster = QImage(size, QImage::Format_ARGB32_Premultiplied); Assert(!raster.isNull()); - raster.setDevicePixelRatio(_factor); + raster.setDevicePixelRatio(_ifactor); if (!transparent && (raster.width() > size.width() || raster.height() > size.height())) { raster.fill(Qt::transparent); } - } else if (raster.devicePixelRatio() != _factor) { - raster.setDevicePixelRatio(_factor); + } else if (raster.devicePixelRatio() != _ifactor) { + raster.setDevicePixelRatio(_ifactor); } if (transparent) { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h index f64fb7e58..0138a492d 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h @@ -114,6 +114,7 @@ private: QOpenGLFunctions *_f = nullptr; QSize _viewport; float _factor = 1.; + int _ifactor = 1; QVector2D _uniformViewport; std::optional _contentBuffer; diff --git a/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp index a304578b2..8fa5f1d13 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip_opengl.cpp @@ -269,9 +269,10 @@ void Pip::RendererGL::createShadowTexture() { void Pip::RendererGL::paint( not_null widget, QOpenGLFunctions &f) { - const auto factor = widget->devicePixelRatio(); + const auto factor = widget->devicePixelRatioF(); if (_factor != factor) { _factor = factor; + _ifactor = int(std::ceil(_factor)); _controlsImage.invalidate(); } _blendingEnabled = false; @@ -667,10 +668,10 @@ void Pip::RendererGL::validateControls() { fullHeight += 2 * meta.icon->height(); } auto image = QImage( - QSize(maxWidth, fullHeight) * _factor, + QSize(maxWidth, fullHeight) * _ifactor, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); - image.setDevicePixelRatio(_factor); + image.setDevicePixelRatio(_ifactor); { auto p = QPainter(&image); auto index = 0; @@ -678,8 +679,8 @@ void Pip::RendererGL::validateControls() { const auto paint = [&](not_null icon) { icon->paint(p, 0, height, maxWidth); _controlsTextures[index++] = QRect( - QPoint(0, height) * _factor, - icon->size() * _factor); + QPoint(0, height) * _ifactor, + icon->size() * _ifactor); height += icon->height(); }; for (const auto &meta : metas) { @@ -702,7 +703,7 @@ void Pip::RendererGL::paintUsingRaster( int bufferOffset, bool transparent) { auto raster = image.takeImage(); - const auto size = rect.size() * _factor; + const auto size = rect.size() * _ifactor; if (raster.width() < size.width() || raster.height() < size.height()) { raster = QImage(size, QImage::Format_ARGB32_Premultiplied); raster.setDevicePixelRatio(_factor); @@ -711,8 +712,8 @@ void Pip::RendererGL::paintUsingRaster( || raster.height() > size.height())) { raster.fill(Qt::transparent); } - } else if (raster.devicePixelRatio() != _factor) { - raster.setDevicePixelRatio(_factor); + } else if (raster.devicePixelRatio() != _ifactor) { + raster.setDevicePixelRatio(_ifactor); } if (transparent) { diff --git a/Telegram/SourceFiles/media/view/media_view_pip_opengl.h b/Telegram/SourceFiles/media/view/media_view_pip_opengl.h index 977240c50..21d9b521e 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_pip_opengl.h @@ -93,6 +93,7 @@ private: QOpenGLFunctions *_f = nullptr; QSize _viewport; float _factor = 1.; + int _ifactor = 1; QVector2D _uniformViewport; std::optional _contentBuffer;