Cleanups, copyright headers and name changing for PRing

This commit is contained in:
Cacodemon345
2025-03-10 20:54:25 +06:00
parent 1ed579a0fc
commit 81461f677d
17 changed files with 136 additions and 1453 deletions

View File

@@ -172,7 +172,6 @@ int force_43 = 0; /* (C) video *
int video_filter_method = 1; /* (C) video */ int video_filter_method = 1; /* (C) video */
int video_vsync = 0; /* (C) video */ int video_vsync = 0; /* (C) video */
int video_framerate = -1; /* (C) video */ int video_framerate = -1; /* (C) video */
char video_shader[512] = { '\0' }; /* (C) video */
bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of
pass-through for serial ports */ pass-through for serial ports */
int bugger_enabled = 0; /* (C) enable ISAbugger */ int bugger_enabled = 0; /* (C) enable ISAbugger */

View File

@@ -200,7 +200,6 @@ load_general(void)
video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1); video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1);
video_vsync = ini_section_get_int(cat, "video_gl_vsync", 0); video_vsync = ini_section_get_int(cat, "video_gl_vsync", 0);
strncpy(video_shader, ini_section_get_string(cat, "video_gl_shader", ""), sizeof(video_shader) - 1);
window_remember = ini_section_get_int(cat, "window_remember", 0); window_remember = ini_section_get_int(cat, "window_remember", 0);
if (window_remember) { if (window_remember) {
@@ -1733,7 +1732,19 @@ load_gl3_shaders(void)
if (shaders > MAX_USER_SHADERS) if (shaders > MAX_USER_SHADERS)
shaders = MAX_USER_SHADERS; shaders = MAX_USER_SHADERS;
for (int i = 0; i < shaders; i++) { if (shaders == 0) {
ini_section_t general = ini_find_section(config, "General");
if (general) {
p = ini_section_get_string(general, "video_gl_shader", NULL);
if (p) {
strncpy(gl3_shader_file[0], p, 512);
ini_delete_var(config, general, "video_gl_shader");
return;
}
}
}
for (i = 0; i < shaders; i++) {
temp[0] = 0; temp[0] = 0;
snprintf(temp, 512, "shader%d", i); snprintf(temp, 512, "shader%d", i);
p = ini_section_get_string(cat, temp, ""); p = ini_section_get_string(cat, temp, "");
@@ -2035,10 +2046,6 @@ save_general(void)
ini_section_set_int(cat, "video_gl_vsync", video_vsync); ini_section_set_int(cat, "video_gl_vsync", video_vsync);
else else
ini_section_delete_var(cat, "video_gl_vsync"); ini_section_delete_var(cat, "video_gl_vsync");
if (strlen(video_shader) > 0)
ini_section_set_string(cat, "video_gl_shader", video_shader);
else
ini_section_delete_var(cat, "video_gl_shader");
if (do_auto_pause) if (do_auto_pause)
ini_section_set_int(cat, "do_auto_pause", do_auto_pause); ini_section_set_int(cat, "do_auto_pause", do_auto_pause);

View File

@@ -126,7 +126,6 @@ extern int video_filter_method; /* (C) video */
extern int video_vsync; /* (C) video */ extern int video_vsync; /* (C) video */
extern int video_framerate; /* (C) video */ extern int video_framerate; /* (C) video */
extern int gfxcard[GFXCARD_MAX]; /* (C) graphics/video card */ extern int gfxcard[GFXCARD_MAX]; /* (C) graphics/video card */
extern char video_shader[512]; /* (C) video */
extern int bugger_enabled; /* (C) enable ISAbugger */ extern int bugger_enabled; /* (C) enable ISAbugger */
extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */ extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */
extern int postcard_enabled; /* (C) enable POST card */ extern int postcard_enabled; /* (C) enable POST card */

View File

@@ -92,36 +92,6 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name);
extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_rename_section(ini_section_t section, const char *name);
extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section);
static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; }
static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
char* str = ini_get_string((ini_t)config, "", name, (char*)defVal);
if (size == 0)
return res;
if (str != NULL)
strncpy(dst, str, size - 1);
else
dst[0] = 0;
return res;
}
static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
*dst = ini_get_int((ini_t)config, "", name, defVal);
return res;
}
static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
*dst = (float)ini_get_double((ini_t)config, "", name, defVal);
return res;
}
static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
*dst = !!ini_get_int((ini_t)config, "", name, defVal);
return res;
}
static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); }
static inline void wx_config_free(void *config) { ini_close(config); };
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -162,7 +162,6 @@ ini_has_entry(ini_section_t self, const char *name)
{ {
section_t *section = (section_t *) self; section_t *section = (section_t *) self;
const entry_t *entry; const entry_t *entry;
int value = 0;
if (section == NULL) if (section == NULL)
return 0; return 0;
@@ -546,6 +545,7 @@ ini_write(ini_t ini, const char *fn)
(void) fclose(fp); (void) fclose(fp);
} }
/* Wide-character version of "trim" */
wchar_t * wchar_t *
trim_w(wchar_t *str) trim_w(wchar_t *str)
{ {
@@ -609,7 +609,6 @@ ini_strip_quotes(ini_t ini)
ent = (entry_t *) sec->entry_head.next; ent = (entry_t *) sec->entry_head.next;
while (ent != NULL) { while (ent != NULL) {
if (ent->name[0] != '\0') { if (ent->name[0] != '\0') {
int i = 0;
int trailing_hash = strcspn(ent->data, "#"); int trailing_hash = strcspn(ent->data, "#");
int trailing_quote; int trailing_quote;
ent->wdata[trailing_hash] = 0; ent->wdata[trailing_hash] = 0;

View File

@@ -87,16 +87,9 @@ add_library(ui STATIC
qt_softwarerenderer.hpp qt_softwarerenderer.hpp
qt_hardwarerenderer.cpp qt_hardwarerenderer.cpp
qt_hardwarerenderer.hpp qt_hardwarerenderer.hpp
qt_openglrenderer.cpp
qt_openglrenderer.hpp
qt_openglrenderer_pcem.cpp qt_openglrenderer_pcem.cpp
qt_openglrenderer_pcem.hpp qt_openglrenderer_pcem.hpp
qt_glsl_parser.cpp qt_glsl_parser.cpp
qt_opengloptions.cpp
qt_opengloptions.hpp
qt_opengloptionsdialog.cpp
qt_opengloptionsdialog.hpp
qt_opengloptionsdialog.ui
qt_settings.cpp qt_settings.cpp
qt_settings.hpp qt_settings.hpp
@@ -197,7 +190,10 @@ add_library(ui STATIC
qt_openglshadermanagerdialog.hpp qt_openglshadermanagerdialog.hpp
qt_openglshadermanagerdialog.cpp qt_openglshadermanagerdialog.cpp
qt_openglshadermanagerdialog.ui qt_openglshadermanagerdialog.ui
qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui
qt_openglshaderconfig.hpp
qt_openglshaderconfig.cpp
qt_openglshaderconfig.ui
) )
if(RTMIDI) if(RTMIDI)

View File

@@ -28,6 +28,43 @@ extern void endblit();
(a)[(n)-1] = 0; \ (a)[(n)-1] = 0; \
} while (0) } while (0)
static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; }
static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
char* str = ini_get_string((ini_t)config, "", name, (char*)defVal);
if (size == 0)
return res;
if (str != NULL)
strncpy(dst, str, size - 1);
else
dst[0] = 0;
return res;
}
static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
*dst = ini_get_int((ini_t)config, "", name, defVal);
return res;
}
static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
*dst = (float)ini_get_double((ini_t)config, "", name, defVal);
return res;
}
static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) {
int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name);
*dst = !!ini_get_int((ini_t)config, "", name, defVal);
return res;
}
static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); }
static inline void wx_config_free(void *config) { ini_close(config); };
static int endswith(const char *str, const char *ext) { static int endswith(const char *str, const char *ext) {
int i; int i;
const char *p; const char *p;

View File

@@ -1,196 +0,0 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* OpenGL renderer options for Qt
*
*
*
* Authors: Teemu Korhonen
*
* Copyright 2022 Teemu Korhonen
*/
#include <QByteArray>
#include <QFile>
#include <QRegularExpression>
#include <QStringBuilder>
#include <stdexcept>
#include "qt_opengloptions.hpp"
extern "C" {
#include <86box/86box.h>
}
/* Default vertex shader. */
static const GLchar *vertex_shader = "\
in vec2 VertexCoord;\n\
in vec2 TexCoord;\n\
out vec2 tex;\n\
void main(){\n\
gl_Position = vec4(VertexCoord, 0.0, 1.0);\n\
tex = TexCoord;\n\
}\n";
/* Default fragment shader. */
static const GLchar *fragment_shader = "\
in vec2 tex;\n\
uniform sampler2D texsampler;\n\
out vec4 color;\n\
void main() {\n\
color = texture(texsampler, tex);\n\
}\n";
OpenGLOptions::OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion)
: QObject(parent)
, m_glslVersion(glslVersion)
{
m_filter = video_filter_method == 0
? FilterType::Nearest
: FilterType::Linear;
if (!loadConfig)
return;
/* Initialize with config. */
m_vsync = video_vsync != 0;
m_framerate = video_framerate;
m_renderBehavior = video_framerate == -1
? RenderBehaviorType::SyncWithVideo
: RenderBehaviorType::TargetFramerate;
QString shaderPath(video_shader);
if (shaderPath.isEmpty()) {
addDefaultShader();
} else {
try {
addShader(shaderPath);
} catch (const std::runtime_error &) {
/* Fallback to default shader */
addDefaultShader();
}
}
}
void
OpenGLOptions::save() const
{
video_vsync = m_vsync ? 1 : 0;
video_framerate = m_renderBehavior == RenderBehaviorType::SyncWithVideo ? -1 : m_framerate;
video_filter_method = m_filter == FilterType::Nearest ? 0 : 1;
/* TODO: multiple shaders */
auto path = m_shaders.first().path().toLocal8Bit();
if (!path.isEmpty())
qstrncpy(video_shader, path.constData(), sizeof(video_shader));
else
video_shader[0] = '\0';
}
OpenGLOptions::FilterType
OpenGLOptions::filter() const
{
/* Filter method is controlled externally */
return video_filter_method == 0
? FilterType::Nearest
: FilterType::Linear;
}
void
OpenGLOptions::setRenderBehavior(RenderBehaviorType value)
{
m_renderBehavior = value;
}
void
OpenGLOptions::setFrameRate(int value)
{
m_framerate = value;
}
void
OpenGLOptions::setVSync(bool value)
{
m_vsync = value;
}
void
OpenGLOptions::setFilter(FilterType value)
{
m_filter = value;
}
void
OpenGLOptions::addShader(const QString &path)
{
QFile shader_file(path);
if (!shader_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
throw std::runtime_error(
QString(tr("Error opening \"%1\": %2"))
.arg(path)
.arg(shader_file.errorString())
.toStdString());
}
auto shader_text = QString(shader_file.readAll());
shader_file.close();
/* Remove parameter lines */
shader_text.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption));
QRegularExpression version("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption);
auto match = version.match(shader_text);
QString version_line(m_glslVersion);
if (match.hasMatch()) {
/* Extract existing version and remove it. */
version_line = match.captured(1);
shader_text.remove(version);
}
auto shader = new QOpenGLShaderProgram(this);
auto throw_shader_error = [path, shader](const QString &what) {
throw std::runtime_error(
QString(what % ":\n\n %2")
.arg(path)
.arg(shader->log())
.toStdString());
};
static const char *extension = "\n#extension GL_ARB_shading_language_420pack : enable\n";
if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % extension % "\n#define VERTEX\n#line 1\n" % shader_text))
throw_shader_error(tr("Error compiling vertex shader in file \"%1\""));
if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % extension % "\n#define FRAGMENT\n#line 1\n" % shader_text))
throw_shader_error(tr("Error compiling fragment shader in file \"%1\""));
if (!shader->link())
throw_shader_error(tr("Error linking shader program in file \"%1\""));
m_shaders << OpenGLShaderPass(shader, path);
}
void
OpenGLOptions::addDefaultShader()
{
auto shader = new QOpenGLShaderProgram(this);
shader->addShaderFromSourceCode(QOpenGLShader::Vertex, m_glslVersion % "\n" % vertex_shader);
shader->addShaderFromSourceCode(QOpenGLShader::Fragment, m_glslVersion % "\n" % fragment_shader);
shader->link();
m_shaders << OpenGLShaderPass(shader, QString());
}

