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:
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user