qt: Refactor renderers buffer ownership

Invert the way buffers are created; make renderer create buffers for
renderer stack.
Use QImage bits as the buffer for software renderer.
This commit is contained in:
ts-korhonen
2022-01-15 21:45:34 +02:00
parent 07446719a4
commit 8c8e2219d8
8 changed files with 108 additions and 44 deletions

View File

@@ -2,6 +2,7 @@
#include <QApplication> #include <QApplication>
#include <QVector2D> #include <QVector2D>
#include <atomic> #include <atomic>
#include <vector>
extern "C" { extern "C" {
#include <86box/86box.h> #include <86box/86box.h>
@@ -21,7 +22,7 @@ void HardwareRenderer::initializeGL()
{ {
m_context->makeCurrent(this); m_context->makeCurrent(this);
initializeOpenGLFunctions(); initializeOpenGLFunctions();
m_texture = new QOpenGLTexture(image); m_texture = new QOpenGLTexture(QImage(2048,2048, QImage::Format::Format_RGB32));
m_blt = new QOpenGLTextureBlitter; m_blt = new QOpenGLTextureBlitter;
m_blt->setRedBlueSwizzle(true); m_blt->setRedBlueSwizzle(true);
m_blt->create(); m_blt->create();
@@ -160,19 +161,19 @@ void HardwareRenderer::setRenderType(RenderType type) {
setFormat(format); setFormat(format);
} }
void HardwareRenderer::onBlit(const std::unique_ptr<uint8_t>* img, int x, int y, int w, int h, std::atomic_flag* in_use) { void HardwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) {
auto tval = this; auto tval = this;
void* nuldata = 0; void* nuldata = 0;
if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return; if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return;
if (!m_texture || !img || !img->get() || (m_texture && !m_texture->isCreated())) if (!m_texture || !m_texture->isCreated())
{ {
in_use->clear(); buf_usage[buf_idx].clear();
source.setRect(x, y, w, h); source.setRect(x, y, w, h);
return; return;
} }
m_context->makeCurrent(this); m_context->makeCurrent(this);
m_texture->setData(QOpenGLTexture::PixelFormat::RGBA, QOpenGLTexture::PixelType::UInt8, (const void*)img->get()); m_texture->setData(QOpenGLTexture::PixelFormat::RGBA, QOpenGLTexture::PixelType::UInt8, (const void*)imagebufs[buf_idx].get());
in_use->clear(); buf_usage[buf_idx].clear();
source.setRect(x, y, w, h); source.setRect(x, y, w, h);
update(); update();
} }
@@ -189,3 +190,13 @@ bool HardwareRenderer::event(QEvent *event)
if (!eventDelegate(event, res)) return QOpenGLWindow::event(event); if (!eventDelegate(event, res)) return QOpenGLWindow::event(event);
return res; return res;
} }
std::vector<std::tuple<uint8_t*, std::atomic_flag*>> HardwareRenderer::getBuffers()
{
std::vector<std::tuple<uint8_t*, std::atomic_flag*>> buffers;
buffers.push_back(std::make_tuple(imagebufs[0].get(), &buf_usage[0]));
buffers.push_back(std::make_tuple(imagebufs[1].get(), &buf_usage[1]));
return buffers;
}

View File

@@ -15,6 +15,9 @@
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include <array>
#include <vector>
#include <memory>
#include <QApplication> #include <QApplication>
#include "qt_renderercomon.hpp" #include "qt_renderercomon.hpp"
@@ -44,9 +47,17 @@ public:
void resizeGL(int w, int h) override; void resizeGL(int w, int h) override;
void initializeGL() override; void initializeGL() override;
void paintGL() override; void paintGL() override;
std::vector<std::tuple<uint8_t*, std::atomic_flag*>> getBuffers() override;
HardwareRenderer(QWidget* parent = nullptr, RenderType rtype = RenderType::OpenGL) HardwareRenderer(QWidget* parent = nullptr, RenderType rtype = RenderType::OpenGL)
: QOpenGLWindow(QOpenGLWindow::NoPartialUpdate, parent->windowHandle()), QOpenGLFunctions() : QOpenGLWindow(QOpenGLWindow::NoPartialUpdate, parent->windowHandle()), QOpenGLFunctions()
{ {
imagebufs[0] = std::unique_ptr<uint8_t>(new uint8_t[2048 * 2048 * 4]);
imagebufs[1] = std::unique_ptr<uint8_t>(new uint8_t[2048 * 2048 * 4]);
buf_usage = std::vector<std::atomic_flag>(2);
buf_usage[0].clear();
buf_usage[1].clear();
setMinimumSize(QSize(16, 16)); setMinimumSize(QSize(16, 16));
setFlags(Qt::FramelessWindowHint); setFlags(Qt::FramelessWindowHint);
parentWidget = parent; parentWidget = parent;
@@ -71,9 +82,11 @@ public:
void setRenderType(RenderType type); void setRenderType(RenderType type);
public slots: public slots:
void onBlit(const std::unique_ptr<uint8_t>* img, int, int, int, int, std::atomic_flag* in_use); void onBlit(int buf_idx, int x, int y, int w, int h);
protected: protected:
std::array<std::unique_ptr<uint8_t>, 2> imagebufs;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
bool event(QEvent* event) override; bool event(QEvent* event) override;
}; };

