mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 08:52:36 +00:00
Merge remote-tracking branch 'origin/main' into kbm-only
This commit is contained in:
commit
3b68058eb1
27
src/common/adaptive_mutex.h
Normal file
27
src/common/adaptive_mutex.h
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __linux__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
class AdaptiveMutex {
|
||||
public:
|
||||
void lock() {
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
void unlock() {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
|
||||
};
|
||||
#endif // PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
|
||||
} // namespace Common
|
@ -60,7 +60,7 @@ static void KernelServiceThread(std::stop_token stoken) {
|
||||
}
|
||||
|
||||
io_context.run();
|
||||
io_context.reset();
|
||||
io_context.restart();
|
||||
|
||||
asio_requests = 0;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
namespace Libraries::Pad {
|
||||
|
||||
using Input::GameController;
|
||||
|
||||
int PS4_SYSV_ABI scePadClose(s32 handle) {
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
@ -290,7 +292,8 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
||||
int connected_count = 0;
|
||||
bool connected = false;
|
||||
Input::State states[64];
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
auto* controller = Common::Singleton<GameController>::Instance();
|
||||
const auto* engine = controller->GetEngine();
|
||||
int ret_num = controller->ReadStates(states, num, &connected, &connected_count);
|
||||
|
||||
if (!connected) {
|
||||
@ -311,9 +314,14 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
||||
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||
Input::GameController::CalculateOrientation(pData[i].acceleration, pData[i].angularVelocity,
|
||||
1.0f / controller->accel_poll_rate,
|
||||
pData[i].orientation);
|
||||
if (engine) {
|
||||
const auto accel_poll_rate = engine->GetAccelPollRate();
|
||||
if (accel_poll_rate != 0.0f) {
|
||||
GameController::CalculateOrientation(pData[i].acceleration,
|
||||
pData[i].angularVelocity,
|
||||
1.0f / accel_poll_rate, pData[i].orientation);
|
||||
}
|
||||
}
|
||||
pData[i].touchData.touchNum =
|
||||
(states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0);
|
||||
pData[i].touchData.touch[0].x = states[i].touchpad[0].x;
|
||||
@ -356,7 +364,8 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
||||
if (handle == ORBIS_PAD_ERROR_DEVICE_NO_HANDLE) {
|
||||
return ORBIS_PAD_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
auto* controller = Common::Singleton<GameController>::Instance();
|
||||
const auto* engine = controller->GetEngine();
|
||||
int connectedCount = 0;
|
||||
bool isConnected = false;
|
||||
Input::State state;
|
||||
@ -374,9 +383,13 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
||||
pData->angularVelocity.x = state.angularVelocity.x;
|
||||
pData->angularVelocity.y = state.angularVelocity.y;
|
||||
pData->angularVelocity.z = state.angularVelocity.z;
|
||||
Input::GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
1.0f / controller->accel_poll_rate,
|
||||
pData->orientation);
|
||||
if (engine) {
|
||||
const auto accel_poll_rate = engine->GetAccelPollRate();
|
||||
if (accel_poll_rate != 0.0f) {
|
||||
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
1.0f / accel_poll_rate, pData->orientation);
|
||||
}
|
||||
}
|
||||
pData->touchData.touchNum =
|
||||
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
||||
pData->touchData.touch[0].x = state.touchpad[0].x;
|
||||
@ -468,7 +481,7 @@ int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pPar
|
||||
return ORBIS_PAD_ERROR_INVALID_LIGHTBAR_SETTING;
|
||||
}
|
||||
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
auto* controller = Common::Singleton<GameController>::Instance();
|
||||
controller->SetLightBarRGB(pParam->r, pParam->g, pParam->b);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
@ -536,7 +549,7 @@ int PS4_SYSV_ABI scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pP
|
||||
if (pParam != nullptr) {
|
||||
LOG_DEBUG(Lib_Pad, "scePadSetVibration called handle = {} data = {} , {}", handle,
|
||||
pParam->smallMotor, pParam->largeMotor);
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
auto* controller = Common::Singleton<GameController>::Instance();
|
||||
controller->SetVibration(pParam->smallMotor, pParam->largeMotor);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -186,7 +186,8 @@ ImGuiID NewFrame(bool is_reusing_frame) {
|
||||
Sdl::NewFrame(is_reusing_frame);
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiDockNodeFlags_PassthruCentralNode;
|
||||
ImGuiWindowFlags flags =
|
||||
ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_AutoHideTabBar;
|
||||
if (!DebugState.IsShowingDebugMenuBar()) {
|
||||
flags |= ImGuiDockNodeFlags_NoTabBar;
|
||||
}
|
||||
|
@ -10,6 +10,55 @@
|
||||
|
||||
namespace Input {
|
||||
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
void State::OnButton(OrbisPadButtonDataOffset button, bool isPressed) {
|
||||
if (isPressed) {
|
||||
buttonsState |= button;
|
||||
} else {
|
||||
buttonsState &= ~button;
|
||||
}
|
||||
}
|
||||
|
||||
void State::OnAxis(Axis axis, int value) {
|
||||
const auto toggle = [&](const auto button) {
|
||||
if (value > 0) {
|
||||
buttonsState |= button;
|
||||
} else {
|
||||
buttonsState &= ~button;
|
||||
}
|
||||
};
|
||||
switch (axis) {
|
||||
case Axis::TriggerLeft:
|
||||
toggle(OrbisPadButtonDataOffset::L2);
|
||||
break;
|
||||
case Axis::TriggerRight:
|
||||
toggle(OrbisPadButtonDataOffset::R2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
axes[static_cast<int>(axis)] = value;
|
||||
}
|
||||
|
||||
void State::OnTouchpad(int touchIndex, bool isDown, float x, float y) {
|
||||
touchpad[touchIndex].state = isDown;
|
||||
touchpad[touchIndex].x = static_cast<u16>(x * 1920);
|
||||
touchpad[touchIndex].y = static_cast<u16>(y * 941);
|
||||
}
|
||||
|
||||
void State::OnGyro(const float gyro[3]) {
|
||||
angularVelocity.x = gyro[0];
|
||||
angularVelocity.y = gyro[1];
|
||||
angularVelocity.z = gyro[2];
|
||||
}
|
||||
|
||||
void State::OnAccel(const float accel[3]) {
|
||||
acceleration.x = accel[0];
|
||||
acceleration.y = accel[1];
|
||||
acceleration.z = accel[2];
|
||||
}
|
||||
|
||||
GameController::GameController() {
|
||||
m_states_num = 0;
|
||||
m_last_state = State();
|
||||
@ -20,7 +69,7 @@ void GameController::ReadState(State* state, bool* isConnected, int* connectedCo
|
||||
|
||||
*isConnected = m_connected;
|
||||
*connectedCount = m_connected_count;
|
||||
*state = GetLastState();
|
||||
*state = m_engine && m_connected ? m_engine->ReadState() : GetLastState();
|
||||
}
|
||||
|
||||
int GameController::ReadStates(State* states, int states_num, bool* isConnected,
|
||||
@ -75,45 +124,22 @@ void GameController::AddState(const State& state) {
|
||||
m_states_num++;
|
||||
}
|
||||
|
||||
void GameController::CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button,
|
||||
bool is_pressed) {
|
||||
void GameController::CheckButton(int id, OrbisPadButtonDataOffset button, bool is_pressed) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
auto state = GetLastState();
|
||||
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
if (is_pressed) {
|
||||
state.buttonsState |= button;
|
||||
} else {
|
||||
state.buttonsState &= ~button;
|
||||
}
|
||||
state.OnButton(button, is_pressed);
|
||||
|
||||
AddState(state);
|
||||
}
|
||||
|
||||
void GameController::Axis(int id, Input::Axis axis, int value) {
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
std::scoped_lock lock{m_mutex};
|
||||
auto state = GetLastState();
|
||||
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
int axis_id = static_cast<int>(axis);
|
||||
state.axes[axis_id] = value;
|
||||
|
||||
if (axis == Input::Axis::TriggerLeft) {
|
||||
if (value > 0) {
|
||||
state.buttonsState |= OrbisPadButtonDataOffset::L2;
|
||||
} else {
|
||||
state.buttonsState &= ~OrbisPadButtonDataOffset::L2;
|
||||
}
|
||||
}
|
||||
|
||||
if (axis == Input::Axis::TriggerRight) {
|
||||
if (value > 0) {
|
||||
state.buttonsState |= OrbisPadButtonDataOffset::R2;
|
||||
} else {
|
||||
state.buttonsState &= ~OrbisPadButtonDataOffset::R2;
|
||||
}
|
||||
}
|
||||
state.OnAxis(axis, value);
|
||||
|
||||
AddState(state);
|
||||
}
|
||||
@ -124,9 +150,7 @@ void GameController::Gyro(int id, const float gyro[3]) {
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
// Update the angular velocity (gyro data)
|
||||
state.angularVelocity.x = gyro[0]; // X-axis
|
||||
state.angularVelocity.y = gyro[1]; // Y-axis
|
||||
state.angularVelocity.z = gyro[2]; // Z-axis
|
||||
state.OnGyro(gyro);
|
||||
|
||||
AddState(state);
|
||||
}
|
||||
@ -136,9 +160,7 @@ void GameController::Acceleration(int id, const float acceleration[3]) {
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
// Update the acceleration values
|
||||
state.acceleration.x = acceleration[0]; // X-axis
|
||||
state.acceleration.y = acceleration[1]; // Y-axis
|
||||
state.acceleration.z = acceleration[2]; // Z-axis
|
||||
state.OnAccel(acceleration);
|
||||
|
||||
AddState(state);
|
||||
}
|
||||
@ -211,62 +233,48 @@ void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceler
|
||||
}
|
||||
|
||||
void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) {
|
||||
if (m_sdl_gamepad != nullptr) {
|
||||
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
|
||||
if (!m_engine) {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock _{m_mutex};
|
||||
m_engine->SetLightBarRGB(r, g, b);
|
||||
}
|
||||
|
||||
bool GameController::SetVibration(u8 smallMotor, u8 largeMotor) {
|
||||
if (m_sdl_gamepad != nullptr) {
|
||||
return SDL_RumbleGamepad(m_sdl_gamepad, (smallMotor / 255.0f) * 0xFFFF,
|
||||
(largeMotor / 255.0f) * 0xFFFF, -1);
|
||||
void GameController::SetVibration(u8 smallMotor, u8 largeMotor) {
|
||||
if (!m_engine) {
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
std::scoped_lock _{m_mutex};
|
||||
m_engine->SetVibration(smallMotor, largeMotor);
|
||||
}
|
||||
|
||||
void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, float y) {
|
||||
if (touchIndex < 2) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
auto state = GetLastState();
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
state.touchpad[touchIndex].state = touchDown;
|
||||
state.touchpad[touchIndex].x = static_cast<u16>(x * 1920);
|
||||
state.touchpad[touchIndex].y = static_cast<u16>(y * 941);
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
state.OnTouchpad(touchIndex, touchDown, x, y);
|
||||
|
||||
AddState(state);
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::TryOpenSDLController() {
|
||||
if (m_sdl_gamepad == nullptr || !SDL_GamepadConnected(m_sdl_gamepad)) {
|
||||
int gamepad_count;
|
||||
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
|
||||
m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr;
|
||||
if (Config::getIsMotionControlsEnabled()) {
|
||||
if (SDL_SetGamepadSensorEnabled(m_sdl_gamepad, SDL_SENSOR_GYRO, true)) {
|
||||
gyro_poll_rate = SDL_GetGamepadSensorDataRate(m_sdl_gamepad, SDL_SENSOR_GYRO);
|
||||
LOG_INFO(Input, "Gyro initialized, poll rate: {}", gyro_poll_rate);
|
||||
} else {
|
||||
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad");
|
||||
}
|
||||
if (SDL_SetGamepadSensorEnabled(m_sdl_gamepad, SDL_SENSOR_ACCEL, true)) {
|
||||
accel_poll_rate = SDL_GetGamepadSensorDataRate(m_sdl_gamepad, SDL_SENSOR_ACCEL);
|
||||
LOG_INFO(Input, "Accel initialized, poll rate: {}", accel_poll_rate);
|
||||
} else {
|
||||
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad");
|
||||
void GameController::SetEngine(std::unique_ptr<Engine> engine) {
|
||||
std::scoped_lock _{m_mutex};
|
||||
m_engine = std::move(engine);
|
||||
if (m_engine) {
|
||||
m_engine->Init();
|
||||
}
|
||||
}
|
||||
|
||||
SDL_free(gamepads);
|
||||
|
||||
SetLightBarRGB(0, 0, 255);
|
||||
}
|
||||
Engine* GameController::GetEngine() {
|
||||
return m_engine.get();
|
||||
}
|
||||
|
||||
u32 GameController::Poll() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (m_connected) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
auto time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
if (m_states_num == 0) {
|
||||
auto diff = (time - m_last_state.time) / 1000;
|
||||
|
@ -3,12 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
|
||||
struct SDL_Gamepad;
|
||||
|
||||
namespace Input {
|
||||
|
||||
enum class Axis {
|
||||
@ -28,7 +28,14 @@ struct TouchpadEntry {
|
||||
u16 y{};
|
||||
};
|
||||
|
||||
struct State {
|
||||
class State {
|
||||
public:
|
||||
void OnButton(Libraries::Pad::OrbisPadButtonDataOffset, bool);
|
||||
void OnAxis(Axis, int);
|
||||
void OnTouchpad(int touchIndex, bool isDown, float x, float y);
|
||||
void OnGyro(const float[3]);
|
||||
void OnAccel(const float[3]);
|
||||
|
||||
Libraries::Pad::OrbisPadButtonDataOffset buttonsState{};
|
||||
u64 time = 0;
|
||||
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0};
|
||||
@ -38,9 +45,19 @@ struct State {
|
||||
Libraries::Pad::OrbisFQuaternion orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
};
|
||||
|
||||
class Engine {
|
||||
public:
|
||||
virtual ~Engine() = default;
|
||||
virtual void Init() = 0;
|
||||
virtual void SetLightBarRGB(u8 r, u8 g, u8 b) = 0;
|
||||
virtual void SetVibration(u8 smallMotor, u8 largeMotor) = 0;
|
||||
virtual State ReadState() = 0;
|
||||
virtual float GetAccelPollRate() const = 0;
|
||||
virtual float GetGyroPollRate() const = 0;
|
||||
};
|
||||
|
||||
inline int GetAxis(int min, int max, int value) {
|
||||
int v = (255 * (value - min)) / (max - min);
|
||||
return (v < 0 ? 0 : (v > 255 ? 255 : v));
|
||||
return std::clamp((255 * (value - min)) / (max - min), 0, 255);
|
||||
}
|
||||
|
||||
constexpr u32 MAX_STATES = 64;
|
||||
@ -59,13 +76,12 @@ public:
|
||||
void Gyro(int id, const float gyro[3]);
|
||||
void Acceleration(int id, const float acceleration[3]);
|
||||
void SetLightBarRGB(u8 r, u8 g, u8 b);
|
||||
bool SetVibration(u8 smallMotor, u8 largeMotor);
|
||||
void SetVibration(u8 smallMotor, u8 largeMotor);
|
||||
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
|
||||
void TryOpenSDLController();
|
||||
void SetEngine(std::unique_ptr<Engine>);
|
||||
Engine* GetEngine();
|
||||
u32 Poll();
|
||||
|
||||
float gyro_poll_rate;
|
||||
float accel_poll_rate;
|
||||
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||
float deltaTime,
|
||||
@ -85,7 +101,7 @@ private:
|
||||
std::array<State, MAX_STATES> m_states;
|
||||
std::array<StateInternal, MAX_STATES> m_private;
|
||||
|
||||
SDL_Gamepad* m_sdl_gamepad = nullptr;
|
||||
std::unique_ptr<Engine> m_engine = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Input
|
||||
|
@ -188,8 +188,12 @@ void CheatsPatches::setupUI() {
|
||||
}
|
||||
});
|
||||
|
||||
QPushButton* closeButton = new QPushButton(tr("Close"));
|
||||
connect(closeButton, &QPushButton::clicked, [this]() { QWidget::close(); });
|
||||
|
||||
controlLayout->addWidget(downloadButton);
|
||||
controlLayout->addWidget(deleteCheatButton);
|
||||
controlLayout->addWidget(closeButton);
|
||||
|
||||
cheatsLayout->addLayout(controlLayout);
|
||||
cheatsTab->setLayout(cheatsLayout);
|
||||
@ -464,6 +468,8 @@ void CheatsPatches::onSaveButtonClicked() {
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Success"), tr("Options saved successfully."));
|
||||
}
|
||||
|
||||
QWidget::close();
|
||||
}
|
||||
|
||||
QCheckBox* CheatsPatches::findCheckBoxByName(const QString& name) {
|
||||
|
@ -251,6 +251,12 @@ void MainWindow::CreateConnects() {
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->shadFolderAct, &QAction::triggered, this, [this]() {
|
||||
QString userPath;
|
||||
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(userPath));
|
||||
});
|
||||
|
||||
connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame);
|
||||
connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this,
|
||||
&MainWindow::StartGame);
|
||||
@ -992,6 +998,7 @@ QIcon MainWindow::RecolorIcon(const QIcon& icon, bool isWhite) {
|
||||
void MainWindow::SetUiIcons(bool isWhite) {
|
||||
ui->bootInstallPkgAct->setIcon(RecolorIcon(ui->bootInstallPkgAct->icon(), isWhite));
|
||||
ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite));
|
||||
ui->shadFolderAct->setIcon(RecolorIcon(ui->shadFolderAct->icon(), isWhite));
|
||||
ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite));
|
||||
#ifdef ENABLE_UPDATER
|
||||
ui->updaterAct->setIcon(RecolorIcon(ui->updaterAct->icon(), isWhite));
|
||||
|
@ -12,6 +12,7 @@ public:
|
||||
QAction* bootInstallPkgAct;
|
||||
QAction* bootGameAct;
|
||||
QAction* addElfFolderAct;
|
||||
QAction* shadFolderAct;
|
||||
QAction* exitAct;
|
||||
QAction* showGameListAct;
|
||||
QAction* refreshGameListAct;
|
||||
@ -89,6 +90,9 @@ public:
|
||||
addElfFolderAct = new QAction(MainWindow);
|
||||
addElfFolderAct->setObjectName("addElfFolderAct");
|
||||
addElfFolderAct->setIcon(QIcon(":images/folder_icon.png"));
|
||||
shadFolderAct = new QAction(MainWindow);
|
||||
shadFolderAct->setObjectName("shadFolderAct");
|
||||
shadFolderAct->setIcon(QIcon(":images/folder_icon.png"));
|
||||
exitAct = new QAction(MainWindow);
|
||||
exitAct->setObjectName("exitAct");
|
||||
exitAct->setIcon(QIcon(":images/exit_icon.png"));
|
||||
@ -274,7 +278,9 @@ public:
|
||||
menuBar->addAction(menuHelp->menuAction());
|
||||
menuFile->addAction(bootInstallPkgAct);
|
||||
menuFile->addAction(bootGameAct);
|
||||
menuFile->addSeparator();
|
||||
menuFile->addAction(addElfFolderAct);
|
||||
menuFile->addAction(shadFolderAct);
|
||||
menuFile->addSeparator();
|
||||
menuFile->addAction(menuRecent->menuAction());
|
||||
menuFile->addSeparator();
|
||||
@ -333,6 +339,8 @@ public:
|
||||
"MainWindow", "Install application from a .pkg file", nullptr));
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
menuRecent->setTitle(QCoreApplication::translate("MainWindow", "Recent Games", nullptr));
|
||||
shadFolderAct->setText(
|
||||
QCoreApplication::translate("MainWindow", "Open shadPS4 Folder", nullptr));
|
||||
exitAct->setText(QCoreApplication::translate("MainWindow", "Exit", nullptr));
|
||||
#if QT_CONFIG(tooltip)
|
||||
exitAct->setToolTip(QCoreApplication::translate("MainWindow", "Exit shadPS4", nullptr));
|
||||
|
@ -522,22 +522,6 @@ bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) {
|
||||
} else {
|
||||
ui->descriptionText->setText(defaultTextEdit);
|
||||
}
|
||||
|
||||
// if the text exceeds the size of the box, it will increase the size
|
||||
QRect currentGeometry = this->geometry();
|
||||
int newWidth = currentGeometry.width();
|
||||
|
||||
int documentHeight = ui->descriptionText->document()->size().height();
|
||||
int visibleHeight = ui->descriptionText->viewport()->height();
|
||||
if (documentHeight > visibleHeight) {
|
||||
ui->descriptionText->setMaximumSize(16777215, 110);
|
||||
this->setGeometry(currentGeometry.x(), currentGeometry.y(), newWidth,
|
||||
currentGeometry.height() + 40);
|
||||
} else {
|
||||
ui->descriptionText->setMaximumSize(16777215, 70);
|
||||
this->setGeometry(currentGeometry.x(), currentGeometry.y(), newWidth,
|
||||
initialHeight);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>970</width>
|
||||
<height>750</height>
|
||||
<height>820</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -68,7 +68,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>586</height>
|
||||
<height>611</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
|
||||
@ -77,43 +77,6 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<layout class="QVBoxLayout" name="systemTabLayoutLeft">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="SystemSettings">
|
||||
<property name="title">
|
||||
<string>System</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="emuSettingsLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="consoleLanguageGroupBox">
|
||||
<property name="title">
|
||||
<string>Console Language</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="settingsLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="consoleLanguageComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="emulatorLanguageGroupBox">
|
||||
<property name="title">
|
||||
<string>Emulator Language</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="langSettingsLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="emulatorLanguageComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
|
||||
<item>
|
||||
@ -217,246 +180,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<layout class="QVBoxLayout" name="updaterTabLayoutLeft">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<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>
|
||||
<widget class="QGroupBox" name="updaterGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="UpdateLayout" stretch="0,0,0">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="updaterComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Update Channel</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="UpdateChannelLayout">
|
||||
<property name="spacing">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="updateComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Release</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nightly</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="checkUpdateButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check for Updates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="updateCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check for Updates at Startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="CompatgroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Game Compatibility</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="CompatLayout">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableCompatibilityCheckBox">
|
||||
<property name="text">
|
||||
<string>Display Compatibility Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCompatibilityOnStartupCheckBox">
|
||||
<property name="text">
|
||||
<string>Update Compatibility Database On Startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="updateCompatibilityButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update Compatibility Database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0">
|
||||
<item>
|
||||
@ -627,6 +350,283 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QVBoxLayout" name="systemTabLayoutLeft">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="SystemSettings">
|
||||
<property name="title">
|
||||
<string>System</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="emuSettingsLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="consoleLanguageGroupBox">
|
||||
<property name="title">
|
||||
<string>Console Language</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="settingsLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="consoleLanguageComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="emulatorLanguageGroupBox">
|
||||
<property name="title">
|
||||
<string>Emulator Language</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="langSettingsLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="emulatorLanguageComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<layout class="QVBoxLayout" name="updaterTabLayoutLeft">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<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>
|
||||
<widget class="QGroupBox" name="updaterGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="UpdateLayout" stretch="0,0,0">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>190</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="updaterComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Update Channel</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="UpdateChannelLayout">
|
||||
<property name="spacing">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="updateComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Release</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nightly</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="checkUpdateButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check for Updates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="updateCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check for Updates at Startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="CompatgroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Game Compatibility</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="CompatLayout">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableCompatibilityCheckBox">
|
||||
<property name="text">
|
||||
<string>Display Compatibility Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCompatibilityOnStartupCheckBox">
|
||||
<property name="text">
|
||||
<string>Update Compatibility Database On Startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="updateCompatibilityButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update Compatibility Database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@ -645,12 +645,12 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>586</height>
|
||||
<height>605</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="inputTabHLayoutTop" stretch="1,1,1">
|
||||
<layout class="QHBoxLayout" name="inputTabHLayoutTop" stretch="1,1">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="cursorTabLayoutLeft">
|
||||
<property name="spacing">
|
||||
@ -664,17 +664,14 @@
|
||||
<property name="title">
|
||||
<string>Cursor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="inputCursorLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="hideCursorGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
@ -701,7 +698,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="idleTimeoutGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
@ -836,7 +833,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@ -872,6 +869,12 @@
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
@ -885,23 +888,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="emptyTabLayoutRight">
|
||||
<item>
|
||||
<spacer name="emptyhorizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@ -943,7 +929,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>586</height>
|
||||
<height>605</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
|
||||
@ -1124,11 +1110,14 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="additionalSettingsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="additionalSettingsLayout">
|
||||
<item>
|
||||
@ -1194,7 +1183,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>586</height>
|
||||
<height>605</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="pathsTabLayout" stretch="0">
|
||||
@ -1233,22 +1222,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@ -1445,10 +1418,16 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="descriptionText">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>70</height>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>الألعاب الأخيرة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>خروج</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Zuletzt gespielt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Beenden</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Juegos recientes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Salir</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>بازی های اخیر</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>خروج</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Viimeisimmät Pelit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Sulje</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Jeux récents</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Ouvrir le dossier de shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Fermer</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Legutóbbi Játékok</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Kilépés</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Giochi Recenti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Uscita</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>最近のゲーム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>終了</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Nylige spill</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Avslutt</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Ostatnie gry</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Wyjdź</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Jogos Recentes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Abrir pasta shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Sair</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Недавние игры</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Выход</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Lojërat e fundit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Dil</translation>
|
||||
|
@ -722,6 +722,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Senaste spel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Avsluta</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Son Oyunlar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Çıkış</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Нещодавні ігри</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Вихід</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>最近启动的游戏</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>退出</translation>
|
||||
|
@ -247,6 +247,10 @@
|
||||
<source>Recent Games</source>
|
||||
<translation>Recent Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation>Exit</translation>
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "common/config.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/version.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "imgui/renderer/imgui_core.h"
|
||||
#include "input/controller.h"
|
||||
@ -24,47 +25,200 @@
|
||||
#include "SDL3/SDL_metal.h"
|
||||
#endif
|
||||
|
||||
namespace Input {
|
||||
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
static OrbisPadButtonDataOffset SDLGamepadToOrbisButton(u8 button) {
|
||||
using OPBDO = OrbisPadButtonDataOffset;
|
||||
|
||||
switch (button) {
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
return OPBDO::Down;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
||||
return OPBDO::Up;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
return OPBDO::Left;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
return OPBDO::Right;
|
||||
case SDL_GAMEPAD_BUTTON_SOUTH:
|
||||
return OPBDO::Cross;
|
||||
case SDL_GAMEPAD_BUTTON_NORTH:
|
||||
return OPBDO::Triangle;
|
||||
case SDL_GAMEPAD_BUTTON_WEST:
|
||||
return OPBDO::Square;
|
||||
case SDL_GAMEPAD_BUTTON_EAST:
|
||||
return OPBDO::Circle;
|
||||
case SDL_GAMEPAD_BUTTON_START:
|
||||
return OPBDO::Options;
|
||||
case SDL_GAMEPAD_BUTTON_TOUCHPAD:
|
||||
return OPBDO::TouchPad;
|
||||
case SDL_GAMEPAD_BUTTON_BACK:
|
||||
return OPBDO::TouchPad;
|
||||
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER:
|
||||
return OPBDO::L1;
|
||||
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER:
|
||||
return OPBDO::R1;
|
||||
case SDL_GAMEPAD_BUTTON_LEFT_STICK:
|
||||
return OPBDO::L3;
|
||||
case SDL_GAMEPAD_BUTTON_RIGHT_STICK:
|
||||
return OPBDO::R3;
|
||||
default:
|
||||
return OPBDO::None;
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_GamepadAxis InputAxisToSDL(Axis axis) {
|
||||
switch (axis) {
|
||||
case Axis::LeftX:
|
||||
return SDL_GAMEPAD_AXIS_LEFTX;
|
||||
case Axis::LeftY:
|
||||
return SDL_GAMEPAD_AXIS_LEFTY;
|
||||
case Axis::RightX:
|
||||
return SDL_GAMEPAD_AXIS_RIGHTX;
|
||||
case Axis::RightY:
|
||||
return SDL_GAMEPAD_AXIS_RIGHTY;
|
||||
case Axis::TriggerLeft:
|
||||
return SDL_GAMEPAD_AXIS_LEFT_TRIGGER;
|
||||
case Axis::TriggerRight:
|
||||
return SDL_GAMEPAD_AXIS_RIGHT_TRIGGER;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
SDLInputEngine::~SDLInputEngine() {
|
||||
if (m_gamepad) {
|
||||
SDL_CloseGamepad(m_gamepad);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLInputEngine::Init() {
|
||||
if (m_gamepad) {
|
||||
SDL_CloseGamepad(m_gamepad);
|
||||
m_gamepad = nullptr;
|
||||
}
|
||||
int gamepad_count;
|
||||
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
|
||||
if (!gamepads) {
|
||||
LOG_ERROR(Input, "Cannot get gamepad list: {}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
if (gamepad_count == 0) {
|
||||
LOG_INFO(Input, "No gamepad found!");
|
||||
SDL_free(gamepads);
|
||||
return;
|
||||
}
|
||||
LOG_INFO(Input, "Got {} gamepads. Opening the first one.", gamepad_count);
|
||||
if (!(m_gamepad = SDL_OpenGamepad(gamepads[0]))) {
|
||||
LOG_ERROR(Input, "Failed to open gamepad 0: {}", SDL_GetError());
|
||||
SDL_free(gamepads);
|
||||
return;
|
||||
}
|
||||
if (Config::getIsMotionControlsEnabled()) {
|
||||
if (SDL_SetGamepadSensorEnabled(m_gamepad, SDL_SENSOR_GYRO, true)) {
|
||||
m_gyro_poll_rate = SDL_GetGamepadSensorDataRate(m_gamepad, SDL_SENSOR_GYRO);
|
||||
LOG_INFO(Input, "Gyro initialized, poll rate: {}", m_gyro_poll_rate);
|
||||
} else {
|
||||
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad");
|
||||
}
|
||||
if (SDL_SetGamepadSensorEnabled(m_gamepad, SDL_SENSOR_ACCEL, true)) {
|
||||
m_accel_poll_rate = SDL_GetGamepadSensorDataRate(m_gamepad, SDL_SENSOR_ACCEL);
|
||||
LOG_INFO(Input, "Accel initialized, poll rate: {}", m_accel_poll_rate);
|
||||
} else {
|
||||
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad");
|
||||
};
|
||||
}
|
||||
SDL_free(gamepads);
|
||||
SetLightBarRGB(0, 0, 255);
|
||||
}
|
||||
|
||||
void SDLInputEngine::SetLightBarRGB(u8 r, u8 g, u8 b) {
|
||||
if (m_gamepad) {
|
||||
SDL_SetGamepadLED(m_gamepad, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLInputEngine::SetVibration(u8 smallMotor, u8 largeMotor) {
|
||||
if (m_gamepad) {
|
||||
const auto low_freq = (smallMotor / 255.0f) * 0xFFFF;
|
||||
const auto high_freq = (largeMotor / 255.0f) * 0xFFFF;
|
||||
SDL_RumbleGamepad(m_gamepad, low_freq, high_freq, -1);
|
||||
}
|
||||
}
|
||||
|
||||
State SDLInputEngine::ReadState() {
|
||||
State state{};
|
||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
// Buttons
|
||||
for (u8 i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; ++i) {
|
||||
auto orbisButton = SDLGamepadToOrbisButton(i);
|
||||
if (orbisButton == OrbisPadButtonDataOffset::None) {
|
||||
continue;
|
||||
}
|
||||
state.OnButton(orbisButton, SDL_GetGamepadButton(m_gamepad, (SDL_GamepadButton)i));
|
||||
}
|
||||
|
||||
// Axes
|
||||
for (int i = 0; i < static_cast<int>(Axis::AxisMax); ++i) {
|
||||
const auto axis = static_cast<Axis>(i);
|
||||
const auto value = SDL_GetGamepadAxis(m_gamepad, InputAxisToSDL(axis));
|
||||
switch (axis) {
|
||||
case Axis::TriggerLeft:
|
||||
case Axis::TriggerRight:
|
||||
state.OnAxis(axis, GetAxis(0, 0x8000, value));
|
||||
break;
|
||||
default:
|
||||
state.OnAxis(axis, GetAxis(-0x8000, 0x8000, value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Touchpad
|
||||
if (SDL_GetNumGamepadTouchpads(m_gamepad) > 0) {
|
||||
for (int finger = 0; finger < 2; ++finger) {
|
||||
bool down;
|
||||
float x, y;
|
||||
if (SDL_GetGamepadTouchpadFinger(m_gamepad, 0, finger, &down, &x, &y, NULL)) {
|
||||
state.OnTouchpad(finger, down, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gyro
|
||||
if (SDL_GamepadHasSensor(m_gamepad, SDL_SENSOR_GYRO)) {
|
||||
float gyro[3];
|
||||
if (SDL_GetGamepadSensorData(m_gamepad, SDL_SENSOR_GYRO, gyro, 3)) {
|
||||
state.OnGyro(gyro);
|
||||
}
|
||||
}
|
||||
|
||||
// Accel
|
||||
if (SDL_GamepadHasSensor(m_gamepad, SDL_SENSOR_ACCEL)) {
|
||||
float accel[3];
|
||||
if (SDL_GetGamepadSensorData(m_gamepad, SDL_SENSOR_ACCEL, accel, 3)) {
|
||||
state.OnAccel(accel);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
float SDLInputEngine::GetGyroPollRate() const {
|
||||
return m_gyro_poll_rate;
|
||||
}
|
||||
|
||||
float SDLInputEngine::GetAccelPollRate() const {
|
||||
return m_accel_poll_rate;
|
||||
}
|
||||
|
||||
} // namespace Input
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
using namespace Libraries::Pad;
|
||||
|
||||
static OrbisPadButtonDataOffset SDLGamepadToOrbisButton(u8 button) {
|
||||
switch (button) {
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
return OrbisPadButtonDataOffset::Down;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
||||
return OrbisPadButtonDataOffset::Up;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
return OrbisPadButtonDataOffset::Left;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
return OrbisPadButtonDataOffset::Right;
|
||||
case SDL_GAMEPAD_BUTTON_SOUTH:
|
||||
return OrbisPadButtonDataOffset::Cross;
|
||||
case SDL_GAMEPAD_BUTTON_NORTH:
|
||||
return OrbisPadButtonDataOffset::Triangle;
|
||||
case SDL_GAMEPAD_BUTTON_WEST:
|
||||
return OrbisPadButtonDataOffset::Square;
|
||||
case SDL_GAMEPAD_BUTTON_EAST:
|
||||
return OrbisPadButtonDataOffset::Circle;
|
||||
case SDL_GAMEPAD_BUTTON_START:
|
||||
return OrbisPadButtonDataOffset::Options;
|
||||
case SDL_GAMEPAD_BUTTON_TOUCHPAD:
|
||||
return OrbisPadButtonDataOffset::TouchPad;
|
||||
case SDL_GAMEPAD_BUTTON_BACK:
|
||||
return OrbisPadButtonDataOffset::TouchPad;
|
||||
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER:
|
||||
return OrbisPadButtonDataOffset::L1;
|
||||
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER:
|
||||
return OrbisPadButtonDataOffset::R1;
|
||||
case SDL_GAMEPAD_BUTTON_LEFT_STICK:
|
||||
return OrbisPadButtonDataOffset::L3;
|
||||
case SDL_GAMEPAD_BUTTON_RIGHT_STICK:
|
||||
return OrbisPadButtonDataOffset::R3;
|
||||
default:
|
||||
return OrbisPadButtonDataOffset::None;
|
||||
}
|
||||
}
|
||||
|
||||
static Uint32 SDLCALL PollController(void* userdata, SDL_TimerID timer_id, Uint32 interval) {
|
||||
auto* controller = reinterpret_cast<Input::GameController*>(userdata);
|
||||
return controller->Poll();
|
||||
@ -116,7 +270,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_
|
||||
SDL_SetWindowFullscreen(window, Config::getIsFullscreen());
|
||||
|
||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||
controller->TryOpenSDLController();
|
||||
controller->SetEngine(std::make_unique<Input::SDLInputEngine>());
|
||||
|
||||
#if defined(SDL_PLATFORM_WIN32)
|
||||
window_info.type = WindowSystemType::Windows;
|
||||
@ -306,7 +460,7 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) {
|
||||
switch (event->type) {
|
||||
case SDL_EVENT_GAMEPAD_ADDED:
|
||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||
controller->TryOpenSDLController();
|
||||
controller->SetEngine(std::make_unique<Input::SDLInputEngine>());
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
||||
@ -317,7 +471,7 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) {
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP: {
|
||||
button = SDLGamepadToOrbisButton(event->gbutton.button);
|
||||
button = Input::SDLGamepadToOrbisButton(event->gbutton.button);
|
||||
if (button == OrbisPadButtonDataOffset::None) {
|
||||
break;
|
||||
}
|
||||
|
@ -7,14 +7,32 @@
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "input/controller.h"
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Gamepad;
|
||||
union SDL_Event;
|
||||
|
||||
namespace Input {
|
||||
class GameController;
|
||||
}
|
||||
|
||||
class SDLInputEngine : public Engine {
|
||||
public:
|
||||
~SDLInputEngine() override;
|
||||
void Init() override;
|
||||
void SetLightBarRGB(u8 r, u8 g, u8 b) override;
|
||||
void SetVibration(u8 smallMotor, u8 largeMotor) override;
|
||||
float GetGyroPollRate() const override;
|
||||
float GetAccelPollRate() const override;
|
||||
State ReadState() override;
|
||||
|
||||
private:
|
||||
SDL_Gamepad* m_gamepad = nullptr;
|
||||
|
||||
float m_gyro_poll_rate{};
|
||||
float m_accel_poll_rate{};
|
||||
};
|
||||
|
||||
} // namespace Input
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
|
@ -24,10 +24,48 @@ void ConvertDepthMode(EmitContext& ctx) {
|
||||
ctx.OpStore(ctx.output_position, vector);
|
||||
}
|
||||
|
||||
void ConvertPositionToClipSpace(EmitContext& ctx) {
|
||||
const Id type{ctx.F32[1]};
|
||||
Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)};
|
||||
const Id x{ctx.OpCompositeExtract(type, position, 0u)};
|
||||
const Id y{ctx.OpCompositeExtract(type, position, 1u)};
|
||||
const Id z{ctx.OpCompositeExtract(type, position, 2u)};
|
||||
const Id w{ctx.OpCompositeExtract(type, position, 3u)};
|
||||
const Id xoffset_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type),
|
||||
ctx.push_data_block,
|
||||
ctx.ConstU32(PushData::XOffsetIndex))};
|
||||
const Id xoffset{ctx.OpLoad(type, xoffset_ptr)};
|
||||
const Id yoffset_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type),
|
||||
ctx.push_data_block,
|
||||
ctx.ConstU32(PushData::YOffsetIndex))};
|
||||
const Id yoffset{ctx.OpLoad(type, yoffset_ptr)};
|
||||
const Id xscale_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type),
|
||||
ctx.push_data_block,
|
||||
ctx.ConstU32(PushData::XScaleIndex))};
|
||||
const Id xscale{ctx.OpLoad(type, xscale_ptr)};
|
||||
const Id yscale_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type),
|
||||
ctx.push_data_block,
|
||||
ctx.ConstU32(PushData::YScaleIndex))};
|
||||
const Id yscale{ctx.OpLoad(type, yscale_ptr)};
|
||||
const Id vport_w =
|
||||
ctx.Constant(type, float(std::min<u32>(ctx.profile.max_viewport_width / 2, 8_KB)));
|
||||
const Id wnd_x = ctx.OpFAdd(type, ctx.OpFMul(type, x, xscale), xoffset);
|
||||
const Id ndc_x = ctx.OpFSub(type, ctx.OpFDiv(type, wnd_x, vport_w), ctx.Constant(type, 1.f));
|
||||
const Id vport_h =
|
||||
ctx.Constant(type, float(std::min<u32>(ctx.profile.max_viewport_height / 2, 8_KB)));
|
||||
const Id wnd_y = ctx.OpFAdd(type, ctx.OpFMul(type, y, yscale), yoffset);
|
||||
const Id ndc_y = ctx.OpFSub(type, ctx.OpFDiv(type, wnd_y, vport_h), ctx.Constant(type, 1.f));
|
||||
const Id vector{ctx.OpCompositeConstruct(ctx.F32[4], std::array<Id, 4>({ndc_x, ndc_y, z, w}))};
|
||||
ctx.OpStore(ctx.output_position, vector);
|
||||
}
|
||||
|
||||
void EmitEpilogue(EmitContext& ctx) {
|
||||
if (ctx.stage == Stage::Vertex && ctx.runtime_info.vs_info.emulate_depth_negative_one_to_one) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (ctx.stage == Stage::Vertex && ctx.runtime_info.vs_info.clip_disable) {
|
||||
ConvertPositionToClipSpace(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitDiscard(EmitContext& ctx) {
|
||||
|
@ -568,25 +568,34 @@ void EmitContext::DefineOutputs() {
|
||||
|
||||
void EmitContext::DefinePushDataBlock() {
|
||||
// Create push constants block for instance steps rates
|
||||
const Id struct_type{Name(
|
||||
TypeStruct(U32[1], U32[1], U32[4], U32[4], U32[4], U32[4], U32[4], U32[4]), "AuxData")};
|
||||
const Id struct_type{Name(TypeStruct(U32[1], U32[1], U32[4], U32[4], U32[4], U32[4], U32[4],
|
||||
U32[4], F32[1], F32[1], F32[1], F32[1]),
|
||||
"AuxData")};
|
||||
Decorate(struct_type, spv::Decoration::Block);
|
||||
MemberName(struct_type, 0, "sr0");
|
||||
MemberName(struct_type, 1, "sr1");
|
||||
MemberName(struct_type, 2, "buf_offsets0");
|
||||
MemberName(struct_type, 3, "buf_offsets1");
|
||||
MemberName(struct_type, 4, "ud_regs0");
|
||||
MemberName(struct_type, 5, "ud_regs1");
|
||||
MemberName(struct_type, 6, "ud_regs2");
|
||||
MemberName(struct_type, 7, "ud_regs3");
|
||||
MemberName(struct_type, Shader::PushData::BufOffsetIndex + 0, "buf_offsets0");
|
||||
MemberName(struct_type, Shader::PushData::BufOffsetIndex + 1, "buf_offsets1");
|
||||
MemberName(struct_type, Shader::PushData::UdRegsIndex + 0, "ud_regs0");
|
||||
MemberName(struct_type, Shader::PushData::UdRegsIndex + 1, "ud_regs1");
|
||||
MemberName(struct_type, Shader::PushData::UdRegsIndex + 2, "ud_regs2");
|
||||
MemberName(struct_type, Shader::PushData::UdRegsIndex + 3, "ud_regs3");
|
||||
MemberName(struct_type, Shader::PushData::XOffsetIndex, "xoffset");
|
||||
MemberName(struct_type, Shader::PushData::YOffsetIndex, "yoffset");
|
||||
MemberName(struct_type, Shader::PushData::XScaleIndex, "xscale");
|
||||
MemberName(struct_type, Shader::PushData::YScaleIndex, "yscale");
|
||||
MemberDecorate(struct_type, 0, spv::Decoration::Offset, 0U);
|
||||
MemberDecorate(struct_type, 1, spv::Decoration::Offset, 4U);
|
||||
MemberDecorate(struct_type, 2, spv::Decoration::Offset, 8U);
|
||||
MemberDecorate(struct_type, 3, spv::Decoration::Offset, 24U);
|
||||
MemberDecorate(struct_type, 4, spv::Decoration::Offset, 40U);
|
||||
MemberDecorate(struct_type, 5, spv::Decoration::Offset, 56U);
|
||||
MemberDecorate(struct_type, 6, spv::Decoration::Offset, 72U);
|
||||
MemberDecorate(struct_type, 7, spv::Decoration::Offset, 88U);
|
||||
MemberDecorate(struct_type, Shader::PushData::BufOffsetIndex + 0, spv::Decoration::Offset, 8U);
|
||||
MemberDecorate(struct_type, Shader::PushData::BufOffsetIndex + 1, spv::Decoration::Offset, 24U);
|
||||
MemberDecorate(struct_type, Shader::PushData::UdRegsIndex + 0, spv::Decoration::Offset, 40U);
|
||||
MemberDecorate(struct_type, Shader::PushData::UdRegsIndex + 1, spv::Decoration::Offset, 56U);
|
||||
MemberDecorate(struct_type, Shader::PushData::UdRegsIndex + 2, spv::Decoration::Offset, 72U);
|
||||
MemberDecorate(struct_type, Shader::PushData::UdRegsIndex + 3, spv::Decoration::Offset, 88U);
|
||||
MemberDecorate(struct_type, Shader::PushData::XOffsetIndex, spv::Decoration::Offset, 104U);
|
||||
MemberDecorate(struct_type, Shader::PushData::YOffsetIndex, spv::Decoration::Offset, 108U);
|
||||
MemberDecorate(struct_type, Shader::PushData::XScaleIndex, spv::Decoration::Offset, 112U);
|
||||
MemberDecorate(struct_type, Shader::PushData::YScaleIndex, spv::Decoration::Offset, 116U);
|
||||
push_data_block = DefineVar(struct_type, spv::StorageClass::PushConstant);
|
||||
Name(push_data_block, "push_data");
|
||||
interfaces.push_back(push_data_block);
|
||||
@ -847,6 +856,10 @@ void EmitContext::DefineSharedMemory() {
|
||||
if (shared_memory_size == 0) {
|
||||
shared_memory_size = DefaultSharedMemSize;
|
||||
}
|
||||
|
||||
const u32 max_shared_memory_size = runtime_info.cs_info.max_shared_memory_size;
|
||||
ASSERT(shared_memory_size <= max_shared_memory_size);
|
||||
|
||||
const u32 num_elements{Common::DivCeil(shared_memory_size, 4U)};
|
||||
const Id type{TypeArray(U32[1], ConstU32(num_elements))};
|
||||
shared_memory_u32_type = TypePointer(spv::StorageClass::Workgroup, type);
|
||||
|
@ -96,11 +96,19 @@ using FMaskResourceList = boost::container::small_vector<FMaskResource, 16>;
|
||||
struct PushData {
|
||||
static constexpr u32 BufOffsetIndex = 2;
|
||||
static constexpr u32 UdRegsIndex = 4;
|
||||
static constexpr u32 XOffsetIndex = 8;
|
||||
static constexpr u32 YOffsetIndex = 9;
|
||||
static constexpr u32 XScaleIndex = 10;
|
||||
static constexpr u32 YScaleIndex = 11;
|
||||
|
||||
u32 step0;
|
||||
u32 step1;
|
||||
std::array<u8, 32> buf_offsets;
|
||||
std::array<u32, NumUserDataRegs> ud_regs;
|
||||
float xoffset;
|
||||
float yoffset;
|
||||
float xscale;
|
||||
float yscale;
|
||||
|
||||
void AddOffset(u32 binding, u32 offset) {
|
||||
ASSERT(offset < 256 && binding < buf_offsets.size());
|
||||
|
@ -30,6 +30,8 @@ struct Profile {
|
||||
bool needs_manual_interpolation{};
|
||||
bool needs_lds_barriers{};
|
||||
u64 min_ssbo_alignment{};
|
||||
u32 max_viewport_width{};
|
||||
u32 max_viewport_height{};
|
||||
};
|
||||
|
||||
} // namespace Shader
|
||||
|
@ -84,6 +84,7 @@ struct VertexRuntimeInfo {
|
||||
u32 num_outputs;
|
||||
std::array<VsOutputMap, 3> outputs;
|
||||
bool emulate_depth_negative_one_to_one{};
|
||||
bool clip_disable{};
|
||||
// Domain
|
||||
AmdGpu::TessellationType tess_type;
|
||||
AmdGpu::TessellationTopology tess_topology;
|
||||
@ -92,7 +93,8 @@ struct VertexRuntimeInfo {
|
||||
|
||||
bool operator==(const VertexRuntimeInfo& other) const noexcept {
|
||||
return emulate_depth_negative_one_to_one == other.emulate_depth_negative_one_to_one &&
|
||||
tess_type == other.tess_type && tess_topology == other.tess_topology &&
|
||||
clip_disable == other.clip_disable && tess_type == other.tess_type &&
|
||||
tess_topology == other.tess_topology &&
|
||||
tess_partitioning == other.tess_partitioning &&
|
||||
hs_output_cp_stride == other.hs_output_cp_stride;
|
||||
}
|
||||
@ -198,6 +200,7 @@ struct FragmentRuntimeInfo {
|
||||
|
||||
struct ComputeRuntimeInfo {
|
||||
u32 shared_memory_size;
|
||||
u32 max_shared_memory_size;
|
||||
std::array<u32, 3> workgroup_size;
|
||||
std::array<bool, 3> tgid_enable;
|
||||
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include <span>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __linux__
|
||||
#include "common/adaptive_mutex.h"
|
||||
#endif
|
||||
#include "common/spin_lock.h"
|
||||
#include "common/types.h"
|
||||
#include "video_core/page_manager.h"
|
||||
@ -272,7 +275,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
Common::AdaptiveMutex lock;
|
||||
#else
|
||||
Common::SpinLock lock;
|
||||
#endif
|
||||
PageManager* tracker;
|
||||
VAddr cpu_addr = 0;
|
||||
WordsArray cpu;
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
#include <memory>
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#ifdef __linux__
|
||||
#include "common/adaptive_mutex.h"
|
||||
#endif
|
||||
#include "common/spin_lock.h"
|
||||
#include "common/types.h"
|
||||
|
||||
@ -36,7 +39,11 @@ private:
|
||||
std::unique_ptr<Impl> impl;
|
||||
Vulkan::Rasterizer* rasterizer;
|
||||
boost::icl::interval_map<VAddr, s32> cached_pages;
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
Common::AdaptiveMutex lock;
|
||||
#else
|
||||
Common::SpinLock lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
||||
|
@ -42,13 +42,14 @@ struct GraphicsPipelineKey {
|
||||
vk::Format stencil_format;
|
||||
|
||||
struct {
|
||||
bool clip_disable : 1;
|
||||
bool depth_test_enable : 1;
|
||||
bool depth_write_enable : 1;
|
||||
bool depth_bounds_test_enable : 1;
|
||||
bool depth_bias_enable : 1;
|
||||
bool stencil_test_enable : 1;
|
||||
// Must be named to be zero-initialized.
|
||||
u8 _unused : 3;
|
||||
u8 _unused : 2;
|
||||
};
|
||||
vk::CompareOp depth_compare_op;
|
||||
|
||||
@ -94,6 +95,10 @@ public:
|
||||
return key.mrt_mask;
|
||||
}
|
||||
|
||||
auto IsClipDisabled() const {
|
||||
return key.clip_disable;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsPrimitiveListTopology() const {
|
||||
return key.prim_type == AmdGpu::PrimitiveType::PointList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::LineList ||
|
||||
|
@ -208,6 +208,7 @@ std::string Instance::GetDriverVersionName() {
|
||||
bool Instance::CreateDevice() {
|
||||
const vk::StructureChain feature_chain = physical_device.getFeatures2<
|
||||
vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT,
|
||||
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT,
|
||||
vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT,
|
||||
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT,
|
||||
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
|
||||
@ -270,7 +271,6 @@ bool Instance::CreateDevice() {
|
||||
legacy_vertex_attributes = add_extension(VK_EXT_LEGACY_VERTEX_ATTRIBUTES_EXTENSION_NAME);
|
||||
image_load_store_lod = add_extension(VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME);
|
||||
amd_gcn_shader = add_extension(VK_AMD_GCN_SHADER_EXTENSION_NAME);
|
||||
add_extension(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
|
||||
|
||||
// These extensions are promoted by Vulkan 1.3, but for greater compatibility we use Vulkan 1.2
|
||||
// with extensions.
|
||||
@ -317,6 +317,9 @@ bool Instance::CreateDevice() {
|
||||
.pQueuePriorities = queue_priorities.data(),
|
||||
};
|
||||
|
||||
const auto topology_list_restart_features =
|
||||
feature_chain.get<vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT>();
|
||||
|
||||
const auto vk12_features = feature_chain.get<vk::PhysicalDeviceVulkan12Features>();
|
||||
vk::StructureChain device_chain = {
|
||||
vk::DeviceCreateInfo{
|
||||
@ -406,6 +409,8 @@ bool Instance::CreateDevice() {
|
||||
},
|
||||
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT{
|
||||
.primitiveTopologyListRestart = true,
|
||||
.primitiveTopologyPatchListRestart =
|
||||
topology_list_restart_features.primitiveTopologyPatchListRestart,
|
||||
},
|
||||
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR{
|
||||
.fragmentShaderBarycentric = true,
|
||||
|
@ -239,6 +239,11 @@ public:
|
||||
return subgroup_size;
|
||||
}
|
||||
|
||||
/// Returns the maximum size of compute shared memory.
|
||||
u32 MaxComputeSharedMemorySize() const {
|
||||
return properties.limits.maxComputeSharedMemorySize;
|
||||
}
|
||||
|
||||
/// Returns the maximum supported elements in a texel buffer
|
||||
u32 MaxTexelBufferElements() const {
|
||||
return properties.limits.maxTexelBufferElements;
|
||||
@ -274,6 +279,14 @@ public:
|
||||
return min_imported_host_pointer_alignment;
|
||||
}
|
||||
|
||||
u32 GetMaxViewportWidth() const {
|
||||
return properties.limits.maxViewportDimensions[0];
|
||||
}
|
||||
|
||||
u32 GetMaxViewportHeight() const {
|
||||
return properties.limits.maxViewportDimensions[1];
|
||||
}
|
||||
|
||||
/// Returns the sample count flags supported by framebuffers.
|
||||
vk::SampleCountFlags GetFramebufferSampleCounts() const {
|
||||
return properties.limits.framebufferColorSampleCounts &
|
||||
|
@ -125,6 +125,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
|
||||
info.vs_info.emulate_depth_negative_one_to_one =
|
||||
!instance.IsDepthClipControlSupported() &&
|
||||
regs.clipper_control.clip_space == Liverpool::ClipSpace::MinusWToW;
|
||||
info.vs_info.clip_disable = graphics_key.clip_disable;
|
||||
if (l_stage == LogicalStage::TessellationEval) {
|
||||
info.vs_info.tess_type = regs.tess_config.type;
|
||||
info.vs_info.tess_topology = regs.tess_config.topology;
|
||||
@ -183,6 +184,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
|
||||
info.cs_info.tgid_enable = {cs_pgm.IsTgidEnabled(0), cs_pgm.IsTgidEnabled(1),
|
||||
cs_pgm.IsTgidEnabled(2)};
|
||||
info.cs_info.shared_memory_size = cs_pgm.SharedMemSize();
|
||||
info.cs_info.max_shared_memory_size = instance.MaxComputeSharedMemorySize();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -209,6 +211,8 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
|
||||
instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,
|
||||
.needs_lds_barriers = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary ||
|
||||
instance.GetDriverID() == vk::DriverId::eMoltenvk,
|
||||
.max_viewport_width = instance.GetMaxViewportWidth(),
|
||||
.max_viewport_height = instance.GetMaxViewportHeight(),
|
||||
};
|
||||
auto [cache_result, cache] = instance.GetDevice().createPipelineCacheUnique({});
|
||||
ASSERT_MSG(cache_result == vk::Result::eSuccess, "Failed to create pipeline cache: {}",
|
||||
@ -261,6 +265,8 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
auto& regs = liverpool->regs;
|
||||
auto& key = graphics_key;
|
||||
|
||||
key.clip_disable =
|
||||
regs.clipper_control.clip_disable || regs.primitive_type == AmdGpu::PrimitiveType::RectList;
|
||||
key.depth_test_enable = regs.depth_control.depth_enable;
|
||||
key.depth_write_enable =
|
||||
regs.depth_control.depth_write_enable && !regs.depth_render_control.depth_clear_enable;
|
||||
|
@ -380,7 +380,7 @@ void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
|
||||
const vk::ImageViewCreateInfo view_info = {
|
||||
.image = frame->image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = swapchain.GetViewFormat(),
|
||||
.format = format,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
@ -476,7 +476,7 @@ bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) {
|
||||
if (!frame) {
|
||||
if (!splash_img.has_value()) {
|
||||
VideoCore::ImageInfo info{};
|
||||
info.pixel_format = vk::Format::eR8G8B8A8Srgb;
|
||||
info.pixel_format = vk::Format::eR8G8B8A8Unorm;
|
||||
info.type = vk::ImageType::e2D;
|
||||
info.size =
|
||||
VideoCore::Extent3D{splash->GetImageInfo().width, splash->GetImageInfo().height, 1};
|
||||
@ -487,6 +487,7 @@ bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) {
|
||||
splash->GetImageInfo().width,
|
||||
splash->GetImageInfo().height, 0);
|
||||
splash_img.emplace(instance, present_scheduler, info);
|
||||
splash_img->flags &= ~VideoCore::GpuDirty;
|
||||
texture_cache.RefreshImage(*splash_img);
|
||||
|
||||
splash_img->Transit(vk::ImageLayout::eTransferSrcOptimal,
|
||||
@ -602,6 +603,23 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
|
||||
.pImageMemoryBarriers = &pre_barrier,
|
||||
});
|
||||
|
||||
const std::array attachments = {vk::RenderingAttachmentInfo{
|
||||
.imageView = frame->image_view,
|
||||
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
}};
|
||||
const vk::RenderingInfo rendering_info{
|
||||
.renderArea =
|
||||
vk::Rect2D{
|
||||
.offset = {0, 0},
|
||||
.extent = {frame->width, frame->height},
|
||||
},
|
||||
.layerCount = 1,
|
||||
.colorAttachmentCount = attachments.size(),
|
||||
.pColorAttachments = attachments.data(),
|
||||
};
|
||||
|
||||
if (image_id != VideoCore::NULL_IMAGE_ID) {
|
||||
auto& image = texture_cache.GetImage(image_id);
|
||||
image.Transit(vk::ImageLayout::eShaderReadOnlyOptimal, vk::AccessFlagBits2::eShaderRead, {},
|
||||
@ -662,26 +680,13 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
|
||||
cmdbuf.pushConstants(*pp_pipeline_layout, vk::ShaderStageFlagBits::eFragment, 0,
|
||||
sizeof(PostProcessSettings), &pp_settings);
|
||||
|
||||
const std::array attachments = {vk::RenderingAttachmentInfo{
|
||||
.imageView = frame->image_view,
|
||||
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
}};
|
||||
|
||||
vk::RenderingInfo rendering_info{
|
||||
.renderArea =
|
||||
vk::Rect2D{
|
||||
.offset = {0, 0},
|
||||
.extent = {frame->width, frame->height},
|
||||
},
|
||||
.layerCount = 1,
|
||||
.colorAttachmentCount = attachments.size(),
|
||||
.pColorAttachments = attachments.data(),
|
||||
};
|
||||
cmdbuf.beginRendering(rendering_info);
|
||||
cmdbuf.draw(3, 1, 0, 0);
|
||||
cmdbuf.endRendering();
|
||||
} else {
|
||||
// Fix display of garbage images on startup on some drivers
|
||||
cmdbuf.beginRendering(rendering_info);
|
||||
cmdbuf.endRendering();
|
||||
}
|
||||
|
||||
const auto post_barrier =
|
||||
|
@ -504,6 +504,17 @@ bool Rasterizer::BindResources(const Pipeline* pipeline) {
|
||||
}
|
||||
push_data.step0 = regs.vgt_instance_step_rate_0;
|
||||
push_data.step1 = regs.vgt_instance_step_rate_1;
|
||||
|
||||
// TODO(roamic): add support for multiple viewports and geometry shaders when ViewportIndex
|
||||
// is encountered and implemented in the recompiler.
|
||||
if (stage->stage == Shader::Stage::Vertex) {
|
||||
push_data.xoffset =
|
||||
regs.viewport_control.xoffset_enable ? regs.viewports[0].xoffset : 0.f;
|
||||
push_data.xscale = regs.viewport_control.xscale_enable ? regs.viewports[0].xscale : 1.f;
|
||||
push_data.yoffset =
|
||||
regs.viewport_control.yoffset_enable ? regs.viewports[0].yoffset : 0.f;
|
||||
push_data.yscale = regs.viewport_control.yscale_enable ? regs.viewports[0].yscale : 1.f;
|
||||
}
|
||||
stage->PushUd(binding, push_data);
|
||||
|
||||
BindBuffers(*stage, binding, push_data, set_writes, buffer_barriers);
|
||||
@ -791,8 +802,6 @@ void Rasterizer::BeginRendering(const GraphicsPipeline& pipeline, RenderState& s
|
||||
const auto mip = view.info.range.base.level;
|
||||
state.width = std::min<u32>(state.width, std::max(image.info.size.width >> mip, 1u));
|
||||
state.height = std::min<u32>(state.height, std::max(image.info.size.height >> mip, 1u));
|
||||
ASSERT(old_img.info.size.width == state.width);
|
||||
ASSERT(old_img.info.size.height == state.height);
|
||||
}
|
||||
auto& image = texture_cache.GetImage(image_id);
|
||||
if (image.binding.force_general) {
|
||||
@ -1032,7 +1041,7 @@ void Rasterizer::UnmapMemory(VAddr addr, u64 size) {
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
|
||||
UpdateViewportScissorState();
|
||||
UpdateViewportScissorState(pipeline);
|
||||
|
||||
auto& regs = liverpool->regs;
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
@ -1112,7 +1121,7 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
|
||||
}
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateViewportScissorState() {
|
||||
void Rasterizer::UpdateViewportScissorState(const GraphicsPipeline& pipeline) {
|
||||
const auto& regs = liverpool->regs;
|
||||
|
||||
const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) {
|
||||
@ -1151,12 +1160,31 @@ void Rasterizer::UpdateViewportScissorState() {
|
||||
? 1.0f
|
||||
: 0.0f;
|
||||
|
||||
if (regs.polygon_control.enable_window_offset) {
|
||||
LOG_ERROR(Render_Vulkan,
|
||||
"PA_SU_SC_MODE_CNTL.VTX_WINDOW_OFFSET_ENABLE support is not yet implemented.");
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < Liverpool::NumViewports; i++) {
|
||||
const auto& vp = regs.viewports[i];
|
||||
const auto& vp_d = regs.viewport_depths[i];
|
||||
if (vp.xscale == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pipeline.IsClipDisabled()) {
|
||||
// In case if clipping is disabled we patch the shader to convert vertex position
|
||||
// from screen space coordinates to NDC by defining a render space as full hardware
|
||||
// window range [0..16383, 0..16383] and setting the viewport to its size.
|
||||
viewports.push_back({
|
||||
.x = 0.f,
|
||||
.y = 0.f,
|
||||
.width = float(std::min<u32>(instance.GetMaxViewportWidth(), 16_KB)),
|
||||
.height = float(std::min<u32>(instance.GetMaxViewportHeight(), 16_KB)),
|
||||
.minDepth = 0.0,
|
||||
.maxDepth = 1.0,
|
||||
});
|
||||
} else {
|
||||
const auto xoffset = vp_ctl.xoffset_enable ? vp.xoffset : 0.f;
|
||||
const auto xscale = vp_ctl.xscale_enable ? vp.xscale : 1.f;
|
||||
const auto yoffset = vp_ctl.yoffset_enable ? vp.yoffset : 0.f;
|
||||
@ -1171,6 +1199,7 @@ void Rasterizer::UpdateViewportScissorState() {
|
||||
.minDepth = zoffset - zscale * reduce_z,
|
||||
.maxDepth = zscale + zoffset,
|
||||
});
|
||||
}
|
||||
|
||||
auto vp_scsr = scsr;
|
||||
if (regs.mode_control.vport_scissor_enable) {
|
||||
@ -1192,8 +1221,8 @@ void Rasterizer::UpdateViewportScissorState() {
|
||||
if (viewports.empty()) {
|
||||
// Vulkan requires providing at least one viewport.
|
||||
constexpr vk::Viewport empty_viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.x = -1.0f,
|
||||
.y = -1.0f,
|
||||
.width = 1.0f,
|
||||
.height = 1.0f,
|
||||
.minDepth = 0.0f,
|
||||
|
@ -76,7 +76,7 @@ private:
|
||||
void EliminateFastClear();
|
||||
|
||||
void UpdateDynamicState(const GraphicsPipeline& pipeline);
|
||||
void UpdateViewportScissorState();
|
||||
void UpdateViewportScissorState(const GraphicsPipeline& pipeline);
|
||||
|
||||
bool FilterDraw();
|
||||
|
||||
|
@ -17,7 +17,7 @@ Swapchain::Swapchain(const Instance& instance_, const Frontend::WindowSDL& windo
|
||||
FindPresentFormat();
|
||||
|
||||
Create(window.GetWidth(), window.GetHeight());
|
||||
ImGui::Core::Initialize(instance, window, image_count, view_format);
|
||||
ImGui::Core::Initialize(instance, window, image_count, surface_format.format);
|
||||
}
|
||||
|
||||
Swapchain::~Swapchain() {
|
||||
@ -57,17 +57,7 @@ void Swapchain::Create(u32 width_, u32 height_) {
|
||||
const u32 queue_family_indices_count = exclusive ? 1u : 2u;
|
||||
const vk::SharingMode sharing_mode =
|
||||
exclusive ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent;
|
||||
const vk::Format view_formats[2] = {
|
||||
surface_format.format,
|
||||
view_format,
|
||||
};
|
||||
const vk::ImageFormatListCreateInfo format_list = {
|
||||
.viewFormatCount = 2,
|
||||
.pViewFormats = view_formats,
|
||||
};
|
||||
const vk::SwapchainCreateInfoKHR swapchain_info = {
|
||||
.pNext = &format_list,
|
||||
.flags = vk::SwapchainCreateFlagBitsKHR::eMutableFormat,
|
||||
.surface = surface,
|
||||
.minImageCount = image_count,
|
||||
.imageFormat = surface_format.format,
|
||||
@ -157,22 +147,20 @@ void Swapchain::FindPresentFormat() {
|
||||
// If there is a single undefined surface format, the device doesn't care, so we'll just use
|
||||
// RGBA sRGB.
|
||||
if (formats[0].format == vk::Format::eUndefined) {
|
||||
surface_format.format = vk::Format::eR8G8B8A8Srgb;
|
||||
surface_format.format = vk::Format::eR8G8B8A8Unorm;
|
||||
surface_format.colorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
|
||||
view_format = FormatToUnorm(surface_format.format);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to find a suitable format.
|
||||
for (const vk::SurfaceFormatKHR& sformat : formats) {
|
||||
vk::Format format = sformat.format;
|
||||
if (format != vk::Format::eR8G8B8A8Srgb && format != vk::Format::eB8G8R8A8Srgb) {
|
||||
if (format != vk::Format::eR8G8B8A8Unorm && format != vk::Format::eB8G8R8A8Unorm) {
|
||||
continue;
|
||||
}
|
||||
|
||||
surface_format.format = format;
|
||||
surface_format.colorSpace = sformat.colorSpace;
|
||||
view_format = FormatToUnorm(surface_format.format);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -274,7 +262,7 @@ void Swapchain::SetupImages() {
|
||||
auto [im_view_result, im_view] = device.createImageView(vk::ImageViewCreateInfo{
|
||||
.image = images[i],
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = FormatToUnorm(surface_format.format),
|
||||
.format = surface_format.format,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
@ -17,17 +17,6 @@ namespace Vulkan {
|
||||
class Instance;
|
||||
class Scheduler;
|
||||
|
||||
inline vk::Format FormatToUnorm(vk::Format fmt) {
|
||||
switch (fmt) {
|
||||
case vk::Format::eR8G8B8A8Srgb:
|
||||
return vk::Format::eR8G8B8A8Unorm;
|
||||
case vk::Format::eB8G8R8A8Srgb:
|
||||
return vk::Format::eB8G8R8A8Unorm;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
class Swapchain {
|
||||
public:
|
||||
explicit Swapchain(const Instance& instance, const Frontend::WindowSDL& window);
|
||||
@ -61,10 +50,6 @@ public:
|
||||
return surface_format;
|
||||
}
|
||||
|
||||
vk::Format GetViewFormat() const {
|
||||
return view_format;
|
||||
}
|
||||
|
||||
vk::SwapchainKHR GetHandle() const {
|
||||
return swapchain;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ int ImageInfo::IsMipOf(const ImageInfo& info) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IsTilingCompatible(info.tiling_idx, tiling_idx)) {
|
||||
if (!IsTilingCompatible(info.tiling_idx, tiling_idx)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -114,9 +114,12 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
|
||||
const auto view_aspect = aspect & vk::ImageAspectFlagBits::eDepth ? "Depth"
|
||||
: aspect & vk::ImageAspectFlagBits::eStencil ? "Stencil"
|
||||
: "Color";
|
||||
Vulkan::SetObjectName(instance.GetDevice(), *image_view, "ImageView {}x{}x{} {:#x}:{:#x} ({})",
|
||||
Vulkan::SetObjectName(
|
||||
instance.GetDevice(), *image_view, "ImageView {}x{}x{} {:#x}:{:#x} {}:{} {}:{} ({})",
|
||||
image.info.size.width, image.info.size.height, image.info.size.depth,
|
||||
image.info.guest_address, image.info.guest_size, view_aspect);
|
||||
image.info.guest_address, image.info.guest_size, info.range.base.level,
|
||||
info.range.base.level + info.range.extent.levels - 1, info.range.base.layer,
|
||||
info.range.base.layer + info.range.extent.layers - 1, view_aspect);
|
||||
}
|
||||
|
||||
ImageView::~ImageView() = default;
|
||||
|
Loading…
Reference in New Issue
Block a user