diff --git a/src/qt/qt_hardwarerenderer.cpp b/src/qt/qt_hardwarerenderer.cpp index f6d6142b9..ca0e60efb 100644 --- a/src/qt/qt_hardwarerenderer.cpp +++ b/src/qt/qt_hardwarerenderer.cpp @@ -2,6 +2,7 @@ #include #include #include +#include extern "C" { #include <86box/86box.h> @@ -21,7 +22,7 @@ void HardwareRenderer::initializeGL() { m_context->makeCurrent(this); initializeOpenGLFunctions(); - m_texture = new QOpenGLTexture(image); + m_texture = new QOpenGLTexture(QImage(2048,2048, QImage::Format::Format_RGB32)); m_blt = new QOpenGLTextureBlitter; m_blt->setRedBlueSwizzle(true); m_blt->create(); @@ -160,19 +161,19 @@ void HardwareRenderer::setRenderType(RenderType type) { setFormat(format); } -void HardwareRenderer::onBlit(const std::unique_ptr* 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; void* nuldata = 0; 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); return; } m_context->makeCurrent(this); - m_texture->setData(QOpenGLTexture::PixelFormat::RGBA, QOpenGLTexture::PixelType::UInt8, (const void*)img->get()); - in_use->clear(); + m_texture->setData(QOpenGLTexture::PixelFormat::RGBA, QOpenGLTexture::PixelType::UInt8, (const void*)imagebufs[buf_idx].get()); + buf_usage[buf_idx].clear(); source.setRect(x, y, w, h); update(); } @@ -189,3 +190,13 @@ bool HardwareRenderer::event(QEvent *event) if (!eventDelegate(event, res)) return QOpenGLWindow::event(event); return res; } + +std::vector> HardwareRenderer::getBuffers() +{ + std::vector> 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; +} \ No newline at end of file diff --git a/src/qt/qt_hardwarerenderer.hpp b/src/qt/qt_hardwarerenderer.hpp index 2a453ab49..b87399e8e 100644 --- a/src/qt/qt_hardwarerenderer.hpp +++ b/src/qt/qt_hardwarerenderer.hpp @@ -15,6 +15,9 @@ #include #include +#include +#include +#include #include #include "qt_renderercomon.hpp" @@ -44,9 +47,17 @@ public: void resizeGL(int w, int h) override; void initializeGL() override; void paintGL() override; + std::vector> getBuffers() override; HardwareRenderer(QWidget* parent = nullptr, RenderType rtype = RenderType::OpenGL) : QOpenGLWindow(QOpenGLWindow::NoPartialUpdate, parent->windowHandle()), QOpenGLFunctions() { + imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + imagebufs[1] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); + setMinimumSize(QSize(16, 16)); setFlags(Qt::FramelessWindowHint); parentWidget = parent; @@ -71,9 +82,11 @@ public: void setRenderType(RenderType type); public slots: - void onBlit(const std::unique_ptr* img, int, int, int, int, std::atomic_flag* in_use); + void onBlit(int buf_idx, int x, int y, int w, int h); protected: + std::array, 2> imagebufs; + void resizeEvent(QResizeEvent *event) override; bool event(QEvent* event) override; }; diff --git a/src/qt/qt_renderercomon.cpp b/src/qt/qt_renderercomon.cpp index ed55e9a71..f094f7cbd 100644 --- a/src/qt/qt_renderercomon.cpp +++ b/src/qt/qt_renderercomon.cpp @@ -16,13 +16,6 @@ extern "C" { RendererCommon::RendererCommon() = default; 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) { double ratio; diff --git a/src/qt/qt_renderercomon.hpp b/src/qt/qt_renderercomon.hpp index 063d6f1bc..a62aa9aa2 100644 --- a/src/qt/qt_renderercomon.hpp +++ b/src/qt/qt_renderercomon.hpp @@ -4,6 +4,10 @@ #include #include +#include +#include +#include + class QWidget; class RendererCommon @@ -12,11 +16,12 @@ public: RendererCommon(); void onResize(int width, int height); + virtual std::vector> getBuffers() = 0; protected: - void onPaint(QPaintDevice* device); bool eventDelegate(QEvent* event, bool& result); - QImage image{QSize(2048, 2048), QImage::Format_RGB32}; QRect source, destination; QWidget* parentWidget{nullptr}; + + std::vector buf_usage; }; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 78e8e99d8..d11b4a0b5 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -27,12 +27,6 @@ RendererStack::RendererStack(QWidget *parent) : ui(new Ui::RendererStack) { 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(2); - buffers_in_use[0].clear(); - buffers_in_use[1].clear(); #ifdef WAYLAND if (QApplication::platformName().contains("wayland")) { @@ -182,7 +176,7 @@ void RendererStack::switchRenderer(Renderer renderer) { switch (renderer) { case Renderer::Software: { - auto sw = new SoftwareRenderer(this); + auto sw = new SoftwareRenderer(this); rendererWindow = sw; connect(this, &RendererStack::blitToRenderer, sw, &SoftwareRenderer::onBlit, Qt::QueuedConnection); current.reset(this->createWindowContainer(sw, this)); @@ -216,13 +210,14 @@ void RendererStack::switchRenderer(Renderer renderer) { break; } } + + imagebufs = std::move(rendererWindow->getBuffers()); + current->setFocusPolicy(Qt::NoFocus); current->setFocusProxy(this); addWidget(current.get()); this->setStyleSheet("background-color: black"); - for (auto& in_use : buffers_in_use) - in_use.clear(); endblit(); } @@ -230,7 +225,7 @@ void RendererStack::switchRenderer(Renderer renderer) { // 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) || buffers_in_use[currentBuf].test_and_set()) + if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || std::get(imagebufs[currentBuf])->test_and_set()) { video_blit_complete(); return; @@ -239,7 +234,7 @@ void RendererStack::blit(int x, int y, int w, int h) sy = y; sw = this->w = w; sh = this->h = h; - auto imagebits = imagebufs[currentBuf].get(); + uint8_t* imagebits = std::get(imagebufs[currentBuf]); for (int y1 = y; y1 < (y + h - 1); y1++) { 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_blit_complete(); - blitToRenderer(&imagebufs[currentBuf], sx, sy, sw, sh, &buffers_in_use[currentBuf]); - currentBuf = (currentBuf + 1) % 2; + emit blitToRenderer(currentBuf, sx, sy, sw, sh); + currentBuf = (currentBuf + 1) % imagebufs.size(); } diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 7a82fc527..46c004c0f 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace Ui { class RendererStack; @@ -46,7 +46,7 @@ public: RendererCommon* rendererWindow{nullptr}; signals: - void blitToRenderer(const std::unique_ptr* 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: 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 currentBuf = 0; - std::array, 2> imagebufs; + std::vector> imagebufs; std::unique_ptr current; - /* atomic flag for each buffer to not overload the renderer */ - std::vector buffers_in_use; - friend class MainWindow; }; diff --git a/src/qt/qt_softwarerenderer.cpp b/src/qt/qt_softwarerenderer.cpp index 962260fd8..3b7ccb2d6 100644 --- a/src/qt/qt_softwarerenderer.cpp +++ b/src/qt/qt_softwarerenderer.cpp @@ -1,20 +1,40 @@ #include "qt_softwarerenderer.hpp" #include +#include -SoftwareRenderer::SoftwareRenderer(QWidget *parent) : QRasterWindow(parent->windowHandle()) { parentWidget = parent; } +extern "C" { +#include <86box/86box.h> +#include <86box/video.h> +} -void SoftwareRenderer::paintEvent(QPaintEvent *event) { - (void) event; +SoftwareRenderer::SoftwareRenderer(QWidget *parent) + : QRasterWindow(parent->windowHandle()) +{ + parentWidget = parent; + + images[0] = std::make_unique(QSize(2048, 2048), QImage::Format_RGB32); + images[1] = std::make_unique(QSize(2048, 2048), QImage::Format_RGB32); + + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); +} + +void SoftwareRenderer::paintEvent(QPaintEvent* event) { + (void)event; onPaint(this); } -void SoftwareRenderer::onBlit(const std::unique_ptr* 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; void* nuldata = 0; if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return; - memcpy(image.bits(), img->get(), 2048 * 2048 * 4); - in_use->clear(); - source.setRect(x, y, w, h); + + cur_image = buf_idx; + buf_usage[(buf_idx + 1) % 2].clear(); + + source.setRect(x, y, w, h), update(); } @@ -29,3 +49,24 @@ bool SoftwareRenderer::event(QEvent *event) if (!eventDelegate(event, res)) return QRasterWindow::event(event); 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> SoftwareRenderer::getBuffers() +{ + std::vector> 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; +} \ No newline at end of file diff --git a/src/qt/qt_softwarerenderer.hpp b/src/qt/qt_softwarerenderer.hpp index c60ab110c..6daf18337 100644 --- a/src/qt/qt_softwarerenderer.hpp +++ b/src/qt/qt_softwarerenderer.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "qt_renderercomon.hpp" @@ -12,11 +14,18 @@ class SoftwareRenderer : public QRasterWindow, public RendererCommon public: explicit SoftwareRenderer(QWidget *parent = nullptr); - void paintEvent(QPaintEvent *event) override; + void paintEvent(QPaintEvent* event) override; + + std::vector> getBuffers() override; + public slots: - void onBlit(const std::unique_ptr* img, int, int, int, int, std::atomic_flag* in_use); + void onBlit(int buf_idx, int x, int y, int w, int h); protected: + std::array, 2> images; + int cur_image = -1; + + void onPaint(QPaintDevice* device); void resizeEvent(QResizeEvent *event) override; bool event(QEvent *event) override; };