View File

@@ -1,102 +0,0 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Header for OpenGL renderer options
*
*
*
* Authors: Teemu Korhonen
*
* Copyright 2022 Teemu Korhonen
*/
#ifndef QT_OPENGLOPTIONS_HPP
#define QT_OPENGLOPTIONS_HPP
#include <QList>
#include <QObject>
#include <QOpenGLContext>
#include <QOpenGLShaderProgram>
class OpenGLShaderPass {
public:
OpenGLShaderPass(QOpenGLShaderProgram *shader, const QString &path)
: m_shader(shader)
, m_path(path)
, m_vertex_coord(shader->attributeLocation("VertexCoord"))
, m_tex_coord(shader->attributeLocation("TexCoord"))
, m_color(shader->attributeLocation("Color"))
, m_mvp_matrix(shader->uniformLocation("MVPMatrix"))
, m_input_size(shader->uniformLocation("InputSize"))
, m_output_size(shader->uniformLocation("OutputSize"))
, m_texture_size(shader->uniformLocation("TextureSize"))
, m_frame_count(shader->uniformLocation("FrameCount"))
{
}
bool bind() const { return m_shader->bind(); }
const QString &path() const { return m_path; }
const GLint &vertex_coord() const { return m_vertex_coord; }
const GLint &tex_coord() const { return m_tex_coord; }
const GLint &color() const { return m_color; }
const GLint &mvp_matrix() const { return m_mvp_matrix; }
const GLint &input_size() const { return m_input_size; }
const GLint &output_size() const { return m_output_size; }
const GLint &texture_size() const { return m_texture_size; }
const GLint &frame_count() const { return m_frame_count; }
private:
QOpenGLShaderProgram *m_shader;
QString m_path;
GLint m_vertex_coord;
GLint m_tex_coord;
GLint m_color;
GLint m_mvp_matrix;
GLint m_input_size;
GLint m_output_size;
GLint m_texture_size;
GLint m_frame_count;
};
class OpenGLOptions : public QObject {
Q_OBJECT
public:
enum RenderBehaviorType { SyncWithVideo,
TargetFramerate };
enum FilterType { Nearest,
Linear };
OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion);
RenderBehaviorType renderBehavior() const { return m_renderBehavior; }
int framerate() const { return m_framerate; }
bool vSync() const { return m_vsync; }
FilterType filter() const;
const QList<OpenGLShaderPass> &shaders() const { return m_shaders; }
void setRenderBehavior(RenderBehaviorType value);
void setFrameRate(int value);
void setVSync(bool value);
void setFilter(FilterType value);
void addShader(const QString &path);
void addDefaultShader();
void save() const;
private:
RenderBehaviorType m_renderBehavior = SyncWithVideo;
int m_framerate = -1;
bool m_vsync = false;
FilterType m_filter = Nearest;
QList<OpenGLShaderPass> m_shaders;
QString m_glslVersion;
};
#endif

