diff --git a/CHANGES b/CHANGES index 372317221..b3a97384f 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ Features: - Booting of multiboot images - Customization of GIF recording - Libretro: Cheat code support + - Support for GLSL shaders Bugfixes: - Util: Fix PowerPC PNG read/write pixel order - Qt: Use safer isLoaded check in GameController diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index 40a43becf..0fcea3f0f 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -84,18 +84,35 @@ static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) { struct GBAGLES2Uniform* uniforms = malloc(sizeof(struct GBAGLES2Uniform) * 3); uniforms[0].name = "gamma"; + uniforms[0].readableName = "Gamma"; uniforms[0].type = GL_FLOAT; uniforms[0].value.f = 1.0f; + uniforms[0].min.f = 0.1f; + uniforms[0].max.f = 3.0f; uniforms[1].name = "scale"; + uniforms[1].readableName = "Scale"; uniforms[1].type = GL_FLOAT_VEC3; uniforms[1].value.fvec3[0] = 1.0f; uniforms[1].value.fvec3[1] = 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].readableName = "Bias"; uniforms[2].type = GL_FLOAT_VEC3; uniforms[2].value.fvec3[0] = 0.0f; uniforms[2].value.fvec3[1] = 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->finalShader, 0, 0, 0, 0, 0, 0); glDeleteFramebuffers(1, &context->finalShader.fbo); diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index d755d6c0e..655cf2f07 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -208,6 +208,19 @@ PainterGL::PainterGL(QGLWidget* parent, QGLFormat::OpenGLVersionFlags glVersion) PainterGL* painter = static_cast(v->user); 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(m_gl->winId())); +#if !defined(_WIN32) || defined(USE_EPOXY) + if (m_supportsShaders) { + m_shader.preprocessShader = static_cast(&reinterpret_cast(m_backend)->initialShader); + } +#endif + m_gl->doneCurrent(); + m_backend->user = this; m_backend->filter = false; m_backend->lockAspectRatio = false; @@ -224,11 +237,14 @@ PainterGL::~PainterGL() { for (auto item : m_free) { delete[] item; } - delete m_backend; - m_backend = nullptr; +#if !defined(_WIN32) || defined(USE_EPOXY) if (m_shader.passes) { GBAGLES2ShaderFree(&m_shader); } +#endif + m_backend->deinit(m_backend); + delete m_backend; + m_backend = nullptr; } void PainterGL::setContext(GBAThread* context) { @@ -265,10 +281,9 @@ void PainterGL::start() { #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif - m_backend->init(m_backend, reinterpret_cast(m_gl->winId())); #if !defined(_WIN32) || defined(USE_EPOXY) - if (m_shader.passes) { + if (m_supportsShaders && m_shader.passes) { GBAGLES2ShaderAttach(reinterpret_cast(m_backend), static_cast(m_shader.passes), m_shader.nPasses); } #endif @@ -314,7 +329,6 @@ void PainterGL::stop() { dequeueAll(); m_backend->clear(m_backend); m_backend->swap(m_backend); - m_backend->deinit(m_backend); m_gl->doneCurrent(); m_gl->context()->moveToThread(m_gl->thread()); moveToThread(m_gl->thread()); diff --git a/src/platform/qt/ShaderSelector.cpp b/src/platform/qt/ShaderSelector.cpp index 34d66ffa1..17dbbf49e 100644 --- a/src/platform/qt/ShaderSelector.cpp +++ b/src/platform/qt/ShaderSelector.cpp @@ -106,55 +106,13 @@ void ShaderSelector::refreshShaders() { } #if !defined(_WIN32) || defined(USE_EPOXY) + m_ui.passes->addTab(makePage(static_cast(m_shaders->preprocessShader)), tr("Preprocessing")); GBAGLES2Shader* shaders = static_cast(m_shaders->passes); for (size_t p = 0; p < m_shaders->nPasses; ++p) { - QWidget* page = new QWidget; - QFormLayout* layout = new QFormLayout; - page->setLayout(layout); - 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); + QWidget* page = makePage(&shaders[p]); + if (page) { + m_ui.passes->addTab(page, tr("Pass %1").arg(p + 1)); } - m_ui.passes->addTab(page, tr("Pass %1").arg(p + 1)); } #endif } @@ -191,3 +149,56 @@ void ShaderSelector::addUniform(QGridLayout* settings, int* value, int min, int // 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; +} diff --git a/src/platform/qt/ShaderSelector.h b/src/platform/qt/ShaderSelector.h index 73b45d73e..680891213 100644 --- a/src/platform/qt/ShaderSelector.h +++ b/src/platform/qt/ShaderSelector.h @@ -10,6 +10,7 @@ #include "ui_ShaderSelector.h" +struct GBAGLES2Shader; class QGridLayout; struct VideoShader; @@ -36,6 +37,7 @@ private slots: private: 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); + QWidget* makePage(GBAGLES2Shader*); Ui::ShaderSelector m_ui; Display* m_display; diff --git a/src/platform/video-backend.h b/src/platform/video-backend.h index 542b7aca2..aa930cbdf 100644 --- a/src/platform/video-backend.h +++ b/src/platform/video-backend.h @@ -36,6 +36,7 @@ struct VideoShader { const char* name; const char* author; const char* description; + void* preprocessShader; void* passes; size_t nPasses; };