Qt: Begin work on shader selector

This commit is contained in:
Jeffrey Pfau 2015-11-19 23:52:17 -08:00
parent ded463ea25
commit 64901c0afe
10 changed files with 352 additions and 12 deletions

View File

@ -94,6 +94,7 @@ set(SOURCE_FILES
SavestateButton.cpp SavestateButton.cpp
SensorView.cpp SensorView.cpp
SettingsView.cpp SettingsView.cpp
ShaderSelector.cpp
ShortcutController.cpp ShortcutController.cpp
ShortcutView.cpp ShortcutView.cpp
Swatch.cpp Swatch.cpp
@ -113,6 +114,7 @@ qt5_wrap_ui(UI_FILES
PaletteView.ui PaletteView.ui
SensorView.ui SensorView.ui
SettingsView.ui SettingsView.ui
ShaderSelector.ui
ShortcutView.ui ShortcutView.ui
VideoView.ui) VideoView.ui)

View File

@ -12,6 +12,7 @@
struct GBAThread; struct GBAThread;
struct VDir; struct VDir;
struct VideoShader;
namespace QGBA { namespace QGBA {
@ -36,6 +37,7 @@ public:
virtual bool isDrawing() const = 0; virtual bool isDrawing() const = 0;
virtual bool supportsShaders() const = 0; virtual bool supportsShaders() const = 0;
virtual VideoShader* shaders() = 0;
signals: signals:
void showCursor(); void showCursor();

View File

@ -44,6 +44,16 @@ bool DisplayGL::supportsShaders() const {
return m_painter->supportsShaders(); 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) { void DisplayGL::startDrawing(GBAThread* thread) {
if (m_drawThread) { if (m_drawThread) {
return; return;
@ -158,8 +168,7 @@ PainterGL::PainterGL(QGLWidget* parent, QGLFormat::OpenGLVersionFlags glVersion)
, m_active(false) , m_active(false)
, m_started(false) , m_started(false)
, m_context(nullptr) , m_context(nullptr)
, m_shaders(nullptr) , m_shader{}
, m_nShaders(0)
, m_backend(nullptr) , m_backend(nullptr)
, m_messagePainter(nullptr) , m_messagePainter(nullptr)
{ {
@ -209,6 +218,9 @@ PainterGL::~PainterGL() {
} }
delete m_backend; delete m_backend;
m_backend = nullptr; m_backend = nullptr;
if (m_shader.passes) {
GBAGLES2ShaderFree(&m_shader);
}
} }
void PainterGL::setContext(GBAThread* context) { void PainterGL::setContext(GBAThread* context) {
@ -248,8 +260,8 @@ void PainterGL::start() {
m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId())); 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_shaders) { if (m_shader.passes) {
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);
} }
#endif #endif
@ -366,13 +378,18 @@ void PainterGL::setShaders(struct VDir* dir) {
#if defined(_WIN32) && defined(USE_EPOXY) #if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent(); epoxy_handle_external_wglMakeCurrent();
#endif #endif
if (m_shaders) { if (m_shader.passes) {
GBAGLES2ShaderDetach(reinterpret_cast<GBAGLES2Context*>(m_backend)); GBAGLES2ShaderDetach(reinterpret_cast<GBAGLES2Context*>(m_backend));
GBAGLES2ShaderFree(&m_shader);
} }
GBAGLES2ShaderLoad(&m_shaders, &m_nShaders, nullptr, dir); GBAGLES2ShaderLoad(&m_shader, dir);
if (m_started) { 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(); m_gl->doneCurrent();
#endif #endif
} }
VideoShader* PainterGL::shaders() {
return &m_shader;
}

View File

@ -19,9 +19,11 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
extern "C" {
#include "platform/video-backend.h"
}
struct GBAThread; struct GBAThread;
struct VideoBackend;
struct GBAGLES2Shader;
namespace QGBA { namespace QGBA {
@ -45,6 +47,7 @@ public:
bool isDrawing() const override { return m_isDrawing; } bool isDrawing() const override { return m_isDrawing; }
bool supportsShaders() const override; bool supportsShaders() const override;
VideoShader* shaders() override;
public slots: public slots:
void startDrawing(GBAThread* context) override; void startDrawing(GBAThread* context) override;
@ -96,6 +99,7 @@ public slots:
void filter(bool filter); void filter(bool filter);
void setShaders(struct VDir*); void setShaders(struct VDir*);
VideoShader* shaders();
private: private:
void performDraw(); void performDraw();
@ -111,8 +115,7 @@ private:
bool m_started; bool m_started;
GBAThread* m_context; GBAThread* m_context;
bool m_supportsShaders; bool m_supportsShaders;
GBAGLES2Shader* m_shaders; VideoShader m_shader;
size_t m_nShaders;
VideoBackend* m_backend; VideoBackend* m_backend;
QSize m_size; QSize m_size;
MessagePainter* m_messagePainter; MessagePainter* m_messagePainter;

View File

@ -22,7 +22,8 @@ public:
DisplayQt(QWidget* parent = nullptr); DisplayQt(QWidget* parent = nullptr);
bool isDrawing() const override { return m_isDrawing; } 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: public slots:
void startDrawing(GBAThread* context) override; void startDrawing(GBAThread* context) override;

View File

@ -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;
});
}

View File

@ -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

View File

@ -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>

View File

@ -33,6 +33,7 @@
#include "PaletteView.h" #include "PaletteView.h"
#include "SensorView.h" #include "SensorView.h"
#include "SettingsView.h" #include "SettingsView.h"
#include "ShaderSelector.h"
#include "ShortcutController.h" #include "ShortcutController.h"
#include "ShortcutView.h" #include "ShortcutView.h"
#include "VideoView.h" #include "VideoView.h"
@ -395,6 +396,11 @@ void Window::openAboutScreen() {
openView(about); openView(about);
} }
void Window::openShaderWindow() {
ShaderSelector* shaderView = new ShaderSelector(m_display);
openView(shaderView);
}
#ifdef BUILD_SDL #ifdef BUILD_SDL
void Window::openGamepadWindow() { void Window::openGamepadWindow() {
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON); const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
@ -1048,6 +1054,13 @@ void Window::setupMenu(QMenuBar* menubar) {
} }
m_config->updateOption("frameskip"); 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(); avMenu->addSeparator();
QMenu* target = avMenu->addMenu(tr("FPS target")); QMenu* target = avMenu->addMenu(tr("FPS target"));

View File

@ -88,6 +88,8 @@ public slots:
void openAboutScreen(); void openAboutScreen();
void openShaderWindow();
#ifdef BUILD_SDL #ifdef BUILD_SDL
void openGamepadWindow(); void openGamepadWindow();
#endif #endif