View File

@@ -16,13 +16,6 @@ extern "C" {
RendererCommon::RendererCommon() = default; RendererCommon::RendererCommon() = default;
extern MainWindow* main_window; extern MainWindow* main_window;
void RendererCommon::onPaint(QPaintDevice* device) {
QPainter painter(device);
painter.setRenderHint(QPainter::SmoothPixmapTransform, video_filter_method > 0 ? true : false);
painter.fillRect(0, 0, device->width(), device->height(), QColorConstants::Black);
painter.setCompositionMode(QPainter::CompositionMode_Plus);
painter.drawImage(destination, image, source);
}
static void integer_scale(double *d, double *g) { static void integer_scale(double *d, double *g) {
double ratio; double ratio;

View File

@@ -4,6 +4,10 @@
#include <QImage> #include <QImage>
#include <QEvent> #include <QEvent>
#include <vector>
#include <tuple>
#include <atomic>
class QWidget; class QWidget;
class RendererCommon class RendererCommon
@@ -12,11 +16,12 @@ public:
RendererCommon(); RendererCommon();
void onResize(int width, int height); void onResize(int width, int height);
virtual std::vector<std::tuple<uint8_t*, std::atomic_flag*>> getBuffers() = 0;
protected: protected:
void onPaint(QPaintDevice* device);
bool eventDelegate(QEvent* event, bool& result); bool eventDelegate(QEvent* event, bool& result);
QImage image{QSize(2048, 2048), QImage::Format_RGB32};
QRect source, destination; QRect source, destination;
QWidget* parentWidget{nullptr}; QWidget* parentWidget{nullptr};
std::vector<std::atomic_flag> buf_usage;
}; };

View File

@@ -27,12 +27,6 @@ RendererStack::RendererStack(QWidget *parent) :
ui(new Ui::RendererStack) ui(new Ui::RendererStack)
{ {
ui->setupUi(this); ui->setupUi(this);
imagebufs[0].reset(new uint8_t[2048 * 2048 * 4]);
imagebufs[1].reset(new uint8_t[2048 * 2048 * 4]);
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")) {
@@ -216,13 +210,14 @@ void RendererStack::switchRenderer(Renderer renderer) {
break; break;
} }
} }
imagebufs = std::move(rendererWindow->getBuffers());
current->setFocusPolicy(Qt::NoFocus); current->setFocusPolicy(Qt::NoFocus);
current->setFocusProxy(this); current->setFocusProxy(this);
addWidget(current.get()); addWidget(current.get());
this->setStyleSheet("background-color: black"); this->setStyleSheet("background-color: black");
for (auto& in_use : buffers_in_use)
in_use.clear();
endblit(); endblit();
} }
@@ -230,7 +225,7 @@ void RendererStack::switchRenderer(Renderer renderer) {
// 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) || buffers_in_use[currentBuf].test_and_set()) if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || std::get<std::atomic_flag*>(imagebufs[currentBuf])->test_and_set())
{ {
video_blit_complete(); video_blit_complete();
return; return;
@@ -239,7 +234,7 @@ void RendererStack::blit(int x, int y, int w, int h)
sy = y; sy = y;
sw = this->w = w; sw = this->w = w;
sh = this->h = h; sh = this->h = h;
auto imagebits = imagebufs[currentBuf].get(); uint8_t* imagebits = std::get<uint8_t*>(imagebufs[currentBuf]);
for (int y1 = y; y1 < (y + h - 1); y1++) for (int y1 = y; y1 < (y + h - 1); y1++)
{ {
auto scanline = imagebits + (y1 * (2048) * 4) + (x * 4); auto scanline = imagebits + (y1 * (2048) * 4) + (x * 4);
@@ -251,6 +246,6 @@ void RendererStack::blit(int x, int y, int w, int h)
video_screenshot((uint32_t *)imagebits, x, y, 2048); video_screenshot((uint32_t *)imagebits, x, y, 2048);
} }
video_blit_complete(); video_blit_complete();
blitToRenderer(&imagebufs[currentBuf], sx, sy, sw, sh, &buffers_in_use[currentBuf]); emit blitToRenderer(currentBuf, sx, sy, sw, sh);
currentBuf = (currentBuf + 1) % 2; currentBuf = (currentBuf + 1) % imagebufs.size();
} }

View File

@@ -7,7 +7,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <atomic> #include <atomic>
#include <array> #include <tuple>
namespace Ui { namespace Ui {
class RendererStack; class RendererStack;
@@ -46,7 +46,7 @@ public:
RendererCommon* rendererWindow{nullptr}; RendererCommon* rendererWindow{nullptr};
signals: signals:
void blitToRenderer(const std::unique_ptr<uint8_t>* img, int, int, int, int, std::atomic_flag* in_use); void blitToRenderer(int buf_idx, int x, int y, int w, int h);
public slots: public slots:
void blit(int x, int y, int w, int h); void blit(int x, int y, int w, int h);
@@ -64,13 +64,10 @@ private:
int x, y, w, h, sx, sy, sw, sh; int x, y, w, h, sx, sy, sw, sh;
int currentBuf = 0; int currentBuf = 0;
std::array<std::unique_ptr<uint8_t>, 2> imagebufs; std::vector<std::tuple<uint8_t*, std::atomic_flag*>> imagebufs;
std::unique_ptr<QWidget> current; std::unique_ptr<QWidget> current;
/* atomic flag for each buffer to not overload the renderer */
std::vector<std::atomic_flag> buffers_in_use;
friend class MainWindow; friend class MainWindow;
}; };

View File

@@ -1,20 +1,40 @@
#include "qt_softwarerenderer.hpp" #include "qt_softwarerenderer.hpp"
#include <QApplication> #include <QApplication>
#include <QPainter>
SoftwareRenderer::SoftwareRenderer(QWidget *parent) : QRasterWindow(parent->windowHandle()) { parentWidget = parent; } extern "C" {
#include <86box/86box.h>
#include <86box/video.h>
}
SoftwareRenderer::SoftwareRenderer(QWidget *parent)
: QRasterWindow(parent->windowHandle())
{
parentWidget = parent;
images[0] = std::make_unique<QImage>(QSize(2048, 2048), QImage::Format_RGB32);
images[1] = std::make_unique<QImage>(QSize(2048, 2048), QImage::Format_RGB32);
buf_usage = std::vector<std::atomic_flag>(2);
buf_usage[0].clear();
buf_usage[1].clear();
}
void SoftwareRenderer::paintEvent(QPaintEvent* event) { void SoftwareRenderer::paintEvent(QPaintEvent* event) {
(void)event; (void)event;
onPaint(this); onPaint(this);
} }
void SoftwareRenderer::onBlit(const std::unique_ptr<uint8_t>* img, int x, int y, int w, int h, std::atomic_flag* in_use) { void SoftwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) {
/* TODO: should look into deleteLater() */
auto tval = this; auto tval = this;
void* nuldata = 0; void* nuldata = 0;
if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return; if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return;
memcpy(image.bits(), img->get(), 2048 * 2048 * 4);
in_use->clear(); cur_image = buf_idx;
source.setRect(x, y, w, h); buf_usage[(buf_idx + 1) % 2].clear();
source.setRect(x, y, w, h),
update(); update();
} }
@@ -29,3 +49,24 @@ bool SoftwareRenderer::event(QEvent *event)
if (!eventDelegate(event, res)) return QRasterWindow::event(event); if (!eventDelegate(event, res)) return QRasterWindow::event(event);
return res; return res;
} }
void SoftwareRenderer::onPaint(QPaintDevice* device) {
if (cur_image == -1)
return;
QPainter painter(device);
painter.setRenderHint(QPainter::SmoothPixmapTransform, video_filter_method > 0 ? true : false);
painter.fillRect(0, 0, device->width(), device->height(), QColorConstants::Black);
painter.setCompositionMode(QPainter::CompositionMode_Plus);
painter.drawImage(destination, *images[cur_image], source);
}
std::vector<std::tuple<uint8_t*, std::atomic_flag*>> SoftwareRenderer::getBuffers()
{
std::vector<std::tuple<uint8_t*, std::atomic_flag*>> buffers;
buffers.push_back(std::make_tuple(images[0]->bits(), &buf_usage[0]));
buffers.push_back(std::make_tuple(images[1]->bits(), &buf_usage[1]));
return buffers;
}

View File

@@ -3,6 +3,8 @@
#include <QWidget> #include <QWidget>
#include <QRasterWindow> #include <QRasterWindow>
#include <QPaintDevice>
#include <array>
#include <atomic> #include <atomic>
#include "qt_renderercomon.hpp" #include "qt_renderercomon.hpp"
@@ -13,10 +15,17 @@ public:
explicit SoftwareRenderer(QWidget *parent = nullptr); explicit SoftwareRenderer(QWidget *parent = nullptr);
void paintEvent(QPaintEvent* event) override; void paintEvent(QPaintEvent* event) override;
std::vector<std::tuple<uint8_t*, std::atomic_flag*>> getBuffers() override;
public slots: public slots:
void onBlit(const std::unique_ptr<uint8_t>* img, int, int, int, int, std::atomic_flag* in_use); void onBlit(int buf_idx, int x, int y, int w, int h);
protected: protected:
std::array<std::unique_ptr<QImage>, 2> images;
int cur_image = -1;
void onPaint(QPaintDevice* device);
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
bool event(QEvent *event) override; bool event(QEvent *event) override;
}; };