qt: Initial OpenGL 3.0 renderer implementation
This commit is contained in:
@@ -21,8 +21,9 @@
|
||||
#include "qt_rendererstack.hpp"
|
||||
#include "ui_qt_rendererstack.h"
|
||||
|
||||
#include "qt_softwarerenderer.hpp"
|
||||
#include "qt_hardwarerenderer.hpp"
|
||||
#include "qt_openglrenderer.hpp"
|
||||
#include "qt_softwarerenderer.hpp"
|
||||
|
||||
#include "qt_mainwindow.hpp"
|
||||
#include "qt_util.hpp"
|
||||
@@ -32,34 +33,33 @@
|
||||
#include <QScreen>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
# include <CoreGraphics/CoreGraphics.h>
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include <86box/mouse.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/video.h>
|
||||
}
|
||||
|
||||
extern MainWindow* main_window;
|
||||
RendererStack::RendererStack(QWidget *parent) :
|
||||
QStackedWidget(parent),
|
||||
ui(new Ui::RendererStack)
|
||||
extern MainWindow *main_window;
|
||||
RendererStack::RendererStack(QWidget *parent)
|
||||
: QStackedWidget(parent)
|
||||
, ui(new Ui::RendererStack)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
#ifdef __unix__
|
||||
#ifdef WAYLAND
|
||||
# ifdef WAYLAND
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
wl_init();
|
||||
}
|
||||
#endif
|
||||
#ifdef EVDEV_INPUT
|
||||
# endif
|
||||
# ifdef EVDEV_INPUT
|
||||
if (QApplication::platformName() == "eglfs") {
|
||||
evdev_init();
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
if (QApplication::platformName() == "xcb") {
|
||||
extern void xinput2_init();
|
||||
xinput2_init();
|
||||
@@ -76,8 +76,7 @@ extern "C" void macos_poll_mouse();
|
||||
void
|
||||
qt_mouse_capture(int on)
|
||||
{
|
||||
if (!on)
|
||||
{
|
||||
if (!on) {
|
||||
mouse_capture = 0;
|
||||
QApplication::setOverrideCursor(Qt::ArrowCursor);
|
||||
#ifdef __APPLE__
|
||||
@@ -93,162 +92,193 @@ qt_mouse_capture(int on)
|
||||
return;
|
||||
}
|
||||
|
||||
void RendererStack::mousePoll()
|
||||
void
|
||||
RendererStack::mousePoll()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return macos_poll_mouse();
|
||||
#else /* !defined __APPLE__ */
|
||||
mouse_x = mousedata.deltax;
|
||||
mouse_y = mousedata.deltay;
|
||||
mouse_z = mousedata.deltaz;
|
||||
mouse_x = mousedata.deltax;
|
||||
mouse_y = mousedata.deltay;
|
||||
mouse_z = mousedata.deltaz;
|
||||
mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0;
|
||||
mouse_buttons = mousedata.mousebuttons;
|
||||
mouse_buttons = mousedata.mousebuttons;
|
||||
|
||||
#ifdef __unix__
|
||||
#ifdef WAYLAND
|
||||
# ifdef __unix__
|
||||
# ifdef WAYLAND
|
||||
if (QApplication::platformName().contains("wayland"))
|
||||
wl_mouse_poll();
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#ifdef EVDEV_INPUT
|
||||
if (QApplication::platformName() == "eglfs") evdev_mouse_poll();
|
||||
# ifdef EVDEV_INPUT
|
||||
if (QApplication::platformName() == "eglfs")
|
||||
evdev_mouse_poll();
|
||||
else
|
||||
#endif
|
||||
if (QApplication::platformName() == "xcb")
|
||||
{
|
||||
# endif
|
||||
if (QApplication::platformName() == "xcb") {
|
||||
extern void xinput2_poll();
|
||||
xinput2_poll();
|
||||
}
|
||||
#endif /* defined __unix__ */
|
||||
#endif /* !defined __APPLE__ */
|
||||
|
||||
# endif /* defined __unix__ */
|
||||
#endif /* !defined __APPLE__ */
|
||||
}
|
||||
|
||||
int ignoreNextMouseEvent = 1;
|
||||
void RendererStack::mouseReleaseEvent(QMouseEvent *event)
|
||||
void
|
||||
RendererStack::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1))
|
||||
{
|
||||
if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1)) {
|
||||
plat_mouse_capture(1);
|
||||
this->setCursor(Qt::BlankCursor);
|
||||
if (!ignoreNextMouseEvent) ignoreNextMouseEvent++; // Avoid jumping cursor when moved.
|
||||
if (!ignoreNextMouseEvent)
|
||||
ignoreNextMouseEvent++; // Avoid jumping cursor when moved.
|
||||
isMouseDown &= ~1;
|
||||
return;
|
||||
}
|
||||
if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3)
|
||||
{
|
||||
if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3) {
|
||||
plat_mouse_capture(0);
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
isMouseDown &= ~1;
|
||||
return;
|
||||
}
|
||||
if (mouse_capture)
|
||||
{
|
||||
if (mouse_capture) {
|
||||
mousedata.mousebuttons &= ~event->button();
|
||||
}
|
||||
isMouseDown &= ~1;
|
||||
}
|
||||
void RendererStack::mousePressEvent(QMouseEvent *event)
|
||||
void
|
||||
RendererStack::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
isMouseDown |= 1;
|
||||
if (mouse_capture)
|
||||
{
|
||||
if (mouse_capture) {
|
||||
mousedata.mousebuttons |= event->button();
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
void RendererStack::wheelEvent(QWheelEvent *event)
|
||||
void
|
||||
RendererStack::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
if (mouse_capture)
|
||||
{
|
||||
if (mouse_capture) {
|
||||
mousedata.deltaz += event->pixelDelta().y();
|
||||
}
|
||||
}
|
||||
|
||||
void RendererStack::mouseMoveEvent(QMouseEvent *event)
|
||||
void
|
||||
RendererStack::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (QApplication::platformName().contains("wayland"))
|
||||
{
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
if (!mouse_capture) { event->ignore(); return; }
|
||||
if (!mouse_capture) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
event->accept();
|
||||
return;
|
||||
#else
|
||||
static QPoint oldPos = QCursor::pos();
|
||||
if (ignoreNextMouseEvent) { oldPos = event->pos(); ignoreNextMouseEvent--; event->accept(); return; }
|
||||
if (ignoreNextMouseEvent) {
|
||||
oldPos = event->pos();
|
||||
ignoreNextMouseEvent--;
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
mousedata.deltax += event->pos().x() - oldPos.x();
|
||||
mousedata.deltay += event->pos().y() - oldPos.y();
|
||||
if (QApplication::platformName() == "eglfs")
|
||||
{
|
||||
leaveEvent((QEvent*)event);
|
||||
if (QApplication::platformName() == "eglfs") {
|
||||
leaveEvent((QEvent *) event);
|
||||
ignoreNextMouseEvent--;
|
||||
}
|
||||
QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2)));
|
||||
ignoreNextMouseEvent = 2;
|
||||
oldPos = event->pos();
|
||||
oldPos = event->pos();
|
||||
#endif
|
||||
}
|
||||
|
||||
void RendererStack::leaveEvent(QEvent* event)
|
||||
void
|
||||
RendererStack::leaveEvent(QEvent *event)
|
||||
{
|
||||
if (QApplication::platformName().contains("wayland"))
|
||||
{
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
if (!mouse_capture) return;
|
||||
if (!mouse_capture)
|
||||
return;
|
||||
ignoreNextMouseEvent = 2;
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void RendererStack::switchRenderer(Renderer renderer) {
|
||||
void
|
||||
RendererStack::switchRenderer(Renderer renderer)
|
||||
{
|
||||
startblit();
|
||||
if (current) {
|
||||
rendererWindow->finalize();
|
||||
removeWidget(current.get());
|
||||
}
|
||||
disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr);
|
||||
|
||||
/* Create new renderer only after previous is destroyed! */
|
||||
connect(current.get(), &QObject::destroyed, [this, renderer](QObject *) { createRenderer(renderer); });
|
||||
|
||||
current.release()->deleteLater();
|
||||
} else {
|
||||
createRenderer(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RendererStack::createRenderer(Renderer renderer)
|
||||
{
|
||||
switch (renderer) {
|
||||
case Renderer::Software:
|
||||
{
|
||||
auto sw = new SoftwareRenderer(this);
|
||||
rendererWindow = sw;
|
||||
connect(this, &RendererStack::blitToRenderer, sw, &SoftwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(sw, this));
|
||||
case Renderer::Software:
|
||||
{
|
||||
auto sw = new SoftwareRenderer(this);
|
||||
rendererWindow = sw;
|
||||
connect(this, &RendererStack::blitToRenderer, sw, &SoftwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(sw, this));
|
||||
}
|
||||
break;
|
||||
case Renderer::OpenGL:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new HardwareRenderer(this);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(hw, this));
|
||||
break;
|
||||
}
|
||||
case Renderer::OpenGLES:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new HardwareRenderer(this, HardwareRenderer::RenderType::OpenGLES);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(hw, this));
|
||||
break;
|
||||
}
|
||||
case Renderer::OpenGL3:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new OpenGLRenderer(this);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection);
|
||||
connect(hw, &OpenGLRenderer::initialized, [=]() {
|
||||
/* Buffers are awailable only after initialization. */
|
||||
imagebufs = rendererWindow->getBuffers();
|
||||
endblit();
|
||||
emit rendererChanged();
|
||||
});
|
||||
connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
|
||||
/* Renderer could initialize, fallback to software. */
|
||||
endblit();
|
||||
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
|
||||
});
|
||||
current.reset(this->createWindowContainer(hw, this));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Renderer::OpenGL:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new HardwareRenderer(this);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(hw, this));
|
||||
break;
|
||||
}
|
||||
case Renderer::OpenGLES:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new HardwareRenderer(this, HardwareRenderer::RenderType::OpenGLES);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(hw, this));
|
||||
break;
|
||||
}
|
||||
case Renderer::OpenGL3:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new HardwareRenderer(this, HardwareRenderer::RenderType::OpenGL3);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
||||
current.reset(this->createWindowContainer(hw, this));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
imagebufs = std::move(rendererWindow->getBuffers());
|
||||
|
||||
current->setFocusPolicy(Qt::NoFocus);
|
||||
current->setFocusProxy(this);
|
||||
@@ -256,31 +286,35 @@ void RendererStack::switchRenderer(Renderer renderer) {
|
||||
|
||||
this->setStyleSheet("background-color: black");
|
||||
|
||||
endblit();
|
||||
currentBuf = 0;
|
||||
|
||||
if (renderer != Renderer::OpenGL3) {
|
||||
imagebufs = rendererWindow->getBuffers();
|
||||
endblit();
|
||||
emit rendererChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// 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) || std::get<std::atomic_flag*>(imagebufs[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();
|
||||
return;
|
||||
}
|
||||
sx = x;
|
||||
sy = y;
|
||||
sw = this->w = w;
|
||||
sh = this->h = h;
|
||||
uint8_t* imagebits = std::get<uint8_t*>(imagebufs[currentBuf]);
|
||||
for (int y1 = y; y1 < (y + h); y1++)
|
||||
{
|
||||
sh = this->h = h;
|
||||
uint8_t *imagebits = std::get<uint8_t *>(imagebufs[currentBuf]);
|
||||
for (int y1 = y; y1 < (y + h); y1++) {
|
||||
auto scanline = imagebits + (y1 * (2048) * 4) + (x * 4);
|
||||
video_copy(scanline, &(buffer32->line[y1][x]), w * 4);
|
||||
}
|
||||
|
||||
if (screenshots)
|
||||
{
|
||||
video_screenshot((uint32_t *)imagebits, x, y, 2048);
|
||||
if (screenshots) {
|
||||
video_screenshot((uint32_t *) imagebits, x, y, 2048);
|
||||
}
|
||||
video_blit_complete();
|
||||
emit blitToRenderer(currentBuf, sx, sy, sw, sh);
|
||||
|
||||
Reference in New Issue
Block a user