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.
This commit is contained in:
ts-korhonen
2021-12-15 00:37:48 +02:00
parent 6a88e48680
commit 7c2cd35965
6 changed files with 23 additions and 9 deletions

View File

@@ -1,5 +1,6 @@
#include "qt_hardwarerenderer.hpp" #include "qt_hardwarerenderer.hpp"
#include <QApplication> #include <QApplication>
#include <atomic>
extern "C" { extern "C" {
#include <86box/86box.h> #include <86box/86box.h>
@@ -34,10 +35,11 @@ void HardwareRenderer::setRenderType(RenderType type) {
setFormat(format); 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; image = img;
source.setRect(x, y, w, h); source.setRect(x, y, w, h);
update(); update();
in_use->clear();
} }
void HardwareRenderer::resizeEvent(QResizeEvent *event) { void HardwareRenderer::resizeEvent(QResizeEvent *event) {

View File

@@ -43,7 +43,7 @@ public:
void setRenderType(RenderType type); void setRenderType(RenderType type);
public slots: 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: protected:
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;

View File

@@ -27,6 +27,11 @@ RendererStack::RendererStack(QWidget *parent) :
imagebufs = QVector<QImage>(2); imagebufs = QVector<QImage>(2);
imagebufs[0] = QImage{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32}; imagebufs[0] = QImage{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32};
imagebufs[1] = 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<std::atomic_flag>(2);
buffers_in_use[0].clear();
buffers_in_use[1].clear();
#ifdef WAYLAND #ifdef WAYLAND
if (QApplication::platformName().contains("wayland")) { if (QApplication::platformName().contains("wayland")) {
wl_init(); wl_init();
@@ -165,7 +170,7 @@ void RendererStack::leaveEvent(QEvent* event)
// called from blitter thread // called from blitter thread
void RendererStack::blit(int x, int y, int w, int h) 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(); video_blit_complete();
return; 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_screenshot((uint32_t *)imagebits, 0, 0, 2048 + 64);
} }
video_blit_complete(); 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; currentBuf = (currentBuf + 1) % 2;
} }
@@ -190,11 +195,11 @@ void RendererStack::on_RendererStack_currentChanged(int arg1) {
disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr); disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr);
switch (arg1) { switch (arg1) {
case 0: case 0:
connect(this, &RendererStack::blitToRenderer, dynamic_cast<SoftwareRenderer*>(currentWidget()), &SoftwareRenderer::onBlit); connect(this, &RendererStack::blitToRenderer, dynamic_cast<SoftwareRenderer*>(currentWidget()), &SoftwareRenderer::onBlit, Qt::QueuedConnection);
break; break;
case 1: case 1:
case 2: case 2:
connect(this, &RendererStack::blitToRenderer, dynamic_cast<HardwareRenderer*>(currentWidget()), &HardwareRenderer::onBlit); connect(this, &RendererStack::blitToRenderer, dynamic_cast<HardwareRenderer*>(currentWidget()), &HardwareRenderer::onBlit, Qt::QueuedConnection);
break; break;
} }
} }

View File

@@ -4,6 +4,8 @@
#include <QStackedWidget> #include <QStackedWidget>
#include <QKeyEvent> #include <QKeyEvent>
#include <QEvent> #include <QEvent>
#include <vector>
#include <atomic>
namespace Ui { namespace Ui {
class RendererStack; class RendererStack;
@@ -32,7 +34,7 @@ public:
} }
signals: 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: public slots:
void blit(int x, int y, int w, int h); void blit(int x, int y, int w, int h);
@@ -57,6 +59,9 @@ private:
// when calling bits(); // when calling bits();
int currentBuf = 0; int currentBuf = 0;
QVector<QImage> imagebufs; QVector<QImage> imagebufs;
/* atomic flag for each buffer to not overload the renderer */
std::vector<std::atomic_flag> buffers_in_use;
}; };
#endif // QT_RENDERERCONTAINER_HPP #endif // QT_RENDERERCONTAINER_HPP

View File

@@ -7,10 +7,11 @@ void SoftwareRenderer::paintEvent(QPaintEvent *event) {
onPaint(this); 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; image = img;
source.setRect(x, y, w, h); source.setRect(x, y, w, h);
update(); update();
in_use->clear();
} }
void SoftwareRenderer::resizeEvent(QResizeEvent *event) { void SoftwareRenderer::resizeEvent(QResizeEvent *event) {

View File

@@ -2,6 +2,7 @@
#define SOFTWARERENDERER_HPP #define SOFTWARERENDERER_HPP
#include <QWidget> #include <QWidget>
#include <atomic>
#include "qt_renderercomon.hpp" #include "qt_renderercomon.hpp"
class SoftwareRenderer : public QWidget, public RendererCommon class SoftwareRenderer : public QWidget, public RendererCommon
@@ -12,7 +13,7 @@ public:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
public slots: 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: protected:
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;