mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
480a3fe171 | ||
|
|
b160eac49f | ||
|
|
37ba82b8b7 | ||
|
|
2d604145f1 | ||
|
|
d60a6df313 | ||
|
|
236d9e3028 | ||
|
|
175327e711 | ||
|
|
6342f99504 | ||
|
|
6164ae9f60 | ||
|
|
d2a5b70b2e | ||
|
|
b2be5dcb59 | ||
|
|
b67c03cc75 | ||
|
|
d613701780 | ||
|
|
4b62562fce | ||
|
|
6ffaca45da | ||
|
|
56fe0b32e6 | ||
|
|
f7c0d6af73 | ||
|
|
b625e2c47a | ||
|
|
97300d59a9 | ||
|
|
f45840a29f | ||
|
|
bfff6ed406 | ||
|
|
ad6f5fd6af |
4
.github/workflows/release_cut_new.yml
vendored
4
.github/workflows/release_cut_new.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
|
||||
|
||||
- name: Create a GitHub Release (Manual)
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
tag_name: ${{ steps.tag_version.outputs.new_tag }}
|
||||
|
||||
- name: Create a GitHub Release (Push)
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
|
||||
@@ -231,7 +231,7 @@ echo "Building PlutoVG..."
|
||||
rm -fr "plutovg-$PLUTOVG"
|
||||
tar xf "plutovg-$PLUTOVG.tar.gz"
|
||||
cd "plutovg-$PLUTOVG"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja
|
||||
cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -118,7 +118,7 @@ CPCS-01005:
|
||||
name-en: "Gun Survivor 4 - BioHazard - Heroes Never Die [with GunCon2]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Fixes character offset with flashlight and blurriness.
|
||||
halfPixelOffset: 5 # Fixes character offset with flashlight and blurriness. Fixes water lines.
|
||||
roundSprite: 2 # Fixes font artifacts.
|
||||
autoFlush: 1 # Fixes light bloom intensity.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
@@ -2081,7 +2081,7 @@ SCAJ-20139:
|
||||
name: "Zero - Shisei no Koe" # Fatal Frame - Rei - Irezumi no Sei
|
||||
region: "NTSC-Unk"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Reduces blurriness.
|
||||
halfPixelOffset: 4 # Reduces blurriness.
|
||||
SCAJ-20140:
|
||||
name: "Bleach - Erabareshi Tamashi"
|
||||
region: "NTSC-Unk"
|
||||
@@ -17320,7 +17320,7 @@ SLES-51448:
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Fixes character offset with flashlight and blurriness.
|
||||
halfPixelOffset: 5 # Fixes character offset with flashlight and blurriness. Fixes water lines.
|
||||
roundSprite: 2 # Fixes font artifacts.
|
||||
autoFlush: 1 # Fixes light bloom intensity.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
@@ -20903,11 +20903,10 @@ SLES-52877:
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Reduces blurriness. Normal Vertex works better, but causes some lights to disappear.
|
||||
roundSprite: 1 # Further reduces blurriness.
|
||||
halfPixelOffset: 5 # Reduces blurriness.
|
||||
bilinearUpscale: 1 # Smooths out fire textures.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
textureInsideRT: 1 # Fixes post effects.
|
||||
SLES-52882:
|
||||
name: "Stolen"
|
||||
region: "PAL-M5"
|
||||
@@ -23948,7 +23947,7 @@ SLES-53825:
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Reduces blurriness.
|
||||
halfPixelOffset: 4 # Reduces blurriness.
|
||||
SLES-53826:
|
||||
name: "Tom Clancy's Splinter Cell - Double Agent"
|
||||
region: "PAL-M5"
|
||||
@@ -30092,7 +30091,7 @@ SLKA-25038:
|
||||
name: "Gun Survivor 4 - BioHazard - Heroes Never Die"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Fixes character offset with flashlight and blurriness.
|
||||
halfPixelOffset: 5 # Fixes character offset with flashlight and blurriness. Fixes water lines.
|
||||
roundSprite: 2 # Fixes font artifacts.
|
||||
autoFlush: 1 # Fixes light bloom intensity.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
@@ -34587,7 +34586,7 @@ SLPM-61039:
|
||||
name-en: "BioHazard Gun Survivor 4 - Heroes Never Die [Store Demo]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Fixes character offset with flashlight and blurriness.
|
||||
halfPixelOffset: 5 # Fixes character offset with flashlight and blurriness. Fixes water lines.
|
||||
roundSprite: 2 # Fixes font artifacts.
|
||||
autoFlush: 1 # Fixes light bloom intensity.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
@@ -40729,7 +40728,7 @@ SLPM-65245:
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Fixes character offset with flashlight and blurriness.
|
||||
halfPixelOffset: 5 # Fixes character offset with flashlight and blurriness. Fixes water lines.
|
||||
roundSprite: 2 # Fixes font artifacts.
|
||||
autoFlush: 1 # Fixes light bloom intensity.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
@@ -44525,11 +44524,10 @@ SLPM-65913:
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Reduces blurriness. Normal Vertex works better, but causes some lights to disappear.
|
||||
roundSprite: 1 # Further reduces blurriness.
|
||||
halfPixelOffset: 5 # Reduces blurriness.
|
||||
bilinearUpscale: 1 # Smooths out fire textures.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
textureInsideRT: 1 # Fixes post effects.
|
||||
SLPM-65914:
|
||||
name: "NANA"
|
||||
name-sort: "ナナ"
|
||||
@@ -49059,11 +49057,10 @@ SLPM-66638:
|
||||
name-en: "Demento [CapColle]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Reduces blurriness. Normal Vertex works better, but causes some lights to disappear.
|
||||
roundSprite: 1 # Further reduces blurriness.
|
||||
halfPixelOffset: 5 # Reduces blurriness.
|
||||
bilinearUpscale: 1 # Smooths out fire textures.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
textureInsideRT: 1 # Fixes post effects.
|
||||
SLPM-66639:
|
||||
name: "ストリートファイターⅢ 3rd STRIKE Fight for the future [カプコレ]"
|
||||
name-sort: "すとりーとふぁいたー3 3rd STRIKE Fight for the future [かぷこれ]"
|
||||
@@ -58219,6 +58216,8 @@ SLPS-25544:
|
||||
name-en: "Fatal Frame III - The Tormented"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Reduces blurriness.
|
||||
SLPS-25545:
|
||||
name: "ファイティング フォー ワンピース"
|
||||
name-sort: "ふぁいてぃんぐ ふぉー わんぴーす"
|
||||
@@ -61443,6 +61442,8 @@ SLPS-73245:
|
||||
name-sort: "ぜろ しせいのこえ [PlayStation2 the Best]"
|
||||
name-en: "Fatal Frame III - The Tormented [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Reduces blurriness.
|
||||
SLPS-73246:
|
||||
name: "ガンダム トゥルーオデッセイ ~失われしGの伝説~ [PlayStation2 the Best]"
|
||||
name-sort: "がんだむ とぅるーおでっせい うしなわれしGのでんせつ [PlayStation2 the Best]"
|
||||
@@ -61554,7 +61555,7 @@ SLPS-73257:
|
||||
name-en: "Fatal Frame III - The Tormented [PlayStation 2 the Best - Reprint]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Reduces blurriness.
|
||||
halfPixelOffset: 4 # Reduces blurriness.
|
||||
SLPS-73258:
|
||||
name: "喧嘩番長2 ~フルスロットル~ [PlayStation2 the Best]"
|
||||
name-sort: "けんかばんちょう2 ふるすろっとる [PlayStation2 the Best]"
|
||||
@@ -64957,7 +64958,7 @@ SLUS-20669:
|
||||
gsHWFixes:
|
||||
PCRTCOverscan: 1 # Shows full image frame.
|
||||
PCRTCOffsets: 1 # Shows full image frame.
|
||||
halfPixelOffset: 4 # Fixes character offset with flashlight and blurriness.
|
||||
halfPixelOffset: 5 # Fixes character offset with flashlight and blurriness. Fixes water lines.
|
||||
roundSprite: 2 # Fixes font artifacts.
|
||||
autoFlush: 1 # Fixes light bloom intensity.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
@@ -67323,11 +67324,10 @@ SLUS-21075:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Reduces blurriness. Normal Vertex works better, but causes some lights to disappear.
|
||||
roundSprite: 1 # Further reduces blurriness.
|
||||
halfPixelOffset: 5 # Reduces blurriness.
|
||||
bilinearUpscale: 1 # Smooths out fire textures.
|
||||
nativeScaling: 2 # Fixes post processing.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
textureInsideRT: 1 # Fixes post effects.
|
||||
SLUS-21076:
|
||||
name: "Atari Anthology"
|
||||
region: "NTSC-U"
|
||||
@@ -68360,7 +68360,7 @@ SLUS-21244:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Reduces blurriness.
|
||||
halfPixelOffset: 4 # Reduces blurriness.
|
||||
SLUS-21245:
|
||||
name: "Suikoden Tactics"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -19,7 +19,7 @@ find_package(LZ4 REQUIRED)
|
||||
find_package(WebP REQUIRED) # v1.3.2, spews an error on Linux because no pkg-config.
|
||||
find_package(SDL3 3.2.6 REQUIRED)
|
||||
find_package(Freetype 2.11.1 REQUIRED)
|
||||
find_package(plutovg 0.0.13 REQUIRED)
|
||||
find_package(plutovg REQUIRED) # v0.0.13 is needed for building plutosvg, but we can support v1.0.0
|
||||
find_package(plutosvg 0.0.6 REQUIRED)
|
||||
|
||||
if(USE_VULKAN)
|
||||
|
||||
@@ -2819,7 +2819,7 @@ QString MainWindow::getDiscDevicePath(const QString& title)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MainWindow::startGameListEntry(const GameList::Entry* entry, std::optional<s32> save_slot, std::optional<bool> fast_boot)
|
||||
void MainWindow::startGameListEntry(const GameList::Entry* entry, std::optional<s32> save_slot, std::optional<bool> fast_boot, bool load_backup)
|
||||
{
|
||||
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>();
|
||||
params->fast_boot = fast_boot;
|
||||
@@ -2828,7 +2828,7 @@ void MainWindow::startGameListEntry(const GameList::Entry* entry, std::optional<
|
||||
|
||||
if (save_slot.has_value() && !entry->serial.empty())
|
||||
{
|
||||
std::string state_filename = VMManager::GetSaveStateFileName(entry->serial.c_str(), entry->crc, save_slot.value());
|
||||
std::string state_filename = VMManager::GetSaveStateFileName(entry->serial.c_str(), entry->crc, save_slot.value(), load_backup);
|
||||
if (!FileSystem::FileExists(state_filename.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("This save state does not exist."));
|
||||
@@ -2953,12 +2953,12 @@ std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_p
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void MainWindow::loadSaveStateSlot(s32 slot)
|
||||
void MainWindow::loadSaveStateSlot(s32 slot, bool load_backup)
|
||||
{
|
||||
if (s_vm_valid)
|
||||
{
|
||||
// easy when we're running
|
||||
g_emu_thread->loadStateFromSlot(slot);
|
||||
g_emu_thread->loadStateFromSlot(slot, load_backup);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -2968,7 +2968,7 @@ void MainWindow::loadSaveStateSlot(s32 slot)
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
startGameListEntry(entry, slot, std::nullopt);
|
||||
startGameListEntry(entry, slot, std::nullopt, load_backup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3015,15 +3015,6 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con
|
||||
|
||||
QAction* delete_save_states_action = menu->addAction(tr("Delete Save States..."));
|
||||
|
||||
// don't include undo in the right click menu
|
||||
if (!is_right_click_menu)
|
||||
{
|
||||
QAction* load_undo_state = menu->addAction(tr("Undo Load State"));
|
||||
load_undo_state->setEnabled(false); // CanUndoLoadState()
|
||||
// connect(load_undo_state, &QAction::triggered, this, &QtHostInterface::undoLoadState);
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
const QByteArray game_serial_utf8(serial.toUtf8());
|
||||
std::string state_filename;
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
@@ -3053,6 +3044,18 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con
|
||||
has_any_states = true;
|
||||
}
|
||||
|
||||
for (s32 i = 1; i <= VMManager::NUM_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
state_filename = VMManager::GetSaveStateFileName(game_serial_utf8.constData(), crc, i, true);
|
||||
if (!FileSystem::StatFile(state_filename.c_str(), &sd))
|
||||
continue;
|
||||
|
||||
action = menu->addAction(tr("Load Backup Slot %1 (%2)").arg(i).arg(formatTimestampForSaveStateMenu(sd.ModificationTime)));
|
||||
connect(action, &QAction::triggered, [this, i]() { loadSaveStateSlot(i, true); });
|
||||
has_any_states = true;
|
||||
}
|
||||
|
||||
delete_save_states_action->setEnabled(has_any_states);
|
||||
if (has_any_states)
|
||||
{
|
||||
|
||||
@@ -267,13 +267,13 @@ private:
|
||||
QString getDiscDevicePath(const QString& title);
|
||||
|
||||
void startGameListEntry(
|
||||
const GameList::Entry* entry, std::optional<s32> save_slot = std::nullopt, std::optional<bool> fast_boot = std::nullopt);
|
||||
const GameList::Entry* entry, std::optional<s32> save_slot = std::nullopt, std::optional<bool> fast_boot = std::nullopt, bool load_backup = false);
|
||||
void setGameListEntryCoverImage(const GameList::Entry* entry);
|
||||
void clearGameListEntryPlayTime(const GameList::Entry* entry);
|
||||
void goToWikiPage(const GameList::Entry* entry);
|
||||
|
||||
std::optional<bool> promptForResumeState(const QString& save_state_path);
|
||||
void loadSaveStateSlot(s32 slot);
|
||||
void loadSaveStateSlot(s32 slot, bool load_backup = false);
|
||||
void loadSaveStateFile(const QString& filename, const QString& state_filename);
|
||||
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
|
||||
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
|
||||
|
||||
@@ -320,18 +320,18 @@ void EmuThread::loadState(const QString& filename)
|
||||
VMManager::LoadState(filename.toUtf8().constData());
|
||||
}
|
||||
|
||||
void EmuThread::loadStateFromSlot(qint32 slot)
|
||||
void EmuThread::loadStateFromSlot(qint32 slot, bool load_backup)
|
||||
{
|
||||
if (!isOnEmuThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "loadStateFromSlot", Qt::QueuedConnection, Q_ARG(qint32, slot));
|
||||
QMetaObject::invokeMethod(this, "loadStateFromSlot", Qt::QueuedConnection, Q_ARG(qint32, slot), Q_ARG(bool, load_backup));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
VMManager::LoadStateFromSlot(slot);
|
||||
VMManager::LoadStateFromSlot(slot, load_backup);
|
||||
}
|
||||
|
||||
void EmuThread::saveState(const QString& filename)
|
||||
|
||||
@@ -87,7 +87,7 @@ public Q_SLOTS:
|
||||
void setVMPaused(bool paused);
|
||||
void shutdownVM(bool save_state = true);
|
||||
void loadState(const QString& filename);
|
||||
void loadStateFromSlot(qint32 slot);
|
||||
void loadStateFromSlot(qint32 slot, bool load_backup = false);
|
||||
void saveState(const QString& filename);
|
||||
void saveStateToSlot(qint32 slot);
|
||||
void toggleFullscreen();
|
||||
|
||||
@@ -117,21 +117,26 @@ void AchievementSettingsWidget::updateEnableState()
|
||||
m_ui.achievementNotificationsDurationLabel->setEnabled(notifications);
|
||||
m_ui.leaderboardNotificationsDuration->setEnabled(lb_notifications);
|
||||
m_ui.leaderboardNotificationsDurationLabel->setEnabled(lb_notifications);
|
||||
m_ui.notificationSoundPath->setEnabled(info);
|
||||
m_ui.notificationSoundBrowse->setEnabled(info);
|
||||
m_ui.notificationSoundOpen->setEnabled(info);
|
||||
m_ui.notificationSoundReset->setEnabled(info);
|
||||
m_ui.notificationSound->setEnabled(enabled);
|
||||
m_ui.unlockSoundPath->setEnabled(unlock);
|
||||
m_ui.unlockSoundBrowse->setEnabled(unlock);
|
||||
m_ui.unlockSoundOpen->setEnabled(unlock);
|
||||
m_ui.unlockSoundReset->setEnabled(unlock);
|
||||
m_ui.unlockSound->setEnabled(enabled);
|
||||
m_ui.lbSoundPath->setEnabled(lbsound);
|
||||
m_ui.lbSoundOpen->setEnabled(lbsound);
|
||||
m_ui.lbSoundBrowse->setEnabled(lbsound);
|
||||
m_ui.lbSoundReset->setEnabled(lbsound);
|
||||
m_ui.lbSound->setEnabled(enabled);
|
||||
|
||||
if (!m_dialog->isPerGameSettings())
|
||||
{
|
||||
m_ui.notificationSoundPath->setEnabled(info);
|
||||
m_ui.notificationSoundBrowse->setEnabled(info);
|
||||
m_ui.notificationSoundOpen->setEnabled(info);
|
||||
m_ui.notificationSoundReset->setEnabled(info);
|
||||
m_ui.notificationSound->setEnabled(enabled);
|
||||
m_ui.unlockSoundPath->setEnabled(unlock);
|
||||
m_ui.unlockSoundBrowse->setEnabled(unlock);
|
||||
m_ui.unlockSoundOpen->setEnabled(unlock);
|
||||
m_ui.unlockSoundReset->setEnabled(unlock);
|
||||
m_ui.unlockSound->setEnabled(enabled);
|
||||
m_ui.lbSoundPath->setEnabled(lbsound);
|
||||
m_ui.lbSoundOpen->setEnabled(lbsound);
|
||||
m_ui.lbSoundBrowse->setEnabled(lbsound);
|
||||
m_ui.lbSoundReset->setEnabled(lbsound);
|
||||
m_ui.lbSound->setEnabled(enabled);
|
||||
}
|
||||
|
||||
m_ui.soundEffects->setEnabled(enabled);
|
||||
m_ui.overlays->setEnabled(enabled);
|
||||
m_ui.encoreMode->setEnabled(enabled);
|
||||
|
||||
@@ -1240,13 +1240,8 @@ void GraphicsSettingsWidget::populateUpscaleMultipliers(u32 max_upscale_multipli
|
||||
{
|
||||
static constexpr std::pair<const char*, float> templates[] = {
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Native (PS2) (Default)"), 1.0f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1.25x Native (~450px)"), 1.25f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1.5x Native (~540px)"), 1.5f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1.75x Native (~630px)"), 1.75f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2x Native (~720px/HD)"), 2.0f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2.5x Native (~900px/HD+)"), 2.5f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "3x Native (~1080px/FHD)"), 3.0f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "3.5x Native (~1260px)"), 3.5f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "4x Native (~1440px/QHD)"), 4.0f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "5x Native (~1800px/QHD+)"), 5.0f},
|
||||
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "6x Native (~2160px/4K UHD)"), 6.0f},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,12 @@
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
[This file contains the template for the PCSX2 code rights license. For the full
|
||||
rant-like preamble of the GPL, see GPL.txt]
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2019 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -1200,75 +1200,6 @@ bool GSHwHack::OI_BurnoutGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GS
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSHwHack::OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
// Haunting Ground clears two targets by doing a direct colour write at 0x3000, covering a target at 0x3380.
|
||||
// To make matters worse, it's masked. This currently isn't handled in our HLE clears, so we need to manually
|
||||
// remove the other target.
|
||||
if (rt && !ds && !t && r.IsConstantDirectWriteMemClear())
|
||||
{
|
||||
GL_CACHE("GSHwHack::OI_HauntingGround()");
|
||||
|
||||
const u32 bp = RFBP;
|
||||
const u32 bw = RFBW;
|
||||
const u32 psm = RFPSM;
|
||||
const u32 fbmsk = RFBMSK;
|
||||
const GSVector4i rc = r.m_r;
|
||||
|
||||
for (int type = 0; type < 2; type++)
|
||||
{
|
||||
auto& list = g_texture_cache->m_dst[type];
|
||||
|
||||
for (auto i = list.begin(); i != list.end();)
|
||||
{
|
||||
GSTextureCache::Target* t = *i;
|
||||
auto ei = i++;
|
||||
|
||||
// There's two cases we hit here - when we clear 3380 via 3000, and when we overlap 3000 by writing to 3380.
|
||||
// The latter is actually only 256x224, which ends at 337F, but because the game's a pain in the ass, it
|
||||
// shuffles 512x512, causing the target to expand. It'd actually be shuffling junk and wasting draw cycles,
|
||||
// but when did that stop anyone? So, we can get away with just saying "if it's before, ignore".
|
||||
if (t->m_TEX0.TBP0 <= bp)
|
||||
{
|
||||
// don't remove ourself..
|
||||
continue;
|
||||
}
|
||||
|
||||
// Has to intersect.
|
||||
if (!t->Overlaps(bp, bw, psm, rc))
|
||||
continue;
|
||||
|
||||
// Another annoying case. Sometimes it clears with RGB masked, only writing to A. We don't want to kill the
|
||||
// target in this case, so we'll dirty A instead.
|
||||
if (fbmsk != 0)
|
||||
{
|
||||
GL_CACHE("OI_HauntingGround(%x, %u, %s, %d,%d => %d,%d): Dirty target at %x %u %s %08X", bp, bw,
|
||||
psm_str(psm), rc.x, rc.y, rc.z, rc.w, t->m_TEX0.TBP0, t->m_TEX0.TBW, psm_str(t->m_TEX0.PSM),
|
||||
fbmsk);
|
||||
|
||||
g_texture_cache->AddDirtyRectTarget(t, rc, psm, bw, RGBAMask{GSUtil::GetChannelMask(psm, fbmsk)});
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_CACHE("OI_HauntingGround(%x, %u, %s, %d,%d => %d,%d): Removing target at %x %u %s", bp, bw,
|
||||
psm_str(psm), rc.x, rc.y, rc.z, rc.w, t->m_TEX0.TBP0, t->m_TEX0.TBW, psm_str(t->m_TEX0.PSM));
|
||||
|
||||
// Need to also remove any sources which reference this target.
|
||||
g_texture_cache->InvalidateSourcesFromTarget(t);
|
||||
|
||||
list.erase(ei);
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_texture_cache->InvalidateVideoMemType(GSTextureCache::DepthStencil, bp);
|
||||
}
|
||||
|
||||
// Not skipping anything. This is just an invalidation hack.
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef RPRIM
|
||||
#undef RCONTEXT
|
||||
|
||||
@@ -1519,7 +1450,6 @@ const GSHwHack::Entry<GSRendererHW::OI_Ptr> GSHwHack::s_before_draw_functions[]
|
||||
CRC_F(OI_SonicUnleashed),
|
||||
CRC_F(OI_ArTonelico2),
|
||||
CRC_F(OI_BurnoutGames),
|
||||
CRC_F(OI_HauntingGround),
|
||||
};
|
||||
|
||||
const GSHwHack::Entry<GSRendererHW::MV_Ptr> GSHwHack::s_move_handler_functions[] = {
|
||||
|
||||
@@ -37,7 +37,6 @@ public:
|
||||
static bool OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_ArTonelico2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_BurnoutGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
static bool MV_Growlanser(GSRendererHW& r);
|
||||
static bool MV_Ico(GSRendererHW& r);
|
||||
|
||||
@@ -3358,6 +3358,15 @@ void GSRendererHW::Draw()
|
||||
|
||||
if (ds->m_TEX0.TBP0 != z_address_info.ZBP || z_address_info.offset != static_cast<u32>(vertical_offset - z_vertical_offset))
|
||||
g_texture_cache->InvalidateTemporaryZ();
|
||||
else if (!m_r.rintersect(z_address_info.rect_since + GSVector4i(0, z_address_info.offset, 0, z_address_info.offset)).rempty() && m_cached_ctx.TEST.ZTST > ZTST_ALWAYS)
|
||||
{
|
||||
GL_CACHE("RT in RT Updating Z copy on draw %d z_offset %d", s_n, z_address_info.offset);
|
||||
GSVector4i dRect = GSVector4i(z_address_info.rect_since.x * ds->m_scale, (z_address_info.offset + z_address_info.rect_since.y) * ds->m_scale, (z_address_info.rect_since.z + (1.0f / ds->m_scale)) * ds->m_scale, (z_address_info.offset + z_address_info.rect_since.w + (1.0f / ds->m_scale)) * ds->m_scale);
|
||||
g_gs_device->StretchRect(ds->m_texture, GSVector4(z_address_info.rect_since.x / static_cast<float>(ds->m_unscaled_size.x), z_address_info.rect_since.y / static_cast<float>(ds->m_unscaled_size.y), (z_address_info.rect_since.z + (1.0f / ds->m_scale)) / static_cast<float>(ds->m_unscaled_size.x), (z_address_info.rect_since.w + (1.0f / ds->m_scale)) / static_cast<float>(ds->m_unscaled_size.y)), g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
z_address_info.rect_since = GSVector4i::zero();
|
||||
g_texture_cache->SetTemporaryZInfo(z_address_info);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_texture_cache->GetTemporaryZ() == nullptr)
|
||||
@@ -4267,10 +4276,11 @@ void GSRendererHW::Draw()
|
||||
GSTextureCache::TempZAddress z_address_info = g_texture_cache->GetTemporaryZInfo();
|
||||
if (ds->m_TEX0.TBP0 == z_address_info.ZBP)
|
||||
{
|
||||
GL_CACHE("RT in RT Updating Z copy on draw %d z_offset %d", s_n, z_address_info.offset);
|
||||
GSVector4i dRect = GSVector4i(real_rect.x * ds->m_scale, (z_address_info.offset + real_rect.y) * ds->m_scale, (real_rect.z + (1.0f / ds->m_scale)) * ds->m_scale, (z_address_info.offset + real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale);
|
||||
g_gs_device->StretchRect(ds->m_texture, GSVector4(real_rect.x / static_cast<float>(ds->m_unscaled_size.x), real_rect.y / static_cast<float>(ds->m_unscaled_size.y), (real_rect.z + (1.0f / ds->m_scale)) / static_cast<float>(ds->m_unscaled_size.x), (real_rect.w + (1.0f / ds->m_scale)) / static_cast<float>(ds->m_unscaled_size.y)), g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
if (z_address_info.rect_since.rempty())
|
||||
z_address_info.rect_since = real_rect;
|
||||
else
|
||||
z_address_info.rect_since = z_address_info.rect_since.runion(real_rect);
|
||||
g_texture_cache->SetTemporaryZInfo(z_address_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6401,8 +6411,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
}
|
||||
}
|
||||
|
||||
copy_range.z = std::min(copy_range.z, copy_size.x);
|
||||
copy_range.w = std::min(copy_range.w, copy_size.y);
|
||||
copy_range.z = std::min(copy_range.z, src_target->m_unscaled_size.x);
|
||||
copy_range.w = std::min(copy_range.w, src_target->m_unscaled_size.y);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1637,7 +1637,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) ||
|
||||
(t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y))))
|
||||
{
|
||||
DevCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
}
|
||||
// Keep note that 2 bw is basically 1 normal page, as bw is in 64 pixels, and 8bit pages are 128 pixels wide, aka 2 bw.
|
||||
@@ -1646,12 +1646,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
(!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y && ((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
|
||||
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))
|
||||
{
|
||||
DevCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
}
|
||||
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].bpp <= 8 && TEX0.TBW == 1)
|
||||
{
|
||||
DevCon.Warning("Too small for relocation, skipping");
|
||||
DbgCon.Warning("Too small for relocation, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1683,7 +1683,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
{
|
||||
if (!region.HasEither() && GSLocalMemory::m_psm[psm].bpp == 32 && (t->m_TEX0.TBW - (((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw)) < static_cast<u32>((block_boundary_rect.width() + 63) / 64))
|
||||
{
|
||||
DevCon.Warning("Bad alignmenet");
|
||||
DbgCon.Warning("Bad alignmenet");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2259,6 +2259,15 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
{
|
||||
const GSLocalMemory::psm_t& s_psm = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
|
||||
// If it overlaps but the target is huge and the Z isn't offset, we need to split the buffer, so let's shrink this one down.
|
||||
// 896 is just 448 * 2,just gives the buffer chance to be larger than normal, in case they do something like 640x640, or something ridiculous.
|
||||
if (!is_shuffle && (ds && offset == 0 && (t->m_valid.w >= 896) && ((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) <= bp))
|
||||
{
|
||||
t->m_valid.w /= 2;
|
||||
t->m_end_block = ((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// I know what you're thinking, and I hate the guy who wrote it too (me). Project Snowblind, Tomb Raider etc decide to offset where they're drawing using a channel shuffle, and this gets messy, so best just to kill the old target.
|
||||
if (is_shuffle && src && src->m_TEX0.PSM == PSMT8 && GSRendererHW::GetInstance()->m_context->FRAME.FBW == 1 && t->m_last_draw != (GSState::s_n - 1) && src->m_from_target && (src->m_from_target->m_TEX0.TBP0 == src->m_TEX0.TBP0 || (((src->m_TEX0.TBP0 - src->m_from_target->m_TEX0.TBP0) >> 5) % std::max(src->m_from_target->m_TEX0.TBW, 1U) == 0)) && widthpage_offset && src->m_from_target != t)
|
||||
{
|
||||
@@ -2729,7 +2738,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
t->m_texture = nullptr;
|
||||
}
|
||||
|
||||
DevCon.Warning("Deleting Z draw %d", GSState::s_n);
|
||||
GL_CACHE("Deleting Z draw %d", GSState::s_n);
|
||||
InvalidateSourcesFromTarget(t);
|
||||
i = rev_list.erase(i);
|
||||
delete t;
|
||||
@@ -3060,7 +3069,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
|
||||
dst->UpdateValidity(GSVector4i::loadh(valid_size));
|
||||
|
||||
if (!is_frame && !preload && !(src && src->m_TEX0.TBP0 == dst->m_TEX0.TBP0))
|
||||
if (!is_frame && !preload/* && !(src && src->m_TEX0.TBP0 == dst->m_TEX0.TBP0)*/)
|
||||
{
|
||||
if ((preserve_target || !draw_rect.eq(GSVector4i::loadh(valid_size))) && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0)
|
||||
{
|
||||
@@ -4277,13 +4286,18 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
|
||||
|
||||
const GSVector4i draw_rect = (t->readbacks_since_draw > 1) ? t->m_drawn_since_read : targetr.rintersect(t->m_drawn_since_read);
|
||||
const GSVector4i dirty_rect = t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size);
|
||||
|
||||
// Getaway (J) stores a Z texture at 0x2800 which it uses and the next frame it stores the reflection map in
|
||||
// 0x2800, so this will misdetect. So if it's not expecting a Z, check for RT's too.
|
||||
z_found = read_start >= t->m_TEX0.TBP0 && read_end <= t->m_end_block && GSLocalMemory::m_psm[psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth;
|
||||
|
||||
// Recently made this section dirty, no need to read it.
|
||||
if (draw_rect.rintersect(dirty_rect).eq(draw_rect))
|
||||
if (z_found && draw_rect.rintersect(dirty_rect).eq(draw_rect))
|
||||
return;
|
||||
|
||||
if (t->m_drawn_since_read.eq(GSVector4i::zero()))
|
||||
{
|
||||
if (draw_rect.rintersect(t->m_valid).eq(draw_rect))
|
||||
if (z_found && draw_rect.rintersect(t->m_valid).eq(draw_rect))
|
||||
return;
|
||||
else
|
||||
continue;
|
||||
@@ -4297,10 +4311,6 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
|
||||
|
||||
Read(t, draw_rect);
|
||||
|
||||
// Getaway (J) stores a Z texture at 0x2800 which it uses and the next frame it stores the reflection map in
|
||||
// 0x2800, so this will misdetect. So if it's not expecting a Z, check for RT's too.
|
||||
z_found = read_start >= t->m_TEX0.TBP0 && read_end <= t->m_end_block && GSLocalMemory::m_psm[psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth;
|
||||
|
||||
if (draw_rect.rintersect(t->m_drawn_since_read).eq(t->m_drawn_since_read))
|
||||
t->m_drawn_since_read = GSVector4i::zero();
|
||||
}
|
||||
@@ -7758,6 +7768,11 @@ void GSTextureCache::SetTemporaryZInfo(u32 address, u32 offset)
|
||||
{
|
||||
m_temporary_z_info.ZBP = address;
|
||||
m_temporary_z_info.offset = offset;
|
||||
m_temporary_z_info.rect_since = GSVector4i::zero();
|
||||
}
|
||||
void GSTextureCache::SetTemporaryZInfo(TempZAddress address_info)
|
||||
{
|
||||
m_temporary_z_info = address_info;
|
||||
}
|
||||
|
||||
void GSTextureCache::SetTemporaryZ(GSTexture* temp_z)
|
||||
|
||||
@@ -210,6 +210,7 @@ public:
|
||||
{
|
||||
u32 ZBP;
|
||||
u32 offset;
|
||||
GSVector4i rect_since;
|
||||
};
|
||||
|
||||
class Target : public Surface
|
||||
@@ -564,6 +565,7 @@ public:
|
||||
GSTexture* GetTemporaryZ();
|
||||
TempZAddress GetTemporaryZInfo();
|
||||
void SetTemporaryZInfo(u32 address, u32 offset);
|
||||
void SetTemporaryZInfo(TempZAddress address_info);
|
||||
/// Invalidates a temporary Z, a partial copy only created from the current DS for the current draw when Z is not offset but RT is.
|
||||
void InvalidateTemporaryZ();
|
||||
|
||||
|
||||
@@ -244,6 +244,11 @@ DEFINE_HOTKEY("LoadStateFromSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
SaveStateSelectorUI::LoadCurrentSlot();
|
||||
})
|
||||
DEFINE_HOTKEY("LoadBackupStateFromSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Load Backup State From Selected Slot"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
SaveStateSelectorUI::LoadCurrentBackupSlot();
|
||||
})
|
||||
DEFINE_HOTKEY("SaveStateAndSelectNextSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Save State and Select Next Slot"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
|
||||
@@ -242,7 +242,6 @@ namespace FullscreenUI
|
||||
static void ApplyLayoutSettings(const SettingsInterface* bsi = nullptr);
|
||||
|
||||
void DrawSvgTexture(GSTexture* padded_texture, ImVec2 unpadded_size);
|
||||
void DrawSvgTexture_UV(GSTexture* padded_texture, ImVec2 unpadded_size, ImVec2 unpadded_uv0, ImVec2 unpadded_uv1);
|
||||
void DrawCachedSvgTexture(const std::string& path, ImVec2 size, SvgScaling mode);
|
||||
void DrawCachedSvgTextureAsync(const std::string& path, ImVec2 size, SvgScaling mode);
|
||||
|
||||
@@ -446,7 +445,7 @@ namespace FullscreenUI
|
||||
|
||||
static void InitializePlaceholderSaveStateListEntry(SaveStateListEntry* li, s32 slot);
|
||||
static bool InitializeSaveStateListEntry(
|
||||
SaveStateListEntry* li, const std::string& title, const std::string& serial, u32 crc, s32 slot);
|
||||
SaveStateListEntry* li, const std::string& title, const std::string& serial, u32 crc, s32 slot, bool backup = false);
|
||||
static void ClearSaveStateEntryList();
|
||||
static u32 PopulateSaveStateListEntries(const std::string& title, const std::string& serial, u32 crc);
|
||||
static bool OpenLoadStateSelectorForGame(const std::string& game_path);
|
||||
@@ -3931,13 +3930,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
||||
};
|
||||
static const char* s_resolution_options[] = {
|
||||
FSUI_NSTR("Native (PS2)"),
|
||||
FSUI_NSTR("1.25x Native (~450px)"),
|
||||
FSUI_NSTR("1.5x Native (~540px)"),
|
||||
FSUI_NSTR("1.75x Native (~630px)"),
|
||||
FSUI_NSTR("2x Native (~720px/HD)"),
|
||||
FSUI_NSTR("2.5x Native (~900px/HD+)"),
|
||||
FSUI_NSTR("3x Native (~1080px/FHD)"),
|
||||
FSUI_NSTR("3.5x Native (~1260px)"),
|
||||
FSUI_NSTR("4x Native (~1440px/QHD)"),
|
||||
FSUI_NSTR("5x Native (~1800px/QHD+)"),
|
||||
FSUI_NSTR("6x Native (~2160px/4K UHD)"),
|
||||
@@ -3950,13 +3944,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
||||
};
|
||||
static const char* s_resolution_values[] = {
|
||||
"1",
|
||||
"1.25",
|
||||
"1.5",
|
||||
"1.75",
|
||||
"2",
|
||||
"2.5",
|
||||
"3",
|
||||
"3.5",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
@@ -5671,9 +5660,9 @@ void FullscreenUI::InitializePlaceholderSaveStateListEntry(SaveStateListEntry* l
|
||||
}
|
||||
|
||||
bool FullscreenUI::InitializeSaveStateListEntry(
|
||||
SaveStateListEntry* li, const std::string& title, const std::string& serial, u32 crc, s32 slot)
|
||||
SaveStateListEntry* li, const std::string& title, const std::string& serial, u32 crc, s32 slot, bool backup)
|
||||
{
|
||||
std::string filename(VMManager::GetSaveStateFileName(serial.c_str(), crc, slot));
|
||||
std::string filename(VMManager::GetSaveStateFileName(serial.c_str(), crc, slot, backup));
|
||||
FILESYSTEM_STAT_DATA sd;
|
||||
if (filename.empty() || !FileSystem::StatFile(filename.c_str(), &sd))
|
||||
{
|
||||
@@ -5681,7 +5670,7 @@ bool FullscreenUI::InitializeSaveStateListEntry(
|
||||
return false;
|
||||
}
|
||||
|
||||
li->title = fmt::format("{}##game_slot_{}", TinyString::from_format(FSUI_FSTR("Save Slot {0}"), slot), slot);
|
||||
li->title = fmt::format("{}##game_slot_{}", TinyString::from_format(FSUI_FSTR("{0} Slot {1}"), backup ? "Backup Save" : "Save", slot), slot);
|
||||
li->summary = fmt::format(FSUI_FSTR("Saved {}"), TimeToPrintableString(sd.ModificationTime));
|
||||
li->slot = slot;
|
||||
li->timestamp = sd.ModificationTime;
|
||||
@@ -5726,6 +5715,10 @@ u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& title, const s
|
||||
SaveStateListEntry li;
|
||||
if (InitializeSaveStateListEntry(&li, title, serial, crc, i) || !s_save_state_selector_loading)
|
||||
s_save_state_selector_slots.push_back(std::move(li));
|
||||
|
||||
SaveStateListEntry bli;
|
||||
if (InitializeSaveStateListEntry(&bli, title, serial, crc, i, true) || !s_save_state_selector_loading)
|
||||
s_save_state_selector_slots.push_back(std::move(bli));
|
||||
}
|
||||
|
||||
return static_cast<u32>(s_save_state_selector_slots.size());
|
||||
@@ -7854,6 +7847,7 @@ TRANSLATE_NOOP("FullscreenUI", "{} unlabelled patch codes found but not enabled.
|
||||
TRANSLATE_NOOP("FullscreenUI", "This Session: {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "All Time: {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Save Slot {0}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "{0} Slot {1}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Saved {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "{} does not exist.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "{} deleted.");
|
||||
@@ -7950,13 +7944,8 @@ TRANSLATE_NOOP("FullscreenUI", "Blend (Bottom Field First, Half FPS)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Adaptive (Top Field First)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Adaptive (Bottom Field First)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Native (PS2)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "1.25x Native (~450px)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "1.5x Native (~540px)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "1.75x Native (~630px)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "2x Native (~720px/HD)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "2.5x Native (~900px/HD+)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "3x Native (~1080px/FHD)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "3.5x Native (~1260px)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "4x Native (~1440px/QHD)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "5x Native (~1800px/QHD+)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "6x Native (~2160px/4K UHD)");
|
||||
|
||||
@@ -671,7 +671,7 @@ ImRect ImGuiFullscreen::CenterImage(const ImVec2& fit_size, const ImVec2& image_
|
||||
|
||||
ImRect ImGuiFullscreen::CenterImage(const ImRect& fit_rect, const ImVec2& image_size, bool fill)
|
||||
{
|
||||
ImRect ret(CenterImage(fit_rect.Max - fit_rect.Min, image_size));
|
||||
ImRect ret(CenterImage(fit_rect.Max - fit_rect.Min, image_size, fill));
|
||||
ret.Translate(fit_rect.Min);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1107,6 +1107,14 @@ void SaveStateSelectorUI::LoadCurrentSlot()
|
||||
Close();
|
||||
}
|
||||
|
||||
void SaveStateSelectorUI::LoadCurrentBackupSlot()
|
||||
{
|
||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||
VMManager::LoadStateFromSlot(slot, true);
|
||||
});
|
||||
Close();
|
||||
}
|
||||
|
||||
void SaveStateSelectorUI::SaveCurrentSlot()
|
||||
{
|
||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace SaveStateSelectorUI
|
||||
|
||||
s32 GetCurrentSlot();
|
||||
void LoadCurrentSlot();
|
||||
void LoadCurrentBackupSlot();
|
||||
void SaveCurrentSlot();
|
||||
} // namespace SaveStateSelectorUI
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace VMManager
|
||||
static bool HasValidOrInitializingVM();
|
||||
static void PrecacheCDVDFile();
|
||||
|
||||
static std::string GetCurrentSaveStateFileName(s32 slot);
|
||||
static std::string GetCurrentSaveStateFileName(s32 slot, bool backup = false);
|
||||
static bool DoLoadState(const char* filename);
|
||||
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
|
||||
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||
@@ -1762,13 +1762,15 @@ bool SaveStateBase::vmFreeze()
|
||||
return IsOkay();
|
||||
}
|
||||
|
||||
std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot)
|
||||
std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot, bool backup)
|
||||
{
|
||||
std::string filename;
|
||||
if (std::strlen(game_serial) > 0)
|
||||
{
|
||||
if (slot < 0)
|
||||
filename = fmt::format("{} ({:08X}).resume.p2s", game_serial, game_crc);
|
||||
else if (backup)
|
||||
filename = fmt::format("{} ({:08X}).{:02d}.p2s.backup", game_serial, game_crc, slot);
|
||||
else
|
||||
filename = fmt::format("{} ({:08X}).{:02d}.p2s", game_serial, game_crc, slot);
|
||||
|
||||
@@ -1778,7 +1780,7 @@ std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_cr
|
||||
return filename;
|
||||
}
|
||||
|
||||
std::string VMManager::GetSaveStateFileName(const char* filename, s32 slot)
|
||||
std::string VMManager::GetSaveStateFileName(const char* filename, s32 slot, bool backup)
|
||||
{
|
||||
pxAssertRel(!HasValidVM(), "Should not have a VM when calling the non-gamelist GetSaveStateFileName()");
|
||||
|
||||
@@ -1786,7 +1788,7 @@ std::string VMManager::GetSaveStateFileName(const char* filename, s32 slot)
|
||||
std::string serial;
|
||||
u32 crc;
|
||||
if (GameList::GetSerialAndCRCForFilename(filename, &serial, &crc))
|
||||
ret = GetSaveStateFileName(serial.c_str(), crc, slot);
|
||||
ret = GetSaveStateFileName(serial.c_str(), crc, slot, backup);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1797,10 +1799,10 @@ bool VMManager::HasSaveStateInSlot(const char* game_serial, u32 game_crc, s32 sl
|
||||
return (!filename.empty() && FileSystem::FileExists(filename.c_str()));
|
||||
}
|
||||
|
||||
std::string VMManager::GetCurrentSaveStateFileName(s32 slot)
|
||||
std::string VMManager::GetCurrentSaveStateFileName(s32 slot, bool backup)
|
||||
{
|
||||
std::unique_lock lock(s_info_mutex);
|
||||
return GetSaveStateFileName(s_disc_serial.c_str(), s_disc_crc, slot);
|
||||
return GetSaveStateFileName(s_disc_serial.c_str(), s_disc_crc, slot, backup);
|
||||
}
|
||||
|
||||
bool VMManager::DoLoadState(const char* filename)
|
||||
@@ -1840,7 +1842,7 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
||||
if (!elist)
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save save state: {}."), error.GetDescription()),
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state: {}."), error.GetDescription()),
|
||||
Host::OSD_ERROR_DURATION);
|
||||
return false;
|
||||
}
|
||||
@@ -1895,7 +1897,7 @@ void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||
else
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save save state to slot {}."), slot_for_message,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state to slot {}."), slot_for_message,
|
||||
Host::OSD_ERROR_DURATION));
|
||||
}
|
||||
|
||||
@@ -1987,13 +1989,13 @@ bool VMManager::LoadState(const char* filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VMManager::LoadStateFromSlot(s32 slot)
|
||||
bool VMManager::LoadStateFromSlot(s32 slot, bool backup)
|
||||
{
|
||||
const std::string filename = GetCurrentSaveStateFileName(slot);
|
||||
const std::string filename = GetCurrentSaveStateFileName(slot, backup);
|
||||
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "There is no save state in slot {}."), slot),
|
||||
fmt::format(TRANSLATE_FS("VMManager", "There is no saved {} in slot {}."), backup ? TRANSLATE("VMManager", "backup state") : "state", slot),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
return false;
|
||||
}
|
||||
@@ -2011,13 +2013,13 @@ bool VMManager::LoadStateFromSlot(s32 slot)
|
||||
if (MemcardBusy::IsBusy())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to load state from slot {} (Memory card is busy)"), slot),
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to load {} from slot {} (Memory card is busy)"), backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Loading state from slot {}..."), slot), Host::OSD_QUICK_DURATION);
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Loading {} from slot {}..."), backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot), Host::OSD_QUICK_DURATION);
|
||||
return DoLoadState(filename.c_str());
|
||||
}
|
||||
|
||||
@@ -2594,7 +2596,7 @@ void VMManager::ShutdownCPUProviders()
|
||||
#else
|
||||
// See the comment in the InitializeCPUProviders for an explaination why we
|
||||
// still need to manage the MTVU thread.
|
||||
if(vu1Thread.IsOpen())
|
||||
if (vu1Thread.IsOpen())
|
||||
vu1Thread.WaitVU();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -118,10 +118,10 @@ namespace VMManager
|
||||
void ReloadInputBindings(bool force = false);
|
||||
|
||||
/// Returns the save state filename for the given game serial/crc.
|
||||
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);
|
||||
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot, bool backup = false);
|
||||
|
||||
/// Returns the path to save state for the specified disc/elf.
|
||||
std::string GetSaveStateFileName(const char* filename, s32 slot);
|
||||
std::string GetSaveStateFileName(const char* filename, s32 slot, bool backup = false);
|
||||
|
||||
/// Returns true if there is a save state in the specified slot.
|
||||
bool HasSaveStateInSlot(const char* game_serial, u32 game_crc, s32 slot);
|
||||
@@ -130,7 +130,7 @@ namespace VMManager
|
||||
bool LoadState(const char* filename);
|
||||
|
||||
/// Loads state from the specified slot.
|
||||
bool LoadStateFromSlot(s32 slot);
|
||||
bool LoadStateFromSlot(s32 slot, bool backup = false);
|
||||
|
||||
/// Saves state to the specified filename.
|
||||
bool SaveState(const char* filename, bool zip_on_thread = true, bool backup_old_state = false);
|
||||
|
||||
Reference in New Issue
Block a user