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