Merge branch 'shadps4-emu:main' into main
@ -954,12 +954,6 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(RESOURCEFOLDER Resources/bronze.png
|
|
||||||
Resources/gold.png
|
|
||||||
Resources/platinum.png
|
|
||||||
Resources/silver.png
|
|
||||||
)
|
|
||||||
|
|
||||||
if (ENABLE_QT_GUI)
|
if (ENABLE_QT_GUI)
|
||||||
qt_add_executable(shadps4
|
qt_add_executable(shadps4
|
||||||
${AUDIO_CORE}
|
${AUDIO_CORE}
|
||||||
@ -971,7 +965,6 @@ if (ENABLE_QT_GUI)
|
|||||||
${SHADER_RECOMPILER}
|
${SHADER_RECOMPILER}
|
||||||
${VIDEO_CORE}
|
${VIDEO_CORE}
|
||||||
${EMULATOR}
|
${EMULATOR}
|
||||||
${RESOURCEFOLDER}
|
|
||||||
src/images/shadPS4.icns
|
src/images/shadPS4.icns
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
@ -984,7 +977,6 @@ else()
|
|||||||
${SHADER_RECOMPILER}
|
${SHADER_RECOMPILER}
|
||||||
${VIDEO_CORE}
|
${VIDEO_CORE}
|
||||||
${EMULATOR}
|
${EMULATOR}
|
||||||
${RESOURCEFOLDER}
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/emulator.cpp
|
src/emulator.cpp
|
||||||
src/emulator.h
|
src/emulator.h
|
||||||
@ -1117,7 +1109,10 @@ include(CMakeRC)
|
|||||||
cmrc_add_resource_library(embedded-resources
|
cmrc_add_resource_library(embedded-resources
|
||||||
ALIAS res::embedded
|
ALIAS res::embedded
|
||||||
NAMESPACE res
|
NAMESPACE res
|
||||||
${RESOURCEFOLDER})
|
src/images/bronze.png
|
||||||
|
src/images/gold.png
|
||||||
|
src/images/platinum.png
|
||||||
|
src/images/silver.png)
|
||||||
|
|
||||||
target_link_libraries(shadps4 PRIVATE res::embedded)
|
target_link_libraries(shadps4 PRIVATE res::embedded)
|
||||||
|
|
||||||
|
@ -19,11 +19,11 @@ path = [
|
|||||||
"documents/Screenshots/*",
|
"documents/Screenshots/*",
|
||||||
"documents/Screenshots/Linux/*",
|
"documents/Screenshots/Linux/*",
|
||||||
"externals/MoltenVK/MoltenVK_icd.json",
|
"externals/MoltenVK/MoltenVK_icd.json",
|
||||||
"Resources/bronze.png",
|
|
||||||
"Resources/gold.png",
|
|
||||||
"Resources/platinum.png",
|
|
||||||
"Resources/silver.png",
|
|
||||||
"scripts/ps4_names.txt",
|
"scripts/ps4_names.txt",
|
||||||
|
"src/images/bronze.png",
|
||||||
|
"src/images/gold.png",
|
||||||
|
"src/images/platinum.png",
|
||||||
|
"src/images/silver.png",
|
||||||
"src/images/about_icon.png",
|
"src/images/about_icon.png",
|
||||||
"src/images/controller_icon.png",
|
"src/images/controller_icon.png",
|
||||||
"src/images/discord.png",
|
"src/images/discord.png",
|
||||||
|
@ -33,13 +33,13 @@ TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::strin
|
|||||||
|
|
||||||
std::string pathString;
|
std::string pathString;
|
||||||
if (trophy_type == "P") {
|
if (trophy_type == "P") {
|
||||||
pathString = "Resources/platinum.png";
|
pathString = "src/images/platinum.png";
|
||||||
} else if (trophy_type == "G") {
|
} else if (trophy_type == "G") {
|
||||||
pathString = "Resources/gold.png";
|
pathString = "src/images/gold.png";
|
||||||
} else if (trophy_type == "S") {
|
} else if (trophy_type == "S") {
|
||||||
pathString = "Resources/silver.png";
|
pathString = "src/images/silver.png";
|
||||||
} else if (trophy_type == "B") {
|
} else if (trophy_type == "B") {
|
||||||
pathString = "Resources/bronze.png";
|
pathString = "src/images/bronze.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resource = cmrc::res::get_filesystem();
|
auto resource = cmrc::res::get_filesystem();
|
||||||
|
@ -315,12 +315,13 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||||||
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||||
|
pData[i].orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
if (engine) {
|
if (engine) {
|
||||||
const auto accel_poll_rate = engine->GetAccelPollRate();
|
const auto gyro_poll_rate = engine->GetAccelPollRate();
|
||||||
if (accel_poll_rate != 0.0f) {
|
if (gyro_poll_rate != 0.0f) {
|
||||||
GameController::CalculateOrientation(pData[i].acceleration,
|
GameController::CalculateOrientation(pData[i].acceleration,
|
||||||
pData[i].angularVelocity,
|
pData[i].angularVelocity,
|
||||||
1.0f / accel_poll_rate, pData[i].orientation);
|
1.0f / gyro_poll_rate, pData[i].orientation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pData[i].touchData.touchNum =
|
pData[i].touchData.touchNum =
|
||||||
@ -384,11 +385,12 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||||||
pData->angularVelocity.x = state.angularVelocity.x;
|
pData->angularVelocity.x = state.angularVelocity.x;
|
||||||
pData->angularVelocity.y = state.angularVelocity.y;
|
pData->angularVelocity.y = state.angularVelocity.y;
|
||||||
pData->angularVelocity.z = state.angularVelocity.z;
|
pData->angularVelocity.z = state.angularVelocity.z;
|
||||||
|
pData->orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
if (engine) {
|
if (engine) {
|
||||||
const auto accel_poll_rate = engine->GetAccelPollRate();
|
const auto gyro_poll_rate = engine->GetAccelPollRate();
|
||||||
if (accel_poll_rate != 0.0f) {
|
if (gyro_poll_rate != 0.0f) {
|
||||||
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||||
1.0f / accel_poll_rate, pData->orientation);
|
1.0f / gyro_poll_rate, pData->orientation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pData->touchData.touchNum =
|
pData->touchData.touchNum =
|
||||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
@ -182,7 +182,7 @@ void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceler
|
|||||||
|
|
||||||
// Normalize accelerometer measurement
|
// Normalize accelerometer measurement
|
||||||
float norm = std::sqrt(ax * ax + ay * ay + az * az);
|
float norm = std::sqrt(ax * ax + ay * ay + az * az);
|
||||||
if (norm == 0.0f)
|
if (norm == 0.0f || deltaTime == 0.0f)
|
||||||
return; // Handle NaN
|
return; // Handle NaN
|
||||||
norm = 1.0f / norm;
|
norm = 1.0f / norm;
|
||||||
ax *= norm;
|
ax *= norm;
|
||||||
|
@ -677,7 +677,8 @@ void SettingsDialog::UpdateSettings() {
|
|||||||
|
|
||||||
const QVector<std::string> TouchPadIndex = {"left", "center", "right", "none"};
|
const QVector<std::string> TouchPadIndex = {"left", "center", "right", "none"};
|
||||||
Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]);
|
Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]);
|
||||||
Config::setIsFullscreen(ui->displayModeComboBox->currentText().toStdString() != "Windowed");
|
Config::setIsFullscreen(screenModeMap.value(ui->displayModeComboBox->currentText()) !=
|
||||||
|
"Windowed");
|
||||||
Config::setFullscreenMode(
|
Config::setFullscreenMode(
|
||||||
screenModeMap.value(ui->displayModeComboBox->currentText()).toStdString());
|
screenModeMap.value(ui->displayModeComboBox->currentText()).toStdString());
|
||||||
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked());
|
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked());
|
||||||
|
@ -123,7 +123,7 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
|
|||||||
QTableWidgetItem* typeitem = new QTableWidgetItem();
|
QTableWidgetItem* typeitem = new QTableWidgetItem();
|
||||||
|
|
||||||
auto resource = cmrc::res::get_filesystem();
|
auto resource = cmrc::res::get_filesystem();
|
||||||
std::string resourceString = "Resources/" + filename;
|
std::string resourceString = "src/images/" + filename;
|
||||||
auto file = resource.open(resourceString);
|
auto file = resource.open(resourceString);
|
||||||
std::vector<char> imgdata(file.begin(), file.end());
|
std::vector<char> imgdata(file.begin(), file.end());
|
||||||
QImage type_icon = QImage::fromData(imgdata).scaled(QSize(64, 64), Qt::KeepAspectRatio,
|
QImage type_icon = QImage::fromData(imgdata).scaled(QSize(64, 64), Qt::KeepAspectRatio,
|
||||||
|
@ -134,13 +134,17 @@ void SDLInputEngine::Init() {
|
|||||||
m_gyro_poll_rate = SDL_GetGamepadSensorDataRate(m_gamepad, SDL_SENSOR_GYRO);
|
m_gyro_poll_rate = SDL_GetGamepadSensorDataRate(m_gamepad, SDL_SENSOR_GYRO);
|
||||||
LOG_INFO(Input, "Gyro initialized, poll rate: {}", m_gyro_poll_rate);
|
LOG_INFO(Input, "Gyro initialized, poll rate: {}", m_gyro_poll_rate);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad");
|
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad, error: {}",
|
||||||
|
SDL_GetError());
|
||||||
|
SDL_SetGamepadSensorEnabled(m_gamepad, SDL_SENSOR_GYRO, false);
|
||||||
}
|
}
|
||||||
if (SDL_SetGamepadSensorEnabled(m_gamepad, SDL_SENSOR_ACCEL, true)) {
|
if (SDL_SetGamepadSensorEnabled(m_gamepad, SDL_SENSOR_ACCEL, true)) {
|
||||||
m_accel_poll_rate = SDL_GetGamepadSensorDataRate(m_gamepad, SDL_SENSOR_ACCEL);
|
m_accel_poll_rate = SDL_GetGamepadSensorDataRate(m_gamepad, SDL_SENSOR_ACCEL);
|
||||||
LOG_INFO(Input, "Accel initialized, poll rate: {}", m_accel_poll_rate);
|
LOG_INFO(Input, "Accel initialized, poll rate: {}", m_accel_poll_rate);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad");
|
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad, error: {}",
|
||||||
|
SDL_GetError());
|
||||||
|
SDL_SetGamepadSensorEnabled(m_gamepad, SDL_SENSOR_ACCEL, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
SDL_Gamepad* m_gamepad = nullptr;
|
SDL_Gamepad* m_gamepad = nullptr;
|
||||||
|
|
||||||
float m_gyro_poll_rate{};
|
float m_gyro_poll_rate = 0.0f;
|
||||||
float m_accel_poll_rate{};
|
float m_accel_poll_rate = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Input
|
} // namespace Input
|
||||||
|
@ -27,7 +27,7 @@ void Translator::EmitScalarAlu(const GcnInst& inst) {
|
|||||||
case Opcode::S_ADD_I32:
|
case Opcode::S_ADD_I32:
|
||||||
return S_ADD_I32(inst);
|
return S_ADD_I32(inst);
|
||||||
case Opcode::S_SUB_I32:
|
case Opcode::S_SUB_I32:
|
||||||
return S_SUB_U32(inst);
|
return S_SUB_I32(inst);
|
||||||
case Opcode::S_ADDC_U32:
|
case Opcode::S_ADDC_U32:
|
||||||
return S_ADDC_U32(inst);
|
return S_ADDC_U32(inst);
|
||||||
case Opcode::S_MIN_I32:
|
case Opcode::S_MIN_I32:
|
||||||
@ -216,24 +216,52 @@ void Translator::EmitSOPK(const GcnInst& inst) {
|
|||||||
void Translator::S_ADD_U32(const GcnInst& inst) {
|
void Translator::S_ADD_U32(const GcnInst& inst) {
|
||||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
SetDst(inst.dst[0], ir.IAdd(src0, src1));
|
const IR::U32 result{ir.IAdd(src0, src1)};
|
||||||
// TODO: Carry out
|
SetDst(inst.dst[0], result);
|
||||||
ir.SetScc(ir.Imm1(false));
|
|
||||||
|
// SCC = tmp >= 0x100000000ULL ? 1'1U : 1'0U;
|
||||||
|
// The above assumes tmp is a 64-bit value.
|
||||||
|
// It should be enough however to test that the truncated result is less than at least one
|
||||||
|
// of the operands. In unsigned addition the result is always bigger than both the operands,
|
||||||
|
// except in the case of overflow where the truncated result is less than both.
|
||||||
|
ir.SetScc(ir.ILessThan(result, src0, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::S_SUB_U32(const GcnInst& inst) {
|
void Translator::S_SUB_U32(const GcnInst& inst) {
|
||||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
SetDst(inst.dst[0], ir.ISub(src0, src1));
|
SetDst(inst.dst[0], ir.ISub(src0, src1));
|
||||||
// TODO: Carry out
|
|
||||||
ir.SetScc(ir.Imm1(false));
|
// SCC = S1.u > S0.u ? 1'1U : 1'0U;
|
||||||
|
ir.SetScc(ir.IGreaterThan(src1, src0, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::S_ADD_I32(const GcnInst& inst) {
|
void Translator::S_ADD_I32(const GcnInst& inst) {
|
||||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
SetDst(inst.dst[0], ir.IAdd(src0, src1));
|
const IR::U32 result{ir.IAdd(src0, src1)};
|
||||||
// TODO: Overflow flag
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
// SCC = ((S0.u[31] == S1.u[31]) && (S0.u[31] != Result.u[31]));
|
||||||
|
const IR::U32 shift{ir.Imm32(31)};
|
||||||
|
const IR::U32 sign0{ir.ShiftRightLogical(src0, shift)};
|
||||||
|
const IR::U32 sign1{ir.ShiftRightLogical(src1, shift)};
|
||||||
|
const IR::U32 signr{ir.ShiftRightLogical(result, shift)};
|
||||||
|
ir.SetScc(ir.LogicalAnd(ir.IEqual(sign0, sign1), ir.INotEqual(sign0, signr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Translator::S_SUB_I32(const GcnInst& inst) {
|
||||||
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
|
const IR::U32 result{ir.ISub(src0, src1)};
|
||||||
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
// SCC = ((S0.u[31] != S1.u[31]) && (S0.u[31] != tmp.u[31]));
|
||||||
|
const IR::U32 shift{ir.Imm32(31)};
|
||||||
|
const IR::U32 sign0{ir.ShiftRightLogical(src0, shift)};
|
||||||
|
const IR::U32 sign1{ir.ShiftRightLogical(src1, shift)};
|
||||||
|
const IR::U32 signr{ir.ShiftRightLogical(result, shift)};
|
||||||
|
ir.SetScc(ir.LogicalAnd(ir.INotEqual(sign0, sign1), ir.INotEqual(sign0, signr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::S_ADDC_U32(const GcnInst& inst) {
|
void Translator::S_ADDC_U32(const GcnInst& inst) {
|
||||||
|
@ -81,6 +81,7 @@ public:
|
|||||||
void S_ADD_U32(const GcnInst& inst);
|
void S_ADD_U32(const GcnInst& inst);
|
||||||
void S_SUB_U32(const GcnInst& inst);
|
void S_SUB_U32(const GcnInst& inst);
|
||||||
void S_ADD_I32(const GcnInst& inst);
|
void S_ADD_I32(const GcnInst& inst);
|
||||||
|
void S_SUB_I32(const GcnInst& inst);
|
||||||
void S_ADDC_U32(const GcnInst& inst);
|
void S_ADDC_U32(const GcnInst& inst);
|
||||||
void S_MIN_U32(bool is_signed, const GcnInst& inst);
|
void S_MIN_U32(bool is_signed, const GcnInst& inst);
|
||||||
void S_MAX_U32(bool is_signed, const GcnInst& inst);
|
void S_MAX_U32(bool is_signed, const GcnInst& inst);
|
||||||
|