mirror of https://github.com/mgba-emu/mgba.git
Qt: Add preprocessor shader step customization
This commit is contained in:
parent
a9ae152dd4
commit
f922f3c152
1
CHANGES
1
CHANGES
|
@ -5,6 +5,7 @@ Features:
|
||||||
- Booting of multiboot images
|
- Booting of multiboot images
|
||||||
- Customization of GIF recording
|
- Customization of GIF recording
|
||||||
- Libretro: Cheat code support
|
- Libretro: Cheat code support
|
||||||
|
- Support for GLSL shaders
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- Util: Fix PowerPC PNG read/write pixel order
|
- Util: Fix PowerPC PNG read/write pixel order
|
||||||
- Qt: Use safer isLoaded check in GameController
|
- Qt: Use safer isLoaded check in GameController
|
||||||
|
|
|
@ -84,18 +84,35 @@ static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
|
||||||
|
|
||||||
struct GBAGLES2Uniform* uniforms = malloc(sizeof(struct GBAGLES2Uniform) * 3);
|
struct GBAGLES2Uniform* uniforms = malloc(sizeof(struct GBAGLES2Uniform) * 3);
|
||||||
uniforms[0].name = "gamma";
|
uniforms[0].name = "gamma";
|
||||||
|
uniforms[0].readableName = "Gamma";
|
||||||
uniforms[0].type = GL_FLOAT;
|
uniforms[0].type = GL_FLOAT;
|
||||||
uniforms[0].value.f = 1.0f;
|
uniforms[0].value.f = 1.0f;
|
||||||
|
uniforms[0].min.f = 0.1f;
|
||||||
|
uniforms[0].max.f = 3.0f;
|
||||||
uniforms[1].name = "scale";
|
uniforms[1].name = "scale";
|
||||||
|
uniforms[1].readableName = "Scale";
|
||||||
uniforms[1].type = GL_FLOAT_VEC3;
|
uniforms[1].type = GL_FLOAT_VEC3;
|
||||||
uniforms[1].value.fvec3[0] = 1.0f;
|
uniforms[1].value.fvec3[0] = 1.0f;
|
||||||
uniforms[1].value.fvec3[1] = 1.0f;
|
uniforms[1].value.fvec3[1] = 1.0f;
|
||||||
uniforms[1].value.fvec3[2] = 1.0f;
|
uniforms[1].value.fvec3[2] = 1.0f;
|
||||||
|
uniforms[1].min.fvec3[0] = -1.0f;
|
||||||
|
uniforms[1].min.fvec3[1] = -1.0f;
|
||||||
|
uniforms[1].min.fvec3[2] = -1.0f;
|
||||||
|
uniforms[1].max.fvec3[0] = 2.0f;
|
||||||
|
uniforms[1].max.fvec3[1] = 2.0f;
|
||||||
|
uniforms[1].max.fvec3[2] = 2.0f;
|
||||||
uniforms[2].name = "bias";
|
uniforms[2].name = "bias";
|
||||||
|
uniforms[2].readableName = "Bias";
|
||||||
uniforms[2].type = GL_FLOAT_VEC3;
|
uniforms[2].type = GL_FLOAT_VEC3;
|
||||||
uniforms[2].value.fvec3[0] = 0.0f;
|
uniforms[2].value.fvec3[0] = 0.0f;
|
||||||
uniforms[2].value.fvec3[1] = 0.0f;
|
uniforms[2].value.fvec3[1] = 0.0f;
|
||||||
uniforms[2].value.fvec3[2] = 0.0f;
|
uniforms[2].value.fvec3[2] = 0.0f;
|
||||||
|
uniforms[2].min.fvec3[0] = -1.0f;
|
||||||
|
uniforms[2].min.fvec3[1] = -1.0f;
|
||||||
|
uniforms[2].min.fvec3[2] = -1.0f;
|
||||||
|
uniforms[2].max.fvec3[0] = 1.0f;
|
||||||
|
uniforms[2].max.fvec3[1] = 1.0f;
|
||||||
|
uniforms[2].max.fvec3[2] = 1.0f;
|
||||||
GBAGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, uniforms, 3);
|
GBAGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, uniforms, 3);
|
||||||
GBAGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, 0, 0);
|
GBAGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, 0, 0);
|
||||||
glDeleteFramebuffers(1, &context->finalShader.fbo);
|
glDeleteFramebuffers(1, &context->finalShader.fbo);
|
||||||
|
|
|
@ -208,6 +208,19 @@ PainterGL::PainterGL(QGLWidget* parent, QGLFormat::OpenGLVersionFlags glVersion)
|
||||||
PainterGL* painter = static_cast<PainterGL*>(v->user);
|
PainterGL* painter = static_cast<PainterGL*>(v->user);
|
||||||
painter->m_gl->swapBuffers();
|
painter->m_gl->swapBuffers();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
m_gl->makeCurrent();
|
||||||
|
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||||
|
epoxy_handle_external_wglMakeCurrent();
|
||||||
|
#endif
|
||||||
|
m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId()));
|
||||||
|
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||||
|
if (m_supportsShaders) {
|
||||||
|
m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<GBAGLES2Context*>(m_backend)->initialShader);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_gl->doneCurrent();
|
||||||
|
|
||||||
m_backend->user = this;
|
m_backend->user = this;
|
||||||
m_backend->filter = false;
|
m_backend->filter = false;
|
||||||
m_backend->lockAspectRatio = false;
|
m_backend->lockAspectRatio = false;
|
||||||
|
@ -224,11 +237,14 @@ PainterGL::~PainterGL() {
|
||||||
for (auto item : m_free) {
|
for (auto item : m_free) {
|
||||||
delete[] item;
|
delete[] item;
|
||||||
}
|
}
|
||||||
delete m_backend;
|
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||||
m_backend = nullptr;
|
|
||||||
if (m_shader.passes) {
|
if (m_shader.passes) {
|
||||||
GBAGLES2ShaderFree(&m_shader);
|
GBAGLES2ShaderFree(&m_shader);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
m_backend->deinit(m_backend);
|
||||||
|
delete m_backend;
|
||||||
|
m_backend = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::setContext(GBAThread* context) {
|
void PainterGL::setContext(GBAThread* context) {
|
||||||
|
@ -265,10 +281,9 @@ void PainterGL::start() {
|
||||||
#if defined(_WIN32) && defined(USE_EPOXY)
|
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||||
epoxy_handle_external_wglMakeCurrent();
|
epoxy_handle_external_wglMakeCurrent();
|
||||||
#endif
|
#endif
|
||||||
m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId()));
|
|
||||||
|
|
||||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||||
if (m_shader.passes) {
|
if (m_supportsShaders && m_shader.passes) {
|
||||||
GBAGLES2ShaderAttach(reinterpret_cast<GBAGLES2Context*>(m_backend), static_cast<GBAGLES2Shader*>(m_shader.passes), m_shader.nPasses);
|
GBAGLES2ShaderAttach(reinterpret_cast<GBAGLES2Context*>(m_backend), static_cast<GBAGLES2Shader*>(m_shader.passes), m_shader.nPasses);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -314,7 +329,6 @@ void PainterGL::stop() {
|
||||||
dequeueAll();
|
dequeueAll();
|
||||||
m_backend->clear(m_backend);
|
m_backend->clear(m_backend);
|
||||||
m_backend->swap(m_backend);
|
m_backend->swap(m_backend);
|
||||||
m_backend->deinit(m_backend);
|
|
||||||
m_gl->doneCurrent();
|
m_gl->doneCurrent();
|
||||||
m_gl->context()->moveToThread(m_gl->thread());
|
m_gl->context()->moveToThread(m_gl->thread());
|
||||||
moveToThread(m_gl->thread());
|
moveToThread(m_gl->thread());
|
||||||
|
|
|
@ -106,55 +106,13 @@ void ShaderSelector::refreshShaders() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||||
|
m_ui.passes->addTab(makePage(static_cast<GBAGLES2Shader*>(m_shaders->preprocessShader)), tr("Preprocessing"));
|
||||||
GBAGLES2Shader* shaders = static_cast<GBAGLES2Shader*>(m_shaders->passes);
|
GBAGLES2Shader* shaders = static_cast<GBAGLES2Shader*>(m_shaders->passes);
|
||||||
for (size_t p = 0; p < m_shaders->nPasses; ++p) {
|
for (size_t p = 0; p < m_shaders->nPasses; ++p) {
|
||||||
QWidget* page = new QWidget;
|
QWidget* page = makePage(&shaders[p]);
|
||||||
QFormLayout* layout = new QFormLayout;
|
if (page) {
|
||||||
page->setLayout(layout);
|
m_ui.passes->addTab(page, tr("Pass %1").arg(p + 1));
|
||||||
for (size_t u = 0 ; u < shaders[p].nUniforms; ++u) {
|
|
||||||
QGridLayout* settings = new QGridLayout;
|
|
||||||
GBAGLES2Uniform* uniform = &shaders[p].uniforms[u];
|
|
||||||
switch (uniform->type) {
|
|
||||||
case GL_FLOAT:
|
|
||||||
addUniform(settings, &uniform->value.f, uniform->min.f, uniform->max.f, 0, 0);
|
|
||||||
break;
|
|
||||||
case GL_FLOAT_VEC2:
|
|
||||||
addUniform(settings, &uniform->value.fvec2[0], uniform->min.fvec2[0], uniform->max.fvec2[0], 0, 0);
|
|
||||||
addUniform(settings, &uniform->value.fvec2[1], uniform->min.fvec2[1], uniform->max.fvec2[1], 0, 1);
|
|
||||||
break;
|
|
||||||
case GL_FLOAT_VEC3:
|
|
||||||
addUniform(settings, &uniform->value.fvec3[0], uniform->min.fvec3[0], uniform->max.fvec3[0], 0, 0);
|
|
||||||
addUniform(settings, &uniform->value.fvec3[1], uniform->min.fvec3[1], uniform->max.fvec3[1], 0, 1);
|
|
||||||
addUniform(settings, &uniform->value.fvec3[2], uniform->min.fvec3[2], uniform->max.fvec3[2], 0, 2);
|
|
||||||
break;
|
|
||||||
case GL_FLOAT_VEC4:
|
|
||||||
addUniform(settings, &uniform->value.fvec4[0], uniform->min.fvec4[0], uniform->max.fvec4[0], 0, 0);
|
|
||||||
addUniform(settings, &uniform->value.fvec4[1], uniform->min.fvec4[1], uniform->max.fvec4[1], 0, 1);
|
|
||||||
addUniform(settings, &uniform->value.fvec4[2], uniform->min.fvec4[2], uniform->max.fvec4[2], 0, 2);
|
|
||||||
addUniform(settings, &uniform->value.fvec4[3], uniform->min.fvec4[3], uniform->max.fvec4[3], 0, 3);
|
|
||||||
break;
|
|
||||||
case GL_INT:
|
|
||||||
addUniform(settings, &uniform->value.i, uniform->min.i, uniform->max.i, 0, 0);
|
|
||||||
break;
|
|
||||||
case GL_INT_VEC2:
|
|
||||||
addUniform(settings, &uniform->value.ivec2[0], uniform->min.ivec2[0], uniform->max.ivec2[0], 0, 0);
|
|
||||||
addUniform(settings, &uniform->value.ivec2[1], uniform->min.ivec2[1], uniform->max.ivec2[1], 0, 1);
|
|
||||||
break;
|
|
||||||
case GL_INT_VEC3:
|
|
||||||
addUniform(settings, &uniform->value.ivec3[0], uniform->min.ivec3[0], uniform->max.ivec3[0], 0, 0);
|
|
||||||
addUniform(settings, &uniform->value.ivec3[1], uniform->min.ivec3[1], uniform->max.ivec3[1], 0, 1);
|
|
||||||
addUniform(settings, &uniform->value.ivec3[2], uniform->min.ivec3[2], uniform->max.ivec3[2], 0, 2);
|
|
||||||
break;
|
|
||||||
case GL_INT_VEC4:
|
|
||||||
addUniform(settings, &uniform->value.ivec4[0], uniform->min.ivec4[0], uniform->max.ivec4[0], 0, 0);
|
|
||||||
addUniform(settings, &uniform->value.ivec4[1], uniform->min.ivec4[1], uniform->max.ivec4[1], 0, 1);
|
|
||||||
addUniform(settings, &uniform->value.ivec4[2], uniform->min.ivec4[2], uniform->max.ivec4[2], 0, 2);
|
|
||||||
addUniform(settings, &uniform->value.ivec4[3], uniform->min.ivec4[3], uniform->max.ivec4[3], 0, 3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
layout->addRow(shaders[p].uniforms[u].readableName, settings);
|
|
||||||
}
|
}
|
||||||
m_ui.passes->addTab(page, tr("Pass %1").arg(p + 1));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -191,3 +149,56 @@ void ShaderSelector::addUniform(QGridLayout* settings, int* value, int min, int
|
||||||
// TODO: Config
|
// TODO: Config
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget* ShaderSelector::makePage(GBAGLES2Shader* shader) {
|
||||||
|
if (!shader->nUniforms) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
QWidget* page = new QWidget;
|
||||||
|
QFormLayout* layout = new QFormLayout;
|
||||||
|
page->setLayout(layout);
|
||||||
|
for (size_t u = 0 ; u < shader->nUniforms; ++u) {
|
||||||
|
QGridLayout* settings = new QGridLayout;
|
||||||
|
GBAGLES2Uniform* uniform = &shader->uniforms[u];
|
||||||
|
switch (uniform->type) {
|
||||||
|
case GL_FLOAT:
|
||||||
|
addUniform(settings, &uniform->value.f, uniform->min.f, uniform->max.f, 0, 0);
|
||||||
|
break;
|
||||||
|
case GL_FLOAT_VEC2:
|
||||||
|
addUniform(settings, &uniform->value.fvec2[0], uniform->min.fvec2[0], uniform->max.fvec2[0], 0, 0);
|
||||||
|
addUniform(settings, &uniform->value.fvec2[1], uniform->min.fvec2[1], uniform->max.fvec2[1], 0, 1);
|
||||||
|
break;
|
||||||
|
case GL_FLOAT_VEC3:
|
||||||
|
addUniform(settings, &uniform->value.fvec3[0], uniform->min.fvec3[0], uniform->max.fvec3[0], 0, 0);
|
||||||
|
addUniform(settings, &uniform->value.fvec3[1], uniform->min.fvec3[1], uniform->max.fvec3[1], 0, 1);
|
||||||
|
addUniform(settings, &uniform->value.fvec3[2], uniform->min.fvec3[2], uniform->max.fvec3[2], 0, 2);
|
||||||
|
break;
|
||||||
|
case GL_FLOAT_VEC4:
|
||||||
|
addUniform(settings, &uniform->value.fvec4[0], uniform->min.fvec4[0], uniform->max.fvec4[0], 0, 0);
|
||||||
|
addUniform(settings, &uniform->value.fvec4[1], uniform->min.fvec4[1], uniform->max.fvec4[1], 0, 1);
|
||||||
|
addUniform(settings, &uniform->value.fvec4[2], uniform->min.fvec4[2], uniform->max.fvec4[2], 0, 2);
|
||||||
|
addUniform(settings, &uniform->value.fvec4[3], uniform->min.fvec4[3], uniform->max.fvec4[3], 0, 3);
|
||||||
|
break;
|
||||||
|
case GL_INT:
|
||||||
|
addUniform(settings, &uniform->value.i, uniform->min.i, uniform->max.i, 0, 0);
|
||||||
|
break;
|
||||||
|
case GL_INT_VEC2:
|
||||||
|
addUniform(settings, &uniform->value.ivec2[0], uniform->min.ivec2[0], uniform->max.ivec2[0], 0, 0);
|
||||||
|
addUniform(settings, &uniform->value.ivec2[1], uniform->min.ivec2[1], uniform->max.ivec2[1], 0, 1);
|
||||||
|
break;
|
||||||
|
case GL_INT_VEC3:
|
||||||
|
addUniform(settings, &uniform->value.ivec3[0], uniform->min.ivec3[0], uniform->max.ivec3[0], 0, 0);
|
||||||
|
addUniform(settings, &uniform->value.ivec3[1], uniform->min.ivec3[1], uniform->max.ivec3[1], 0, 1);
|
||||||
|
addUniform(settings, &uniform->value.ivec3[2], uniform->min.ivec3[2], uniform->max.ivec3[2], 0, 2);
|
||||||
|
break;
|
||||||
|
case GL_INT_VEC4:
|
||||||
|
addUniform(settings, &uniform->value.ivec4[0], uniform->min.ivec4[0], uniform->max.ivec4[0], 0, 0);
|
||||||
|
addUniform(settings, &uniform->value.ivec4[1], uniform->min.ivec4[1], uniform->max.ivec4[1], 0, 1);
|
||||||
|
addUniform(settings, &uniform->value.ivec4[2], uniform->min.ivec4[2], uniform->max.ivec4[2], 0, 2);
|
||||||
|
addUniform(settings, &uniform->value.ivec4[3], uniform->min.ivec4[3], uniform->max.ivec4[3], 0, 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
layout->addRow(shader->uniforms[u].readableName, settings);
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "ui_ShaderSelector.h"
|
#include "ui_ShaderSelector.h"
|
||||||
|
|
||||||
|
struct GBAGLES2Shader;
|
||||||
class QGridLayout;
|
class QGridLayout;
|
||||||
struct VideoShader;
|
struct VideoShader;
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ private slots:
|
||||||
private:
|
private:
|
||||||
void addUniform(QGridLayout*, float* value, float min, float max, int y, int x);
|
void addUniform(QGridLayout*, float* value, float min, float max, int y, int x);
|
||||||
void addUniform(QGridLayout*, int* value, int min, int max, int y, int x);
|
void addUniform(QGridLayout*, int* value, int min, int max, int y, int x);
|
||||||
|
QWidget* makePage(GBAGLES2Shader*);
|
||||||
|
|
||||||
Ui::ShaderSelector m_ui;
|
Ui::ShaderSelector m_ui;
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct VideoShader {
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* author;
|
const char* author;
|
||||||
const char* description;
|
const char* description;
|
||||||
|
void* preprocessShader;
|
||||||
void* passes;
|
void* passes;
|
||||||
size_t nPasses;
|
size_t nPasses;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue