mirror of https://github.com/mgba-emu/mgba.git
Qt: Begin work on shader selector
This commit is contained in:
parent
ded463ea25
commit
64901c0afe
|
@ -94,6 +94,7 @@ set(SOURCE_FILES
|
|||
SavestateButton.cpp
|
||||
SensorView.cpp
|
||||
SettingsView.cpp
|
||||
ShaderSelector.cpp
|
||||
ShortcutController.cpp
|
||||
ShortcutView.cpp
|
||||
Swatch.cpp
|
||||
|
@ -113,6 +114,7 @@ qt5_wrap_ui(UI_FILES
|
|||
PaletteView.ui
|
||||
SensorView.ui
|
||||
SettingsView.ui
|
||||
ShaderSelector.ui
|
||||
ShortcutView.ui
|
||||
VideoView.ui)
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
struct GBAThread;
|
||||
struct VDir;
|
||||
struct VideoShader;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
|
@ -36,6 +37,7 @@ public:
|
|||
|
||||
virtual bool isDrawing() const = 0;
|
||||
virtual bool supportsShaders() const = 0;
|
||||
virtual VideoShader* shaders() = 0;
|
||||
|
||||
signals:
|
||||
void showCursor();
|
||||
|
|
|
@ -44,6 +44,16 @@ bool DisplayGL::supportsShaders() const {
|
|||
return m_painter->supportsShaders();
|
||||
}
|
||||
|
||||
VideoShader* DisplayGL::shaders() {
|
||||
VideoShader* shaders = nullptr;
|
||||
if (m_drawThread) {
|
||||
QMetaObject::invokeMethod(m_painter, "shaders", Qt::BlockingQueuedConnection, Q_RETURN_ARG(VideoShader*, shaders));
|
||||
} else {
|
||||
shaders = m_painter->shaders();
|
||||
}
|
||||
return shaders;
|
||||
}
|
||||
|
||||
void DisplayGL::startDrawing(GBAThread* thread) {
|
||||
if (m_drawThread) {
|
||||
return;
|
||||
|
@ -158,8 +168,7 @@ PainterGL::PainterGL(QGLWidget* parent, QGLFormat::OpenGLVersionFlags glVersion)
|
|||
, m_active(false)
|
||||
, m_started(false)
|
||||
, m_context(nullptr)
|
||||
, m_shaders(nullptr)
|
||||
, m_nShaders(0)
|
||||
, m_shader{}
|
||||
, m_backend(nullptr)
|
||||
, m_messagePainter(nullptr)
|
||||
{
|
||||
|
@ -209,6 +218,9 @@ PainterGL::~PainterGL() {
|
|||
}
|
||||
delete m_backend;
|
||||
m_backend = nullptr;
|
||||
if (m_shader.passes) {
|
||||
GBAGLES2ShaderFree(&m_shader);
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::setContext(GBAThread* context) {
|
||||
|
@ -248,8 +260,8 @@ void PainterGL::start() {
|
|||
m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId()));
|
||||
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
if (m_shaders) {
|
||||
GBAGLES2ShaderAttach(reinterpret_cast<GBAGLES2Context*>(m_backend), m_shaders, m_nShaders);
|
||||
if (m_shader.passes) {
|
||||
GBAGLES2ShaderAttach(reinterpret_cast<GBAGLES2Context*>(m_backend), static_cast<GBAGLES2Shader*>(m_shader.passes), m_shader.nPasses);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -366,13 +378,18 @@ void PainterGL::setShaders(struct VDir* dir) {
|
|||
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
#endif
|
||||
if (m_shaders) {
|
||||
if (m_shader.passes) {
|
||||
GBAGLES2ShaderDetach(reinterpret_cast<GBAGLES2Context*>(m_backend));
|
||||
GBAGLES2ShaderFree(&m_shader);
|
||||
}
|
||||
GBAGLES2ShaderLoad(&m_shaders, &m_nShaders, nullptr, dir);
|
||||
GBAGLES2ShaderLoad(&m_shader, dir);
|
||||
if (m_started) {
|
||||
GBAGLES2ShaderAttach(reinterpret_cast<GBAGLES2Context*>(m_backend), m_shaders, m_nShaders);
|
||||
GBAGLES2ShaderAttach(reinterpret_cast<GBAGLES2Context*>(m_backend), static_cast<GBAGLES2Shader*>(m_shader.passes), m_shader.nPasses);
|
||||
}
|
||||
m_gl->doneCurrent();
|
||||
#endif
|
||||
}
|
||||
|
||||
VideoShader* PainterGL::shaders() {
|
||||
return &m_shader;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
extern "C" {
|
||||
#include "platform/video-backend.h"
|
||||
}
|
||||
|
||||
struct GBAThread;
|
||||
struct VideoBackend;
|
||||
struct GBAGLES2Shader;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
|
@ -45,6 +47,7 @@ public:
|
|||
|
||||
bool isDrawing() const override { return m_isDrawing; }
|
||||
bool supportsShaders() const override;
|
||||
VideoShader* shaders() override;
|
||||
|
||||
public slots:
|
||||
void startDrawing(GBAThread* context) override;
|
||||
|
@ -96,6 +99,7 @@ public slots:
|
|||
void filter(bool filter);
|
||||
|
||||
void setShaders(struct VDir*);
|
||||
VideoShader* shaders();
|
||||
|
||||
private:
|
||||
void performDraw();
|
||||
|
@ -111,8 +115,7 @@ private:
|
|||
bool m_started;
|
||||
GBAThread* m_context;
|
||||
bool m_supportsShaders;
|
||||
GBAGLES2Shader* m_shaders;
|
||||
size_t m_nShaders;
|
||||
VideoShader m_shader;
|
||||
VideoBackend* m_backend;
|
||||
QSize m_size;
|
||||
MessagePainter* m_messagePainter;
|
||||
|
|
|
@ -22,7 +22,8 @@ public:
|
|||
DisplayQt(QWidget* parent = nullptr);
|
||||
|
||||
bool isDrawing() const override { return m_isDrawing; }
|
||||
bool supportsShaders() const override { return 0; }
|
||||
bool supportsShaders() const override { return false; }
|
||||
VideoShader* shaders() override { return nullptr; }
|
||||
|
||||
public slots:
|
||||
void startDrawing(GBAThread* context) override;
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "ShaderSelector.h"
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QSpinBox>
|
||||
|
||||
extern "C" {
|
||||
#include "platform/video-backend.h"
|
||||
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#include "platform/opengl/gles2.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
ShaderSelector::ShaderSelector(Display* display, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_display(display)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
refreshShaders();
|
||||
}
|
||||
|
||||
ShaderSelector::~ShaderSelector() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void ShaderSelector::clear() {
|
||||
m_ui.shaderName->setText(tr("No shader active"));
|
||||
m_ui.description->clear();
|
||||
m_ui.author->clear();
|
||||
|
||||
while (QWidget* page = m_ui.passes->widget(0)) {
|
||||
m_ui.passes->removeTab(0);
|
||||
delete page;
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderSelector::refreshShaders() {
|
||||
clear();
|
||||
m_shaders = m_display->shaders();
|
||||
if (!m_shaders) {
|
||||
return;
|
||||
}
|
||||
m_ui.shaderName->setText(m_shaders->name);
|
||||
m_ui.description->setText(m_shaders->description);
|
||||
m_ui.author->setText(tr("by %1").arg(m_shaders->author));
|
||||
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
GBAGLES2Shader* shaders = static_cast<GBAGLES2Shader*>(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;
|
||||
std::function<void (size_t, size_t)> bind;
|
||||
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
|
||||
}
|
||||
|
||||
void ShaderSelector::addUniform(QGridLayout* settings, float* value, float min, float max, int y, int x) {
|
||||
QDoubleSpinBox* f = new QDoubleSpinBox;
|
||||
f->setDecimals(3);
|
||||
if (min < max) {
|
||||
f->setMinimum(min);
|
||||
f->setMaximum(max);
|
||||
}
|
||||
f->setValue(*value);
|
||||
f->setSingleStep(0.001);
|
||||
f->setAccelerated(true);
|
||||
settings->addWidget(f, y, x);
|
||||
connect(f, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [value](double v) {
|
||||
*value = v;
|
||||
});
|
||||
}
|
||||
|
||||
void ShaderSelector::addUniform(QGridLayout* settings, int* value, int min, int max, int y, int x) {
|
||||
QSpinBox* i = new QSpinBox;
|
||||
if (min < max) {
|
||||
i->setMinimum(min);
|
||||
i->setMaximum(max);
|
||||
}
|
||||
i->setValue(*value);
|
||||
i->setSingleStep(1);
|
||||
i->setAccelerated(true);
|
||||
settings->addWidget(i, y, x);
|
||||
connect(i, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [value](int v) {
|
||||
*value = v;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef QGBA_SHADER_SELECTOR_H
|
||||
#define QGBA_SHADER_SELECTOR_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_ShaderSelector.h"
|
||||
|
||||
class QGridLayout;
|
||||
struct VideoShader;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class Display;
|
||||
|
||||
class ShaderSelector : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ShaderSelector(Display* display, QWidget* parent = nullptr);
|
||||
~ShaderSelector();
|
||||
|
||||
public slots:
|
||||
void refreshShaders();
|
||||
void clear();
|
||||
|
||||
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);
|
||||
|
||||
Ui::ShaderSelector m_ui;
|
||||
Display* m_display;
|
||||
VideoShader* m_shaders;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,114 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ShaderSelector</class>
|
||||
<widget class="QDialog" name="ShaderSelector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Shaders</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Active Shader:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="shaderName">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="author">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="description">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="passes">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ShaderSelector</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -33,6 +33,7 @@
|
|||
#include "PaletteView.h"
|
||||
#include "SensorView.h"
|
||||
#include "SettingsView.h"
|
||||
#include "ShaderSelector.h"
|
||||
#include "ShortcutController.h"
|
||||
#include "ShortcutView.h"
|
||||
#include "VideoView.h"
|
||||
|
@ -395,6 +396,11 @@ void Window::openAboutScreen() {
|
|||
openView(about);
|
||||
}
|
||||
|
||||
void Window::openShaderWindow() {
|
||||
ShaderSelector* shaderView = new ShaderSelector(m_display);
|
||||
openView(shaderView);
|
||||
}
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
void Window::openGamepadWindow() {
|
||||
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
|
||||
|
@ -1048,6 +1054,13 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
}
|
||||
m_config->updateOption("frameskip");
|
||||
|
||||
QAction* shaderView = new QAction(tr("Shader options..."), avMenu);
|
||||
connect(shaderView, SIGNAL(triggered()), this, SLOT(openShaderWindow()));
|
||||
if (!m_display->supportsShaders()) {
|
||||
shaderView->setEnabled(false);
|
||||
}
|
||||
addControlledAction(avMenu, shaderView, "shaderSelector");
|
||||
|
||||
avMenu->addSeparator();
|
||||
|
||||
QMenu* target = avMenu->addMenu(tr("FPS target"));
|
||||
|
|
|
@ -88,6 +88,8 @@ public slots:
|
|||
|
||||
void openAboutScreen();
|
||||
|
||||
void openShaderWindow();
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
void openGamepadWindow();
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue