Qt: Post processing UI

This commit is contained in:
Connor McLaughlin 2020-09-13 01:20:02 +10:00
parent 2819715260
commit 021f333ec2
17 changed files with 496 additions and 69 deletions

View File

@ -54,6 +54,11 @@ set(SRCS
mainwindow.ui mainwindow.ui
memorycardsettingswidget.cpp memorycardsettingswidget.cpp
memorycardsettingswidget.h memorycardsettingswidget.h
postprocessingchainconfigwidget.cpp
postprocessingchainconfigwidget.h
postprocessingchainconfigwidget.ui
postprocessingshaderconfigwidget.cpp
postprocessingshaderconfigwidget.h
qtdisplaywidget.cpp qtdisplaywidget.cpp
qtdisplaywidget.h qtdisplaywidget.h
qthostinterface.cpp qthostinterface.cpp

View File

@ -1,9 +1,11 @@
#include "displaysettingswidget.h" #include "displaysettingswidget.h"
#include "core/gpu.h" #include "core/gpu.h"
#include "core/settings.h" #include "core/settings.h"
#include "postprocessingchainconfigwidget.h"
#include "qtutils.h" #include "qtutils.h"
#include "settingsdialog.h" #include "settingsdialog.h"
#include "settingwidgetbinder.h" #include "settingwidgetbinder.h"
#include <QtWidgets/QMessageBox>
// For enumerating adapters. // For enumerating adapters.
#include "frontend-common/vulkan_host_display.h" #include "frontend-common/vulkan_host_display.h"
@ -45,6 +47,25 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
&DisplaySettingsWidget::onGPUAdapterIndexChanged); &DisplaySettingsWidget::onGPUAdapterIndexChanged);
populateGPUAdapters(); populateGPUAdapters();
{
std::string post_chain = g_host_interface->GetStringSettingValue("Display", "PostProcessChain");
if (!post_chain.empty() && !m_ui.postChain->setConfigString(post_chain))
{
QMessageBox::critical(this, tr("Error"),
tr("The current post-processing chain is invalid, it has been reset. Any changes made will "
"overwrite the existing config."));
}
}
connect(m_ui.postChain, &PostProcessingChainConfigWidget::chainConfigStringChanged,
[this](const std::string& new_config) {
if (new_config.empty())
m_host_interface->RemoveSettingValue("Display", "PostProcessChain");
else
m_host_interface->SetStringSettingValue("Display", "PostProcessChain", new_config.c_str());
m_host_interface->applySettings();
});
dialog->registerWidgetHelp( dialog->registerWidgetHelp(
m_ui.renderer, tr("Renderer"), Settings::GetRendererDisplayName(Settings::DEFAULT_GPU_RENDERER), m_ui.renderer, tr("Renderer"), Settings::GetRendererDisplayName(Settings::DEFAULT_GPU_RENDERER),
tr("Chooses the backend to use for rendering the console/game visuals. <br>Depending on your system and hardware, " tr("Chooses the backend to use for rendering the console/game visuals. <br>Depending on your system and hardware, "

View File

@ -5,6 +5,7 @@
#include "ui_displaysettingswidget.h" #include "ui_displaysettingswidget.h"
class QtHostInterface; class QtHostInterface;
class PostProcessingChainConfigWidget;
class SettingsDialog; class SettingsDialog;
class DisplaySettingsWidget : public QWidget class DisplaySettingsWidget : public QWidget

View File

@ -26,86 +26,90 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
<string>Basic</string> <string>Basic</string>
</property> </property>
<layout class="QFormLayout" name="formLayout_3"> <layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>Renderer:</string> <string>Renderer:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="renderer"/> <widget class="QComboBox" name="renderer"/>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Adapter:</string> <string>Adapter:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="adapter"/> <widget class="QComboBox" name="adapter"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Screen Display</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="displayAspectRatio"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Crop:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="displayCropMode"/>
</item> </item>
<item row="2" column="0" colspan="2"> <item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="displayLinearFiltering"> <widget class="QCheckBox" name="vsync">
<property name="text"> <property name="text">
<string>Linear Upscaling</string> <string>VSync</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="2"> </layout>
<widget class="QCheckBox" name="displayIntegerScaling">
<property name="text">
<string>Integer Upscaling</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="vsync">
<property name="text">
<string>VSync</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Screen Display</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="displayAspectRatio"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Crop:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="displayCropMode"/>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="displayLinearFiltering">
<property name="text">
<string>Linear Upscaling</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="displayIntegerScaling">
<property name="text">
<string>Integer Upscaling</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5"> <widget class="QGroupBox" name="groupBox_5">
<property name="title"> <property name="title">
<string>On-Screen Display</string> <string>On-Screen Display</string>
@ -149,21 +153,53 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Post-Processing Chain</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="PostProcessingChainConfigWidget" name="postChain" native="true"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>40</height> <height>40</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>PostProcessingChainConfigWidget</class>
<extends>QWidget</extends>
<header>postprocessingchainconfigwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View File

@ -56,6 +56,8 @@
<ClCompile Include="mainwindow.cpp" /> <ClCompile Include="mainwindow.cpp" />
<ClCompile Include="controllersettingswidget.cpp" /> <ClCompile Include="controllersettingswidget.cpp" />
<ClCompile Include="memorycardsettingswidget.cpp" /> <ClCompile Include="memorycardsettingswidget.cpp" />
<ClCompile Include="postprocessingchainconfigwidget.cpp" />
<ClCompile Include="postprocessingshaderconfigwidget.cpp" />
<ClCompile Include="qthostinterface.cpp" /> <ClCompile Include="qthostinterface.cpp" />
<ClCompile Include="qtprogresscallback.cpp" /> <ClCompile Include="qtprogresscallback.cpp" />
<ClCompile Include="qtutils.cpp" /> <ClCompile Include="qtutils.cpp" />
@ -84,6 +86,8 @@
<QtMoc Include="gamelistsettingswidget.h" /> <QtMoc Include="gamelistsettingswidget.h" />
<QtMoc Include="gamelistwidget.h" /> <QtMoc Include="gamelistwidget.h" />
<QtMoc Include="gamepropertiesdialog.h" /> <QtMoc Include="gamepropertiesdialog.h" />
<QtMoc Include="postprocessingchainconfigwidget.h" />
<QtMoc Include="postprocessingshaderconfigwidget.h" />
<QtMoc Include="mainwindow.h" /> <QtMoc Include="mainwindow.h" />
<QtMoc Include="qthostinterface.h" /> <QtMoc Include="qthostinterface.h" />
<ClInclude Include="qtutils.h" /> <ClInclude Include="qtutils.h" />
@ -143,6 +147,9 @@
<QtUi Include="gamepropertiesdialog.ui"> <QtUi Include="gamepropertiesdialog.ui">
<FileType>Document</FileType> <FileType>Document</FileType>
</QtUi> </QtUi>
<QtUi Include="postprocessingchainconfigwidget.ui">
<FileType>Document</FileType>
</QtUi>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtResource Include="resources\resources.qrc"> <QtResource Include="resources\resources.qrc">
@ -169,6 +176,8 @@
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" /> <ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" /> <ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
<ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_postprocessingchainconfigwidget.cpp" />
<ClCompile Include="$(IntDir)moc_postprocessingshaderconfigwidget.cpp" />
<ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" /> <ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" />
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" /> <ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
<ClCompile Include="$(IntDir)moc_qtprogresscallback.cpp" /> <ClCompile Include="$(IntDir)moc_qtprogresscallback.cpp" />

View File

@ -0,0 +1,174 @@
#include "postprocessingchainconfigwidget.h"
#include "frontend-common/postprocessing_chain.h"
#include <QtGui/QCursor>
#include <QtWidgets/QMenu>
#include <QtWidgets/QMessageBox>
PostProcessingChainConfigWidget::PostProcessingChainConfigWidget(QWidget* parent) : QWidget(parent)
{
m_ui.setupUi(this);
connectUi();
updateButtonStates();
}
PostProcessingChainConfigWidget::~PostProcessingChainConfigWidget() = default;
void PostProcessingChainConfigWidget::connectUi()
{
connect(m_ui.add, &QPushButton::clicked, this, &PostProcessingChainConfigWidget::onAddButtonClicked);
connect(m_ui.remove, &QPushButton::clicked, this, &PostProcessingChainConfigWidget::onRemoveButtonClicked);
connect(m_ui.clear, &QPushButton::clicked, this, &PostProcessingChainConfigWidget::onClearButtonClicked);
connect(m_ui.moveUp, &QPushButton::clicked, this, &PostProcessingChainConfigWidget::onMoveUpButtonClicked);
connect(m_ui.moveDown, &QPushButton::clicked, this, &PostProcessingChainConfigWidget::onMoveDownButtonClicked);
connect(m_ui.shaderSettings, &QPushButton::clicked, this,
&PostProcessingChainConfigWidget::onShaderConfigButtonClicked);
connect(m_ui.shaders, &QListWidget::itemSelectionChanged, this, &PostProcessingChainConfigWidget::updateButtonStates);
m_ui.loadPreset->setEnabled(false);
m_ui.savePreset->setEnabled(false);
}
bool PostProcessingChainConfigWidget::setConfigString(const std::string_view& config_string)
{
if (!m_chain.CreateFromString(config_string))
return false;
updateList();
return true;
}
std::optional<u32> PostProcessingChainConfigWidget::getSelectedIndex() const
{
QList<QListWidgetItem*> selected_items = m_ui.shaders->selectedItems();
return selected_items.empty() ? std::nullopt :
std::optional<u32>(selected_items.first()->data(Qt::UserRole).toUInt());
}
void PostProcessingChainConfigWidget::updateList()
{
m_ui.shaders->clear();
for (u32 i = 0; i < m_chain.GetStageCount(); i++)
{
const FrontendCommon::PostProcessingShader& shader = m_chain.GetShaderStage(i);
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(shader.GetName()), m_ui.shaders);
item->setData(Qt::UserRole, QVariant(i));
}
updateButtonStates();
}
void PostProcessingChainConfigWidget::configChanged()
{
if (m_chain.IsEmpty())
chainConfigStringChanged(std::string());
else
chainConfigStringChanged(m_chain.GetConfigString());
}
void PostProcessingChainConfigWidget::updateButtonStates()
{
std::optional<u32> index = getSelectedIndex();
m_ui.remove->setEnabled(index.has_value());
m_ui.clear->setEnabled(!m_chain.IsEmpty());
m_ui.shaderSettings->setEnabled(index.has_value());
if (index.has_value())
{
m_ui.moveUp->setEnabled(index.value() > 0);
m_ui.moveDown->setEnabled(index.value() < (m_chain.GetStageCount() - 1u));
}
else
{
m_ui.moveUp->setEnabled(false);
m_ui.moveDown->setEnabled(false);
}
}
void PostProcessingChainConfigWidget::onAddButtonClicked()
{
QMenu menu;
const std::vector<std::string> shaders(FrontendCommon::PostProcessingChain::GetAvailableShaderNames());
if (shaders.empty())
{
menu.addAction(tr("No Shaders Available"))->setEnabled(false);
}
else
{
for (const std::string& shader : shaders)
{
QAction* action = menu.addAction(QString::fromStdString(shader));
connect(action, &QAction::triggered, [this, &shader]() {
if (!m_chain.AddStage(shader))
{
QMessageBox::critical(this, tr("Error"), tr("Failed to add shader. The log may contain more information."));
return;
}
updateList();
configChanged();
});
}
}
menu.exec(QCursor::pos());
}
void PostProcessingChainConfigWidget::onRemoveButtonClicked()
{
QList<QListWidgetItem*> selected_items = m_ui.shaders->selectedItems();
if (selected_items.empty())
return;
QListWidgetItem* item = selected_items.first();
u32 index = item->data(Qt::UserRole).toUInt();
if (index < m_chain.GetStageCount())
{
m_chain.RemoveStage(index);
updateList();
configChanged();
}
}
void PostProcessingChainConfigWidget::onClearButtonClicked()
{
if (QMessageBox::question(this, tr("Question"), tr("Are you sure you want to clear all shader stages?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
m_chain.ClearStages();
updateList();
configChanged();
}
}
void PostProcessingChainConfigWidget::onMoveUpButtonClicked()
{
std::optional<u32> index = getSelectedIndex();
if (index.has_value())
{
m_chain.MoveStageUp(index.value());
updateList();
configChanged();
}
}
void PostProcessingChainConfigWidget::onMoveDownButtonClicked()
{
std::optional<u32> index = getSelectedIndex();
if (index.has_value())
{
m_chain.MoveStageDown(index.value());
updateList();
configChanged();
}
}
void PostProcessingChainConfigWidget::onShaderConfigButtonClicked()
{
std::optional<u32> index = getSelectedIndex();
if (index.has_value())
{
}
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "common/types.h"
#include "ui_postprocessingchainconfigwidget.h"
#include "frontend-common/postprocessing_chain.h"
#include <QtWidgets/QWidget>
#include <optional>
#include <memory>
#include <string_view>
namespace FrontendCommon {
class PostProcessingChain;
}
class PostProcessingChainConfigWidget : public QWidget
{
Q_OBJECT
public:
PostProcessingChainConfigWidget(QWidget* parent);
~PostProcessingChainConfigWidget();
bool setConfigString(const std::string_view& config_string);
Q_SIGNALS:
void chainConfigStringChanged(const std::string& new_config_string);
private Q_SLOTS:
void onAddButtonClicked();
void onRemoveButtonClicked();
void onClearButtonClicked();
void onMoveUpButtonClicked();
void onMoveDownButtonClicked();
void onShaderConfigButtonClicked();
void updateButtonStates();
private:
void connectUi();
std::optional<u32> getSelectedIndex() const;
void updateList();
void configChanged();
Ui::PostProcessingChainConfigWidget m_ui;
FrontendCommon::PostProcessingChain m_chain;
};

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PostProcessingChainConfigWidget</class>
<widget class="QWidget" name="PostProcessingChainConfigWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>497</width>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="add">
<property name="text">
<string>Add</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/list-add.png</normaloff>:/icons/list-add.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="remove">
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/list-remove.png</normaloff>:/icons/list-remove.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="clear">
<property name="text">
<string>Clear</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="moveUp">
<property name="text">
<string>Move Up</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/go-up-16.png</normaloff>:/icons/go-up-16.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="moveDown">
<property name="text">
<string>Move Down</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/go-down-16.png</normaloff>:/icons/go-down-16.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="shaderSettings">
<property name="text">
<string>Shader Settings...</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/preferences-system@2x.png</normaloff>:/icons/preferences-system@2x.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="loadPreset">
<property name="text">
<string>Load Preset</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="savePreset">
<property name="text">
<string>Save Preset</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QListWidget" name="shaders">
<property name="minimumSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources/resources.qrc"/>
</resources>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -32,6 +32,8 @@
<file>icons/duck.png</file> <file>icons/duck.png</file>
<file>icons/duck_128.png</file> <file>icons/duck_128.png</file>
<file>icons/duck_64.png</file> <file>icons/duck_64.png</file>
<file>icons/edit-clear-16.png</file>
<file>icons/edit-clear-16@2x.png</file>
<file>icons/edit-find.png</file> <file>icons/edit-find.png</file>
<file>icons/flag-eu.png</file> <file>icons/flag-eu.png</file>
<file>icons/flag-eu@2x.png</file> <file>icons/flag-eu@2x.png</file>
@ -43,6 +45,10 @@
<file>icons/flag-us@2x.png</file> <file>icons/flag-us@2x.png</file>
<file>icons/folder-open.png</file> <file>icons/folder-open.png</file>
<file>icons/folder-open@2x.png</file> <file>icons/folder-open@2x.png</file>
<file>icons/go-down-16.png</file>
<file>icons/go-down-16@2x.png</file>
<file>icons/go-up-16.png</file>
<file>icons/go-up-16@2x.png</file>
<file>icons/input-gaming.png</file> <file>icons/input-gaming.png</file>
<file>icons/input-gaming@2x.png</file> <file>icons/input-gaming@2x.png</file>
<file>icons/list-add.png</file> <file>icons/list-add.png</file>