View File

@@ -1,116 +0,0 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* OpenGL renderer options dialog for Qt
*
*
*
* Authors: Teemu Korhonen
*
* Copyright 2022 Teemu Korhonen
*/
#include <QFileDialog>
#include <QMessageBox>
#include <QStringBuilder>
#include <stdexcept>
#include "qt_opengloptionsdialog.hpp"
#include "qt_util.hpp"
#include "ui_qt_opengloptionsdialog.h"
OpenGLOptionsDialog::OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function<OpenGLOptions *()> optionsFactory)
: QDialog(parent)
, ui(new Ui::OpenGLOptionsDialog)
, createOptions(optionsFactory)
{
ui->setupUi(this);
if (options.renderBehavior() == OpenGLOptions::SyncWithVideo)
ui->syncWithVideo->setChecked(true);
else {
ui->syncToFramerate->setChecked(true);
ui->targetFps->setValue(options.framerate());
}
ui->vsync->setChecked(options.vSync());
if (!options.shaders().isEmpty()) {
auto path = options.shaders().first().path();
if (!path.isEmpty())
ui->shader->setPlainText(path);
}
}
OpenGLOptionsDialog::~OpenGLOptionsDialog()
{
delete ui;
}
void
OpenGLOptionsDialog::accept()
{
auto options = createOptions();
options->setRenderBehavior(
ui->syncWithVideo->isChecked()
? OpenGLOptions::SyncWithVideo
: OpenGLOptions::TargetFramerate);
options->setFrameRate(ui->targetFps->value());
options->setVSync(ui->vsync->isChecked());
auto shader = ui->shader->toPlainText();
try {
if (!shader.isEmpty())
options->addShader(shader);
else
options->addDefaultShader();
} catch (const std::runtime_error &e) {
delete options;
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Shader error"));
msgBox.setText(tr("Could not load shaders."));
msgBox.setInformativeText(tr("More information in details."));
msgBox.setDetailedText(e.what());
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Close);
msgBox.setDefaultButton(QMessageBox::Close);
msgBox.setStyleSheet("QTextEdit { min-width: 45em; }");
msgBox.exec();
return;
}
options->save();
emit optionsChanged(options);
QDialog::accept();
}
void
OpenGLOptionsDialog::on_addShader_clicked()
{
auto shader = QFileDialog::getOpenFileName(
this,
QString(),
QString(),
tr("OpenGL Shaders") % util::DlgFilter({ "glsl" }, true));
if (shader.isNull())
return;
ui->shader->setPlainText(shader);
}

View File

@@ -1,51 +0,0 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Header for OpenGL renderer options dialog
*
* Authors: Teemu Korhonen
*
* Copyright 2022 Teemu Korhonen
*/
#ifndef QT_OPENGLOPTIONSDIALOG_H
#define QT_OPENGLOPTIONSDIALOG_H
#include <QDialog>
#include <functional>
#include "qt_opengloptions.hpp"
namespace Ui {
class OpenGLOptionsDialog;
}
class OpenGLOptionsDialog : public QDialog {
Q_OBJECT
public:
explicit OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function<OpenGLOptions *()> optionsFactory);
~OpenGLOptionsDialog();
signals:
void optionsChanged(OpenGLOptions *options);
public slots:
void accept() override;
private:
Ui::OpenGLOptionsDialog *ui;
std::function<OpenGLOptions *()> createOptions;
private slots:
void on_addShader_clicked();
};
#endif // QT_OPENGLOPTIONSDIALOG_H

View File

