Cleanups, copyright headers and name changing for PRing
This commit is contained in:
@@ -172,7 +172,6 @@ int force_43 = 0; /* (C) video *
|
||||
int video_filter_method = 1; /* (C) video */
|
||||
int video_vsync = 0; /* (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
|
||||
pass-through for serial ports */
|
||||
int bugger_enabled = 0; /* (C) enable ISAbugger */
|
||||
|
||||
19
src/config.c
19
src/config.c
@@ -200,7 +200,6 @@ load_general(void)
|
||||
|
||||
video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1);
|
||||
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);
|
||||
if (window_remember) {
|
||||
@@ -1733,7 +1732,19 @@ load_gl3_shaders(void)
|
||||
if (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;
|
||||
snprintf(temp, 512, "shader%d", i);
|
||||
p = ini_section_get_string(cat, temp, "");
|
||||
@@ -2035,10 +2046,6 @@ save_general(void)
|
||||
ini_section_set_int(cat, "video_gl_vsync", video_vsync);
|
||||
else
|
||||
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)
|
||||
ini_section_set_int(cat, "do_auto_pause", do_auto_pause);
|
||||
|
||||
@@ -126,7 +126,6 @@ extern int video_filter_method; /* (C) video */
|
||||
extern int video_vsync; /* (C) video */
|
||||
extern int video_framerate; /* (C) video */
|
||||
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 novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */
|
||||
extern int postcard_enabled; /* (C) enable POST card */
|
||||
|
||||
@@ -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_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
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -162,7 +162,6 @@ ini_has_entry(ini_section_t self, const char *name)
|
||||
{
|
||||
section_t *section = (section_t *) self;
|
||||
const entry_t *entry;
|
||||
int value = 0;
|
||||
|
||||
if (section == NULL)
|
||||
return 0;
|
||||
@@ -546,6 +545,7 @@ ini_write(ini_t ini, const char *fn)
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
/* Wide-character version of "trim" */
|
||||
wchar_t *
|
||||
trim_w(wchar_t *str)
|
||||
{
|
||||
@@ -609,7 +609,6 @@ ini_strip_quotes(ini_t ini)
|
||||
ent = (entry_t *) sec->entry_head.next;
|
||||
while (ent != NULL) {
|
||||
if (ent->name[0] != '\0') {
|
||||
int i = 0;
|
||||
int trailing_hash = strcspn(ent->data, "#");
|
||||
int trailing_quote;
|
||||
ent->wdata[trailing_hash] = 0;
|
||||
|
||||
@@ -87,16 +87,9 @@ add_library(ui STATIC
|
||||
qt_softwarerenderer.hpp
|
||||
qt_hardwarerenderer.cpp
|
||||
qt_hardwarerenderer.hpp
|
||||
qt_openglrenderer.cpp
|
||||
qt_openglrenderer.hpp
|
||||
qt_openglrenderer_pcem.cpp
|
||||
qt_openglrenderer_pcem.hpp
|
||||
qt_glsl_parser.cpp
|
||||
qt_opengloptions.cpp
|
||||
qt_opengloptions.hpp
|
||||
qt_opengloptionsdialog.cpp
|
||||
qt_opengloptionsdialog.hpp
|
||||
qt_opengloptionsdialog.ui
|
||||
|
||||
qt_settings.cpp
|
||||
qt_settings.hpp
|
||||
@@ -197,7 +190,10 @@ add_library(ui STATIC
|
||||
qt_openglshadermanagerdialog.hpp
|
||||
qt_openglshadermanagerdialog.cpp
|
||||
qt_openglshadermanagerdialog.ui
|
||||
qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui
|
||||
|
||||
qt_openglshaderconfig.hpp
|
||||
qt_openglshaderconfig.cpp
|
||||
qt_openglshaderconfig.ui
|
||||
)
|
||||
|
||||
if(RTMIDI)
|
||||
|
||||
@@ -28,6 +28,43 @@ extern void endblit();
|
||||
(a)[(n)-1] = 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) {
|
||||
int i;
|
||||
const char *p;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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><html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html></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>
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_mainwindow.hpp"
|
||||
|
||||
@@ -114,7 +137,7 @@ next_pow2(unsigned int n)
|
||||
}
|
||||
|
||||
int
|
||||
OpenGLRendererPCem::create_program(struct shader_program *program)
|
||||
OpenGLRenderer::create_program(struct shader_program *program)
|
||||
{
|
||||
GLint status;
|
||||
program->id = glw.glCreateProgram();
|
||||
@@ -146,7 +169,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program)
|
||||
}
|
||||
|
||||
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];
|
||||
char version[50];
|
||||
@@ -197,19 +220,19 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons
|
||||
}
|
||||
|
||||
GLuint
|
||||
OpenGLRendererPCem::get_uniform(GLuint program, const char *name)
|
||||
OpenGLRenderer::get_uniform(GLuint program, const char *name)
|
||||
{
|
||||
return glw.glGetUniformLocation(program, name);
|
||||
}
|
||||
|
||||
GLuint
|
||||
OpenGLRendererPCem::get_attrib(GLuint program, const char *name)
|
||||
OpenGLRenderer::get_attrib(GLuint program, const char *name)
|
||||
{
|
||||
return glw.glGetAttribLocation(program, name);
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::find_uniforms(struct glsl_shader *glsl, int num_pass)
|
||||
OpenGLRenderer::find_uniforms(struct glsl_shader *glsl, int num_pass)
|
||||
{
|
||||
int i;
|
||||
char s[50];
|
||||
@@ -294,7 +317,7 @@ setup_scale(struct shader *shader, struct shader_pass *pass)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::create_texture(struct shader_texture *tex)
|
||||
OpenGLRenderer::create_texture(struct shader_texture *tex)
|
||||
{
|
||||
if (tex->width > max_texture_size)
|
||||
tex->width = max_texture_size;
|
||||
@@ -314,7 +337,7 @@ OpenGLRendererPCem::create_texture(struct shader_texture *tex)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_texture(struct shader_texture *tex)
|
||||
OpenGLRenderer::delete_texture(struct shader_texture *tex)
|
||||
{
|
||||
if (tex->id > 0)
|
||||
glw.glDeleteTextures(1, (GLuint *) &tex->id);
|
||||
@@ -322,7 +345,7 @@ OpenGLRendererPCem::delete_texture(struct shader_texture *tex)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo)
|
||||
OpenGLRenderer::delete_fbo(struct shader_fbo *fbo)
|
||||
{
|
||||
if (fbo->id >= 0) {
|
||||
glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id);
|
||||
@@ -331,7 +354,7 @@ OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_program(struct shader_program *program)
|
||||
OpenGLRenderer::delete_program(struct shader_program *program)
|
||||
{
|
||||
if (program->vertex_shader)
|
||||
glw.glDeleteShader(program->vertex_shader);
|
||||
@@ -341,7 +364,7 @@ OpenGLRendererPCem::delete_program(struct shader_program *program)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo)
|
||||
OpenGLRenderer::delete_vbo(struct shader_vbo *vbo)
|
||||
{
|
||||
if (vbo->color >= 0)
|
||||
glw.glDeleteBuffers(1, (GLuint *) &vbo->color);
|
||||
@@ -350,7 +373,7 @@ OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_pass(struct shader_pass *pass)
|
||||
OpenGLRenderer::delete_pass(struct shader_pass *pass)
|
||||
{
|
||||
delete_fbo(&pass->fbo);
|
||||
delete_vbo(&pass->vbo);
|
||||
@@ -359,14 +382,14 @@ OpenGLRendererPCem::delete_pass(struct shader_pass *pass)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_prev(struct shader_prev *prev)
|
||||
OpenGLRenderer::delete_prev(struct shader_prev *prev)
|
||||
{
|
||||
delete_fbo(&prev->fbo);
|
||||
delete_vbo(&prev->vbo);
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl)
|
||||
OpenGLRenderer::delete_shader(struct glsl_shader *glsl)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < glsl->num_passes; ++i)
|
||||
@@ -381,7 +404,7 @@ OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::delete_glsl(glsl_t *glsl)
|
||||
OpenGLRenderer::delete_glsl(glsl_t *glsl)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < glsl->num_shaders; ++i)
|
||||
@@ -395,7 +418,7 @@ OpenGLRendererPCem::delete_glsl(glsl_t *glsl)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo)
|
||||
OpenGLRenderer::create_fbo(struct shader_fbo *fbo)
|
||||
{
|
||||
create_texture(&fbo->texture);
|
||||
|
||||
@@ -410,7 +433,7 @@ OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo)
|
||||
}
|
||||
|
||||
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.format = GL_RGBA;
|
||||
@@ -442,7 +465,7 @@ OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo)
|
||||
}
|
||||
|
||||
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) {
|
||||
glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id);
|
||||
@@ -454,7 +477,7 @@ OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height)
|
||||
}
|
||||
|
||||
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))
|
||||
return 0;
|
||||
@@ -474,7 +497,7 @@ OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass)
|
||||
}
|
||||
|
||||
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))
|
||||
return 0;
|
||||
@@ -494,7 +517,7 @@ OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass)
|
||||
|
||||
/* create the default scene shader */
|
||||
void
|
||||
OpenGLRendererPCem::create_scene_shader()
|
||||
OpenGLRenderer::create_scene_shader()
|
||||
{
|
||||
struct shader scene_shader_conf;
|
||||
memset(&scene_shader_conf, 0, sizeof(struct shader));
|
||||
@@ -554,7 +577,7 @@ load_texture(const char *f, struct shader_texture *tex)
|
||||
}
|
||||
|
||||
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;
|
||||
glslp_t *p = glslp_parse(f);
|
||||
@@ -704,7 +727,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f)
|
||||
}
|
||||
|
||||
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;
|
||||
glsl_t *glsl;
|
||||
@@ -731,7 +754,7 @@ OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512])
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::read_shader_config()
|
||||
OpenGLRenderer::read_shader_config()
|
||||
{
|
||||
char s[512];
|
||||
int i, j;
|
||||
@@ -747,10 +770,9 @@ OpenGLRendererPCem::read_shader_config()
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent)
|
||||
OpenGLRenderer::OpenGLRenderer(QWidget *parent)
|
||||
: QWindow(parent->windowHandle())
|
||||
, renderTimer(new QTimer(this))
|
||||
, options(nullptr)
|
||||
{
|
||||
connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } );
|
||||
imagebufs[0] = std::unique_ptr<uint8_t>(new uint8_t[2048 * 2048 * 4]);
|
||||
@@ -785,10 +807,10 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent)
|
||||
isFinalized = false;
|
||||
}
|
||||
|
||||
OpenGLRendererPCem::~OpenGLRendererPCem() { finalize(); }
|
||||
OpenGLRenderer::~OpenGLRenderer() { finalize(); }
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::initialize()
|
||||
OpenGLRenderer::initialize()
|
||||
{
|
||||
try {
|
||||
context = new QOpenGLContext(this);
|
||||
@@ -796,15 +818,15 @@ OpenGLRendererPCem::initialize()
|
||||
context->setFormat(format());
|
||||
|
||||
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))
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
@@ -813,7 +835,7 @@ OpenGLRendererPCem::initialize()
|
||||
glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]);
|
||||
glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]);
|
||||
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 Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
@@ -1035,7 +1057,7 @@ OpenGLRendererPCem::initialize()
|
||||
glw.glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
context->swapBuffers(this);
|
||||
} catch (const opengl_init_error_pcem &e) {
|
||||
} catch (const opengl_init_error &e) {
|
||||
/* Mark all buffers as in use */
|
||||
for (auto &flag : buf_usage)
|
||||
flag.test_and_set();
|
||||
@@ -1051,7 +1073,7 @@ OpenGLRendererPCem::initialize()
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::finalize()
|
||||
OpenGLRenderer::finalize()
|
||||
{
|
||||
if (isFinalized)
|
||||
return;
|
||||
@@ -1074,7 +1096,7 @@ OpenGLRendererPCem::finalize()
|
||||
}
|
||||
|
||||
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())
|
||||
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 *>>
|
||||
OpenGLRendererPCem::getBuffers()
|
||||
OpenGLRenderer::getBuffers()
|
||||
{
|
||||
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> buffers;
|
||||
|
||||
@@ -1123,7 +1145,7 @@ OpenGLRendererPCem::getBuffers()
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::exposeEvent(QExposeEvent *event)
|
||||
OpenGLRenderer::exposeEvent(QExposeEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
@@ -1134,7 +1156,7 @@ OpenGLRendererPCem::exposeEvent(QExposeEvent *event)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::resizeEvent(QResizeEvent *event)
|
||||
OpenGLRenderer::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
@@ -1153,7 +1175,7 @@ OpenGLRendererPCem::resizeEvent(QResizeEvent *event)
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::render_pass(struct render_data *data)
|
||||
OpenGLRenderer::render_pass(struct render_data *data)
|
||||
{
|
||||
int i;
|
||||
GLuint texture_unit = 0;
|
||||
@@ -1298,7 +1320,7 @@ OpenGLRendererPCem::render_pass(struct render_data *data)
|
||||
}
|
||||
|
||||
bool
|
||||
OpenGLRendererPCem::event(QEvent *event)
|
||||
OpenGLRenderer::event(QEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
@@ -1309,13 +1331,13 @@ OpenGLRendererPCem::event(QEvent *event)
|
||||
}
|
||||
|
||||
QDialog*
|
||||
OpenGLRendererPCem::getOptions(QWidget *parent)
|
||||
OpenGLRenderer::getOptions(QWidget *parent)
|
||||
{
|
||||
return new OpenGLShaderManagerDialog(parent);
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRendererPCem::render()
|
||||
OpenGLRenderer::render()
|
||||
{
|
||||
if (!context)
|
||||
return;
|
||||
@@ -1353,17 +1375,12 @@ OpenGLRendererPCem::render()
|
||||
|
||||
struct {
|
||||
uint32_t x, y, w, h;
|
||||
} rect, video_rect;
|
||||
} rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.w = source.width();
|
||||
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[1] = pass->state.output_size[1] = rect.h;
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
*
|
||||
*
|
||||
* Authors: Teemu Korhonen
|
||||
* Cacodemon345
|
||||
*
|
||||
* Copyright 2022 Teemu Korhonen
|
||||
* Copyright 2025 Cacodemon345
|
||||
*/
|
||||
|
||||
#ifndef QT_OpenGLRendererPCem_HPP
|
||||
#define QT_OpenGLRendererPCem_HPP
|
||||
#ifndef QT_OpenGLRenderer_HPP
|
||||
#define QT_OpenGLRenderer_HPP
|
||||
|
||||
#if defined Q_OS_MACOS || __arm__
|
||||
# define NO_BUFFER_STORAGE
|
||||
@@ -37,7 +39,6 @@
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "qt_opengloptions.hpp"
|
||||
#include "qt_renderercommon.hpp"
|
||||
|
||||
extern "C"
|
||||
@@ -55,14 +56,14 @@ struct render_data {
|
||||
int frame_count;
|
||||
};
|
||||
|
||||
class OpenGLRendererPCem : public QWindow, public RendererCommon {
|
||||
class OpenGLRenderer : public QWindow, public RendererCommon {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QOpenGLContext *context;
|
||||
|
||||
OpenGLRendererPCem(QWidget *parent = nullptr);
|
||||
~OpenGLRendererPCem();
|
||||
OpenGLRenderer(QWidget *parent = nullptr);
|
||||
~OpenGLRenderer();
|
||||
|
||||
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;
|
||||
|
||||
QTimer *renderTimer;
|
||||
OpenGLOptions *options;
|
||||
|
||||
QString glslVersion = "";
|
||||
|
||||
@@ -98,7 +98,6 @@ private:
|
||||
int max_texture_size = 65536;
|
||||
int frameCounter = 0;
|
||||
|
||||
OpenGLOptions::FilterType currentFilter;
|
||||
QOpenGLExtraFunctions glw;
|
||||
struct shader_texture scene_texture;
|
||||
glsl_t *active_shader;
|
||||
@@ -144,12 +143,11 @@ private:
|
||||
|
||||
private slots:
|
||||
void render();
|
||||
//void updateOptions(OpenGLOptions *newOptions);
|
||||
};
|
||||
|
||||
class opengl_init_error_pcem : public std::runtime_error {
|
||||
class opengl_init_error : public std::runtime_error {
|
||||
public:
|
||||
opengl_init_error_pcem(const QString &what)
|
||||
opengl_init_error(const QString &what)
|
||||
: std::runtime_error(what.toStdString())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "ui_qt_rendererstack.h"
|
||||
|
||||
#include "qt_hardwarerenderer.hpp"
|
||||
#include "qt_openglrenderer.hpp"
|
||||
#include "qt_openglrenderer_pcem.hpp"
|
||||
#include "qt_softwarerenderer.hpp"
|
||||
#include "qt_vulkanwindowrenderer.hpp"
|
||||
@@ -341,16 +340,16 @@ RendererStack::createRenderer(Renderer renderer)
|
||||
case Renderer::OpenGL3PCem:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new OpenGLRendererPCem(this);
|
||||
auto hw = new OpenGLRenderer(this);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection);
|
||||
connect(hw, &OpenGLRendererPCem::initialized, [=]() {
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection);
|
||||
connect(hw, &OpenGLRenderer::initialized, [=]() {
|
||||
/* Buffers are available only after initialization. */
|
||||
imagebufs = rendererWindow->getBuffers();
|
||||
endblit();
|
||||
emit rendererChanged();
|
||||
});
|
||||
connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() {
|
||||
connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
|
||||
/* Renderer not could initialize, fallback to software. */
|
||||
imagebufs = {};
|
||||
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
|
||||
@@ -361,16 +360,16 @@ RendererStack::createRenderer(Renderer renderer)
|
||||
case Renderer::OpenGL3:
|
||||
{
|
||||
this->createWinId();
|
||||
auto hw = new OpenGLRendererPCem(this);
|
||||
auto hw = new OpenGLRenderer(this);
|
||||
rendererWindow = hw;
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection);
|
||||
connect(hw, &OpenGLRendererPCem::initialized, [=]() {
|
||||
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection);
|
||||
connect(hw, &OpenGLRenderer::initialized, [=]() {
|
||||
/* Buffers are available only after initialization. */
|
||||
imagebufs = rendererWindow->getBuffers();
|
||||
endblit();
|
||||
emit rendererChanged();
|
||||
});
|
||||
connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() {
|
||||
connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
|
||||
/* Renderer not could initialize, fallback to software. */
|
||||
imagebufs = {};
|
||||
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
|
||||
|
||||
Reference in New Issue
Block a user