This commit is contained in:
ts-korhonen
2021-12-25 21:35:50 +02:00
9 changed files with 159 additions and 35 deletions

View File

@@ -5,6 +5,7 @@
#if !defined(_WIN32) || !defined(__clang__) #if !defined(_WIN32) || !defined(__clang__)
#include <strings.h> #include <strings.h>
#endif #endif
#include <string.h>
#include <stdint.h> #include <stdint.h>
#include <wchar.h> #include <wchar.h>

View File

@@ -1,10 +1,12 @@
#include "qt_hardwarerenderer.hpp" #include "qt_hardwarerenderer.hpp"
#include <QApplication> #include <QApplication>
#include <QVector2D>
#include <atomic> #include <atomic>
extern "C" { extern "C" {
#include <86box/86box.h> #include <86box/86box.h>
#include <86box/plat.h> #include <86box/plat.h>
#include <86box/video.h>
} }
void HardwareRenderer::resizeGL(int w, int h) void HardwareRenderer::resizeGL(int w, int h)
@@ -12,14 +14,74 @@ void HardwareRenderer::resizeGL(int w, int h)
glViewport(0, 0, w, h); glViewport(0, 0, w, h);
} }
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
void HardwareRenderer::initializeGL() void HardwareRenderer::initializeGL()
{ {
m_context->makeCurrent(this); m_context->makeCurrent(this);
initializeOpenGLFunctions(); initializeOpenGLFunctions();
m_texture = new QOpenGLTexture(image);
m_blt = new QOpenGLTextureBlitter;
m_blt->setRedBlueSwizzle(true);
m_blt->create();
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char *vsrc =
"attribute highp vec4 vertex;\n"
"attribute mediump vec4 texCoord;\n"
"varying mediump vec4 texc;\n"
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * vertex;\n"
" texc = texCoord;\n"
"}\n";
vshader->compileSourceCode(vsrc);
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char *fsrc =
"uniform sampler2D texture;\n"
"varying mediump vec4 texc;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc.st).bgra;\n"
"}\n";
fshader->compileSourceCode(fsrc);
m_prog = new QOpenGLShaderProgram;
m_prog->addShader(vshader);
m_prog->addShader(fshader);
m_prog->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
m_prog->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
m_prog->link();
m_prog->bind();
m_prog->setUniformValue("texture", 0);
} }
void HardwareRenderer::paintGL() { void HardwareRenderer::paintGL() {
onPaint(this); m_context->makeCurrent(this);
QVector<QVector2D> verts, texcoords;
QMatrix4x4 mat;
mat.setToIdentity();
mat.ortho(QRect(0, 0, width(), height()));
verts.push_back(QVector2D((float)destination.x(), (float)destination.y()));
verts.push_back(QVector2D((float)destination.x(), (float)destination.y() + destination.height()));
verts.push_back(QVector2D((float)destination.x() + destination.width(), (float)destination.y() + destination.height()));
verts.push_back(QVector2D((float)destination.x() + destination.width(), (float)destination.y()));
texcoords.push_back(QVector2D((float)source.x() / 2048.f, (float)(source.y()) / 2048.f));
texcoords.push_back(QVector2D((float)source.x() / 2048.f, (float)(source.y() + source.height()) / 2048.f));
texcoords.push_back(QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y() + source.height()) / 2048.f));
texcoords.push_back(QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y()) / 2048.f));
m_prog->setUniformValue("matrix", mat);
m_prog->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
m_prog->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
m_prog->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, verts.data());
m_prog->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, texcoords.data());
m_texture->bind();
m_texture->setMinMagFilters(video_filter_method ? QOpenGLTexture::Linear : QOpenGLTexture::Nearest, video_filter_method ? QOpenGLTexture::Linear : QOpenGLTexture::Nearest);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
} }
void HardwareRenderer::setRenderType(RenderType type) { void HardwareRenderer::setRenderType(RenderType type) {
@@ -37,7 +99,11 @@ void HardwareRenderer::setRenderType(RenderType type) {
} }
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(const std::unique_ptr<uint8_t>* img, int x, int y, int w, int h, std::atomic_flag* in_use) {
memcpy(image.bits(), img->get(), 2048 * 2048 * 4); auto tval = this;
void* nuldata = 0;
if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return;
m_context->makeCurrent(this);
m_texture->setData(QOpenGLTexture::PixelFormat::RGBA, QOpenGLTexture::PixelType::UInt8, (const void*)img->get());
in_use->clear(); in_use->clear();
source.setRect(x, y, w, h); source.setRect(x, y, w, h);
update(); update();

View File

@@ -3,6 +3,10 @@
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLWindow> #include <QOpenGLWindow>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QOpenGLTextureBlitter>
#include <QPainter> #include <QPainter>
#include <QEvent> #include <QEvent>
#include <QKeyEvent> #include <QKeyEvent>
@@ -25,6 +29,9 @@ private:
bool wayland = false; bool wayland = false;
QWidget* parentWidget{nullptr}; QWidget* parentWidget{nullptr};
QOpenGLContext* m_context; QOpenGLContext* m_context;
QOpenGLTexture* m_texture;
QOpenGLShaderProgram* m_prog;
QOpenGLTextureBlitter* m_blt;
public: public:
void resizeGL(int w, int h) override; void resizeGL(int w, int h) override;
void initializeGL() override; void initializeGL() override;
@@ -41,7 +48,8 @@ public:
} }
~HardwareRenderer() ~HardwareRenderer()
{ {
makeCurrent(); m_context->makeCurrent(this);
if (m_blt) m_blt->destroy();
} }
enum class RenderType { enum class RenderType {

View File

@@ -1,4 +1,5 @@
#include <QApplication> #include <QApplication>
#include <QSurfaceFormat>
#include <QDebug> #include <QDebug>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QThread> #include <QThread>
@@ -94,6 +95,9 @@ main_thread_fn()
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QApplication app(argc, argv); QApplication app(argc, argv);
QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
fmt.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(fmt);
app.setStyle(new StyleOverride()); app.setStyle(new StyleOverride());
#ifdef __APPLE__ #ifdef __APPLE__
CocoaEventFilter cocoafilter; CocoaEventFilter cocoafilter;
@@ -101,9 +105,16 @@ int main(int argc, char* argv[]) {
#endif #endif
elapsed_timer.start(); elapsed_timer.start();
pc_init(argc, argv); if (!pc_init(argc, argv))
{
return 0;
}
if (! pc_init_modules()) { if (! pc_init_modules()) {
#ifdef Q_OS_MACOS
ui_msgbox_header(MBX_FATAL, VC(L"No ROMs found."), VC(L"86Box could not find any usable ROM images.\n\nPlease <a href='https://github.com/86Box/roms/releases/latest'>download</a> a ROM set and extract it into the \"~/Library/Application Support/net.86box.86box/roms\" directory."));
#else
ui_msgbox_header(MBX_FATAL, VC(L"No ROMs found."), VC(L"86Box could not find any usable ROM images.\n\nPlease <a href='https://github.com/86Box/roms/releases/latest'>download</a> a ROM set and extract it into the \"roms\" directory.")); ui_msgbox_header(MBX_FATAL, VC(L"No ROMs found."), VC(L"86Box could not find any usable ROM images.\n\nPlease <a href='https://github.com/86Box/roms/releases/latest'>download</a> a ROM set and extract it into the \"roms\" directory."));
#endif
return 6; return 6;
} }
@@ -134,6 +145,7 @@ int main(int argc, char* argv[]) {
/* Set the PAUSE mode depending on the renderer. */ /* Set the PAUSE mode depending on the renderer. */
// plat_pause(0); // plat_pause(0);
if (settings_only) dopause = 1;
QTimer onesec; QTimer onesec;
QObject::connect(&onesec, &QTimer::timeout, &app, [] { QObject::connect(&onesec, &QTimer::timeout, &app, [] {
pc_onesec(); pc_onesec();

View File

@@ -138,6 +138,17 @@ MainWindow::MainWindow(QWidget *parent) :
ui->actionHiDPI_scaling->setChecked(dpi_scale); ui->actionHiDPI_scaling->setChecked(dpi_scale);
ui->actionHide_status_bar->setChecked(hide_status_bar); ui->actionHide_status_bar->setChecked(hide_status_bar);
ui->actionUpdate_status_bar_icons->setChecked(update_icons); ui->actionUpdate_status_bar_icons->setChecked(update_icons);
#if defined Q_OS_WINDOWS || defined Q_OS_MACOS
/* Make the option visible only if ANGLE is loaded. */
ui->actionHardware_Renderer_OpenGL_ES->setVisible(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES);
if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGLES && vid_api == 2) vid_api = 1;
#endif
if (QApplication::platformName().contains("eglfs") && vid_api >= 1) {
fprintf(stderr, "OpenGL renderers are unsupported on EGLFS.\n");
vid_api = 0;
}
QActionGroup* actGroup = nullptr; QActionGroup* actGroup = nullptr;
switch (vid_api) { switch (vid_api) {
case 0: case 0:
@@ -254,11 +265,6 @@ MainWindow::MainWindow(QWidget *parent) :
ui->actionChange_contrast_for_monochrome_display->setChecked(true); ui->actionChange_contrast_for_monochrome_display->setChecked(true);
} }
#if defined Q_OS_WINDOWS || defined Q_OS_MACOS
/* Make the option visible only if ANGLE is loaded. */
ui->actionHardware_Renderer_OpenGL_ES->setVisible(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES);
#endif
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
ui->stackedWidget->setFocusPolicy(Qt::NoFocus); ui->stackedWidget->setFocusPolicy(Qt::NoFocus);
ui->centralwidget->setFocusPolicy(Qt::NoFocus); ui->centralwidget->setFocusPolicy(Qt::NoFocus);
@@ -270,7 +276,7 @@ MainWindow::MainWindow(QWidget *parent) :
} }
void MainWindow::closeEvent(QCloseEvent *event) { void MainWindow::closeEvent(QCloseEvent *event) {
if (confirm_exit) if (confirm_exit && cpu_thread_run)
{ {
QMessageBox questionbox(QMessageBox::Icon::Question, "86Box", "Are you sure you want to exit 86Box?", QMessageBox::Yes | QMessageBox::No, this); QMessageBox questionbox(QMessageBox::Icon::Question, "86Box", "Are you sure you want to exit 86Box?", QMessageBox::Yes | QMessageBox::No, this);
QCheckBox *chkbox = new QCheckBox("Do not ask me again"); QCheckBox *chkbox = new QCheckBox("Do not ask me again");
@@ -310,7 +316,7 @@ void MainWindow::showEvent(QShowEvent *event) {
setGeometry(window_x, window_y, window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height())); setGeometry(window_x, window_y, window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()));
} }
if (vid_resize == 2) { if (vid_resize == 2) {
setFixedSize(fixed_size_x, fixed_size_y + this->menuBar()->height() + this->statusBar()->height()); setFixedSize(fixed_size_x, fixed_size_y + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()));
scrnsz_x = fixed_size_x; scrnsz_x = fixed_size_x;
scrnsz_y = fixed_size_y; scrnsz_y = fixed_size_y;
} }
@@ -374,6 +380,10 @@ void MainWindow::on_actionSettings_triggered() {
break; break;
} }
plat_pause(currentPause); plat_pause(currentPause);
if (settings_only) {
cpu_thread_run = 0;
close();
}
} }
std::array<uint32_t, 256> x11_to_xt_base std::array<uint32_t, 256> x11_to_xt_base
@@ -861,10 +871,11 @@ static std::array<uint32_t, 256>& selected_keycode = x11_to_xt_base;
uint16_t x11_keycode_to_keysym(uint32_t keycode) uint16_t x11_keycode_to_keysym(uint32_t keycode)
{ {
uint16_t finalkeycode = 0;
#if defined(Q_OS_WINDOWS) #if defined(Q_OS_WINDOWS)
return keycode & 0xFFFF; finalkeycode = (keycode & 0xFFFF);
#elif defined(__APPLE__) #elif defined(__APPLE__)
return darwin_to_xt[keycode]; finalkeycode = darwin_to_xt[keycode];
#else #else
static Display* x11display = nullptr; static Display* x11display = nullptr;
if (QApplication::platformName().contains("wayland")) if (QApplication::platformName().contains("wayland"))
@@ -874,8 +885,8 @@ uint16_t x11_keycode_to_keysym(uint32_t keycode)
else if (QApplication::platformName().contains("eglfs")) else if (QApplication::platformName().contains("eglfs"))
{ {
keycode -= 8; keycode -= 8;
if (keycode <= 88) return keycode; if (keycode <= 88) finalkeycode = keycode;
else return evdev_to_xt[keycode]; else finalkeycode = evdev_to_xt[keycode];
} }
else if (!x11display) else if (!x11display)
{ {
@@ -889,18 +900,27 @@ uint16_t x11_keycode_to_keysym(uint32_t keycode)
selected_keycode = x11_to_xt_vnc; selected_keycode = x11_to_xt_vnc;
} }
} }
return selected_keycode[keycode]; if (!QApplication::platformName().contains("eglfs")) finalkeycode = selected_keycode[keycode];
#endif #endif
if (rctrl_is_lalt && finalkeycode == 0x11D)
{
finalkeycode = 0x38;
}
return finalkeycode;
} }
void MainWindow::on_actionFullscreen_triggered() { void MainWindow::on_actionFullscreen_triggered() {
if (video_fullscreen > 0) { if (video_fullscreen > 0) {
showNormal(); showNormal();
ui->menubar->show(); ui->menubar->show();
ui->statusbar->show(); if (!hide_status_bar) ui->statusbar->show();
video_fullscreen = 0; video_fullscreen = 0;
setGeometry(geometry()); if (vid_resize != 1) {
if (vid_resize == 2) setFixedSize(fixed_size_x, fixed_size_y + menuBar()->height() + (!hide_status_bar ? statusBar()->height() : 0));
emit resizeContents(scrnsz_x, scrnsz_y);
}
} else { } else {
setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
ui->menubar->hide(); ui->menubar->hide();
ui->statusbar->hide(); ui->statusbar->hide();
showFullScreen(); showFullScreen();
@@ -963,7 +983,7 @@ void MainWindow::showMessage_(const QString &header, const QString &message) {
void MainWindow::keyPressEvent(QKeyEvent* event) void MainWindow::keyPressEvent(QKeyEvent* event)
{ {
if (send_keyboard_input) if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen))
{ {
#ifdef __APPLE__ #ifdef __APPLE__
keyboard_input(1, x11_keycode_to_keysym(event->nativeVirtualKey())); keyboard_input(1, x11_keycode_to_keysym(event->nativeVirtualKey()));
@@ -1027,7 +1047,8 @@ void MainWindow::on_actionHardware_Renderer_OpenGL_ES_triggered() {
void MainWindow::focusInEvent(QFocusEvent* event) void MainWindow::focusInEvent(QFocusEvent* event)
{ {
this->grabKeyboard(); if (settings_only) ui->actionSettings->trigger();
else this->grabKeyboard();
} }
void MainWindow::focusOutEvent(QFocusEvent* event) void MainWindow::focusOutEvent(QFocusEvent* event)
@@ -1047,6 +1068,7 @@ void MainWindow::on_actionResizable_window_triggered(bool checked) {
setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); setWindowFlag(Qt::MSWindowsFixedSizeDialogHint);
} }
show(); show();
ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api);
ui->menuWindow_scale_factor->setEnabled(! checked); ui->menuWindow_scale_factor->setEnabled(! checked);
emit resizeContents(scrnsz_x, scrnsz_y); emit resizeContents(scrnsz_x, scrnsz_y);

View File

@@ -11,16 +11,20 @@
#include <QFileInfo> #include <QFileInfo>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDateTime>
#include <QLibrary> #include <QLibrary>
#include <QElapsedTimer> #include <QElapsedTimer>
#include "qt_mainwindow.hpp"
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
// static QByteArray buf; // static QByteArray buf;
extern QElapsedTimer elapsed_timer; extern QElapsedTimer elapsed_timer;
extern MainWindow* main_window;
QElapsedTimer elapsed_timer; QElapsedTimer elapsed_timer;
static std::atomic_int blitmx_contention = 0; static std::atomic_int blitmx_contention = 0;
@@ -50,6 +54,8 @@ extern "C" {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
#define NOMINMAX #define NOMINMAX
#include <windows.h> #include <windows.h>
#else
#include <strings.h>
#endif #endif
#include <86box/86box.h> #include <86box/86box.h>
#include <86box/device.h> #include <86box/device.h>
@@ -75,14 +81,20 @@ uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for
int stricmp(const char* s1, const char* s2) int stricmp(const char* s1, const char* s2)
{ {
return QByteArray(s1).compare(s2, Qt::CaseInsensitive); #ifdef Q_OS_WINDOWS
return _stricmp(s1, s2);
#else
return strcasecmp(s1, s2);
#endif
} }
int strnicmp(const char *s1, const char *s2, size_t n) int strnicmp(const char *s1, const char *s2, size_t n)
{ {
QByteArray b1(s1, std::min(strlen(s1), n)); #ifdef Q_OS_WINDOWS
QByteArray b2(s2, std::min(strlen(s2), n)); return _strnicmp(s1, s2, n);
return b1.compare(b2, Qt::CaseInsensitive); #else
return strncasecmp(s1, s2, n);
#endif
} }
void void
@@ -283,14 +295,9 @@ plat_tempfile(char *bufp, char *prefix, char *suffix)
name.append(QString("%1-").arg(prefix)); name.append(QString("%1-").arg(prefix));
} }
name.append("XXXXXX"); name.append(QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss-zzzz"));
if (suffix) name.append(suffix);
if (suffix != nullptr) { sprintf(&bufp[strlen(bufp)], "%s", name.toUtf8().data());
name.append(suffix);
}
QTemporaryFile temp(name);
QByteArray buf(bufp);
buf = temp.fileName().toUtf8();
} }
void plat_remove(char* path) void plat_remove(char* path)
@@ -359,6 +366,7 @@ plat_power_off(void)
cycles -= 99999999; cycles -= 99999999;
cpu_thread_run = 0; cpu_thread_run = 0;
main_window->close();
} }
void set_language(uint32_t id) { void set_language(uint32_t id) {

View File

@@ -203,6 +203,7 @@ void RendererStack::switchRenderer(Renderer renderer) {
current->setFocusProxy(this); current->setFocusProxy(this);
addWidget(current.get()); addWidget(current.get());
this->setStyleSheet("background-color: black");
for (auto& in_use : buffers_in_use) for (auto& in_use : buffers_in_use)
in_use.clear(); in_use.clear();
@@ -226,7 +227,7 @@ void RendererStack::blit(int x, int y, int w, int h)
if (screenshots) if (screenshots)
{ {
video_screenshot((uint32_t *)imagebits, 0, 0, 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]); blitToRenderer(&imagebufs[currentBuf], sx, sy, sw, sh, &buffers_in_use[currentBuf]);

View File

@@ -8,6 +8,9 @@ void SoftwareRenderer::paintEvent(QPaintEvent *event) {
} }
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(const std::unique_ptr<uint8_t>* img, int x, int y, int w, int h, std::atomic_flag* in_use) {
auto tval = this;
void* nuldata = 0;
if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return;
memcpy(image.bits(), img->get(), 2048 * 2048 * 4); memcpy(image.bits(), img->get(), 2048 * 2048 * 4);
in_use->clear(); in_use->clear();
source.setRect(x, y, w, h); source.setRect(x, y, w, h);

View File

@@ -45,14 +45,17 @@ void SpecifyDimensions::on_SpecifyDimensions_accepted()
window_remember = 0; window_remember = 0;
fixed_size_x = ui->spinBoxWidth->value(); fixed_size_x = ui->spinBoxWidth->value();
fixed_size_y = ui->spinBoxHeight->value(); fixed_size_y = ui->spinBoxHeight->value();
main_window->setFixedSize(ui->spinBoxWidth->value(), ui->spinBoxHeight->value() + (hide_status_bar ? main_window->statusBar()->height() : 0) + main_window->menuBar()->height()); main_window->setFixedSize(ui->spinBoxWidth->value(), ui->spinBoxHeight->value() + (!hide_status_bar ? main_window->statusBar()->height() : 0) + main_window->menuBar()->height());
emit main_window->updateMenuResizeOptions(); emit main_window->updateMenuResizeOptions();
main_window->show(); main_window->show();
main_window->ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api);
} }
else else
{ {
if (vid_resize != 1) main_window->ui->actionResizable_window->trigger(); main_window->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
main_window->ui->actionResizable_window->setChecked(false);
vid_resize = 0; vid_resize = 0;
main_window->ui->actionResizable_window->trigger();
window_remember = 1; window_remember = 1;
window_w = ui->spinBoxWidth->value(); window_w = ui->spinBoxWidth->value();
window_h = ui->spinBoxHeight->value(); window_h = ui->spinBoxHeight->value();