@@ -1,280 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OpenGLOptionsDialog</class>
<widget class="QDialog" name="OpenGLOptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>320</height>
</rect>
</property>
<property name="windowTitle">
<string>OpenGL 3.0 renderer options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Render behavior</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="3,1">
<item row="1" column="0">
<widget class="QRadioButton" name="syncToFramerate">
<property name="text">
<string>Use target framerate:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="targetFps">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> fps</string>
</property>
<property name="minimum">
<number>15</number>
</property>
<property name="maximum">
<number>240</number>
</property>
<property name="value">
<number>60</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="vsync">
<property name="text">
<string>VSync</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="syncWithVideo">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Render each frame immediately, in sync with the emulated display.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;This is the recommended option if the shaders in use don't utilize frametime for animated effects.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Synchronize with video</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSlider" name="fpsSlider">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>15</number>
</property>
<property name="maximum">
<number>240</number>
</property>
<property name="value">
<number>60</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Shaders</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="3,1">
<item row="2" column="1">
<widget class="QPushButton" name="removeShader">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" rowspan="3">
<widget class="QTextEdit" name="shader">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>No shader selected</string>
</property>
</widget>
</item>
<item row="1" column="1" alignment="Qt::AlignTop">
<widget class="QPushButton" name="addShader">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>syncWithVideo</tabstop>
<tabstop>syncToFramerate</tabstop>
<tabstop>fpsSlider</tabstop>
<tabstop>targetFps</tabstop>
<tabstop>vsync</tabstop>
<tabstop>shader</tabstop>
<tabstop>addShader</tabstop>
<tabstop>removeShader</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>OpenGLOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>310</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OpenGLOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>325</x>
<y>310</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>syncToFramerate</sender>
<signal>toggled(bool)</signal>
<receiver>targetFps</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>140</x>
<y>71</y>
</hint>
<hint type="destinationlabel">
<x>380</x>
<y>98</y>
</hint>
</hints>
</connection>
<connection>
<sender>syncToFramerate</sender>
<signal>toggled(bool)</signal>
<receiver>fpsSlider</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>158</x>
<y>66</y>
</hint>
<hint type="destinationlabel">
<x>168</x>
<y>87</y>
</hint>
</hints>
</connection>
<connection>
<sender>fpsSlider</sender>
<signal>valueChanged(int)</signal>
<receiver>targetFps</receiver>
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
<x>252</x>
<y>90</y>
</hint>
<hint type="destinationlabel">
<x>308</x>
<y>89</y>
</hint>
</hints>
</connection>
<connection>
<sender>targetFps</sender>
<signal>valueChanged(int)</signal>
<receiver>fpsSlider</receiver>
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
<x>364</x>
<y>93</y>
</hint>
<hint type="destinationlabel">
<x>134</x>
<y>93</y>
</hint>
</hints>
</connection>
<connection>
<sender>removeShader</sender>
<signal>clicked()</signal>
<receiver>shader</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel">
<x>333</x>
<y>201</y>
</hint>
<hint type="destinationlabel">
<x>235</x>
<y>208</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -1,468 +0,0 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* OpenGL renderer for Qt
*
*
*
* Authors: Teemu Korhonen
*
* Copyright 2022 Teemu Korhonen
*/
#include <QCoreApplication>
#include <QMessageBox>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QStringBuilder>
#include <QSurfaceFormat>
#include <cmath>
#include "qt_opengloptionsdialog.hpp"
#include "qt_openglrenderer.hpp"
#ifndef GL_MAP_PERSISTENT_BIT
# define GL_MAP_PERSISTENT_BIT 0x0040
#endif
#ifndef GL_MAP_COHERENT_BIT
# define GL_MAP_COHERENT_BIT 0x0080
#endif
OpenGLRenderer::OpenGLRenderer(QWidget *parent)
: QWindow(parent->windowHandle())
, renderTimer(new QTimer(this))
, options(nullptr)
{
renderTimer->setTimerType(Qt::PreciseTimer);
/* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */
connect(renderTimer, &QTimer::timeout, this, &OpenGLRenderer::render);
buf_usage = std::vector<std::atomic_flag>(BUFFERCOUNT);
for (auto &flag : buf_usage)
flag.clear();
setSurfaceType(QWindow::OpenGLSurface);
QSurfaceFormat format;
#ifdef Q_OS_MACOS
format.setVersion(4, 1);
#else
format.setVersion(3, 2);
#endif
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
format.setRenderableType(QSurfaceFormat::OpenGLES);
setFormat(format);
parentWidget = parent;
source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT);
}
OpenGLRenderer::~OpenGLRenderer()
{
finalize();
}
void
OpenGLRenderer::exposeEvent(QExposeEvent *event)
{
Q_UNUSED(event);
if (!isInitialized)
initialize();
onResize(size().width(), size().height());
}
void
OpenGLRenderer::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
onResize(event->size().width(), event->size().height());
if (notReady())
return;
context->makeCurrent(this);
glViewport(
destination.x() * devicePixelRatio(),
destination.y() * devicePixelRatio(),
destination.width() * devicePixelRatio(),
destination.height() * devicePixelRatio());
}
bool
OpenGLRenderer::event(QEvent *event)
{
Q_UNUSED(event);
bool res = false;
if (!eventDelegate(event, res))
return QWindow::event(event);
return res;
}
void
OpenGLRenderer::initialize()
{
try {
context = new QOpenGLContext(this);
context->setFormat(format());
if (!context->create())
throw opengl_init_error(tr("Couldn't create OpenGL context."));
if (!context->makeCurrent(this))
throw opengl_init_error(tr("Couldn't switch to OpenGL context."));
auto version = context->format().version();
if (version.first < 3)
throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second));
initializeOpenGLFunctions();
/* Prepare the shader version string */
glslVersion = reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
glslVersion.truncate(4);
glslVersion.remove('.');
glslVersion.prepend("#version ");
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
glslVersion.append(" es");
else if (context->format().profile() == QSurfaceFormat::CoreProfile)
glslVersion.append(" core");
initializeExtensions();
initializeBuffers();
/* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */
const GLfloat surface[] = {
-1.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f,
-1.f, -1.f, 0.f, 1.f, 1.f, 1.f, 1.f, 1.f,
1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f
};
glGenVertexArrays(1, &vertexArrayID);
glBindVertexArray(vertexArrayID);
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
reloadOptions();
glClearColor(0.f, 0.f, 0.f, 1.f);
glViewport(
destination.x() * devicePixelRatio(),
destination.y() * devicePixelRatio(),
destination.width() * devicePixelRatio(),
destination.height() * devicePixelRatio());
GLenum error = glGetError();
if (error != GL_NO_ERROR)
throw opengl_init_error(tr("OpenGL initialization failed. Error %1.").arg(error));
isInitialized = true;
emit initialized();
glClear(GL_COLOR_BUFFER_BIT);
context->swapBuffers(this);
} catch (const opengl_init_error &e) {
/* Mark all buffers as in use */
for (auto &flag : buf_usage)
flag.test_and_set();
QMessageBox::critical((QWidget *) qApp->findChild<QWindow *>(), tr("Error initializing OpenGL"), e.what() % tr("\nFalling back to software rendering."));
context->doneCurrent();
isFinalized = true;
isInitialized = true;
emit errorInitializing();
}
}
void
OpenGLRenderer::finalize()
{
if (isFinalized)
return;
renderTimer->stop();
context->makeCurrent(this);
if (hasBufferStorage)
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glDeleteBuffers(1, &unpackBufferID);
glDeleteTextures(1, &textureID);
glDeleteBuffers(1, &vertexBufferID);
glDeleteVertexArrays(1, &vertexArrayID);
if (!hasBufferStorage && unpackBuffer)
free(unpackBuffer);
context->doneCurrent();
isFinalized = true;
}
QDialog *
OpenGLRenderer::getOptions(QWidget *parent)
{
auto dialog = new OpenGLOptionsDialog(parent, *options, [this]() { return new OpenGLOptions(this, false, glslVersion); });
connect(dialog, &OpenGLOptionsDialog::optionsChanged, this, &OpenGLRenderer::updateOptions);
return dialog;
}
void
OpenGLRenderer::initializeExtensions()
{
#ifndef NO_BUFFER_STORAGE
if (context->hasExtension("GL_ARB_buffer_storage") || context->hasExtension("GL_EXT_buffer_storage")) {
hasBufferStorage = true;
glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress(context->hasExtension("GL_EXT_buffer_storage") ? "glBufferStorageEXT" : "glBufferStorage");
if (!glBufferStorage)
glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress("glBufferStorage");
}
#endif
}
void
OpenGLRenderer::initializeBuffers()
{
glGenBuffers(1, &unpackBufferID);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID);
if (hasBufferStorage) {
#ifndef NO_BUFFER_STORAGE
/* Create persistent buffer for pixel transfer. */
glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
unpackBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
#endif
} else {
/* Fallback; create our own buffer. */
unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT);
if (unpackBuffer == nullptr)
throw opengl_init_error(tr("Allocating memory for unpack buffer failed."));
glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW);
}
}
void
OpenGLRenderer::applyOptions()
{
/* TODO: change detection in options */
if (options->framerate() > 0) {
int interval = (int) ceilf(1000.f / (float) options->framerate());
renderTimer->setInterval(std::chrono::milliseconds(interval));
}
if (options->renderBehavior() == OpenGLOptions::TargetFramerate)
renderTimer->start();
else
renderTimer->stop();
auto format = this->format();
int interval = options->vSync() ? 1 : 0;
if (format.swapInterval() != interval) {
format.setSwapInterval(interval);
setFormat(format);
context->setFormat(format);
}
GLint filter = options->filter() == OpenGLOptions::Linear ? GL_LINEAR : GL_NEAREST;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
currentFilter = options->filter();
}
void
OpenGLRenderer::reloadOptions()
{
if (options) {
delete options;
options = nullptr;
}
options = new OpenGLOptions(this, true, glslVersion);
applyOptions();
}
void
OpenGLRenderer::applyShader(const OpenGLShaderPass &shader)
{
if (!shader.bind())
return;
if (shader.vertex_coord() != -1) {
glEnableVertexAttribArray(shader.vertex_coord());
glVertexAttribPointer(shader.vertex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
}
if (shader.tex_coord() != -1) {
glEnableVertexAttribArray(shader.tex_coord());
glVertexAttribPointer(shader.tex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat)));
}
if (shader.color() != -1) {
glEnableVertexAttribArray(shader.color());
glVertexAttribPointer(shader.color(), 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (4 * sizeof(GLfloat)));
}
if (shader.mvp_matrix() != -1) {
static const GLfloat mvp[] = {
1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, 0.f, 0.f, 1.f
};
glUniformMatrix4fv(shader.mvp_matrix(), 1, GL_FALSE, mvp);
}
if (shader.output_size() != -1)
glUniform2f(shader.output_size(), destination.width(), destination.height());
if (shader.input_size() != -1)
glUniform2f(shader.input_size(), source.width(), source.height());
if (shader.texture_size() != -1)
glUniform2f(shader.texture_size(), source.width(), source.height());
if (shader.frame_count() != -1)
glUniform1i(shader.frame_count(), frameCounter);
}
void
OpenGLRenderer::render()
{
context->makeCurrent(this);
if (options->filter() != currentFilter)
applyOptions();
/* TODO: multiple shader passes */
applyShader(options->shaders().first());
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
context->swapBuffers(this);
frameCounter = (frameCounter + 1) & 1023;
}
void
OpenGLRenderer::updateOptions(OpenGLOptions *newOptions)
{
context->makeCurrent(this);
glUseProgram(0);
delete options;
options = newOptions;
options->setParent(this);
applyOptions();
}
std::vector<std::tuple<uint8_t *, std::atomic_flag *>>
OpenGLRenderer::getBuffers()
{
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> buffers;
if (notReady() || !unpackBuffer)
return buffers;
/* Split the buffer area */
for (int i = 0; i < BUFFERCOUNT; i++) {
buffers.push_back(std::make_tuple((uint8_t *) unpackBuffer + BUFFERBYTES * i, &buf_usage[i]));
}
return buffers;
}
void
OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h)
{
if (notReady())
return;
context->makeCurrent(this);
#ifdef Q_OS_MACOS
glViewport(
destination.x() * devicePixelRatio(),
destination.y() * devicePixelRatio(),
destination.width() * devicePixelRatio(),
destination.height() * devicePixelRatio());
#endif
if (source.width() != w || source.height() != h) {
source.setRect(0, 0, w, h);
/* Resize the texture */
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID);
}
if (!hasBufferStorage)
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * buf_idx, h * ROW_LENGTH * sizeof(uint32_t) + (y * ROW_LENGTH * sizeof(uint32_t)), (uint8_t *) unpackBuffer + BUFFERBYTES * buf_idx);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x);
glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
/* TODO: check if fence sync is implementable here and still has any benefit. */
glFinish();
buf_usage[buf_idx].clear();
if (options->renderBehavior() == OpenGLOptions::SyncWithVideo)
render();
}

