Qt: More updates.

This commit is contained in:
BearOso 2023-08-05 16:59:56 -05:00
parent 876eaa8fb2
commit 2fd8b52163
32 changed files with 186 additions and 48 deletions

View File

@ -25,8 +25,7 @@ WGLContext::~WGLContext()
void WGLContext::deinit()
{
if (wglMakeCurrent)
wglMakeCurrent(nullptr, nullptr);
wglMakeCurrent(nullptr, nullptr);
if (hglrc)
wglDeleteContext(hglrc);
if (hdc)

View File

@ -22,7 +22,7 @@ class WGLContext : public OpenGLContext
void swap_buffers() override;
void swap_interval(int frames) override;
void make_current() override;
bool ready();
bool ready() override;
void deinit();
HWND hwnd;

2
external/glslang vendored

@ -1 +1 @@
Subproject commit 9c7fd1a33e5cecbe465e1cd70170167d5e40d398
Subproject commit 3ebb72cc7429f0ab8218104dc3687c659c0f364d

View File

@ -76,6 +76,7 @@ add_library(snes9x-core ${SNES9X_CORE_SOURCES})
target_include_directories(snes9x-core PRIVATE ../)
target_compile_definitions(snes9x-core PRIVATE ZLIB HAVE_STDINT_H ALLOW_CPU_OVERCLOCK)
find_package(Qt6 REQUIRED COMPONENTS Widgets Gui)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL REQUIRED sdl2)
@ -153,8 +154,10 @@ if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
else()
list(APPEND PLATFORM_SOURCES
../common/video/wgl_context.cpp
../external/glad/src/wgl.c)
../external/glad/src/wgl.c
src/resources/snes9x_icon.rc)
list(APPEND LIBS opengl32)
list(APPEND DEFINES SDL_MAIN_HANDLED)
endif()
set(QT_UI_FILES
@ -170,6 +173,7 @@ set(QT_UI_FILES
set(USE_SANITIZERS CACHE BOOL OFF)
set(BUILD_TESTS CACHE BOOL OFF)
set(BUILD_TOOLS CACHE BOOL OFF)
set(BUNDLE_SPEEX FORCE BOOL ON)
add_subdirectory("../external/cubeb" "cubeb" EXCLUDE_FROM_ALL)
list(APPEND LIBS cubeb)
list(APPEND INCLUDES "../external/cubeb/include")
@ -255,6 +259,10 @@ list(APPEND SOURCES ../external/imgui/imgui.cpp
list(APPEND INCLUDES ../external/imgui)
add_executable(snes9x-qt ${QT_GUI_SOURCES} ${SOURCES} ${PLATFORM_SOURCES} src/resources/snes9x.qrc)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set_target_properties(snes9x-qt PROPERTIES WIN32_EXECUTABLE True)
endif()
target_link_libraries(snes9x-qt snes9x-core ${LIBS})
target_compile_definitions(snes9x-qt PRIVATE ${DEFINES})
target_compile_options(snes9x-qt PRIVATE ${FLAGS})

37
qt/QtStaticBuildVars.txt Normal file
View File

@ -0,0 +1,37 @@
-DBUILD_SHARED_LIBS=0
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_INSTALL_PREFIX="C:/Qt"
-DFEATURE_androiddeployqt=0
-DFEATURE_brotli=0
-DFEATURE_dbus=0
-DFEATURE_freetype=0
-DFEATURE_harfbuzz=0
-DFEATURE_imageformat_ppm=0
-DFEATURE_islamiccivilcalendar=0
-DFEATURE_jalalicalendar=0
-DFEATURE_lcdnumber=0
-DFEATURE_movie=0
-DFEATURE_openssl_linked=0
-DFEATURE_openssl_runtime=0
-DFEATURE_optimize_size=1
-DFEATURE_pdf=0
-DFEATURE_printsupport=0
-DFEATURE_shani=0
-DFEATURE_sql=0
-DFEATURE_static=1
-DFEATURE_system_doubleconversion=0
-DFEATURE_system_freetype=0
-DFEATURE_system_harfbuzz=0
-DFEATURE_system_jpeg=0
-DFEATURE_system_libb2=0
-DFEATURE_system_png=0
-DFEATURE_system_proxies=0
-DFEATURE_system_textmarkdownreader=0
-DFEATURE_system_zlib=0
-DFEATURE_testlib=0
-DFEATURE_textodfwriter=0
-DFEATURE_vkgen=0
-DFEATURE_vulkan=0
-DFEATURE_zstd=0
-DQT_BUILD_EXAMPLES_BY_DEFAULT=0
-DQT_BUILD_TESTS_BY_DEFAULT=0

View File

@ -1,4 +1,5 @@
#include "BindingPanel.hpp"
#include "EmuApplication.hpp"
#include <QTimer>
BindingPanel::BindingPanel(EmuApplication *app)

View File

@ -1,8 +1,10 @@
#pragma once
#include <QtEvents>
#include <QIcon>
#include <QWidget>
#include <QTableWidget>
#include "EmuApplication.hpp"
#include "EmuBinding.hpp"
class EmuApplication;
class BindingPanel : public QWidget
{

View File

@ -1,5 +1,7 @@
#include "ControllerPanel.hpp"
#include "SDLInputManager.hpp"
#include "EmuApplication.hpp"
#include "EmuConfig.hpp"
#include "SDL_gamecontroller.h"
#include <optional>
#include <QtEvents>

View File

@ -1,9 +1,10 @@
#pragma once
#include "ui_ControllerPanel.h"
#include "BindingPanel.hpp"
#include "EmuApplication.hpp"
#include <QMenu>
class EmuApplication;
class ControllerPanel :
public Ui::ControllerPanel,
public BindingPanel

View File

@ -1,4 +1,6 @@
#include "DisplayPanel.hpp"
#include "EmuMainWindow.hpp"
#include "EmuConfig.hpp"
#include <QFileDialog>
DisplayPanel::DisplayPanel(EmuApplication *app_)

View File

@ -1,4 +1,7 @@
#include "EmuApplication.hpp"
#include "EmuMainWindow.hpp"
#include "SDLInputManager.hpp"
#include "Snes9xController.hpp"
#include "common/audio/s9x_sound_driver_sdl.hpp"
#include "common/audio/s9x_sound_driver_cubeb.hpp"
#include <qlabel.h>
@ -135,13 +138,14 @@ void EmuApplication::startGame()
core->screen_output_function = [&](uint16_t *data, int width, int height, int stride_bytes, double frame_rate) {
if (window->canvas)
{
QMetaObject::invokeMethod(window.get(), "output", Qt::ConnectionType::DirectConnection,
Q_ARG(uint8_t *, (uint8_t *)data),
Q_ARG(int, width),
Q_ARG(int, height),
Q_ARG(QImage::Format, QImage::Format_RGB16),
Q_ARG(int, stride_bytes),
Q_ARG(double, frame_rate));
window->output((uint8_t *)data, width, height, QImage::Format_RGB16, stride_bytes, frame_rate);
// QMetaObject::invokeMethod(window.get(), "output", Qt::ConnectionType::DirectConnection,
// Q_ARG(uint8_t *, (uint8_t *)data),
// Q_ARG(int, width),
// Q_ARG(int, height),
// Q_ARG(QImage::Format, QImage::Format_RGB16),
// Q_ARG(int, stride_bytes),
// Q_ARG(double, frame_rate));
}
};

View File

@ -3,11 +3,12 @@
#include <QTimer>
#include <QThread>
#include "EmuMainWindow.hpp"
#include "EmuConfig.hpp"
#include "SDLInputManager.hpp"
#include "Snes9xController.hpp"
#include "common/audio/s9x_sound_driver.hpp"
class EmuMainWindow;
class EmuConfig;
class EmuBinding;
class SDLInputManager;
class Snes9xController;
class S9xSoundDriver;
struct EmuThread : public QThread
{

View File

@ -1,4 +1,5 @@
#include "EmuCanvas.hpp"
#include "EmuConfig.hpp"
#include <qnamespace.h>
#include <qwidget.h>

View File

@ -1,9 +1,10 @@
#pragma once
#include <QWidget>
#include <QImage>
#include "EmuConfig.hpp"
#include "../../vulkan/std_chrono_throttle.hpp"
class EmuConfig;
class EmuCanvas : public QWidget
{
public:
@ -33,7 +34,7 @@ class EmuCanvas : public QWidget
struct Parameter
{
bool operator==(const Parameter &other)
bool operator==(const Parameter &other) const
{
if (name == other.name &&
id == other.id &&

View File

@ -17,6 +17,7 @@ using namespace QNativeInterface;
#include "EmuMainWindow.hpp"
#include "snes9x_imgui.h"
#include "imgui_impl_opengl3.h"
#include <locale.h>
static const char *stock_vertex_shader_140 = R"(
#version 140

View File

@ -1,6 +1,10 @@
#include "EmuCanvasQt.hpp"
#include "EmuConfig.hpp"
#include <QGuiApplication>
#include <QtEvents>
#include <QThread>
#include <qguiapplication.h>
EmuCanvasQt::EmuCanvasQt(EmuConfig *config, QWidget *parent, QWidget *main_window)
: EmuCanvas(config, parent, main_window)
@ -19,8 +23,11 @@ void EmuCanvasQt::deinit()
void EmuCanvasQt::draw()
{
QWidget::repaint(0, 0, width(), height());
qimage_mutex.lock();
qimage = QImage((const uchar *)output_data.buffer, output_data.width, output_data.height, output_data.bytes_per_line, output_data.format);
qimage_mutex.unlock();
throttle();
update();
}
void EmuCanvasQt::paintEvent(QPaintEvent *event)
@ -34,7 +41,6 @@ void EmuCanvasQt::paintEvent(QPaintEvent *event)
}
QPainter paint(this);
QImage image((const uchar *)output_data.buffer, output_data.width, output_data.height, output_data.bytes_per_line, output_data.format);
paint.setRenderHint(QPainter::SmoothPixmapTransform, config->bilinear_filter);
QRect dest = { 0, 0, width(), height() };
if (config->maintain_aspect_ratio)
@ -43,7 +49,9 @@ void EmuCanvasQt::paintEvent(QPaintEvent *event)
dest = applyAspect(dest);
}
paint.drawImage(dest, image, QRect(0, 0, output_data.width, output_data.height));
qimage_mutex.lock();
paint.drawImage(dest, qimage, QRect(0, 0, output_data.width, output_data.height));
qimage_mutex.unlock();
}
void EmuCanvasQt::resizeEvent(QResizeEvent *event)

View File

@ -4,6 +4,7 @@
#include "EmuCanvas.hpp"
#include <QPainter>
#include <mutex>
class EmuCanvasQt : public EmuCanvas
{
@ -16,6 +17,9 @@ class EmuCanvasQt : public EmuCanvas
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
std::mutex qimage_mutex;
QImage qimage;
};
#endif

View File

@ -185,7 +185,9 @@ void EmuCanvasVulkan::draw()
throttle();
context->swapchain->swap();
if (config->reduce_input_lag)
{
context->wait_idle();
}
}
}

View File

@ -16,7 +16,7 @@ class EmuCanvasVulkan : public EmuCanvas
EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window);
~EmuCanvasVulkan();
void createContext();
void createContext() override;
void deinit() override;
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
@ -30,7 +30,7 @@ class EmuCanvasVulkan : public EmuCanvas
void draw() override;
bool initImGui();
void recreateUIAssets();
void recreateUIAssets() override;
vk::UniqueRenderPass imgui_render_pass;
vk::UniqueDescriptorPool imgui_descriptor_pool;

View File

@ -2,6 +2,8 @@
#define __EMU_CONFIG_HPP
#include <string>
#include <vector>
#include "EmuBinding.hpp"
struct EmuConfig

View File

@ -13,6 +13,7 @@
#include "EmuMainWindow.hpp"
#include "EmuSettingsWindow.hpp"
#include "EmuApplication.hpp"
#include "EmuBinding.hpp"
#include "EmuCanvasVulkan.hpp"
#include "EmuCanvasOpenGL.hpp"
#include "EmuCanvasQt.hpp"
@ -464,10 +465,13 @@ bool EmuMainWindow::event(QEvent *event)
switch (event->type())
{
case QEvent::Close:
app->suspendThread();
if (isFullScreen())
{
toggleFullscreen();
}
QGuiApplication::processEvents();
QGuiApplication::sync();
app->stopThread();
if (canvas)
canvas->deinit();

View File

@ -1,10 +1,11 @@
#include "EmuSettingsWindow.hpp"
#include "src/EmuMainWindow.hpp"
#include "EmuMainWindow.hpp"
#include "EmuConfig.hpp"
#include <QScrollArea>
EmuSettingsWindow::EmuSettingsWindow(QWidget *parent, EmuApplication *app)
: QDialog(parent), app(app)
EmuSettingsWindow::EmuSettingsWindow(QWidget *parent, EmuApplication *app_)
: QDialog(parent), app(app_)
{
setupUi(this);
@ -35,13 +36,19 @@ EmuSettingsWindow::EmuSettingsWindow(QWidget *parent, EmuApplication *app)
stackedWidget->setCurrentIndex(0);
closeButton->connect(closeButton, &QPushButton::clicked, [&](bool) {
connect(closeButton, &QPushButton::clicked, [&](bool) {
this->close();
});
panelList->connect(panelList, &QListWidget::currentItemChanged, [&](QListWidgetItem *prev, QListWidgetItem *cur) {
connect(panelList, &QListWidget::currentItemChanged, [&](QListWidgetItem *prev, QListWidgetItem *cur) {
stackedWidget->setCurrentIndex(panelList->currentRow());
});
connect(defaultsButton, &QPushButton::clicked, [&](bool) {
app->config->setDefaults(stackedWidget->currentIndex());
stackedWidget->currentWidget()->hide();
stackedWidget->currentWidget()->show();
});
}
EmuSettingsWindow::~EmuSettingsWindow()

View File

@ -1,4 +1,7 @@
#include "EmulationPanel.hpp"
#include "EmuApplication.hpp"
#include "EmuConfig.hpp"
EmulationPanel::EmulationPanel(EmuApplication *app_)
: app(app_)
{

View File

@ -1,6 +1,7 @@
#pragma once
#include "ui_EmulationPanel.h"
#include "EmuApplication.hpp"
class EmuApplication;
class EmulationPanel :
public Ui::EmulationPanel,

View File

@ -1,4 +1,6 @@
#include "FoldersPanel.hpp"
#include "EmuBinding.hpp"
#include "EmuConfig.hpp"
#include <QSpinBox>
#include <QFileDialog>

View File

@ -1,4 +1,6 @@
#include "GeneralPanel.hpp"
#include "EmuApplication.hpp"
#include "EmuConfig.hpp"
GeneralPanel::GeneralPanel(EmuApplication *app_)
: app(app_)

View File

@ -145,9 +145,10 @@ void ShaderParametersDialog::save()
saved_parameters = *parameters;
auto filename = config->findConfigDir() + "/customized_shader" + extension;
canvas->saveParameters(filename);
config->shader = filename;
QDir dir(config->findConfigDir().c_str());
auto filename = dir.absoluteFilePath(QString::fromStdString("customized_shader" + extension));
canvas->saveParameters(filename.toStdString());
config->shader = QDir::toNativeSeparators(filename).toStdString();
}
void ShaderParametersDialog::saveAs()
@ -155,7 +156,7 @@ void ShaderParametersDialog::saveAs()
auto folder = config->last_shader_folder;
auto filename = QFileDialog::getSaveFileName(this, tr("Save Shader Preset As"), folder.c_str());
canvas->saveParameters(filename.toStdString());
config->shader = filename.toStdString();
config->shader = QDir::toNativeSeparators(filename).toStdString();
}
void ShaderParametersDialog::refreshWidgets()

View File

@ -1,4 +1,6 @@
#include "SoundPanel.hpp"
#include "EmuApplication.hpp"
#include "EmuConfig.hpp"
static const int playback_rates[] = { 96000, 48000, 44100 };

View File

@ -1,11 +1,25 @@
#include "EmuApplication.hpp"
#include "EmuConfig.hpp"
#include "EmuMainWindow.hpp"
#include "SDLInputManager.hpp"
#include <QStyle>
#include <QStyleHints>
#include <qnamespace.h>
#ifndef _WIN32
#include <csignal>
#endif
#ifdef _WIN32
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, const char *lpCmdLine, int nShowCmd)
{
char **argv = nullptr;
int argc = 0;
#else
int main(int argc, char *argv[])
{
#endif
EmuApplication emu;
emu.qtapp = std::make_unique<QApplication>(argc, argv);

BIN
qt/src/resources/snes9x.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
IDI_ICON1 ICON "snes9x.ico"

View File

@ -22,25 +22,50 @@ microseconds Throttle::remaining()
#include <windows.h>
void Throttle::wait_for_frame()
{
static HANDLE timer = nullptr;
static UINT (WINAPI *NtDelayExecution)(BOOL, LARGE_INTEGER *) = nullptr;
static UINT (WINAPI *NtQueryTimerResolution) (ULONG *, ULONG *, ULONG *) = nullptr;
static UINT (WINAPI *NtSetTimerResolution) (ULONG, BOOL, ULONG *) = nullptr;
static int timer_resolution = 12500;
if (timer == nullptr)
timer = CreateWaitableTimer(nullptr, true, nullptr);
if (NtDelayExecution == nullptr)
{
HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
if (ntdll)
{
NtDelayExecution = reinterpret_cast<typeof NtDelayExecution>(GetProcAddress(ntdll, "NtDelayExecution"));
NtQueryTimerResolution = reinterpret_cast<typeof NtQueryTimerResolution>(GetProcAddress(ntdll, "NtQueryTimerResolution"));
NtSetTimerResolution = reinterpret_cast<typeof NtSetTimerResolution>(GetProcAddress(ntdll, "NtSetTimerResolution"));
}
if (NtQueryTimerResolution)
{
ULONG min, max, current;
NtQueryTimerResolution(&min, &max, &current);
if (NtSetTimerResolution)
NtSetTimerResolution(max, true, &current);
timer_resolution = current * 5 / 4;
}
}
auto time_to_wait = remaining();
if (time_to_wait < -frame_duration_us)
if (time_to_wait < -(frame_duration_us / 8))
{
reset();
return;
}
if (time_to_wait.count() > 2000)
if (NtDelayExecution)
{
LARGE_INTEGER li;
li.QuadPart = -(time_to_wait.count() - 2000) * 10;
SetWaitableTimer(timer, &li, 0, nullptr, nullptr, false);
WaitForSingleObject(timer, INFINITE);
if (time_to_wait.count() * 10 > timer_resolution)
{
LARGE_INTEGER li;
li.QuadPart = -(time_to_wait.count() * 10 - timer_resolution);
NtDelayExecution(false, &li);
}
}
time_to_wait = remaining();
@ -64,7 +89,7 @@ void Throttle::wait_for_frame()
}
if (time_to_wait.count() > 1000)
std::this_thread::sleep_for(time_to_wait - 1ms);
std::this_thread::sleep_for(time_to_wait - 1000us);
time_to_wait = remaining();
while (time_to_wait.count() > 0)