From 7c2cd359655037e61680320b781b329ca9c9c3ff Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Wed, 15 Dec 2021 00:37:48 +0200 Subject: [PATCH] qt: Add overload protection to renderers Added atomic_flags for renderer buffers to prevent concurrent usage and overloading the renderer with draw requests when it's busy. --- src/qt/qt_hardwarerenderer.cpp | 4 +++- src/qt/qt_hardwarerenderer.hpp | 2 +- src/qt/qt_rendererstack.cpp | 13 +++++++++---- src/qt/qt_rendererstack.hpp | 7 ++++++- src/qt/qt_softwarerenderer.cpp | 3 ++- src/qt/qt_softwarerenderer.hpp | 3 ++- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/qt/qt_hardwarerenderer.cpp b/src/qt/qt_hardwarerenderer.cpp index 0659e41a5..4b12fc249 100644 --- a/src/qt/qt_hardwarerenderer.cpp +++ b/src/qt/qt_hardwarerenderer.cpp @@ -1,5 +1,6 @@ #include "qt_hardwarerenderer.hpp" #include +#include extern "C" { #include <86box/86box.h> @@ -34,10 +35,11 @@ void HardwareRenderer::setRenderType(RenderType type) { setFormat(format); } -void HardwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) { +void HardwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h, std::atomic_flag* in_use) { image = img; source.setRect(x, y, w, h); update(); + in_use->clear(); } void HardwareRenderer::resizeEvent(QResizeEvent *event) { diff --git a/src/qt/qt_hardwarerenderer.hpp b/src/qt/qt_hardwarerenderer.hpp index 916e52141..fa9e7ec31 100644 --- a/src/qt/qt_hardwarerenderer.hpp +++ b/src/qt/qt_hardwarerenderer.hpp @@ -43,7 +43,7 @@ public: void setRenderType(RenderType type); public slots: - void onBlit(const QImage& img, int, int, int, int); + void onBlit(const QImage& img, int, int, int, int, std::atomic_flag* in_use); protected: void resizeEvent(QResizeEvent *event) override; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index fed414d12..07546ea3a 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -27,6 +27,11 @@ RendererStack::RendererStack(QWidget *parent) : imagebufs = QVector(2); imagebufs[0] = QImage{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32}; imagebufs[1] = QImage{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32}; + + buffers_in_use = std::vector(2); + buffers_in_use[0].clear(); + buffers_in_use[1].clear(); + #ifdef WAYLAND if (QApplication::platformName().contains("wayland")) { wl_init(); @@ -165,7 +170,7 @@ void RendererStack::leaveEvent(QEvent* event) // called from blitter thread void RendererStack::blit(int x, int y, int w, int h) { - if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL)) + if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || buffers_in_use[currentBuf].test_and_set()) { video_blit_complete(); return; @@ -182,7 +187,7 @@ void RendererStack::blit(int x, int y, int w, int h) video_screenshot((uint32_t *)imagebits, 0, 0, 2048 + 64); } video_blit_complete(); - blitToRenderer(imagebufs[currentBuf], sx, sy, sw, sh); + blitToRenderer(imagebufs[currentBuf], sx, sy, sw, sh, &buffers_in_use[currentBuf]); currentBuf = (currentBuf + 1) % 2; } @@ -190,11 +195,11 @@ void RendererStack::on_RendererStack_currentChanged(int arg1) { disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr); switch (arg1) { case 0: - connect(this, &RendererStack::blitToRenderer, dynamic_cast(currentWidget()), &SoftwareRenderer::onBlit); + connect(this, &RendererStack::blitToRenderer, dynamic_cast(currentWidget()), &SoftwareRenderer::onBlit, Qt::QueuedConnection); break; case 1: case 2: - connect(this, &RendererStack::blitToRenderer, dynamic_cast(currentWidget()), &HardwareRenderer::onBlit); + connect(this, &RendererStack::blitToRenderer, dynamic_cast(currentWidget()), &HardwareRenderer::onBlit, Qt::QueuedConnection); break; } } diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 239bd5bef..b54db0390 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace Ui { class RendererStack; @@ -32,7 +34,7 @@ public: } signals: - void blitToRenderer(const QImage& img, int, int, int, int); + void blitToRenderer(const QImage& img, int, int, int, int, std::atomic_flag* in_use); public slots: void blit(int x, int y, int w, int h); @@ -57,6 +59,9 @@ private: // when calling bits(); int currentBuf = 0; QVector imagebufs; + + /* atomic flag for each buffer to not overload the renderer */ + std::vector buffers_in_use; }; #endif // QT_RENDERERCONTAINER_HPP diff --git a/src/qt/qt_softwarerenderer.cpp b/src/qt/qt_softwarerenderer.cpp index 0565d2d6c..b424c8bad 100644 --- a/src/qt/qt_softwarerenderer.cpp +++ b/src/qt/qt_softwarerenderer.cpp @@ -7,10 +7,11 @@ void SoftwareRenderer::paintEvent(QPaintEvent *event) { onPaint(this); } -void SoftwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h) { +void SoftwareRenderer::onBlit(const QImage& img, int x, int y, int w, int h, std::atomic_flag* in_use) { image = img; source.setRect(x, y, w, h); update(); + in_use->clear(); } void SoftwareRenderer::resizeEvent(QResizeEvent *event) { diff --git a/src/qt/qt_softwarerenderer.hpp b/src/qt/qt_softwarerenderer.hpp index 873e9f732..1e37f65d4 100644 --- a/src/qt/qt_softwarerenderer.hpp +++ b/src/qt/qt_softwarerenderer.hpp @@ -2,6 +2,7 @@ #define SOFTWARERENDERER_HPP #include +#include #include "qt_renderercomon.hpp" class SoftwareRenderer : public QWidget, public RendererCommon @@ -12,7 +13,7 @@ public: void paintEvent(QPaintEvent *event) override; public slots: - void onBlit(const QImage& img, int, int, int, int); + void onBlit(const QImage& img, int, int, int, int, std::atomic_flag* in_use); protected: void resizeEvent(QResizeEvent *event) override;