View File

@@ -1,125 +0,0 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Header file for OpenGL renderer
*
*
*
* Authors: Teemu Korhonen
*
* Copyright 2022 Teemu Korhonen
*/
#ifndef QT_OPENGLRENDERER_HPP
#define QT_OPENGLRENDERER_HPP
#if defined Q_OS_MACOS || __arm__
# define NO_BUFFER_STORAGE
#endif
#include <QOpenGLContext>
#include <QOpenGLExtraFunctions>
#include <QResizeEvent>
#include <QTimer>
#include <QWidget>
#include <QWindow>
#if !defined NO_BUFFER_STORAGE && !(QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include <QtOpenGLExtensions/QOpenGLExtensions>
#endif
#include <atomic>
#include <stdexcept>
#include <tuple>
#include <vector>
#include "qt_opengloptions.hpp"
#include "qt_renderercommon.hpp"
typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
class OpenGLRenderer : public QWindow, protected QOpenGLExtraFunctions, public RendererCommon {
Q_OBJECT
public:
QOpenGLContext *context;
OpenGLRenderer(QWidget *parent = nullptr);
~OpenGLRenderer();
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() override;
void finalize() override final;
bool hasOptions() const override { return true; }
QDialog *getOptions(QWidget *parent) override;
void reloadOptions() override;
signals:
void initialized();
void errorInitializing();
public slots:
void onBlit(int buf_idx, int x, int y, int w, int h);
protected:
void exposeEvent(QExposeEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
bool event(QEvent *event) override;
private:
static constexpr int INIT_WIDTH = 640;
static constexpr int INIT_HEIGHT = 400;
static constexpr int ROW_LENGTH = 2048;
static constexpr int BUFFERPIXELS = 4194304;
static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */
static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */
QTimer *renderTimer;
OpenGLOptions *options;
QString glslVersion;
bool isInitialized = false;
bool isFinalized = false;
GLuint unpackBufferID = 0;
GLuint vertexArrayID = 0;
GLuint vertexBufferID = 0;
GLuint textureID = 0;
int frameCounter = 0;
OpenGLOptions::FilterType currentFilter;
void *unpackBuffer = nullptr;
void initialize();
void initializeExtensions();
void initializeBuffers();
void applyOptions();
void applyShader(const OpenGLShaderPass &shader);
bool notReady() const { return !isInitialized || isFinalized; }
/* GL_ARB_buffer_storage */
bool hasBufferStorage = false;
#ifndef NO_BUFFER_STORAGE
PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr;
#endif
private slots:
void render();
void updateOptions(OpenGLOptions *newOptions);
};
class opengl_init_error : public std::runtime_error {
public:
opengl_init_error(const QString &what)
: std::runtime_error(what.toStdString())
{
}
};
#endif

View File

@@ -1,3 +1,26 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* OpenGL renderer for Qt, mostly ported over from PCem.
*
*
*
* Authors: Teemu Korhonen
* Cacodemon345
* bit
* Sarah Walker
*
* Copyright 2022 Teemu Korhonen
* Copyright 2025 Cacodemon345
* Copyright 2017 Bit
* Copyright 2017-2020 Sarah Walker
*/
#include "qt_renderercommon.hpp" #include "qt_renderercommon.hpp"
#include "qt_mainwindow.hpp" #include "qt_mainwindow.hpp"
@@ -114,7 +137,7 @@ next_pow2(unsigned int n)
} }
int int
OpenGLRendererPCem::create_program(struct shader_program *program) OpenGLRenderer::create_program(struct shader_program *program)
{ {
GLint status; GLint status;
program->id = glw.glCreateProgram(); program->id = glw.glCreateProgram();
@@ -146,7 +169,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program)
} }
int int
OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst)
{ {
const char *source[3]; const char *source[3];
char version[50]; char version[50];
@@ -197,19 +220,19 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons
} }
GLuint GLuint
OpenGLRendererPCem::get_uniform(GLuint program, const char *name) OpenGLRenderer::get_uniform(GLuint program, const char *name)
{ {
return glw.glGetUniformLocation(program, name); return glw.glGetUniformLocation(program, name);
} }
GLuint GLuint
OpenGLRendererPCem::get_attrib(GLuint program, const char *name) OpenGLRenderer::get_attrib(GLuint program, const char *name)
{ {
return glw.glGetAttribLocation(program, name); return glw.glGetAttribLocation(program, name);
} }
void void
OpenGLRendererPCem::find_uniforms(struct glsl_shader *glsl, int num_pass) OpenGLRenderer::find_uniforms(struct glsl_shader *glsl, int num_pass)
{ {
int i; int i;
char s[50]; char s[50];
@@ -294,7 +317,7 @@ setup_scale(struct shader *shader, struct shader_pass *pass)
} }
void void
OpenGLRendererPCem::create_texture(struct shader_texture *tex) OpenGLRenderer::create_texture(struct shader_texture *tex)
{ {
if (tex->width > max_texture_size) if (tex->width > max_texture_size)
tex->width = max_texture_size; tex->width = max_texture_size;
@@ -314,7 +337,7 @@ OpenGLRendererPCem::create_texture(struct shader_texture *tex)
} }
void void
OpenGLRendererPCem::delete_texture(struct shader_texture *tex) OpenGLRenderer::delete_texture(struct shader_texture *tex)
{ {
if (tex->id > 0) if (tex->id > 0)
glw.glDeleteTextures(1, (GLuint *) &tex->id); glw.glDeleteTextures(1, (GLuint *) &tex->id);
@@ -322,7 +345,7 @@ OpenGLRendererPCem::delete_texture(struct shader_texture *tex)
} }
void void
OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) OpenGLRenderer::delete_fbo(struct shader_fbo *fbo)
{ {
if (fbo->id >= 0) { if (fbo->id >= 0) {
glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id);
@@ -331,7 +354,7 @@ OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo)
} }
void void
OpenGLRendererPCem::delete_program(struct shader_program *program) OpenGLRenderer::delete_program(struct shader_program *program)
{ {
if (program->vertex_shader) if (program->vertex_shader)
glw.glDeleteShader(program->vertex_shader); glw.glDeleteShader(program->vertex_shader);
@@ -341,7 +364,7 @@ OpenGLRendererPCem::delete_program(struct shader_program *program)
} }
void void
OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) OpenGLRenderer::delete_vbo(struct shader_vbo *vbo)
{ {
if (vbo->color >= 0) if (vbo->color >= 0)
glw.glDeleteBuffers(1, (GLuint *) &vbo->color); glw.glDeleteBuffers(1, (GLuint *) &vbo->color);
@@ -350,7 +373,7 @@ OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo)
} }
void void
OpenGLRendererPCem::delete_pass(struct shader_pass *pass) OpenGLRenderer::delete_pass(struct shader_pass *pass)
{ {
delete_fbo(&pass->fbo); delete_fbo(&pass->fbo);
delete_vbo(&pass->vbo); delete_vbo(&pass->vbo);
@@ -359,14 +382,14 @@ OpenGLRendererPCem::delete_pass(struct shader_pass *pass)
} }
void void
OpenGLRendererPCem::delete_prev(struct shader_prev *prev) OpenGLRenderer::delete_prev(struct shader_prev *prev)
{ {
delete_fbo(&prev->fbo); delete_fbo(&prev->fbo);
delete_vbo(&prev->vbo); delete_vbo(&prev->vbo);
} }
void void
OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) OpenGLRenderer::delete_shader(struct glsl_shader *glsl)
{ {
int i; int i;
for (i = 0; i < glsl->num_passes; ++i) for (i = 0; i < glsl->num_passes; ++i)
@@ -381,7 +404,7 @@ OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl)
} }
void void
OpenGLRendererPCem::delete_glsl(glsl_t *glsl) OpenGLRenderer::delete_glsl(glsl_t *glsl)
{ {
int i; int i;
for (i = 0; i < glsl->num_shaders; ++i) for (i = 0; i < glsl->num_shaders; ++i)
@@ -395,7 +418,7 @@ OpenGLRendererPCem::delete_glsl(glsl_t *glsl)
} }
void void
OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) OpenGLRenderer::create_fbo(struct shader_fbo *fbo)
{ {
create_texture(&fbo->texture); create_texture(&fbo->texture);
@@ -410,7 +433,7 @@ OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo)
} }
void void
OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) OpenGLRenderer::setup_fbo(struct shader *shader, struct shader_fbo *fbo)
{ {
fbo->texture.internal_format = GL_RGBA8; fbo->texture.internal_format = GL_RGBA8;
fbo->texture.format = GL_RGBA; fbo->texture.format = GL_RGBA;
@@ -442,7 +465,7 @@ OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo)
} }
void void
OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) OpenGLRenderer::recreate_fbo(struct shader_fbo *fbo, int width, int height)
{ {
if (width != fbo->texture.width || height != fbo->texture.height) { if (width != fbo->texture.width || height != fbo->texture.height) {
glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id);
@@ -454,7 +477,7 @@ OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height)
} }
int int
OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) OpenGLRenderer::create_default_shader_tex(struct shader_pass *pass)
{ {
if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program))
return 0; return 0;
@@ -474,7 +497,7 @@ OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass)
} }
int int
OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) OpenGLRenderer::create_default_shader_color(struct shader_pass *pass)
{ {
if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program))
return 0; return 0;
@@ -494,7 +517,7 @@ OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass)
/* create the default scene shader */ /* create the default scene shader */
void void
OpenGLRendererPCem::create_scene_shader() OpenGLRenderer::create_scene_shader()
{ {
struct shader scene_shader_conf; struct shader scene_shader_conf;
memset(&scene_shader_conf, 0, sizeof(struct shader)); memset(&scene_shader_conf, 0, sizeof(struct shader));
@@ -554,7 +577,7 @@ load_texture(const char *f, struct shader_texture *tex)
} }
glsl_t * glsl_t *
OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f)
{ {
int i, j; int i, j;
glslp_t *p = glslp_parse(f); glslp_t *p = glslp_parse(f);
@@ -704,7 +727,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f)
} }
glsl_t * glsl_t *
OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) OpenGLRenderer::load_shaders(int num, char shaders[MAX_USER_SHADERS][512])
{ {
int i; int i;
glsl_t *glsl; glsl_t *glsl;
@@ -731,7 +754,7 @@ OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512])
} }
void void
OpenGLRendererPCem::read_shader_config() OpenGLRenderer::read_shader_config()
{ {
char s[512]; char s[512];
int i, j; int i, j;
@@ -747,10 +770,9 @@ OpenGLRendererPCem::read_shader_config()
} }
} }
OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) OpenGLRenderer::OpenGLRenderer(QWidget *parent)
: QWindow(parent->windowHandle()) : QWindow(parent->windowHandle())
, renderTimer(new QTimer(this)) , renderTimer(new QTimer(this))
, options(nullptr)
{ {
connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } ); connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } );
imagebufs[0] = std::unique_ptr<uint8_t>(new uint8_t[2048 * 2048 * 4]); imagebufs[0] = std::unique_ptr<uint8_t>(new uint8_t[2048 * 2048 * 4]);
@@ -785,10 +807,10 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent)
isFinalized = false; isFinalized = false;
} }
OpenGLRendererPCem::~OpenGLRendererPCem() { finalize(); } OpenGLRenderer::~OpenGLRenderer() { finalize(); }
void void
OpenGLRendererPCem::initialize() OpenGLRenderer::initialize()
{ {
try { try {
context = new QOpenGLContext(this); context = new QOpenGLContext(this);
@@ -796,15 +818,15 @@ OpenGLRendererPCem::initialize()
context->setFormat(format()); context->setFormat(format());
if (!context->create()) if (!context->create())
throw opengl_init_error_pcem(tr("Couldn't create OpenGL context.")); throw opengl_init_error(tr("Couldn't create OpenGL context."));
if (!context->makeCurrent(this)) if (!context->makeCurrent(this))
throw opengl_init_error_pcem(tr("Couldn't switch to OpenGL context.")); throw opengl_init_error(tr("Couldn't switch to OpenGL context."));
auto version = context->format().version(); auto version = context->format().version();
if (version.first < 3) if (version.first < 3)
throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second));
glw.initializeOpenGLFunctions(); glw.initializeOpenGLFunctions();
@@ -813,7 +835,7 @@ OpenGLRendererPCem::initialize()
glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]);
glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]);
if (glsl_version[0] < 3) { if (glsl_version[0] < 3) {
throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1]));
} }
pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION));
pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION));
@@ -1035,7 +1057,7 @@ OpenGLRendererPCem::initialize()
glw.glClear(GL_COLOR_BUFFER_BIT); glw.glClear(GL_COLOR_BUFFER_BIT);
context->swapBuffers(this); context->swapBuffers(this);
} catch (const opengl_init_error_pcem &e) { } catch (const opengl_init_error &e) {
/* Mark all buffers as in use */ /* Mark all buffers as in use */
for (auto &flag : buf_usage) for (auto &flag : buf_usage)
flag.test_and_set(); flag.test_and_set();
@@ -1051,7 +1073,7 @@ OpenGLRendererPCem::initialize()
} }
void void
OpenGLRendererPCem::finalize() OpenGLRenderer::finalize()
{ {
if (isFinalized) if (isFinalized)
return; return;
@@ -1074,7 +1096,7 @@ OpenGLRendererPCem::finalize()
} }
void void
OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h)
{ {
if (notReady()) if (notReady())
return; return;
@@ -1112,7 +1134,7 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h)
} }
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> std::vector<std::tuple<uint8_t *, std::atomic_flag *>>
OpenGLRendererPCem::getBuffers() OpenGLRenderer::getBuffers()
{ {
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> buffers; std::vector<std::tuple<uint8_t *, std::atomic_flag *>> buffers;
@@ -1123,7 +1145,7 @@ OpenGLRendererPCem::getBuffers()
} }
void void
OpenGLRendererPCem::exposeEvent(QExposeEvent *event) OpenGLRenderer::exposeEvent(QExposeEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
@@ -1134,7 +1156,7 @@ OpenGLRendererPCem::exposeEvent(QExposeEvent *event)
} }
void void
OpenGLRendererPCem::resizeEvent(QResizeEvent *event) OpenGLRenderer::resizeEvent(QResizeEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
@@ -1153,7 +1175,7 @@ OpenGLRendererPCem::resizeEvent(QResizeEvent *event)
} }
void void
OpenGLRendererPCem::render_pass(struct render_data *data) OpenGLRenderer::render_pass(struct render_data *data)
{ {
int i; int i;
GLuint texture_unit = 0; GLuint texture_unit = 0;
@@ -1298,7 +1320,7 @@ OpenGLRendererPCem::render_pass(struct render_data *data)
} }
bool bool
OpenGLRendererPCem::event(QEvent *event) OpenGLRenderer::event(QEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
@@ -1309,13 +1331,13 @@ OpenGLRendererPCem::event(QEvent *event)
} }
QDialog* QDialog*
OpenGLRendererPCem::getOptions(QWidget *parent) OpenGLRenderer::getOptions(QWidget *parent)
{ {
return new OpenGLShaderManagerDialog(parent); return new OpenGLShaderManagerDialog(parent);
} }
void void
OpenGLRendererPCem::render() OpenGLRenderer::render()
{ {
if (!context) if (!context)
return; return;
@@ -1353,17 +1375,12 @@ OpenGLRendererPCem::render()
struct { struct {
uint32_t x, y, w, h; uint32_t x, y, w, h;
} rect, video_rect; } rect;
rect.x = 0; rect.x = 0;
rect.y = 0; rect.y = 0;
rect.w = source.width(); rect.w = source.width();
rect.h = source.height(); rect.h = source.height();
video_rect.x = source.x();
video_rect.y = source.y();
video_rect.w = source.width();
video_rect.h = source.height();
pass->state.input_size[0] = pass->state.output_size[0] = rect.w; pass->state.input_size[0] = pass->state.output_size[0] = rect.w;
pass->state.input_size[1] = pass->state.output_size[1] = rect.h; pass->state.input_size[1] = pass->state.output_size[1] = rect.h;

View File

@@ -11,12 +11,14 @@
* *
* *
* Authors: Teemu Korhonen * Authors: Teemu Korhonen
* Cacodemon345
* *
* Copyright 2022 Teemu Korhonen * Copyright 2022 Teemu Korhonen
* Copyright 2025 Cacodemon345
*/ */
#ifndef QT_OpenGLRendererPCem_HPP #ifndef QT_OpenGLRenderer_HPP
#define QT_OpenGLRendererPCem_HPP #define QT_OpenGLRenderer_HPP
#if defined Q_OS_MACOS || __arm__ #if defined Q_OS_MACOS || __arm__
# define NO_BUFFER_STORAGE # define NO_BUFFER_STORAGE
@@ -37,7 +39,6 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "qt_opengloptions.hpp"
#include "qt_renderercommon.hpp" #include "qt_renderercommon.hpp"
extern "C" extern "C"
@@ -55,14 +56,14 @@ struct render_data {
int frame_count; int frame_count;
}; };
class OpenGLRendererPCem : public QWindow, public RendererCommon { class OpenGLRenderer : public QWindow, public RendererCommon {
Q_OBJECT Q_OBJECT
public: public:
QOpenGLContext *context; QOpenGLContext *context;
OpenGLRendererPCem(QWidget *parent = nullptr); OpenGLRenderer(QWidget *parent = nullptr);
~OpenGLRendererPCem(); ~OpenGLRenderer();
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() override; std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() override;
@@ -88,7 +89,6 @@ private:
std::array<std::unique_ptr<uint8_t>, 2> imagebufs; std::array<std::unique_ptr<uint8_t>, 2> imagebufs;
QTimer *renderTimer; QTimer *renderTimer;
OpenGLOptions *options;
QString glslVersion = ""; QString glslVersion = "";
@@ -98,7 +98,6 @@ private:
int max_texture_size = 65536; int max_texture_size = 65536;
int frameCounter = 0; int frameCounter = 0;
OpenGLOptions::FilterType currentFilter;
QOpenGLExtraFunctions glw; QOpenGLExtraFunctions glw;
struct shader_texture scene_texture; struct shader_texture scene_texture;
glsl_t *active_shader; glsl_t *active_shader;
@@ -144,12 +143,11 @@ private:
private slots: private slots:
void render(); void render();
//void updateOptions(OpenGLOptions *newOptions);
}; };
class opengl_init_error_pcem : public std::runtime_error { class opengl_init_error : public std::runtime_error {
public: public:
opengl_init_error_pcem(const QString &what) opengl_init_error(const QString &what)
: std::runtime_error(what.toStdString()) : std::runtime_error(what.toStdString())
{ {
} }

View File

@@ -22,7 +22,6 @@
#include "ui_qt_rendererstack.h" #include "ui_qt_rendererstack.h"
#include "qt_hardwarerenderer.hpp" #include "qt_hardwarerenderer.hpp"
#include "qt_openglrenderer.hpp"
#include "qt_openglrenderer_pcem.hpp" #include "qt_openglrenderer_pcem.hpp"
#include "qt_softwarerenderer.hpp" #include "qt_softwarerenderer.hpp"
#include "qt_vulkanwindowrenderer.hpp" #include "qt_vulkanwindowrenderer.hpp"
@@ -341,16 +340,16 @@ RendererStack::createRenderer(Renderer renderer)
case Renderer::OpenGL3PCem: case Renderer::OpenGL3PCem:
{ {
this->createWinId(); this->createWinId();
auto hw = new OpenGLRendererPCem(this); auto hw = new OpenGLRenderer(this);
rendererWindow = hw; rendererWindow = hw;
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection);
connect(hw, &OpenGLRendererPCem::initialized, [=]() { connect(hw, &OpenGLRenderer::initialized, [=]() {
/* Buffers are available only after initialization. */ /* Buffers are available only after initialization. */
imagebufs = rendererWindow->getBuffers(); imagebufs = rendererWindow->getBuffers();
endblit(); endblit();
emit rendererChanged(); emit rendererChanged();
}); });
connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
/* Renderer not could initialize, fallback to software. */ /* Renderer not could initialize, fallback to software. */
imagebufs = {}; imagebufs = {};
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
@@ -361,16 +360,16 @@ RendererStack::createRenderer(Renderer renderer)
case Renderer::OpenGL3: case Renderer::OpenGL3:
{ {
this->createWinId(); this->createWinId();
auto hw = new OpenGLRendererPCem(this); auto hw = new OpenGLRenderer(this);
rendererWindow = hw; rendererWindow = hw;
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection);
connect(hw, &OpenGLRendererPCem::initialized, [=]() { connect(hw, &OpenGLRenderer::initialized, [=]() {
/* Buffers are available only after initialization. */ /* Buffers are available only after initialization. */
imagebufs = rendererWindow->getBuffers(); imagebufs = rendererWindow->getBuffers();
endblit(); endblit();
emit rendererChanged(); emit rendererChanged();
}); });
connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
/* Renderer not could initialize, fallback to software. */ /* Renderer not could initialize, fallback to software. */
imagebufs = {}; imagebufs = {};
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });