This commit is contained in:
Nayla Hanegan 2024-11-04 10:59:00 -05:00
commit 76c08d3a22
119 changed files with 47784 additions and 40258 deletions

View file

@ -672,7 +672,7 @@ dolphin_make_imported_target_if_missing(LibLZMA::LibLZMA LIBLZMA)
dolphin_find_optional_system_library_pkgconfig(ZSTD libzstd>=1.4.0 zstd::zstd Externals/zstd)
dolphin_find_optional_system_library_pkgconfig(ZLIB zlib-ng ZLIB::ZLIB Externals/zlib-ng)
add_subdirectory(Externals/zlib-ng)
dolphin_find_optional_system_library_pkgconfig(MINIZIP
"minizip>=4.0.4" minizip::minizip Externals/minizip-ng

View file

@ -1,4 +1,4 @@
# GEDE01, GEDP01 - Eternal Darkness
# GEDE01, GEDP01, GEDJ01, GEDW01 - Eternal Darkness
[Core]
# Values set here will override the main Dolphin settings.

View file

@ -0,0 +1,8 @@
# GEDE01 - Eternal Darkness
[OnFrame]
$Fix startup hang
0x801EF444:dword:0x480371ED
[OnFrame_Enabled]
$Fix startup hang

View file

@ -0,0 +1,8 @@
# GEDJ01 - Eternal Darkness
[OnFrame]
$Fix startup hang
0x801E4588:dword:0x48036E71
[OnFrame_Enabled]
$Fix startup hang

View file

@ -0,0 +1,8 @@
# GEDP01 - Eternal Darkness
[OnFrame]
$Fix startup hang
0x801E3BC4:dword:0x48036F15
[OnFrame_Enabled]
$Fix startup hang

View file

@ -0,0 +1,8 @@
# GEDW01 - Eternal Darkness
[OnFrame]
$Fix startup hang
0x801BE42C:dword:0x48036E65
[OnFrame_Enabled]
$Fix startup hang

View file

@ -9,8 +9,5 @@
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
[Video_Hacks]
EFBAccessEnable = False
ImmediateXFBEnable = False

View file

@ -1,14 +0,0 @@
# GXBE69, GXBP69 - SSX3
[Core]
# Values set here will override the main Dolphin settings.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Hacks]
EFBAccessEnable = False

View file

@ -16,6 +16,3 @@ $Disable blur
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBAccessEnable = False

View file

@ -1,14 +0,0 @@
# SNCE8P, SNCJ8P, SNCP8P - SONIC COLOURS
[Core]
# Values set here will override the main Dolphin settings.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Hacks]
EFBAccessEnable = False

22
Flatpak/SDL2/SDL2.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": "SDL2",
"buildsystem": "autotools",
"config-opts": ["--disable-static"],
"sources": [
{
"type": "dir",
"path": "../../Externals/SDL/SDL"
}
],
"cleanup": [ "/bin/sdl2-config",
"/include",
"/lib/libSDL2.la",
"/lib/libSDL2main.a",
"/lib/libSDL2main.la",
"/lib/libSDL2_test.a",
"/lib/libSDL2_test.la",
"/lib/cmake",
"/share/aclocal",
"/lib/pkgconfig"]
}

8
Flatpak/fill_release_node.sh Executable file
View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
DATE=$(git log -1 --pretty=%cd --date=iso8601 --date=format:'%Y-%m-%d')
sed -i -e "s/@DATE_PLACEHOLDER/${DATE}/" org.DolphinEmu.dolphin-emu.metainfo.xml
VERSION=$(git describe --tags | sed -E 's/^([0-9]+-[0-9]+).*/\1/')
sed -i -e "s/@VERSION_PLACEHOLDER/${VERSION}/" org.DolphinEmu.dolphin-emu.metainfo.xml

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2016 Jeremy Newton -->
<component type="desktop-application">
<id>org.DolphinEmu.dolphin-emu</id>
<name>Dolphin Emulator</name>
<developer id="org.dolphin-emu">
<name>Dolphin Emulator Project</name>
</developer>
<summary>GameCube / Wii</summary>
<metadata_license>CC-BY-SA-3.0</metadata_license>
<project_license>GPL-2.0+</project_license>
<content_rating type="oars-1.0"/>
<!-- Descriptions taken from Dolphin Homepage -->
<description><p>Dolphin is an emulator for two recent Nintendo video game consoles: the GameCube and the Wii. It allows PC gamers to enjoy games for these two consoles in full HD (1080p) with several enhancements: compatibility with all PC controllers, turbo speed, networked multiplayer, and even more!</p></description>
<screenshots>
<screenshot type="default">
<caption>Dolphin's main window</caption>
<image type="source">http://dolphin-emu.org/m/user/flatpak/screenshot_1.png</image>
</screenshot>
<screenshot>
<caption>In-game</caption>
<image type="source">http://dolphin-emu.org/m/user/flatpak/screenshot_2.png</image>
</screenshot>
<screenshot>
<caption>Graphics configuration</caption>
<image type="source">http://dolphin-emu.org/m/user/flatpak/screenshot_3.png</image>
</screenshot>
<screenshot>
<caption>Controller configuration</caption>
<image type="source">http://dolphin-emu.org/m/user/flatpak/screenshot_4.png</image>
</screenshot>
</screenshots>
<launchable type="desktop-id">dolphin-emu.desktop</launchable>
<provides>
<binary>dolphin-emu</binary>
<id>dolphin-emu.desktop</id>
</provides>
<releases>
<release version="@VERSION_PLACEHOLDER" date="@DATE_PLACEHOLDER"/>
</releases>
<url type="homepage">https://dolphin-emu.org</url>
<url type="bugtracker">https://bugs.dolphin-emu.org/projects/emulator/issues</url>
<url type="faq">https://dolphin-emu.org/docs/faq/</url>
<url type="help">https://dolphin-emu.org/docs/guides/</url>
<url type="translate">https://www.transifex.com/projects/p/dolphin-emu</url>
<url type="contact">https://dolphin-emu.org/docs/faq/#ive-got-idea-make-dolphin-better-how-should-i-tell</url>
<url type="vcs-browser">https://github.com/dolphin-emu/dolphin</url>
<url type="contribute">https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md</url>
</component>

View file

@ -0,0 +1,83 @@
app-id: org.DolphinEmu.dolphin-emu
runtime: org.kde.Platform
runtime-version: '6.7'
sdk: org.kde.Sdk
command: dolphin-emu-wrapper
rename-desktop-file: dolphin-emu.desktop
rename-icon: dolphin-emu
finish-args:
- --device=all
- --socket=pulseaudio
# dolphin doesn't work on wayland (only the ui does), if a user were to set
# this env variable globally to wayland then games wouldn't work.
# we overwrite the setting and force xcb to prevent this from happening.
- --env=QT_QPA_PLATFORM=xcb
- --socket=x11
- --share=network
- --share=ipc
# required for the emulated bluetooth adapter feature to work.
- --allow=bluetooth
- --filesystem=xdg-run/app/com.discordapp.Discord:create
- --talk-name=org.freedesktop.ScreenSaver
# required for Gamescope on Steam Deck
- --filesystem=xdg-run/gamescope-0:ro
modules:
# enables motion controls on non-wii controllers (switch, ps4, etc)
# requires a udev rule enabling Motion Sensors access
- name: libevdev
buildsystem: meson
config-opts:
- -Dtests=disabled
- -Ddocumentation=disabled
sources:
- type: archive
url: https://www.freedesktop.org/software/libevdev/libevdev-1.13.3.tar.xz
sha256: abf1aace86208eebdd5d3550ffded4c8d73bb405b796d51c389c9d0604cbcfbf
x-checker-data:
type: anitya
project-id: 20540
stable-only: true
url-template: https://www.freedesktop.org/software/libevdev/libevdev-$version.tar.xz
# needed for screensaver inhibition
- name: xdg-screensaver-shim
buildsystem: meson
sources:
- type: archive
url: https://github.com/Unrud/xdg-screensaver-shim/archive/0.0.2.tar.gz
sha256: 0ed2a69fe6ee6cbffd2fe16f85116db737f17fb1e79bfb812d893cf15c728399
# build the vendored SDL2 from Externals until the runtime gets 2.30.6
- SDL2/SDL2.json
- name: dolphin-emu
buildsystem: cmake-ninja
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DENABLE_ALSA=OFF
- -DENABLE_SDL=ON
- -DENABLE_EVDEV=ON
- -DDISTRIBUTOR=dolphin-emu.org
cleanup:
- /share/man
post-install:
- install -D -t ${FLATPAK_DEST}/bin/ dolphin-emu-wrapper
- "${FLATPAK_BUILDER_BUILDDIR}/Flatpak/fill_release_node.sh"
- install -Dm644 -t ${FLATPAK_DEST}/share/metainfo/ org.DolphinEmu.dolphin-emu.metainfo.xml
- desktop-file-edit --set-key=Exec --set-value='/app/bin/dolphin-emu-wrapper'
/app/share/applications/dolphin-emu.desktop
sources:
- type: dir
path: ..
- type: file
path: org.DolphinEmu.dolphin-emu.metainfo.xml.in
dest-filename: org.DolphinEmu.dolphin-emu.metainfo.xml
- type: script
commands:
- |
for i in {0..9}; do
test -S $XDG_RUNTIME_DIR/discord-ipc-$i ||
ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-$i;
done
dolphin-emu "$@"
dest-filename: dolphin-emu-wrapper

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -302,7 +302,7 @@ public final class NativeLibrary
public static native int DefaultCPUCore();
public static native String GetDefaultGraphicsBackendName();
public static native String GetDefaultGraphicsBackendConfigName();
public static native int GetMaxLogLevel();

View file

@ -789,7 +789,7 @@ enum class BooleanSetting(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"EFBAccessEnable",
true
false
),
GFX_HACK_EFB_DEFER_INVALIDATION(
Settings.FILE_GFX,

View file

@ -45,7 +45,7 @@ enum class StringSetting(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"GFXBackend",
NativeLibrary.GetDefaultGraphicsBackendName()
NativeLibrary.GetDefaultGraphicsBackendConfigName()
),
MAIN_DUMP_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "DumpPath", ""),
MAIN_LOAD_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "LoadPath", ""),

View file

@ -146,7 +146,7 @@ void Host_UpdateDisasmDialog()
{
}
void Host_JitCacheCleared()
void Host_JitCacheInvalidation()
{
}
@ -408,9 +408,10 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCo
}
JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv* env, jclass)
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendConfigName(JNIEnv* env,
jclass)
{
return ToJString(env, VideoBackendBase::GetDefaultBackendName());
return ToJString(env, VideoBackendBase::GetDefaultBackendConfigName());
}
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv*, jclass)

View file

@ -47,7 +47,7 @@ private:
std::array<uint32_t, 36 + sizeof...(ExtraMatches)> _conns;
std::optional<V> _val;
TrieEntry() { std::fill(_conns.begin(), _conns.end(), INVALID_CONN); }
TrieEntry() { _conns.fill(INVALID_CONN); }
};
constexpr size_t IndexOf(char c) const

View file

@ -17,72 +17,72 @@
namespace Common
{
SettingsHandler::SettingsHandler() : m_buffer{}, m_position{0}, m_key{INITIAL_SEED}, decoded{""}
namespace
{
// Key used to encrypt/decrypt setting.txt contents
constexpr u32 INITIAL_SEED = 0x73B5DBFA;
} // namespace
SettingsWriter::SettingsWriter() : m_buffer{}, m_position{0}, m_key{INITIAL_SEED}
{
}
SettingsHandler::SettingsHandler(const Buffer& buffer) : SettingsHandler()
{
m_buffer = buffer;
Decrypt();
}
const SettingsHandler::Buffer& SettingsHandler::GetBytes() const
const SettingsBuffer& SettingsWriter::GetBytes() const
{
return m_buffer;
}
std::string SettingsHandler::GetValue(std::string_view key) const
std::string SettingsReader::GetValue(std::string_view key) const
{
constexpr char delim[] = "\n";
std::string toFind = std::string(delim).append(key).append("=");
size_t found = decoded.find(toFind);
size_t found = m_decoded.find(toFind);
if (found != std::string_view::npos)
{
size_t delimFound = decoded.find(delim, found + toFind.length());
size_t delimFound = m_decoded.find(delim, found + toFind.length());
if (delimFound == std::string_view::npos)
delimFound = decoded.length() - 1;
return decoded.substr(found + toFind.length(), delimFound - (found + toFind.length()));
delimFound = m_decoded.length() - 1;
return m_decoded.substr(found + toFind.length(), delimFound - (found + toFind.length()));
}
else
{
toFind = std::string(key).append("=");
found = decoded.find(toFind);
found = m_decoded.find(toFind);
if (found == 0)
{
size_t delimFound = decoded.find(delim, found + toFind.length());
size_t delimFound = m_decoded.find(delim, found + toFind.length());
if (delimFound == std::string_view::npos)
delimFound = decoded.length() - 1;
return decoded.substr(found + toFind.length(), delimFound - (found + toFind.length()));
delimFound = m_decoded.length() - 1;
return m_decoded.substr(found + toFind.length(), delimFound - (found + toFind.length()));
}
}
return "";
}
void SettingsHandler::Decrypt()
SettingsReader::SettingsReader(const SettingsBuffer& buffer) : m_decoded{""}
{
while (m_position < m_buffer.size())
u32 key = INITIAL_SEED;
for (u32 position = 0; position < buffer.size(); ++position)
{
decoded.push_back((u8)(m_buffer[m_position] ^ m_key));
m_position++;
m_key = (m_key >> 31) | (m_key << 1);
m_decoded.push_back((u8)(buffer[position] ^ key));
key = (key >> 31) | (key << 1);
}
// The decoded data normally uses CRLF line endings, but occasionally
// (see the comment in WriteLine), lines can be separated by CRLFLF.
// To handle this, we remove every CR and treat LF as the line ending.
// (We ignore empty lines.)
std::erase(decoded, '\x0d');
std::erase(m_decoded, '\x0d');
}
void SettingsHandler::AddSetting(std::string_view key, std::string_view value)
void SettingsWriter::AddSetting(std::string_view key, std::string_view value)
{
WriteLine(fmt::format("{}={}\r\n", key, value));
}
void SettingsHandler::WriteLine(std::string_view str)
void SettingsWriter::WriteLine(std::string_view str)
{
const u32 old_position = m_position;
const u32 old_key = m_key;
@ -106,7 +106,7 @@ void SettingsHandler::WriteLine(std::string_view str)
}
}
void SettingsHandler::WriteByte(u8 b)
void SettingsWriter::WriteByte(u8 b)
{
if (m_position >= m_buffer.size())
return;
@ -116,7 +116,7 @@ void SettingsHandler::WriteByte(u8 b)
m_key = (m_key >> 31) | (m_key << 1);
}
std::string SettingsHandler::GenerateSerialNumber()
std::string SettingsWriter::GenerateSerialNumber()
{
const std::time_t t = std::time(nullptr);

View file

@ -13,34 +13,35 @@
namespace Common
{
class SettingsHandler
using SettingsBuffer = std::array<u8, 0x100>;
class SettingsWriter
{
public:
enum
{
SETTINGS_SIZE = 0x100,
// Key used to encrypt/decrypt setting.txt contents
INITIAL_SEED = 0x73B5DBFA
};
using Buffer = std::array<u8, SETTINGS_SIZE>;
SettingsHandler();
explicit SettingsHandler(const Buffer& buffer);
SettingsWriter();
void AddSetting(std::string_view key, std::string_view value);
const Buffer& GetBytes() const;
std::string GetValue(std::string_view key) const;
const SettingsBuffer& GetBytes() const;
static std::string GenerateSerialNumber();
private:
void Decrypt();
void WriteLine(std::string_view str);
void WriteByte(u8 b);
std::array<u8, SETTINGS_SIZE> m_buffer;
SettingsBuffer m_buffer;
u32 m_position, m_key;
std::string decoded;
};
class SettingsReader
{
public:
explicit SettingsReader(const SettingsBuffer& buffer);
std::string GetValue(std::string_view key) const;
private:
std::string m_decoded;
};
} // namespace Common

View file

@ -24,6 +24,8 @@
#include "Common/Version.h"
#include "Common/WorkQueueThread.h"
#include "Core/Config/AchievementSettings.h"
#include "Core/Config/FreeLookSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h"
@ -62,7 +64,7 @@ void AchievementManager::Init()
[](const char* message, const rc_client_t* client) {
INFO_LOG_FMT(ACHIEVEMENTS, "{}", message);
});
rc_client_set_hardcore_enabled(m_client, Config::Get(Config::RA_HARDCORE_ENABLED));
SetHardcoreMode();
m_queue.Reset("AchievementManagerQueue", [](const std::function<void()>& func) { func(); });
m_image_queue.Reset("AchievementManagerImageQueue",
[](const std::function<void()>& func) { func(); });
@ -361,6 +363,13 @@ std::recursive_mutex& AchievementManager::GetLock()
void AchievementManager::SetHardcoreMode()
{
rc_client_set_hardcore_enabled(m_client, Config::Get(Config::RA_HARDCORE_ENABLED));
if (Config::Get(Config::RA_HARDCORE_ENABLED))
{
if (Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f)
Config::SetBaseOrCurrent(Config::MAIN_EMULATION_SPEED, 1.0f);
Config::SetBaseOrCurrent(Config::FREE_LOOK_ENABLED, false);
Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, false);
}
}
bool AchievementManager::IsHardcoreModeActive() const

View file

@ -371,12 +371,12 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
const auto fs = system.GetIOS()->GetFS();
{
Common::SettingsHandler::Buffer data;
Common::SettingsBuffer data;
const auto file = fs->OpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, settings_file_path,
IOS::HLE::FS::Mode::Read);
if (file && file->Read(data.data(), data.size()))
{
Common::SettingsHandler settings_reader(data);
const Common::SettingsReader settings_reader(data);
serno = settings_reader.GetValue("SERNO");
model = settings_reader.GetValue("MODEL");
@ -413,7 +413,7 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
if (Core::WantsDeterminism())
serno = "123456789";
else
serno = Common::SettingsHandler::GenerateSerialNumber();
serno = Common::SettingsWriter::GenerateSerialNumber();
INFO_LOG_FMT(BOOT, "No previous serial number found, generated one instead: {}", serno);
}
else
@ -421,20 +421,21 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
INFO_LOG_FMT(BOOT, "Using serial number: {}", serno);
}
Common::SettingsHandler gen;
gen.AddSetting("AREA", region_setting.area);
gen.AddSetting("MODEL", model);
gen.AddSetting("DVD", "0");
gen.AddSetting("MPCH", "0x7FFE");
gen.AddSetting("CODE", region_setting.code);
gen.AddSetting("SERNO", serno);
gen.AddSetting("VIDEO", region_setting.video);
gen.AddSetting("GAME", region_setting.game);
Common::SettingsWriter settings_writer;
settings_writer.AddSetting("AREA", region_setting.area);
settings_writer.AddSetting("MODEL", model);
settings_writer.AddSetting("DVD", "0");
settings_writer.AddSetting("MPCH", "0x7FFE");
settings_writer.AddSetting("CODE", region_setting.code);
settings_writer.AddSetting("SERNO", serno);
settings_writer.AddSetting("VIDEO", region_setting.video);
settings_writer.AddSetting("GAME", region_setting.game);
constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite;
const auto settings_file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID,
settings_file_path, {rw_mode, rw_mode, rw_mode});
if (!settings_file || !settings_file->Write(gen.GetBytes().data(), gen.GetBytes().size()))
if (!settings_file ||
!settings_file->Write(settings_writer.GetBytes().data(), settings_writer.GetBytes().size()))
{
PanicAlertFmtT("SetupWiiMemory: Can't create setting.txt file");
return false;
@ -443,7 +444,7 @@ bool CBoot::SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType con
auto& memory = system.GetMemory();
// Write the 256 byte setting.txt to memory.
memory.CopyToEmu(0x3800, gen.GetBytes().data(), gen.GetBytes().size());
memory.CopyToEmu(0x3800, settings_writer.GetBytes().data(), settings_writer.GetBytes().size());
INFO_LOG_FMT(BOOT, "Setup Wii Memory...");

View file

@ -178,7 +178,7 @@ const Info<int> GFX_STEREO_DEPTH_PERCENTAGE{{System::GFX, "Stereoscopy", "Stereo
// Graphics.Hacks
const Info<bool> GFX_HACK_EFB_ACCESS_ENABLE{{System::GFX, "Hacks", "EFBAccessEnable"}, true};
const Info<bool> GFX_HACK_EFB_ACCESS_ENABLE{{System::GFX, "Hacks", "EFBAccessEnable"}, false};
const Info<bool> GFX_HACK_EFB_DEFER_INVALIDATION{
{System::GFX, "Hacks", "EFBAccessDeferInvalidation"}, false};
const Info<int> GFX_HACK_EFB_ACCESS_TILE_SIZE{{System::GFX, "Hacks", "EFBAccessTileSize"}, 64};

View file

@ -212,7 +212,7 @@ const Info<bool> MAIN_RAM_OVERRIDE_ENABLE{{System::Main, "Core", "RAMOverrideEna
const Info<u32> MAIN_MEM1_SIZE{{System::Main, "Core", "MEM1Size"}, Memory::MEM1_SIZE_RETAIL};
const Info<u32> MAIN_MEM2_SIZE{{System::Main, "Core", "MEM2Size"}, Memory::MEM2_SIZE_RETAIL};
const Info<std::string> MAIN_GFX_BACKEND{{System::Main, "Core", "GFXBackend"},
VideoBackendBase::GetDefaultBackendName()};
VideoBackendBase::GetDefaultBackendConfigName()};
const Info<HSP::HSPDeviceType> MAIN_HSP_DEVICE{{System::Main, "Core", "HSPDevice"},
HSP::HSPDeviceType::None};
const Info<u32> MAIN_ARAM_EXPANSION_SIZE{{System::Main, "Core", "ARAMExpansionSize"}, 0x400000};

View file

@ -6,19 +6,14 @@
#include <algorithm>
#include <array>
#include "Common/Config/Config.h"
#include "Core/Config/AchievementSettings.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/UISettings.h"
#include "Core/Config/WiimoteSettings.h"
namespace ConfigLoaders
{
bool IsSettingSaveable(const Config::Location& config_location)
{
static constexpr std::array<Config::System, 3> systems_not_saveable = {
Config::System::GCPad, Config::System::WiiPad, Config::System::GCKeyboard};
static constexpr std::array systems_not_saveable = {Config::System::GCPad, Config::System::WiiPad,
Config::System::GCKeyboard};
if (std::find(begin(systems_not_saveable), end(systems_not_saveable), config_location.system) ==
end(systems_not_saveable))

View file

@ -217,7 +217,7 @@ void SConfig::OnNewTitleLoad(const Core::CPUThreadGuard& guard)
}
CBoot::LoadMapFromFilename(guard, ppc_symbol_db);
HLE::Reload(system);
PatchEngine::Reload();
PatchEngine::Reload(system);
HiresTexture::Update();
WC24PatchEngine::Reload();
}

View file

@ -17,6 +17,7 @@
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "ConfigManager.h"
@ -272,6 +273,7 @@ static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
{
ppc_state.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j);
}
Host_JitCacheInvalidation();
return Installation::Installed;
}

View file

@ -60,7 +60,7 @@ void Host_PPCSymbolsChanged();
void Host_RefreshDSPDebuggerWindow();
void Host_RequestRenderWindowSize(int width, int height);
void Host_UpdateDisasmDialog();
void Host_JitCacheCleared();
void Host_JitCacheInvalidation();
void Host_JitProfileDataWiped();
void Host_UpdateMainFrame();
void Host_UpdateTitle(const std::string& title);

View file

@ -133,13 +133,13 @@ IPCReply GetRealProductCode(Core::System& system, const IOCtlVRequest& request)
if (!file)
return IPCReply(IPC_ENOENT);
Common::SettingsHandler::Buffer data;
Common::SettingsBuffer data;
if (!file.ReadBytes(data.data(), data.size()))
return IPCReply(IPC_ENOENT);
Common::SettingsHandler gen(data);
const std::string code = gen.GetValue("CODE");
const Common::SettingsReader settings_reader(data);
const std::string code = settings_reader.GetValue("CODE");
const size_t length = std::min<size_t>(request.io_vectors[0].size, code.length());
if (length == 0)

View file

@ -10,6 +10,7 @@
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
@ -575,7 +576,7 @@ SharedContentMap::GetFilenameFromSHA1(const std::array<u8, 20>& sha1) const
if (it == m_entries.end())
return {};
const std::string id_string(it->id.begin(), it->id.end());
const std::string_view id_string(reinterpret_cast<const char*>(it->id.data()), it->id.size());
return fmt::format("/shared1/{}.app", id_string);
}
@ -591,20 +592,22 @@ std::vector<std::array<u8, 20>> SharedContentMap::GetHashes() const
std::string SharedContentMap::AddSharedContent(const std::array<u8, 20>& sha1)
{
auto filename = GetFilenameFromSHA1(sha1);
if (filename)
return *filename;
if (auto filename = GetFilenameFromSHA1(sha1))
return *std::move(filename);
const std::string id = fmt::format("{:08x}", m_last_id);
Entry entry;
std::copy(id.cbegin(), id.cend(), entry.id.begin());
Entry& entry = m_entries.emplace_back();
static_assert(sizeof(m_last_id) == 4,
"'m_last_id' must be represented by 8 characters when formatted in hexadecimal.");
static_assert(std::tuple_size_v<decltype(entry.id)> == sizeof(m_last_id) * 2,
"'entry.id' must be a std::array capable of storing every nibble of 'm_last_id'.");
fmt::format_to(entry.id.data(), "{:08x}", m_last_id);
entry.sha1 = sha1;
m_entries.push_back(entry);
WriteEntries();
filename = fmt::format("/shared1/{}.app", id);
m_last_id++;
return *filename;
const std::string_view id_string(reinterpret_cast<const char*>(entry.id.data()), entry.id.size());
return fmt::format("/shared1/{}.app", id_string);
}
bool SharedContentMap::DeleteSharedContent(const std::array<u8, 20>& sha1)

View file

@ -923,7 +923,7 @@ IPCReply NetKDRequestDevice::HandleRequestRegisterUserId(const IOS::HLE::IOCtlRe
return IPCReply{IPC_SUCCESS};
}
Common::SettingsHandler::Buffer data;
Common::SettingsBuffer data;
if (!file->Read(data.data(), data.size()))
{
WriteReturnValue(memory, NWC24::WC24_ERR_FILE_READ, request.buffer_out);
@ -931,8 +931,8 @@ IPCReply NetKDRequestDevice::HandleRequestRegisterUserId(const IOS::HLE::IOCtlRe
return IPCReply{IPC_SUCCESS};
}
const Common::SettingsHandler gen{data};
const std::string serno = gen.GetValue("SERNO");
const Common::SettingsReader settings_reader{data};
const std::string serno = settings_reader.GetValue("SERNO");
const std::string form_data =
fmt::format("mlid=w{}&hdid={}&rgncd={}", m_config.Id(), m_ios.GetIOSC().GetDeviceId(), serno);
const Common::HttpRequest::Response response = m_http.Post(m_config.GetAccountURL(), form_data);
@ -1076,12 +1076,12 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
const auto fs = m_ios.GetFS();
if (const auto file = fs->OpenFile(PID_KD, PID_KD, settings_file_path, FS::Mode::Read))
{
Common::SettingsHandler::Buffer data;
Common::SettingsBuffer data;
if (file->Read(data.data(), data.size()))
{
const Common::SettingsHandler gen{data};
area = gen.GetValue("AREA");
model = gen.GetValue("MODEL");
const Common::SettingsReader settings_reader{data};
area = settings_reader.GetValue("AREA");
model = settings_reader.GetValue("MODEL");
}
}

View file

@ -296,6 +296,13 @@ void RemoveMemoryPatch(std::size_t index)
std::erase(s_on_frame_memory, index);
}
static void ApplyStartupPatches(Core::System& system)
{
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(system);
ApplyPatches(guard, s_on_frame);
}
bool ApplyFramePatches(Core::System& system)
{
const auto& ppc_state = system.GetPPCState();
@ -335,10 +342,11 @@ void Shutdown()
Gecko::Shutdown();
}
void Reload()
void Reload(Core::System& system)
{
Shutdown();
LoadPatches();
ApplyStartupPatches(system);
}
} // namespace PatchEngine

View file

@ -61,7 +61,7 @@ void RemoveMemoryPatch(std::size_t index);
bool ApplyFramePatches(Core::System& system);
void Shutdown();
void Reload();
void Reload(Core::System& system);
inline int GetPatchTypeCharLength(PatchType type)
{

View file

@ -442,7 +442,7 @@ void CachedInterpreter::ClearCache()
ClearCodeSpace();
ResetFreeMemoryRanges();
RefreshConfig();
Host_JitCacheCleared();
Host_JitCacheInvalidation();
}
void CachedInterpreter::LogGeneratedCode() const

View file

@ -313,7 +313,7 @@ void Jit64::ClearCache()
RefreshConfig();
asm_routines.Regenerate();
ResetFreeMemoryRanges();
Host_JitCacheCleared();
Host_JitCacheInvalidation();
}
void Jit64::FreeRanges()

View file

@ -197,7 +197,7 @@ void JitArm64::GenerateAsmAndResetFreeMemoryRanges()
ResetFreeMemoryRanges(routines_near_end - routines_near_start,
routines_far_end - routines_far_start);
Host_JitCacheCleared();
Host_JitCacheInvalidation();
}
void JitArm64::FreeRanges()
@ -262,12 +262,11 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
if (js.op->canEndBlock)
{
// also flush the program counter
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
MOVI2R(WA, js.compilerPC);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(pc));
ADD(WA, WA, 4);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(npc));
gpr.Unlock(WA);
}
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
@ -283,24 +282,23 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
{
if (js.isLastInstruction)
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(npc));
WriteExceptionExit(WA);
gpr.Unlock(WA);
}
else
{
// only exit if ppcstate.npc was changed
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(npc));
ARM64Reg WB = gpr.GetReg();
{
auto WB = gpr.GetScopedReg();
MOVI2R(WB, js.compilerPC + 4);
CMP(WB, WA);
gpr.Unlock(WB);
}
FixupBranch c = B(CC_EQ);
WriteExceptionExit(WA);
SetJumpTarget(c);
gpr.Unlock(WA);
}
}
else if (ShouldHandleFPExceptionForInstruction(js.op))
@ -399,11 +397,12 @@ void JitArm64::IntializeSpeculativeConstants()
SwitchToNearCode();
}
ARM64Reg tmp = gpr.GetReg();
{
auto tmp = gpr.GetScopedReg();
ARM64Reg value = gpr.R(i);
MOVI2R(tmp, compile_time_value);
CMP(value, tmp);
gpr.Unlock(tmp);
}
FixupBranch no_fail = B(CCFlags::CC_EQ);
B(fail);
@ -442,16 +441,15 @@ void JitArm64::MSRUpdated(u32 msr)
}
else
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
MOVI2R(WA, feature_flags);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(feature_flags));
gpr.Unlock(WA);
}
}
void JitArm64::MSRUpdated(ARM64Reg msr)
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
// Update mem_ptr
@ -472,8 +470,6 @@ void JitArm64::MSRUpdated(ARM64Reg msr)
if (other_feature_flags != 0)
ORR(WA, WA, LogicalImm(other_feature_flags, GPRSize::B32));
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(feature_flags));
gpr.Unlock(WA);
}
void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return,
@ -671,13 +667,16 @@ void JitArm64::FakeLKExit(u32 exit_address_after_return, ARM64Reg exit_address_a
// function has been called!
gpr.Lock(ARM64Reg::W30);
}
const u8* host_address_after_return;
{
// Push {ARM_PC (64-bit); PPC_PC (32-bit); feature_flags (32-bit)} on the stack
ARM64Reg after_reg = ARM64Reg::INVALID_REG;
Arm64RegCache::ScopedARM64Reg after_reg;
ARM64Reg reg_to_push;
const u64 feature_flags = m_ppc_state.feature_flags;
if (exit_address_after_return_reg == ARM64Reg::INVALID_REG)
{
after_reg = gpr.GetReg();
after_reg = gpr.GetScopedReg();
reg_to_push = EncodeRegTo64(after_reg);
MOVI2R(reg_to_push, feature_flags << 32 | exit_address_after_return);
}
@ -687,19 +686,18 @@ void JitArm64::FakeLKExit(u32 exit_address_after_return, ARM64Reg exit_address_a
}
else
{
after_reg = gpr.GetReg();
after_reg = gpr.GetScopedReg();
reg_to_push = EncodeRegTo64(after_reg);
ORRI2R(reg_to_push, EncodeRegTo64(exit_address_after_return_reg), feature_flags << 32,
reg_to_push);
}
ARM64Reg code_reg = gpr.GetReg();
auto code_reg = gpr.GetScopedReg();
constexpr s32 adr_offset = sizeof(u32) * 3;
const u8* host_address_after_return = GetCodePtr() + adr_offset;
host_address_after_return = GetCodePtr() + adr_offset;
ADR(EncodeRegTo64(code_reg), adr_offset);
STP(IndexType::Pre, EncodeRegTo64(code_reg), reg_to_push, ARM64Reg::SP, -16);
gpr.Unlock(code_reg);
if (after_reg != ARM64Reg::INVALID_REG)
gpr.Unlock(after_reg);
}
FixupBranch skip_exit = BL();
DEBUG_ASSERT(GetCodePtr() == host_address_after_return || HasWriteFailed());
@ -832,10 +830,9 @@ void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external, bool always
void JitArm64::WriteConditionalExceptionExit(int exception, u64 increment_sp_on_exit)
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
WriteConditionalExceptionExit(exception, WA, Arm64Gen::ARM64Reg::INVALID_REG,
increment_sp_on_exit);
gpr.Unlock(WA);
}
void JitArm64::WriteConditionalExceptionExit(int exception, ARM64Reg temp_gpr, ARM64Reg temp_fpr,
@ -1227,7 +1224,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
// asynchronous.
if (jo.optimizeGatherPipe && gatherPipeIntCheck)
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
@ -1253,8 +1250,6 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
SwitchToNearCode();
SetJumpTarget(no_ext_exception);
SetJumpTarget(exit);
gpr.Unlock(WA);
}
}
@ -1268,12 +1263,11 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
// The only thing that currently sets op.skip is the BLR following optimization.
// If any non-branch instruction starts setting that too, this will need to be changed.
ASSERT(op.inst.hex == 0x4e800020);
const ARM64Reg bw_reg_a = gpr.GetReg(), bw_reg_b = gpr.GetReg();
const auto bw_reg_a = gpr.GetScopedReg(), bw_reg_b = gpr.GetScopedReg();
const BitSet32 gpr_caller_save =
gpr.GetCallerSavedUsed() & ~BitSet32{DecodeReg(bw_reg_a), DecodeReg(bw_reg_b)};
WriteBranchWatch<true>(op.address, op.branchTo, op.inst, bw_reg_a, bw_reg_b,
gpr_caller_save, fpr.GetCallerSavedUsed());
gpr.Unlock(bw_reg_a, bw_reg_b);
}
}
else
@ -1311,10 +1305,12 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
{
FixupBranch b1;
// This instruction uses FPU - needs to add FP exception bailout
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(msr));
FixupBranch b1 = TBNZ(WA, 13); // Test FP enabled bit
b1 = TBNZ(WA, 13); // Test FP enabled bit
FixupBranch far_addr = B();
SwitchToFarCode();
@ -1326,8 +1322,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
ORR(WA, WA, LogicalImm(EXCEPTION_FPU_UNAVAILABLE, GPRSize::B32));
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
gpr.Unlock(WA);
}
WriteExceptionExit(js.compilerPC, false, true);

View file

@ -24,13 +24,12 @@ void JitArm64::sc(UGeckoInstruction inst)
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
ORR(WA, WA, LogicalImm(EXCEPTION_SYSCALL, GPRSize::B32));
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
gpr.Unlock(WA);
}
WriteExceptionExit(js.compilerPC + 4, false, true);
}
@ -51,9 +50,10 @@ void JitArm64::rfi(UGeckoInstruction inst)
// R1 = MSR contents
// R2 = Mask
// R3 = Mask
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = gpr.GetReg();
ARM64Reg WC = gpr.GetReg();
auto WA = gpr.GetScopedReg();
{
auto WB = gpr.GetScopedReg();
auto WC = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WC, PPC_REG, PPCSTATE_OFF(msr));
@ -65,14 +65,13 @@ void JitArm64::rfi(UGeckoInstruction inst)
ORR(WA, WA, WC); // rB = Masked MSR OR masked SRR1
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(msr)); // STR rB in to rA
gpr.Unlock(WB, WC);
}
MSRUpdated(WA);
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF_SPR(SPR_SRR0));
WriteExceptionExit(WA);
gpr.Unlock(WA);
}
template <bool condition>
@ -144,10 +143,10 @@ void JitArm64::bx(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
ARM64Reg WA = ARM64Reg::INVALID_REG;
Arm64GPRCache::ScopedARM64Reg WA = ARM64Reg::INVALID_REG;
if (inst.LK)
{
WA = gpr.GetReg();
WA = gpr.GetScopedReg();
MOVI2R(WA, js.compilerPC + 4);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF_SPR(SPR_LR));
}
@ -156,13 +155,12 @@ void JitArm64::bx(UGeckoInstruction inst)
{
if (IsDebuggingEnabled())
{
const ARM64Reg WB = gpr.GetReg(), WC = gpr.GetReg();
const auto WB = gpr.GetScopedReg(), WC = gpr.GetScopedReg();
BitSet32 gpr_caller_save = gpr.GetCallerSavedUsed() & ~BitSet32{DecodeReg(WB), DecodeReg(WC)};
if (WA != ARM64Reg::INVALID_REG && js.op->skipLRStack)
gpr_caller_save[DecodeReg(WA)] = false;
WriteBranchWatch<true>(js.compilerPC, js.op->branchTo, inst, WB, WC, gpr_caller_save,
fpr.GetCallerSavedUsed());
gpr.Unlock(WB, WC);
}
if (inst.LK && !js.op->skipLRStack)
{
@ -172,9 +170,6 @@ void JitArm64::bx(UGeckoInstruction inst)
FakeLKExit(js.compilerPC + 4, WA);
}
if (WA != ARM64Reg::INVALID_REG)
gpr.Unlock(WA);
return;
}
@ -184,13 +179,12 @@ void JitArm64::bx(UGeckoInstruction inst)
if (js.op->branchIsIdleLoop)
{
if (WA == ARM64Reg::INVALID_REG)
WA = gpr.GetReg();
WA = gpr.GetScopedReg();
if (IsDebuggingEnabled())
{
const ARM64Reg WB = gpr.GetReg();
const auto WB = gpr.GetScopedReg();
WriteBranchWatch<true>(js.compilerPC, js.op->branchTo, inst, WA, WB, {}, {});
gpr.Unlock(WB);
}
// make idle loops go faster
@ -198,7 +192,7 @@ void JitArm64::bx(UGeckoInstruction inst)
MOVP2R(XA, &CoreTiming::GlobalIdle);
BLR(XA);
gpr.Unlock(WA);
WA.Unlock();
WriteExceptionExit(js.op->branchTo);
return;
@ -206,16 +200,12 @@ void JitArm64::bx(UGeckoInstruction inst)
if (IsDebuggingEnabled())
{
const ARM64Reg WB = gpr.GetReg(), WC = gpr.GetReg();
const auto WB = gpr.GetScopedReg(), WC = gpr.GetScopedReg();
const BitSet32 gpr_caller_save =
WA != ARM64Reg::INVALID_REG ? BitSet32{DecodeReg(WA)} & CALLER_SAVED_GPRS : BitSet32{};
WriteBranchWatch<true>(js.compilerPC, js.op->branchTo, inst, WB, WC, gpr_caller_save, {});
gpr.Unlock(WB, WC);
}
WriteExit(js.op->branchTo, inst.LK, js.compilerPC + 4, WA);
if (WA != ARM64Reg::INVALID_REG)
gpr.Unlock(WA);
}
void JitArm64::bcx(UGeckoInstruction inst)
@ -223,10 +213,14 @@ void JitArm64::bcx(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = inst.LK || IsDebuggingEnabled() ? gpr.GetReg() : WA;
ARM64Reg WC = IsDebuggingEnabled() && inst.LK && !js.op->branchIsIdleLoop ? gpr.GetReg() :
ARM64Reg::INVALID_REG;
auto WA = gpr.GetScopedReg();
auto WB = inst.LK || IsDebuggingEnabled() ? gpr.GetScopedReg() :
Arm64GPRCache::ScopedARM64Reg(WA.GetReg());
{
auto WC = IsDebuggingEnabled() && inst.LK && !js.op->branchIsIdleLoop ?
gpr.GetScopedReg() :
Arm64GPRCache::ScopedARM64Reg(ARM64Reg::INVALID_REG);
FixupBranch pCTRDontBranch;
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
@ -290,9 +284,7 @@ void JitArm64::bcx(UGeckoInstruction inst)
SetJumpTarget(pConditionDontBranch);
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
SetJumpTarget(pCTRDontBranch);
if (WC != ARM64Reg::INVALID_REG)
gpr.Unlock(WC);
}
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
{
@ -311,10 +303,6 @@ void JitArm64::bcx(UGeckoInstruction inst)
WriteBranchWatch<false>(js.compilerPC, js.compilerPC + 4, inst, WA, WB, gpr_caller_save,
fpr.GetCallerSavedUsed());
}
gpr.Unlock(WA);
if (WB != WA)
gpr.Unlock(WB);
}
void JitArm64::bcctrx(UGeckoInstruction inst)
@ -337,34 +325,29 @@ void JitArm64::bcctrx(UGeckoInstruction inst)
gpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
ARM64Reg WB = ARM64Reg::INVALID_REG;
Arm64GPRCache::ScopedARM64Reg WB = ARM64Reg::INVALID_REG;
if (inst.LK_3)
{
WB = gpr.GetReg();
WB = gpr.GetScopedReg();
MOVI2R(WB, js.compilerPC + 4);
STR(IndexType::Unsigned, WB, PPC_REG, PPCSTATE_OFF_SPR(SPR_LR));
}
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF_SPR(SPR_CTR));
AND(WA, WA, LogicalImm(~0x3, GPRSize::B32));
if (IsDebuggingEnabled())
{
const ARM64Reg WC = gpr.GetReg(), WD = gpr.GetReg();
const auto WC = gpr.GetScopedReg(), WD = gpr.GetScopedReg();
BitSet32 gpr_caller_save = BitSet32{DecodeReg(WA)};
if (WB != ARM64Reg::INVALID_REG)
gpr_caller_save[DecodeReg(WB)] = true;
gpr_caller_save &= CALLER_SAVED_GPRS;
WriteBranchWatchDestInRegister(js.compilerPC, WA, inst, WC, WD, gpr_caller_save, {});
gpr.Unlock(WC, WD);
}
WriteExit(WA, inst.LK_3, js.compilerPC + 4, WB);
if (WB != ARM64Reg::INVALID_REG)
gpr.Unlock(WB);
gpr.Unlock(WA);
}
void JitArm64::bclrx(UGeckoInstruction inst)
@ -375,10 +358,19 @@ void JitArm64::bclrx(UGeckoInstruction inst)
bool conditional =
(inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0;
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB =
conditional || inst.LK || IsDebuggingEnabled() ? gpr.GetReg() : ARM64Reg::INVALID_REG;
ARM64Reg WC = IsDebuggingEnabled() ? gpr.GetReg() : ARM64Reg::INVALID_REG;
auto WA = gpr.GetScopedReg();
Arm64GPRCache::ScopedARM64Reg WB;
if (conditional || inst.LK || IsDebuggingEnabled())
{
WB = gpr.GetScopedReg();
}
{
Arm64GPRCache::ScopedARM64Reg WC;
if (IsDebuggingEnabled())
{
WC = gpr.GetScopedReg();
}
FixupBranch pCTRDontBranch;
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
@ -451,9 +443,7 @@ void JitArm64::bclrx(UGeckoInstruction inst)
SetJumpTarget(pConditionDontBranch);
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
SetJumpTarget(pCTRDontBranch);
if (WC != ARM64Reg::INVALID_REG)
gpr.Unlock(WC);
}
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
{
@ -472,8 +462,4 @@ void JitArm64::bclrx(UGeckoInstruction inst)
WriteBranchWatch<false>(js.compilerPC, js.compilerPC + 4, inst, WA, WB, gpr_caller_save,
fpr.GetCallerSavedUsed());
}
gpr.Unlock(WA);
if (WB != ARM64Reg::INVALID_REG)
gpr.Unlock(WB);
}

View file

@ -102,15 +102,16 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
const ARM64Reg VC = use_c ? reg_encoder(fpr.R(c, type)) : ARM64Reg::INVALID_REG;
const ARM64Reg VD = reg_encoder(fpr.RW(d, type_out));
ARM64Reg V0Q = ARM64Reg::INVALID_REG;
ARM64Reg V1Q = ARM64Reg::INVALID_REG;
{
Arm64FPRCache::ScopedARM64Reg V0Q = ARM64Reg::INVALID_REG;
Arm64FPRCache::ScopedARM64Reg V1Q = ARM64Reg::INVALID_REG;
ARM64Reg rounded_c_reg = VC;
if (round_c)
{
ASSERT_MSG(DYNA_REC, !inputs_are_singles, "Tried to apply 25-bit precision to single");
V0Q = fpr.GetReg();
V0Q = fpr.GetScopedReg();
rounded_c_reg = reg_encoder(V0Q);
Force25BitPrecision(rounded_c_reg, VC);
}
@ -119,7 +120,7 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
if (fma && inaccurate_fma && VD == VB)
{
if (V0Q == ARM64Reg::INVALID_REG)
V0Q = fpr.GetReg();
V0Q = fpr.GetScopedReg();
inaccurate_fma_reg = reg_encoder(V0Q);
}
@ -128,7 +129,7 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
m_accurate_nans && (VD == VA || (use_b && VD == VB) || (use_c && VD == VC));
if (preserve_d)
{
V1Q = fpr.GetReg();
V1Q = fpr.GetScopedReg();
result_reg = reg_encoder(V1Q);
}
@ -244,11 +245,7 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
for (FixupBranch fixup : nan_fixups)
SetJumpTarget(fixup);
if (V0Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V0Q);
if (V1Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V1Q);
}
if (output_is_single)
{
@ -449,19 +446,20 @@ void JitArm64::FloatCompare(UGeckoInstruction inst, bool upper)
gpr.BindCRToRegister(crf, false);
const ARM64Reg XA = gpr.CR(crf);
ARM64Reg fpscr_reg = ARM64Reg::INVALID_REG;
Arm64GPRCache::ScopedARM64Reg fpscr_reg = ARM64Reg::INVALID_REG;
if (fprf)
{
fpscr_reg = gpr.GetReg();
fpscr_reg = gpr.GetScopedReg();
LDR(IndexType::Unsigned, fpscr_reg, PPC_REG, PPCSTATE_OFF(fpscr));
AND(fpscr_reg, fpscr_reg, LogicalImm(~FPCC_MASK, GPRSize::B32));
}
ARM64Reg V0Q = ARM64Reg::INVALID_REG;
ARM64Reg V1Q = ARM64Reg::INVALID_REG;
{
Arm64FPRCache::ScopedARM64Reg V0Q;
Arm64FPRCache::ScopedARM64Reg V1Q;
if (upper_a)
{
V0Q = fpr.GetReg();
V0Q = fpr.GetScopedReg();
m_float_emit.DUP(singles ? 32 : 64, paired_reg_encoder(V0Q), paired_reg_encoder(VA), 1);
VA = reg_encoder(V0Q);
}
@ -473,18 +471,14 @@ void JitArm64::FloatCompare(UGeckoInstruction inst, bool upper)
}
else
{
V1Q = fpr.GetReg();
V1Q = fpr.GetScopedReg();
m_float_emit.DUP(singles ? 32 : 64, paired_reg_encoder(V1Q), paired_reg_encoder(VB), 1);
VB = reg_encoder(V1Q);
}
}
m_float_emit.FCMP(VA, VB);
if (V0Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V0Q);
if (V1Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V1Q);
}
FixupBranch pNaN, pLesser, pGreater;
FixupBranch continue1, continue2, continue3;
@ -538,7 +532,6 @@ void JitArm64::FloatCompare(UGeckoInstruction inst, bool upper)
if (fprf)
{
STR(IndexType::Unsigned, fpscr_reg, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(fpscr_reg);
}
}
@ -572,7 +565,7 @@ void JitArm64::fctiwx(UGeckoInstruction inst)
if (single)
{
const ARM64Reg V0 = fpr.GetReg();
const auto V0 = fpr.GetScopedReg();
if (is_fctiwzx)
{
@ -589,12 +582,10 @@ void JitArm64::fctiwx(UGeckoInstruction inst)
m_float_emit.BIC(16, EncodeRegToDouble(V0), 0x7);
m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(VD), EncodeRegToDouble(V0));
fpr.Unlock(V0);
}
else
{
const ARM64Reg WA = gpr.GetReg();
const auto WA = gpr.GetScopedReg();
if (is_fctiwzx)
{
@ -608,8 +599,6 @@ void JitArm64::fctiwx(UGeckoInstruction inst)
ORR(EncodeRegTo64(WA), EncodeRegTo64(WA), LogicalImm(0xFFF8'0000'0000'0000ULL, GPRSize::B64));
m_float_emit.FMOV(EncodeRegToDouble(VD), EncodeRegTo64(WA));
gpr.Unlock(WA);
}
ASSERT_MSG(DYNA_REC, b == d || single == fpr.IsSingle(b, true),

View file

@ -86,10 +86,9 @@ void JitArm64::LoadCarry()
{
case CarryFlag::InPPCState:
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
CMP(WA, 1);
gpr.Unlock(WA);
break;
}
case CarryFlag::InHostCarry:
@ -119,18 +118,16 @@ void JitArm64::FlushCarry()
}
case CarryFlag::InHostCarry:
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
CSET(WA, CC_CS);
STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
gpr.Unlock(WA);
break;
}
case CarryFlag::ConstantTrue:
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
MOVI2R(WA, 1);
STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
gpr.Unlock(WA);
break;
}
case CarryFlag::ConstantFalse:
@ -155,9 +152,10 @@ void JitArm64::reg_imm(u32 d, u32 a, u32 value, u32 (*do_op)(u32, u32),
else
{
gpr.BindToRegister(d, d == a);
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
(this->*op)(gpr.R(d), gpr.R(a), value, WA);
gpr.Unlock(WA);
}
if (Rc)
ComputeRC0(gpr.R(d));
@ -245,9 +243,8 @@ void JitArm64::addix(UGeckoInstruction inst)
{
gpr.BindToRegister(d, d == a);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ADDI2R(gpr.R(d), gpr.R(a), imm, WA);
gpr.Unlock(WA);
}
}
else
@ -544,9 +541,10 @@ void JitArm64::addx(UGeckoInstruction inst)
int imm_value = gpr.GetImm(imm_reg);
gpr.BindToRegister(d, d == in_reg);
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
ADDI2R(gpr.R(d), gpr.R(in_reg), imm_value, WA);
gpr.Unlock(WA);
}
if (inst.Rc)
ComputeRC0(gpr.R(d));
}
@ -722,9 +720,8 @@ void JitArm64::cmpi(UGeckoInstruction inst)
if (B != 0)
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
SUBI2R(CR, CR, B, EncodeRegTo64(WA));
gpr.Unlock(WA);
}
}
@ -796,10 +793,9 @@ void JitArm64::rlwinmx_internal(UGeckoInstruction inst, u32 sh)
}
else
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
MOVI2R(WA, mask);
AND(gpr.R(a), WA, gpr.R(s), ArithOption(gpr.R(s), ShiftType::ROR, 32 - sh));
gpr.Unlock(WA);
}
if (inst.Rc)
@ -829,11 +825,12 @@ void JitArm64::rlwnmx(UGeckoInstruction inst)
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
gpr.BindToRegister(a, a == s || a == b);
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
NEG(WA, gpr.R(b));
RORV(gpr.R(a), gpr.R(s), WA);
ANDI2R(gpr.R(a), gpr.R(a), mask, WA);
gpr.Unlock(WA);
}
if (inst.Rc)
ComputeRC0(gpr.R(a));
@ -878,8 +875,8 @@ void JitArm64::srawix(UGeckoInstruction inst)
if (js.op->wantsCA)
{
ARM64Reg WA = gpr.GetReg();
ARM64Reg dest = inplace_carry ? WA : ARM64Reg::WSP;
auto WA = gpr.GetScopedReg();
ARM64Reg dest = inplace_carry ? ARM64Reg(WA) : ARM64Reg::WSP;
if (a != s)
{
ASR(RA, RS, amount);
@ -901,7 +898,6 @@ void JitArm64::srawix(UGeckoInstruction inst)
CSINC(WA, ARM64Reg::WSP, ARM64Reg::WSP, CC_EQ);
ComputeCarry(WA);
}
gpr.Unlock(WA);
}
else
{
@ -936,9 +932,10 @@ void JitArm64::addic(UGeckoInstruction inst)
else
{
gpr.BindToRegister(d, d == a);
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
CARRY_IF_NEEDED(ADDI2R, ADDSI2R, gpr.R(d), gpr.R(a), simm, WA);
gpr.Unlock(WA);
}
ComputeCarry();
if (rc)
@ -1037,12 +1034,10 @@ void JitArm64::mulli(UGeckoInstruction inst)
gpr.BindToRegister(d, allocate_reg);
// Reuse d to hold the immediate if possible, allocate a register otherwise.
ARM64Reg WA = allocate_reg ? gpr.GetReg() : gpr.R(d);
auto WA = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(gpr.R(d));
MOVI2R(WA, (u32)(s32)inst.SIMM_16);
MUL(gpr.R(d), gpr.R(a), WA);
if (allocate_reg)
gpr.Unlock(WA);
}
}
@ -1137,16 +1132,16 @@ void JitArm64::addzex(UGeckoInstruction inst)
{
case CarryFlag::InPPCState:
{
gpr.BindToRegister(d, d == a);
ARM64Reg WA = d == a ? gpr.GetReg() : gpr.R(d);
const bool allocate_reg = d == a;
gpr.BindToRegister(d, allocate_reg);
{
auto WA = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(gpr.R(d));
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(a), WA);
}
ComputeCarry();
if (d == a)
gpr.Unlock(WA);
break;
}
case CarryFlag::InHostCarry:
@ -1229,18 +1224,16 @@ void JitArm64::subfex(UGeckoInstruction inst)
{
case CarryFlag::InPPCState:
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
ADDI2R(gpr.R(d), WA, ~i + j, gpr.R(d));
gpr.Unlock(WA);
break;
}
case CarryFlag::InHostCarry:
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
MOVI2R(WA, ~i + j);
ADC(gpr.R(d), WA, ARM64Reg::WZR);
gpr.Unlock(WA);
break;
}
case CarryFlag::ConstantTrue:
@ -1274,9 +1267,17 @@ void JitArm64::subfex(UGeckoInstruction inst)
else
{
gpr.BindToRegister(d, d == a || d == b);
ARM64Reg RB = mex ? gpr.GetReg() : gpr.R(b);
{
Arm64GPRCache::ScopedARM64Reg RB;
if (mex)
{
RB = gpr.GetScopedReg();
MOVI2R(RB, -1);
}
else
{
RB = gpr.R(b);
}
if (js.carryFlag == CarryFlag::ConstantTrue)
{
@ -1287,10 +1288,9 @@ void JitArm64::subfex(UGeckoInstruction inst)
LoadCarry();
CARRY_IF_NEEDED(SBC, SBCS, gpr.R(d), RB, gpr.R(a));
}
}
ComputeCarry();
if (mex)
gpr.Unlock(RB);
}
if (inst.Rc)
@ -1343,12 +1343,13 @@ void JitArm64::subfzex(UGeckoInstruction inst)
{
case CarryFlag::InPPCState:
{
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
MVN(gpr.R(d), gpr.R(a));
CARRY_IF_NEEDED(ADD, ADDS, gpr.R(d), gpr.R(d), WA);
}
ComputeCarry();
gpr.Unlock(WA);
break;
}
case CarryFlag::InHostCarry:
@ -1394,21 +1395,20 @@ void JitArm64::subfic(UGeckoInstruction inst)
{
const bool will_read = d == a;
const bool is_zero = imm == 0;
const bool allocate_reg = will_read && !is_zero;
gpr.BindToRegister(d, will_read);
// d = imm - a
ARM64Reg RD = gpr.R(d);
ARM64Reg WA = ARM64Reg::WZR;
{
Arm64GPRCache::ScopedARM64Reg WA(ARM64Reg::WZR);
if (!is_zero)
{
WA = will_read ? gpr.GetReg() : RD;
WA = will_read ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(RD);
MOVI2R(WA, imm);
}
CARRY_IF_NEEDED(SUB, SUBS, RD, WA, gpr.R(a));
if (allocate_reg)
gpr.Unlock(WA);
CARRY_IF_NEEDED(SUB, SUBS, RD, WA, gpr.R(a));
}
ComputeCarry();
}
@ -1433,10 +1433,9 @@ void JitArm64::addex(UGeckoInstruction inst)
{
case CarryFlag::InPPCState:
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
ADDI2R(gpr.R(d), WA, i + j, gpr.R(d));
gpr.Unlock(WA);
break;
}
case CarryFlag::InHostCarry:
@ -1477,9 +1476,17 @@ void JitArm64::addex(UGeckoInstruction inst)
else
{
gpr.BindToRegister(d, d == a || d == b);
ARM64Reg RB = mex ? gpr.GetReg() : gpr.R(b);
{
Arm64GPRCache::ScopedARM64Reg RB;
if (mex)
{
RB = gpr.GetScopedReg();
MOVI2R(RB, -1);
}
else
{
RB = gpr.R(b);
}
if (js.carryFlag == CarryFlag::ConstantFalse)
{
@ -1490,10 +1497,9 @@ void JitArm64::addex(UGeckoInstruction inst)
LoadCarry();
CARRY_IF_NEEDED(ADC, ADCS, gpr.R(d), gpr.R(a), RB);
}
}
ComputeCarry();
if (mex)
gpr.Unlock(RB);
}
if (inst.Rc)
@ -1575,7 +1581,7 @@ void JitArm64::divwux(UGeckoInstruction inst)
{
UnsignedMagic m = UnsignedDivisionConstants(divisor);
ARM64Reg WI = allocate_reg ? gpr.GetReg() : RD;
auto WI = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(RD);
ARM64Reg XD = EncodeRegTo64(RD);
MOVI2R(WI, m.multiplier);
@ -1590,9 +1596,6 @@ void JitArm64::divwux(UGeckoInstruction inst)
}
LSR(XD, XD, 32 + m.shift);
if (allocate_reg)
gpr.Unlock(WI);
}
if (inst.Rc)
@ -1719,7 +1722,7 @@ void JitArm64::divwx(UGeckoInstruction inst)
ARM64Reg RA = gpr.R(a);
ARM64Reg RD = gpr.R(d);
ARM64Reg WA = allocate_reg ? gpr.GetReg() : RD;
auto WA = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(RD);
TST(RA, RA);
ADDI2R(WA, RA, abs_val - 1, WA);
@ -1729,9 +1732,6 @@ void JitArm64::divwx(UGeckoInstruction inst)
NEG(RD, WA, ArithOption(WA, ShiftType::ASR, MathUtil::IntLog2(abs_val)));
else
ASR(RD, WA, MathUtil::IntLog2(abs_val));
if (allocate_reg)
gpr.Unlock(WA);
}
else
{
@ -1739,8 +1739,8 @@ void JitArm64::divwx(UGeckoInstruction inst)
SignedMagic m = SignedDivisionConstants(divisor);
ARM64Reg RD = gpr.R(d);
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = allocate_reg ? gpr.GetReg() : RD;
auto WA = gpr.GetScopedReg();
auto WB = allocate_reg ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(RD);
ARM64Reg XD = EncodeRegTo64(RD);
ARM64Reg XA = EncodeRegTo64(WA);
@ -1776,10 +1776,6 @@ void JitArm64::divwx(UGeckoInstruction inst)
ASR(XD, XD, 32 + m.shift);
ADD(RD, WA, RD);
}
gpr.Unlock(WA);
if (allocate_reg)
gpr.Unlock(WB);
}
if (inst.Rc)
@ -1982,8 +1978,7 @@ void JitArm64::srawx(UGeckoInstruction inst)
else
{
gpr.BindToRegister(a, a == s);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
if (a != s)
{
@ -2009,8 +2004,6 @@ void JitArm64::srawx(UGeckoInstruction inst)
CSET(WA, CC_NEQ);
ComputeCarry(WA);
gpr.Unlock(WA);
}
}
else
@ -2018,8 +2011,8 @@ void JitArm64::srawx(UGeckoInstruction inst)
const bool will_read = a == b || a == s;
gpr.BindToRegister(a, will_read);
const bool allocate_reg = will_read || js.op->wantsCA;
ARM64Reg WA = allocate_reg ? gpr.GetReg() : gpr.R(a);
auto WA =
will_read || js.op->wantsCA ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(gpr.R(a));
LSL(EncodeRegTo64(WA), EncodeRegTo64(gpr.R(s)), 32);
ASRV(EncodeRegTo64(WA), EncodeRegTo64(WA), EncodeRegTo64(gpr.R(b)));
@ -2031,9 +2024,6 @@ void JitArm64::srawx(UGeckoInstruction inst)
CSET(WA, CC_NEQ);
ComputeCarry(WA);
}
if (allocate_reg)
gpr.Unlock(WA);
}
if (inst.Rc)
@ -2088,10 +2078,9 @@ void JitArm64::rlwimix(UGeckoInstruction inst)
// No rotation
// No mask inversion
gpr.BindToRegister(a, true);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
UBFX(WA, gpr.R(s), lsb, width);
BFI(gpr.R(a), WA, lsb, width);
gpr.Unlock(WA);
}
else if (inst.SH && inst.MB <= inst.ME)
{
@ -2103,28 +2092,22 @@ void JitArm64::rlwimix(UGeckoInstruction inst)
}
else
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ROR(WA, gpr.R(s), (rot_dist + lsb) % 32);
BFI(gpr.R(a), WA, lsb, width);
gpr.Unlock(WA);
}
}
else
{
gpr.BindToRegister(a, true);
const bool allocate_reg = a == s;
ARM64Reg RA = gpr.R(a);
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = allocate_reg ? gpr.GetReg() : RA;
auto WA = gpr.GetScopedReg();
auto WB = a == s ? gpr.GetScopedReg() : Arm64GPRCache::ScopedARM64Reg(RA);
MOVI2R(WA, mask);
BIC(WB, RA, WA);
AND(WA, WA, gpr.R(s), ArithOption(gpr.R(s), ShiftType::ROR, rot_dist));
ORR(RA, WB, WA);
gpr.Unlock(WA);
if (allocate_reg)
gpr.Unlock(WB);
}
if (inst.Rc)

View file

@ -538,9 +538,12 @@ void JitArm64::lmw(UGeckoInstruction inst)
else
ADDI2R(addr_reg, gpr.R(a), offset, addr_reg);
ARM64Reg addr_base_reg = a_is_addr_base_reg ? ARM64Reg::INVALID_REG : gpr.GetReg();
Arm64RegCache::ScopedARM64Reg addr_base_reg;
if (!a_is_addr_base_reg)
{
addr_base_reg = gpr.GetScopedReg();
MOV(addr_base_reg, addr_reg);
}
BitSet32 gprs_to_discard{};
if (!jo.memcheck)
@ -628,8 +631,6 @@ void JitArm64::lmw(UGeckoInstruction inst)
gpr.Unlock(ARM64Reg::W1, ARM64Reg::W30);
if (jo.memcheck || !jo.fastmem)
gpr.Unlock(ARM64Reg::W0);
if (!a_is_addr_base_reg)
gpr.Unlock(addr_base_reg);
}
void JitArm64::stmw(UGeckoInstruction inst)
@ -655,9 +656,12 @@ void JitArm64::stmw(UGeckoInstruction inst)
else
ADDI2R(addr_reg, gpr.R(a), offset, addr_reg);
ARM64Reg addr_base_reg = a_is_addr_base_reg ? ARM64Reg::INVALID_REG : gpr.GetReg();
Arm64GPRCache::ScopedARM64Reg addr_base_reg;
if (!a_is_addr_base_reg)
{
addr_base_reg = gpr.GetScopedReg();
MOV(addr_base_reg, addr_reg);
}
BitSet32 gprs_to_discard{};
if (!jo.memcheck)
@ -748,8 +752,6 @@ void JitArm64::stmw(UGeckoInstruction inst)
gpr.Unlock(ARM64Reg::W1, ARM64Reg::W2, ARM64Reg::W30);
if (!jo.fastmem)
gpr.Unlock(ARM64Reg::W0);
if (!a_is_addr_base_reg)
gpr.Unlock(addr_base_reg);
}
void JitArm64::dcbx(UGeckoInstruction inst)
@ -786,8 +788,8 @@ void JitArm64::dcbx(UGeckoInstruction inst)
// bdnz afterwards! So if we invalidate a single cache line, we don't adjust the registers at
// all, if we invalidate 2 cachelines we adjust the registers by one step, and so on.
const ARM64Reg reg_cycle_count = gpr.GetReg();
const ARM64Reg reg_downcount = gpr.GetReg();
const auto reg_cycle_count = gpr.GetScopedReg();
const auto reg_downcount = gpr.GetScopedReg();
// Figure out how many loops we want to do.
const u8 cycle_count_per_loop =
@ -855,12 +857,9 @@ void JitArm64::dcbx(UGeckoInstruction inst)
SetJumpTarget(branch_out);
SetJumpTarget(branch_over);
}
gpr.Unlock(reg_cycle_count, reg_downcount);
}
constexpr ARM64Reg effective_addr = WB;
const ARM64Reg physical_addr = gpr.GetReg();
if (a)
ADD(effective_addr, gpr.R(a), gpr.R(b));
@ -874,6 +873,8 @@ void JitArm64::dcbx(UGeckoInstruction inst)
ADD(gpr.R(b), gpr.R(b), WA, ArithOption(WA, ShiftType::LSL, 5)); // Rb += (WA * 32)
}
auto physical_addr = gpr.GetScopedReg();
// Translate effective address to physical address.
const u8* loop_start = GetCodePtr();
FixupBranch bat_lookup_failed;
@ -939,7 +940,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
SwitchToNearCode();
SetJumpTarget(near_addr);
gpr.Unlock(WA, WB, physical_addr);
gpr.Unlock(WA, WB);
if (make_loop)
gpr.Unlock(loop_counter);
}

View file

@ -268,14 +268,14 @@ void JitArm64::stfXX(UGeckoInstruction inst)
const bool have_single = fpr.IsSingle(inst.FS, true);
ARM64Reg V0 =
Arm64FPRCache::ScopedARM64Reg V0 =
fpr.R(inst.FS, want_single && have_single ? RegType::LowerPairSingle : RegType::LowerPair);
if (want_single && !have_single)
{
const ARM64Reg single_reg = fpr.GetReg();
auto single_reg = fpr.GetScopedReg();
ConvertDoubleToSingleLower(inst.FS, single_reg, V0);
V0 = single_reg;
V0 = std::move(single_reg);
}
gpr.Lock(ARM64Reg::W1, ARM64Reg::W2, ARM64Reg::W30);
@ -425,9 +425,6 @@ void JitArm64::stfXX(UGeckoInstruction inst)
MOV(gpr.R(a), addr_reg);
}
if (want_single && !have_single)
fpr.Unlock(V0);
gpr.Unlock(ARM64Reg::W1, ARM64Reg::W2, ARM64Reg::W30);
fpr.Unlock(ARM64Reg::Q0);
if (!jo.fastmem)

View file

@ -173,20 +173,21 @@ void JitArm64::psq_stXX(UGeckoInstruction inst)
const bool have_single = fpr.IsSingle(inst.RS);
ARM64Reg VS = fpr.R(inst.RS, have_single ? RegType::Single : RegType::Register);
Arm64FPRCache::ScopedARM64Reg VS =
fpr.R(inst.RS, have_single ? RegType::Single : RegType::Register);
if (js.assumeNoPairedQuantize)
{
if (!have_single)
{
const ARM64Reg single_reg = fpr.GetReg();
auto single_reg = fpr.GetScopedReg();
if (w)
m_float_emit.FCVT(32, 64, EncodeRegToDouble(single_reg), EncodeRegToDouble(VS));
else
m_float_emit.FCVTN(32, EncodeRegToDouble(single_reg), EncodeRegToDouble(VS));
VS = single_reg;
VS = std::move(single_reg);
}
}
else
@ -279,9 +280,6 @@ void JitArm64::psq_stXX(UGeckoInstruction inst)
MOV(gpr.R(inst.RA), addr_reg);
}
if (js.assumeNoPairedQuantize && !have_single)
fpr.Unlock(VS);
gpr.Unlock(ARM64Reg::W1, ARM64Reg::W2, ARM64Reg::W30);
fpr.Unlock(ARM64Reg::Q0);
if (!js.assumeNoPairedQuantize || !jo.fastmem)

View file

@ -108,16 +108,17 @@ void JitArm64::ps_arith(UGeckoInstruction inst)
const ARM64Reg VC = use_c ? reg_encoder(fpr.R(c, type)) : ARM64Reg::INVALID_REG;
const ARM64Reg VD = reg_encoder(fpr.RW(d, type));
ARM64Reg V0Q = ARM64Reg::INVALID_REG;
ARM64Reg V1Q = ARM64Reg::INVALID_REG;
ARM64Reg V2Q = ARM64Reg::INVALID_REG;
{
Arm64FPRCache::ScopedARM64Reg V0Q = ARM64Reg::INVALID_REG;
Arm64FPRCache::ScopedARM64Reg V1Q = ARM64Reg::INVALID_REG;
Arm64FPRCache::ScopedARM64Reg V2Q = ARM64Reg::INVALID_REG;
ARM64Reg rounded_c_reg = VC;
if (round_c)
{
ASSERT_MSG(DYNA_REC, !singles, "Tried to apply 25-bit precision to single");
V0Q = fpr.GetReg();
V0Q = fpr.GetScopedReg();
rounded_c_reg = reg_encoder(V0Q);
Force25BitPrecision(rounded_c_reg, VC);
}
@ -126,7 +127,7 @@ void JitArm64::ps_arith(UGeckoInstruction inst)
if (fma && inaccurate_fma && VD == VB)
{
if (V0Q == ARM64Reg::INVALID_REG)
V0Q = fpr.GetReg();
V0Q = fpr.GetScopedReg();
inaccurate_fma_reg = reg_encoder(V0Q);
}
@ -137,17 +138,17 @@ void JitArm64::ps_arith(UGeckoInstruction inst)
m_accurate_nans && (VD == VA || (use_b && VD == VB) || (use_c && VD == VC));
if (need_accurate_fma_reg || preserve_d)
{
V1Q = fpr.GetReg();
V1Q = fpr.GetScopedReg();
result_reg = reg_encoder(V1Q);
}
if (m_accurate_nans)
{
if (V0Q == ARM64Reg::INVALID_REG)
V0Q = fpr.GetReg();
V0Q = fpr.GetScopedReg();
if (duplicated_c || VD == result_reg)
V2Q = fpr.GetReg();
V2Q = fpr.GetScopedReg();
}
switch (op5)
@ -295,13 +296,7 @@ void JitArm64::ps_arith(UGeckoInstruction inst)
if (m_accurate_nans)
SetJumpTarget(nan_fixup);
if (V0Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V0Q);
if (V1Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V1Q);
if (V2Q != ARM64Reg::INVALID_REG)
fpr.Unlock(V2Q);
}
ASSERT_MSG(DYNA_REC, singles == singles_func(),
"Register allocation turned singles into doubles in the middle of ps_arith");
@ -339,12 +334,11 @@ void JitArm64::ps_sel(UGeckoInstruction inst)
}
else
{
const ARM64Reg V0Q = fpr.GetReg();
const auto V0Q = fpr.GetScopedReg();
const ARM64Reg V0 = reg_encoder(V0Q);
m_float_emit.FCMGE(size, V0, VA);
m_float_emit.BSL(V0, VC, VB);
m_float_emit.MOV(VD, V0);
fpr.Unlock(V0Q);
}
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c)),
@ -375,16 +369,21 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
const ARM64Reg VB = fpr.R(b, type);
const ARM64Reg VC = fpr.R(c, type);
const ARM64Reg VD = fpr.RW(d, type);
const ARM64Reg V0 = fpr.GetReg();
{
const auto V0 = fpr.GetScopedReg();
m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(VB), 1);
if (m_accurate_nans)
{
// If the first input is NaN, set the temp register for the second input to 0. This is because:
// If the first input is NaN, set the temp register for the second input to 0. This is
// because:
//
// - If the second input is also NaN, setting it to 0 ensures that the first NaN will be picked.
// - If only the first input is NaN, setting the second input to 0 has no effect on the result.
// - If the second input is also NaN, setting it to 0 ensures that the first NaN will be
// picked.
// - If only the first input is NaN, setting the second input to 0 has no effect on the
// result.
//
// Either way, we can then do an FADD as usual, and the FADD will make the NaN quiet.
m_float_emit.FCMP(scalar_reg_encoder(VA));
@ -408,8 +407,7 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
m_float_emit.FADD(scalar_reg_encoder(V0), scalar_reg_encoder(V0), scalar_reg_encoder(VA));
m_float_emit.INS(size, VD, 0, V0, 0);
}
fpr.Unlock(V0);
}
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c)),
"Register allocation turned singles into doubles in the middle of ps_sumX");

View file

@ -254,18 +254,26 @@ void Arm64GPRCache::FlushRegisters(BitSet32 regs, FlushMode mode, ARM64Reg tmp_r
// We've got two guest registers in a row to store
OpArg& reg1 = m_guest_registers[GUEST_GPR_OFFSET + i];
OpArg& reg2 = m_guest_registers[GUEST_GPR_OFFSET + i + 1];
if (reg1.IsDirty() && reg2.IsDirty() && reg1.GetType() == RegType::Register &&
reg2.GetType() == RegType::Register)
const bool reg1_imm = reg1.GetType() == RegType::Immediate;
const bool reg2_imm = reg2.GetType() == RegType::Immediate;
const bool reg1_zero = reg1_imm && reg1.GetImm() == 0;
const bool reg2_zero = reg2_imm && reg2.GetImm() == 0;
const bool flush_all = mode == FlushMode::All;
if (reg1.IsDirty() && reg2.IsDirty() &&
(reg1.GetType() == RegType::Register || (reg1_imm && (reg1_zero || flush_all))) &&
(reg2.GetType() == RegType::Register || (reg2_imm && (reg2_zero || flush_all))))
{
const size_t ppc_offset = GetGuestByIndex(i).ppc_offset;
if (ppc_offset <= 252)
{
ARM64Reg RX1 = R(GetGuestByIndex(i));
ARM64Reg RX2 = R(GetGuestByIndex(i + 1));
ARM64Reg RX1 = reg1_zero ? ARM64Reg::WZR : R(GetGuestByIndex(i));
ARM64Reg RX2 = reg2_zero ? ARM64Reg::WZR : R(GetGuestByIndex(i + 1));
m_emit->STP(IndexType::Signed, RX1, RX2, PPC_REG, u32(ppc_offset));
if (mode == FlushMode::All)
if (flush_all)
{
if (!reg1_zero)
UnlockRegister(EncodeRegTo32(RX1));
if (!reg2_zero)
UnlockRegister(EncodeRegTo32(RX2));
reg1.Flush();
reg2.Flush();

View file

@ -177,6 +177,59 @@ public:
// Requires unlocking after done
Arm64Gen::ARM64Reg GetReg();
class ScopedARM64Reg
{
public:
inline ScopedARM64Reg() = default;
ScopedARM64Reg(const ScopedARM64Reg&) = delete;
explicit inline ScopedARM64Reg(Arm64RegCache& cache) : m_reg(cache.GetReg()), m_gpr(&cache) {}
inline ScopedARM64Reg(Arm64Gen::ARM64Reg reg) : m_reg(reg) {}
inline ScopedARM64Reg(ScopedARM64Reg&& scoped_reg) { *this = std::move(scoped_reg); }
inline ~ScopedARM64Reg() { Unlock(); }
inline ScopedARM64Reg& operator=(const ScopedARM64Reg&) = delete;
inline ScopedARM64Reg& operator=(Arm64Gen::ARM64Reg reg)
{
Unlock();
m_reg = reg;
return *this;
}
inline ScopedARM64Reg& operator=(ScopedARM64Reg&& scoped_reg)
{
// Taking ownership of an existing scoped register, no need to release.
m_reg = scoped_reg.m_reg;
m_gpr = scoped_reg.m_gpr;
scoped_reg.Invalidate();
return *this;
}
inline Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
inline operator Arm64Gen::ARM64Reg() const { return GetReg(); }
inline void Unlock()
{
// Only unlock the register if GPR is set.
if (m_gpr != nullptr)
{
m_gpr->Unlock(m_reg);
}
Invalidate();
}
private:
inline void Invalidate()
{
m_reg = Arm64Gen::ARM64Reg::INVALID_REG;
m_gpr = nullptr;
}
Arm64Gen::ARM64Reg m_reg = Arm64Gen::ARM64Reg::INVALID_REG;
Arm64RegCache* m_gpr = nullptr;
};
// Returns a temporary register
// Unlocking is implicitly handled through RAII
inline ScopedARM64Reg GetScopedReg() { return ScopedARM64Reg(*this); }
void UpdateLastUsed(BitSet32 regs_used);
// Get available host registers

View file

@ -48,17 +48,16 @@ void JitArm64::FixGTBeforeSettingCRFieldBit(Arm64Gen::ARM64Reg reg)
// if the internal representation either has bit 63 set or has all bits set to zero.
// If all bits are zero and we set some bit that's unrelated to GT, we need to set bit 63 so GT
// doesn't accidentally become considered set. Gross but necessary; this can break actual games.
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
ORR(XA, reg, LogicalImm(1ULL << 63, GPRSize::B64));
CMP(reg, ARM64Reg::ZR);
CSEL(reg, reg, XA, CC_NEQ);
gpr.Unlock(WA);
}
void JitArm64::UpdateFPExceptionSummary(ARM64Reg fpscr)
{
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
// fpscr.VX = (fpscr & FPSCR_VX_ANY) != 0
MOVI2R(WA, FPSCR_VX_ANY);
@ -71,8 +70,6 @@ void JitArm64::UpdateFPExceptionSummary(ARM64Reg fpscr)
TST(WA, fpscr, ArithOption(fpscr, ShiftType::LSR, 22));
CSET(WA, CCFlags::CC_NEQ);
BFI(fpscr, WA, MathUtil::IntLog2(FPSCR_FEX), 1);
gpr.Unlock(WA);
}
void JitArm64::UpdateRoundingMode()
@ -135,7 +132,7 @@ void JitArm64::mcrxr(UGeckoInstruction inst)
JITDISABLE(bJITSystemRegistersOff);
gpr.BindCRToRegister(inst.CRFD, false);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = gpr.CR(inst.CRFD);
ARM64Reg WB = EncodeRegTo32(XB);
@ -155,8 +152,6 @@ void JitArm64::mcrxr(UGeckoInstruction inst)
// Clear XER[0-3]
static_assert(PPCSTATE_OFF(xer_ca) + 1 == PPCSTATE_OFF(xer_so_ov));
STRH(IndexType::Unsigned, ARM64Reg::WZR, PPC_REG, PPCSTATE_OFF(xer_ca));
gpr.Unlock(WA);
}
void JitArm64::mfsr(UGeckoInstruction inst)
@ -186,14 +181,12 @@ void JitArm64::mfsrin(UGeckoInstruction inst)
ARM64Reg RB = gpr.R(b);
ARM64Reg RD = gpr.R(d);
ARM64Reg index = gpr.GetReg();
auto index = gpr.GetScopedReg();
ARM64Reg addr = EncodeRegTo64(RD);
UBFM(index, RB, 28, 31);
ADDI2R(addr, PPC_REG, PPCSTATE_OFF_SR(0), addr);
LDR(RD, addr, ArithOption(EncodeRegTo64(index), true));
gpr.Unlock(index);
}
void JitArm64::mtsrin(UGeckoInstruction inst)
@ -206,14 +199,12 @@ void JitArm64::mtsrin(UGeckoInstruction inst)
ARM64Reg RB = gpr.R(b);
ARM64Reg RD = gpr.R(d);
ARM64Reg index = gpr.GetReg();
ARM64Reg addr = gpr.GetReg();
auto index = gpr.GetScopedReg();
auto addr = gpr.GetScopedReg();
UBFM(index, RB, 28, 31);
ADDI2R(EncodeRegTo64(addr), PPC_REG, PPCSTATE_OFF_SR(0), EncodeRegTo64(addr));
STR(RD, EncodeRegTo64(addr), ArithOption(EncodeRegTo64(index), true));
gpr.Unlock(index, addr);
}
void JitArm64::twx(UGeckoInstruction inst)
@ -223,7 +214,7 @@ void JitArm64::twx(UGeckoInstruction inst)
s32 a = inst.RA;
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
if (inst.OPCD == 3) // twi
{
@ -278,8 +269,6 @@ void JitArm64::twx(UGeckoInstruction inst)
fpr.Flush(FlushMode::All, ARM64Reg::INVALID_REG);
WriteExit(js.compilerPC + 4);
}
gpr.Unlock(WA);
}
void JitArm64::mfspr(UGeckoInstruction inst)
@ -294,19 +283,19 @@ void JitArm64::mfspr(UGeckoInstruction inst)
case SPR_TL:
case SPR_TU:
{
ARM64Reg Wg = gpr.GetReg();
auto Wg = gpr.GetScopedReg();
ARM64Reg Xg = EncodeRegTo64(Wg);
ARM64Reg Wresult = gpr.GetReg();
auto Wresult = gpr.GetScopedReg();
ARM64Reg Xresult = EncodeRegTo64(Wresult);
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = gpr.GetReg();
auto WA = gpr.GetScopedReg();
auto WB = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = EncodeRegTo64(WB);
ARM64Reg VC = fpr.GetReg();
ARM64Reg VD = fpr.GetReg();
auto VC = fpr.GetScopedReg();
auto VD = fpr.GetScopedReg();
ARM64Reg SC = EncodeRegToSingle(VC);
ARM64Reg SD = EncodeRegToSingle(VD);
@ -371,8 +360,6 @@ void JitArm64::mfspr(UGeckoInstruction inst)
else
LSR(EncodeRegTo64(gpr.R(n)), Xresult, 32);
gpr.Unlock(Wg, Wresult, WA, WB);
fpr.Unlock(VC, VD);
break;
}
}
@ -381,22 +368,18 @@ void JitArm64::mfspr(UGeckoInstruction inst)
LSR(EncodeRegTo64(gpr.R(d)), Xresult, 32);
else
MOV(gpr.R(d), Wresult);
gpr.Unlock(Wg, Wresult, WA, WB);
fpr.Unlock(VC, VD);
}
break;
case SPR_XER:
{
gpr.BindToRegister(d, false);
ARM64Reg RD = gpr.R(d);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
LDRH(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_stringctrl));
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
ORR(RD, RD, WA, ArithOption(WA, ShiftType::LSL, XER_CA_SHIFT));
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov));
ORR(RD, RD, WA, ArithOption(WA, ShiftType::LSL, XER_OV_SHIFT));
gpr.Unlock(WA);
}
break;
case SPR_WPAR:
@ -462,14 +445,13 @@ void JitArm64::mtspr(UGeckoInstruction inst)
case SPR_XER:
{
ARM64Reg RD = gpr.R(inst.RD);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
AND(WA, RD, LogicalImm(0xFFFFFF7F, GPRSize::B32));
STRH(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_stringctrl));
UBFM(WA, RD, XER_CA_SHIFT, XER_CA_SHIFT + 1);
STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
UBFM(WA, RD, XER_OV_SHIFT, 31); // Same as WA = RD >> XER_OV_SHIFT
STRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov));
gpr.Unlock(WA);
}
break;
default:
@ -553,9 +535,10 @@ void JitArm64::crXXX(UGeckoInstruction inst)
return;
}
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg WB = gpr.GetReg();
{
auto WB = gpr.GetScopedReg();
ARM64Reg XB = EncodeRegTo64(WB);
// creqv or crnand or crnor
@ -623,44 +606,41 @@ void JitArm64::crXXX(UGeckoInstruction inst)
ORR(XA, XA, XB);
break;
}
}
// Store result bit in CRBD
int field = inst.CRBD >> 2;
int bit = 3 - (inst.CRBD & 3);
gpr.Unlock(WB);
WB = ARM64Reg::INVALID_REG;
gpr.BindCRToRegister(field, true);
XB = gpr.CR(field);
ARM64Reg CR = gpr.CR(field);
if (bit != PowerPC::CR_GT_BIT)
FixGTBeforeSettingCRFieldBit(XB);
FixGTBeforeSettingCRFieldBit(CR);
switch (bit)
{
case PowerPC::CR_SO_BIT: // set bit 59 to input
BFI(XB, XA, PowerPC::CR_EMU_SO_BIT, 1);
BFI(CR, XA, PowerPC::CR_EMU_SO_BIT, 1);
break;
case PowerPC::CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input
AND(XB, XB, LogicalImm(0xFFFF'FFFF'0000'0000, GPRSize::B64));
AND(CR, CR, LogicalImm(0xFFFF'FFFF'0000'0000, GPRSize::B64));
EOR(XA, XA, LogicalImm(1, GPRSize::B64));
ORR(XB, XB, XA);
ORR(CR, CR, XA);
break;
case PowerPC::CR_GT_BIT: // set bit 63 to !input
EOR(XA, XA, LogicalImm(1, GPRSize::B64));
BFI(XB, XA, 63, 1);
BFI(CR, XA, 63, 1);
break;
case PowerPC::CR_LT_BIT: // set bit 62 to input
BFI(XB, XA, PowerPC::CR_EMU_LT_BIT, 1);
BFI(CR, XA, PowerPC::CR_EMU_LT_BIT, 1);
break;
}
ORR(XB, XB, LogicalImm(1ULL << 32, GPRSize::B64));
gpr.Unlock(WA);
ORR(CR, CR, LogicalImm(1ULL << 32, GPRSize::B64));
}
void JitArm64::mfcr(UGeckoInstruction inst)
@ -670,8 +650,8 @@ void JitArm64::mfcr(UGeckoInstruction inst)
gpr.BindToRegister(inst.RD, false);
ARM64Reg WA = gpr.R(inst.RD);
ARM64Reg WB = gpr.GetReg();
ARM64Reg WC = gpr.GetReg();
auto WB = gpr.GetScopedReg();
auto WC = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = EncodeRegTo64(WB);
ARM64Reg XC = EncodeRegTo64(WC);
@ -716,8 +696,6 @@ void JitArm64::mfcr(UGeckoInstruction inst)
else if (!js.op->crInUse[i])
gpr.StoreCRRegisters(BitSet8{i}, WC);
}
gpr.Unlock(WB, WC);
}
void JitArm64::mtcrf(UGeckoInstruction inst)
@ -729,7 +707,7 @@ void JitArm64::mtcrf(UGeckoInstruction inst)
if (crm != 0)
{
ARM64Reg RS = gpr.R(inst.RS);
ARM64Reg WB = gpr.GetReg();
auto WB = gpr.GetScopedReg();
ARM64Reg XB = EncodeRegTo64(WB);
MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data());
for (int i = 0; i < 8; ++i)
@ -753,7 +731,6 @@ void JitArm64::mtcrf(UGeckoInstruction inst)
LDR(CR, XB, ArithOption(CR, true));
}
}
gpr.Unlock(WB);
}
}
@ -771,7 +748,7 @@ void JitArm64::mcrfs(UGeckoInstruction inst)
gpr.BindCRToRegister(field, false);
ARM64Reg CR = gpr.CR(field);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg WCR = EncodeRegTo32(CR);
ARM64Reg XA = EncodeRegTo64(WA);
@ -789,8 +766,6 @@ void JitArm64::mcrfs(UGeckoInstruction inst)
MOVP2R(XA, PowerPC::ConditionRegister::s_crTable.data());
LDR(CR, XA, ArithOption(CR, true));
gpr.Unlock(WA);
}
void JitArm64::mffsx(UGeckoInstruction inst)
@ -799,7 +774,7 @@ void JitArm64::mffsx(UGeckoInstruction inst)
JITDISABLE(bJITSystemRegistersOff);
FALLBACK_IF(inst.Rc);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
ARM64Reg XA = EncodeRegTo64(WA);
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
@ -808,8 +783,6 @@ void JitArm64::mffsx(UGeckoInstruction inst)
ORR(XA, XA, LogicalImm(0xFFF8'0000'0000'0000, GPRSize::B64));
m_float_emit.FMOV(EncodeRegToDouble(VD), XA);
gpr.Unlock(WA);
}
void JitArm64::mtfsb0x(UGeckoInstruction inst)
@ -824,7 +797,8 @@ void JitArm64::mtfsb0x(UGeckoInstruction inst)
if (mask == FPSCR_FEX || mask == FPSCR_VX)
return;
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
@ -833,8 +807,7 @@ void JitArm64::mtfsb0x(UGeckoInstruction inst)
if ((mask & (FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
}
if (inst.CRBD >= 29)
UpdateRoundingMode();
@ -852,25 +825,24 @@ void JitArm64::mtfsb1x(UGeckoInstruction inst)
if (mask == FPSCR_FEX || mask == FPSCR_VX)
return;
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
if ((mask & FPSCR_ANY_X) != 0)
{
ARM64Reg WB = gpr.GetReg();
auto WB = gpr.GetScopedReg();
TST(WA, LogicalImm(mask, GPRSize::B32));
ORR(WB, WA, LogicalImm(1 << 31, GPRSize::B32));
CSEL(WA, WA, WB, CCFlags::CC_NEQ);
gpr.Unlock(WB);
}
ORR(WA, WA, LogicalImm(mask, GPRSize::B32));
if ((mask & (FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
}
if (inst.CRBD >= 29)
UpdateRoundingMode();
@ -887,7 +859,8 @@ void JitArm64::mtfsfix(UGeckoInstruction inst)
u8 shift = 28 - 4 * inst.CRFD;
u32 mask = 0xF << shift;
ARM64Reg WA = gpr.GetReg();
{
auto WA = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
@ -902,17 +875,15 @@ void JitArm64::mtfsfix(UGeckoInstruction inst)
}
else
{
ARM64Reg WB = gpr.GetReg();
auto WB = gpr.GetScopedReg();
MOVZ(WB, imm);
BFI(WA, WB, shift, 4);
gpr.Unlock(WB);
}
if ((mask & (FPSCR_FEX | FPSCR_VX | FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
}
// Field 7 contains NI and RN.
if (inst.CRFD == 7)
@ -936,20 +907,19 @@ void JitArm64::mtfsfx(UGeckoInstruction inst)
if (mask == 0xFFFFFFFF)
{
ARM64Reg VB = fpr.R(inst.FB, RegType::LowerPair);
ARM64Reg WA = gpr.GetReg();
auto WA = gpr.GetScopedReg();
m_float_emit.FMOV(WA, EncodeRegToSingle(VB));
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
}
else if (mask != 0)
{
ARM64Reg VB = fpr.R(inst.FB, RegType::LowerPair);
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = gpr.GetReg();
auto WA = gpr.GetScopedReg();
{
auto WB = gpr.GetScopedReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
m_float_emit.FMOV(WB, EncodeRegToSingle(VB));
@ -962,23 +932,18 @@ void JitArm64::mtfsfx(UGeckoInstruction inst)
}
else
{
ARM64Reg WC = gpr.GetReg();
auto WC = gpr.GetScopedReg();
MOVI2R(WC, mask);
BIC(WA, WA, WC);
AND(WB, WB, WC);
gpr.Unlock(WC);
}
ORR(WA, WA, WB);
gpr.Unlock(WB);
}
if ((mask & (FPSCR_FEX | FPSCR_VX | FPSCR_ANY_X | FPSCR_ANY_E)) != 0)
UpdateFPExceptionSummary(WA);
STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr));
gpr.Unlock(WA);
}
if (inst.FM & 1)

View file

@ -86,7 +86,7 @@ void Host_UpdateDisasmDialog()
{
}
void Host_JitCacheCleared()
void Host_JitCacheInvalidation()
{
}

View file

@ -21,6 +21,7 @@
#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h"
@ -36,7 +37,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(QWidget* parent) : QWidget(
// If hardcore is enabled when the emulator starts, make sure it turns off what it needs to
if (Config::Get(Config::RA_HARDCORE_ENABLED))
ToggleHardcore();
UpdateHardcoreMode();
}
void AchievementSettingsWidget::UpdateData(int login_failed_code)
@ -258,11 +259,7 @@ void AchievementSettingsWidget::ToggleRAIntegration()
instance.Init();
else
instance.Shutdown();
if (Config::Get(Config::RA_HARDCORE_ENABLED))
{
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
emit Settings::Instance().HardcoreStateChanged();
}
UpdateHardcoreMode();
}
void AchievementSettingsWidget::Login()
@ -275,25 +272,32 @@ void AchievementSettingsWidget::Login()
}
void AchievementSettingsWidget::Logout()
{
auto confirm = ModalMessageBox::question(
this, tr("Confirm Logout"), tr("Are you sure you want to log out of RetroAchievements?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal);
if (confirm == QMessageBox::Yes)
{
AchievementManager::GetInstance().Logout();
SaveSettings();
}
}
void AchievementSettingsWidget::ToggleHardcore()
{
SaveSettings();
AchievementManager::GetInstance().SetHardcoreMode();
if (Config::Get(Config::RA_HARDCORE_ENABLED))
{
if (Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f)
Config::SetBaseOrCurrent(Config::MAIN_EMULATION_SPEED, 1.0f);
Config::SetBaseOrCurrent(Config::FREE_LOOK_ENABLED, false);
Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, false);
Settings::Instance().SetDebugModeEnabled(false);
auto confirm = ModalMessageBox::question(
this, tr("Confirm Hardcore Off"), tr("Are you sure you want to turn hardcore mode off?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal);
if (confirm != QMessageBox::Yes)
{
SignalBlocking(m_common_hardcore_enabled_input)->setChecked(true);
return;
}
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
emit Settings::Instance().HardcoreStateChanged();
}
SaveSettings();
UpdateHardcoreMode();
}
void AchievementSettingsWidget::ToggleUnofficial()
@ -323,4 +327,15 @@ void AchievementSettingsWidget::ToggleProgress()
SaveSettings();
}
void AchievementSettingsWidget::UpdateHardcoreMode()
{
AchievementManager::GetInstance().SetHardcoreMode();
if (Config::Get(Config::RA_HARDCORE_ENABLED))
{
Settings::Instance().SetDebugModeEnabled(false);
}
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
emit Settings::Instance().HardcoreStateChanged();
}
#endif // USE_RETRO_ACHIEVEMENTS

View file

@ -39,6 +39,8 @@ private:
void ToggleDiscordPresence();
void ToggleProgress();
void UpdateHardcoreMode();
QGroupBox* m_common_box;
QVBoxLayout* m_common_layout;
ToolTipCheckBox* m_common_integration_enabled_input;

View file

@ -318,6 +318,8 @@ add_executable(dolphin-mpn
QtUtils/ParallelProgressDialog.h
QtUtils/PartiallyClosableTabWidget.cpp
QtUtils/PartiallyClosableTabWidget.h
QtUtils/QtUtils.cpp
QtUtils/QtUtils.h
QtUtils/SetWindowDecorations.cpp
QtUtils/SetWindowDecorations.h
QtUtils/SignalBlocking.h

View file

@ -140,20 +140,14 @@ void ARCodeWidget::SortAlphabetically()
void ARCodeWidget::SortEnabledCodesFirst()
{
std::stable_sort(m_ar_codes.begin(), m_ar_codes.end(), [](const auto& a, const auto& b) {
return a.enabled && a.enabled != b.enabled;
});
std::ranges::stable_partition(m_ar_codes, std::identity{}, &ActionReplay::ARCode::enabled);
UpdateList();
SaveCodes();
}
void ARCodeWidget::SortDisabledCodesFirst()
{
std::stable_sort(m_ar_codes.begin(), m_ar_codes.end(), [](const auto& a, const auto& b) {
return !a.enabled && a.enabled != b.enabled;
});
std::ranges::stable_partition(m_ar_codes, std::logical_not{}, &ActionReplay::ARCode::enabled);
UpdateList();
SaveCodes();
}

View file

@ -317,20 +317,14 @@ void GeckoCodeWidget::SortAlphabetically()
void GeckoCodeWidget::SortEnabledCodesFirst()
{
std::stable_sort(m_gecko_codes.begin(), m_gecko_codes.end(), [](const auto& a, const auto& b) {
return a.enabled && a.enabled != b.enabled;
});
std::ranges::stable_partition(m_gecko_codes, std::identity{}, &Gecko::GeckoCode::enabled);
UpdateList();
SaveCodes();
}
void GeckoCodeWidget::SortDisabledCodesFirst()
{
std::stable_sort(m_gecko_codes.begin(), m_gecko_codes.end(), [](const auto& a, const auto& b) {
return !a.enabled && a.enabled != b.enabled;
});
std::ranges::stable_partition(m_gecko_codes, std::logical_not{}, &Gecko::GeckoCode::enabled);
UpdateList();
SaveCodes();
}

View file

@ -241,7 +241,7 @@ void GeneralWidget::AddDescriptions()
"recommended. Different games and different GPUs will behave differently on each "
"backend, so for the best emulation experience it is recommended to try each and "
"select the backend that is least problematic.<br><br><dolphin_emphasis>If unsure, "
"select OpenGL.</dolphin_emphasis>");
"select %1.</dolphin_emphasis>");
static const char TR_FULLSCREEN_DESCRIPTION[] =
QT_TR_NOOP("Uses the entire screen for rendering.<br><br>If disabled, a "
"render window will be created instead.<br><br><dolphin_emphasis>If "
@ -313,7 +313,9 @@ void GeneralWidget::AddDescriptions()
"unsure, leave this unchecked.</dolphin_emphasis>");
m_backend_combo->SetTitle(tr("Backend"));
m_backend_combo->SetDescription(tr(TR_BACKEND_DESCRIPTION));
m_backend_combo->SetDescription(
tr(TR_BACKEND_DESCRIPTION)
.arg(QString::fromStdString(VideoBackendBase::GetDefaultBackendDisplayName())));
m_adapter_combo->SetTitle(tr("Adapter"));

View file

@ -223,7 +223,7 @@ void HacksWidget::AddDescriptions()
"Ignores any requests from the CPU to read from or write to the EFB. "
"<br><br>Improves performance in some games, but will disable all EFB-based "
"graphical effects or gameplay-related features.<br><br><dolphin_emphasis>If unsure, "
"leave this unchecked.</dolphin_emphasis>");
"leave this checked.</dolphin_emphasis>");
static const char TR_IGNORE_FORMAT_CHANGE_DESCRIPTION[] = QT_TR_NOOP(
"Ignores any changes to the EFB format.<br><br>Improves performance in many games "
"without "

View file

@ -313,7 +313,7 @@ void JITWidget::SaveQSettings() const
void JITWidget::ConnectSlots()
{
auto* const host = Host::GetInstance();
connect(host, &Host::JitCacheCleared, this, &JITWidget::OnJitCacheCleared);
connect(host, &Host::JitCacheInvalidation, this, &JITWidget::OnJitCacheInvalidation);
connect(host, &Host::UpdateDisasmDialog, this, &JITWidget::OnUpdateDisasmDialog);
connect(host, &Host::PPCSymbolsChanged, this, &JITWidget::OnPPCSymbolsUpdated);
connect(host, &Host::PPCBreakpointsChanged, this, &JITWidget::OnPPCBreakpointsChanged);
@ -326,7 +326,7 @@ void JITWidget::ConnectSlots()
void JITWidget::DisconnectSlots()
{
auto* const host = Host::GetInstance();
disconnect(host, &Host::JitCacheCleared, this, &JITWidget::OnJitCacheCleared);
disconnect(host, &Host::JitCacheInvalidation, this, &JITWidget::OnJitCacheInvalidation);
disconnect(host, &Host::UpdateDisasmDialog, this, &JITWidget::OnUpdateDisasmDialog);
disconnect(host, &Host::PPCSymbolsChanged, this, &JITWidget::OnPPCSymbolsUpdated);
disconnect(host, &Host::PPCBreakpointsChanged, this, &JITWidget::OnPPCBreakpointsChanged);
@ -340,7 +340,7 @@ void JITWidget::Show()
{
ConnectSlots();
// Handle every slot that may have missed a signal while this widget was hidden.
// OnJitCacheCleared() can be skipped.
// OnJitCacheInvalidation() can be skipped.
// OnUpdateDisasmDialog() can be skipped.
// OnPPCSymbolsUpdated() can be skipped.
// OnPPCBreakpointsChanged() can be skipped.
@ -446,7 +446,7 @@ void JITWidget::OnStatusBarPressed()
ShowFreeMemoryStatus();
}
void JITWidget::OnJitCacheCleared()
void JITWidget::OnJitCacheInvalidation()
{
if (Core::GetState(m_system) != Core::State::Paused)
return;

View file

@ -102,7 +102,7 @@ private:
void OnStatusBarPressed();
// Conditionally connected slots (external signals)
void OnJitCacheCleared();
void OnJitCacheInvalidation();
void OnUpdateDisasmDialog();
void OnPPCSymbolsUpdated();
void OnPPCBreakpointsChanged();

View file

@ -112,7 +112,7 @@ void JitBlockTableModel::UpdateSymbols()
void JitBlockTableModel::ConnectSlots()
{
auto* const host = Host::GetInstance();
connect(host, &Host::JitCacheCleared, this, &JitBlockTableModel::OnJitCacheCleared);
connect(host, &Host::JitCacheInvalidation, this, &JitBlockTableModel::OnJitCacheInvalidation);
connect(host, &Host::JitProfileDataWiped, this, &JitBlockTableModel::OnJitProfileDataWiped);
connect(host, &Host::UpdateDisasmDialog, this, &JitBlockTableModel::OnUpdateDisasmDialog);
connect(host, &Host::PPCSymbolsChanged, this, &JitBlockTableModel::OnPPCSymbolsUpdated);
@ -125,7 +125,7 @@ void JitBlockTableModel::ConnectSlots()
void JitBlockTableModel::DisconnectSlots()
{
auto* const host = Host::GetInstance();
disconnect(host, &Host::JitCacheCleared, this, &JitBlockTableModel::OnJitCacheCleared);
disconnect(host, &Host::JitCacheInvalidation, this, &JitBlockTableModel::OnJitCacheInvalidation);
disconnect(host, &Host::JitProfileDataWiped, this, &JitBlockTableModel::OnJitProfileDataWiped);
disconnect(host, &Host::UpdateDisasmDialog, this, &JitBlockTableModel::OnUpdateDisasmDialog);
disconnect(host, &Host::PPCSymbolsChanged, this, &JitBlockTableModel::OnPPCSymbolsUpdated);
@ -169,7 +169,7 @@ void JitBlockTableModel::OnFilterSymbolTextChanged(const QString& string)
m_filtering_by_symbols = !string.isEmpty();
}
void JitBlockTableModel::OnJitCacheCleared()
void JitBlockTableModel::OnJitCacheInvalidation()
{
Update(Core::GetState(m_system));
}
@ -187,7 +187,9 @@ void JitBlockTableModel::OnUpdateDisasmDialog()
void JitBlockTableModel::OnPPCSymbolsUpdated()
{
UpdateSymbols();
// Previously, this was only a call to `UpdateSymbols`, but HLE patch engine code can
// invalidate JIT blocks when specific symbols are loaded. What can be done about it?
Update(Core::GetState(m_system));
}
void JitBlockTableModel::OnPPCBreakpointsChanged()

View file

@ -106,7 +106,7 @@ private:
void Hide();
// Conditionally connected slots (external signals)
void OnJitCacheCleared();
void OnJitCacheInvalidation();
void OnJitProfileDataWiped();
void OnUpdateDisasmDialog();
void OnPPCSymbolsUpdated();

View file

@ -205,6 +205,7 @@
<ClCompile Include="QtUtils\ModalMessageBox.cpp" />
<ClCompile Include="QtUtils\NonDefaultQPushButton.cpp" />
<ClCompile Include="QtUtils\PartiallyClosableTabWidget.cpp" />
<ClCompile Include="QtUtils\QtUtils.cpp" />
<ClCompile Include="QtUtils\SetWindowDecorations.cpp" />
<ClCompile Include="QtUtils\UTF8CodePointCountValidator.cpp" />
<ClCompile Include="QtUtils\WindowActivationEventFilter.cpp" />
@ -412,6 +413,7 @@
<ClInclude Include="QtUtils\FromStdString.h" />
<QtMoc Include="QtUtils\ParallelProgressDialog.h" />
<QtMoc Include="QtUtils\PartiallyClosableTabWidget.h" />
<ClInclude Include="QtUtils\QtUtils.h" />
<ClInclude Include="QtUtils\SetWindowDecorations.h" />
<QtMoc Include="QtUtils\UTF8CodePointCountValidator.h" />
<QtMoc Include="QtUtils\WindowActivationEventFilter.h" />

View file

@ -256,9 +256,9 @@ void Host_UpdateDisasmDialog()
QueueOnObject(QApplication::instance(), [] { emit Host::GetInstance()->UpdateDisasmDialog(); });
}
void Host_JitCacheCleared()
void Host_JitCacheInvalidation()
{
QueueOnObject(QApplication::instance(), [] { emit Host::GetInstance()->JitCacheCleared(); });
QueueOnObject(QApplication::instance(), [] { emit Host::GetInstance()->JitCacheInvalidation(); });
}
void Host_JitProfileDataWiped()

View file

@ -40,7 +40,7 @@ signals:
void RequestStop();
void RequestRenderSize(int w, int h);
void UpdateDisasmDialog();
void JitCacheCleared();
void JitCacheInvalidation();
void JitProfileDataWiped();
void PPCSymbolsChanged();
void PPCBreakpointsChanged();

View file

@ -257,7 +257,8 @@ int main(int argc, char* argv[])
Settings::Instance().InitDefaultPalette();
Settings::Instance().ApplyStyle();
MainWindow win{std::move(boot), static_cast<const char*>(options.get("movie"))};
MainWindow win{Core::System::GetInstance(), std::move(boot),
static_cast<const char*>(options.get("movie"))};

View file

@ -67,6 +67,7 @@
#include "Core/State.h"
#include "Core/System.h"
#include "Core/WiiUtils.h"
#include "DiscIO/DirectoryBlob.h"
#include "DiscIO/NANDImporter.h"
#include "DiscIO/RiivolutionPatcher.h"
@ -80,7 +81,6 @@
#include "DolphinQt/Config/LogConfigWidget.h"
#include "DolphinQt/Config/LogWidget.h"
#include "DolphinQt/Config/Mapping/MappingWindow.h"
#include "DolphinQt/Config/PropertiesDialog.h"
#include "DolphinQt/Config/SettingsWindow.h"
#include "DolphinQt/Debugger/AssemblerWidget.h"
#include "DolphinQt/Debugger/BreakpointWidget.h"
@ -145,8 +145,6 @@
#undef None
#endif
#include <qprocess.h>
#if defined(__unix__) || defined(__unix) || defined(__APPLE__)
void MainWindow::OnSignal()
{
@ -219,9 +217,9 @@ static std::vector<std::string> StringListToStdVector(QStringList list)
return result;
}
MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters,
MainWindow::MainWindow(Core::System& system, std::unique_ptr<BootParameters> boot_parameters,
const std::string& movie_path)
: QMainWindow(nullptr)
: QMainWindow(nullptr), m_system(system)
{
setWindowTitle(QString::fromStdString(Common::GetScmRevStr()));
setWindowIcon(Resources::GetAppIcon());
@ -275,6 +273,8 @@ MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters,
#ifdef USE_RETRO_ACHIEVEMENTS
AchievementManager::GetInstance().Init();
if (AchievementManager::GetInstance().IsHardcoreModeActive())
Settings::Instance().SetDebugModeEnabled(false);
#endif // USE_RETRO_ACHIEVEMENTS
#if defined(__unix__) || defined(__unix) || defined(__APPLE__)
@ -292,7 +292,7 @@ MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters,
if (!movie_path.empty())
{
std::optional<std::string> savestate_path;
if (Core::System::GetInstance().GetMovie().PlayInput(movie_path, &savestate_path))
if (m_system.GetMovie().PlayInput(movie_path, &savestate_path))
{
m_pending_boot->boot_session_data.SetSavestateData(std::move(savestate_path),
DeleteSavestateAfterBoot::No);
@ -465,17 +465,17 @@ void MainWindow::CreateComponents()
m_wii_tas_input_windows[i] = new WiiTASInputWindow(nullptr, i);
}
m_jit_widget = new JITWidget(Core::System::GetInstance(), this);
m_jit_widget = new JITWidget(m_system, this);
m_log_widget = new LogWidget(this);
m_log_config_widget = new LogConfigWidget(this);
m_memory_widget = new MemoryWidget(Core::System::GetInstance(), this);
m_memory_widget = new MemoryWidget(m_system, this);
m_network_widget = new NetworkWidget(this);
m_register_widget = new RegisterWidget(this);
m_thread_widget = new ThreadWidget(this);
m_watch_widget = new WatchWidget(this);
m_breakpoint_widget = new BreakpointWidget(this);
m_code_widget = new CodeWidget(this);
m_cheats_manager = new CheatsManager(Core::System::GetInstance(), this);
m_cheats_manager = new CheatsManager(m_system, this);
m_assembler_widget = new AssemblerWidget(this);
const auto request_watch = [this](QString name, u32 addr) {
@ -512,7 +512,7 @@ void MainWindow::CreateComponents()
connect(m_memory_widget, &MemoryWidget::RequestWatch, request_watch);
connect(m_breakpoint_widget, &BreakpointWidget::ShowCode, [this](u32 address) {
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
if (Core::GetState(m_system) == Core::State::Paused)
m_code_widget->SetAddress(address, CodeViewWidget::SetAddressUpdate::WithDetailedUpdate);
});
connect(m_breakpoint_widget, &BreakpointWidget::ShowMemory, m_memory_widget,
@ -567,6 +567,8 @@ void MainWindow::ConnectMenuBar()
connect(m_menu_bar, &MenuBar::ImportNANDBackup, this, &MainWindow::OnImportNANDBackup);
connect(m_menu_bar, &MenuBar::PerformOnlineUpdate, this, &MainWindow::PerformOnlineUpdate);
connect(m_menu_bar, &MenuBar::BootWiiSystemMenu, this, &MainWindow::BootWiiSystemMenu);
connect(m_menu_bar, &MenuBar::StartNetPlay, this, &MainWindow::ShowNetPlaySetupDialog);
connect(m_menu_bar, &MenuBar::BrowseNetPlay, this, &MainWindow::ShowNetPlayBrowser);
connect(m_menu_bar, &MenuBar::ShowFIFOPlayer, this, &MainWindow::ShowFIFOPlayer);
connect(m_menu_bar, &MenuBar::ShowSkylanderPortal, this, &MainWindow::ShowSkylanderPortal);
connect(m_menu_bar, &MenuBar::ShowInfinityBase, this, &MainWindow::ShowInfinityBase);
@ -651,7 +653,7 @@ void MainWindow::ConnectHotkeys()
connect(m_hotkey_scheduler, &HotkeyScheduler::ConnectWiiRemote, this,
&MainWindow::OnConnectWiiRemote);
connect(m_hotkey_scheduler, &HotkeyScheduler::ToggleReadOnlyMode, [this] {
auto& movie = Core::System::GetInstance().GetMovie();
auto& movie = m_system.GetMovie();
bool read_only = !movie.IsReadOnly();
movie.SetReadOnly(read_only);
emit ReadOnlyModeChanged(read_only);
@ -696,8 +698,6 @@ void MainWindow::ConnectToolBar()
connect(m_tool_bar, &ToolBar::ControllersPressed, this, &MainWindow::ShowControllersWindow);
connect(m_tool_bar, &ToolBar::GraphicsPressed, this, &MainWindow::ShowGraphicsWindow);
connect(m_tool_bar, &ToolBar::StartNetPlayPressed, this, &MainWindow::ShowNetPlaySetupDialog);
connect(m_tool_bar, &ToolBar::ViewGeckoCodes, this, &MainWindow::ShowGeckoCodes);
connect(m_tool_bar, &ToolBar::StepPressed, m_code_widget, &CodeWidget::Step);
connect(m_tool_bar, &ToolBar::StepOverPressed, m_code_widget, &CodeWidget::StepOver);
connect(m_tool_bar, &ToolBar::StepOutPressed, m_code_widget, &CodeWidget::StepOut);
@ -808,14 +808,12 @@ void MainWindow::ChangeDisc()
if (paths.empty())
return;
auto& system = Core::System::GetInstance();
system.GetDVDInterface().ChangeDisc(Core::CPUThreadGuard{system}, paths);
m_system.GetDVDInterface().ChangeDisc(Core::CPUThreadGuard{m_system}, paths);
}
void MainWindow::EjectDisc()
{
auto& system = Core::System::GetInstance();
system.GetDVDInterface().EjectDisc(Core::CPUThreadGuard{system}, DVD::EjectCause::User);
m_system.GetDVDInterface().EjectDisc(Core::CPUThreadGuard{m_system}, DVD::EjectCause::User);
}
void MainWindow::OpenUserFolder()
@ -840,9 +838,9 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
// Otherwise, play the default game.
// Otherwise, play the last played game, if there is one.
// Otherwise, prompt for a new game.
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
if (Core::GetState(m_system) == Core::State::Paused)
{
Core::SetState(Core::System::GetInstance(), Core::State::Running);
Core::SetState(m_system, Core::State::Running);
}
else
{
@ -870,12 +868,12 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
void MainWindow::Pause()
{
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
Core::SetState(m_system, Core::State::Paused);
}
void MainWindow::TogglePause()
{
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
if (Core::GetState(m_system) == Core::State::Paused)
{
Play();
}
@ -918,7 +916,7 @@ void MainWindow::OnStopComplete()
bool MainWindow::RequestStop()
{
if (Core::IsUninitialized(Core::System::GetInstance()))
if (Core::IsUninitialized(m_system))
{
Core::QueueHostJob([this](Core::System&) { OnStopComplete(); }, true);
return true;
@ -944,13 +942,13 @@ bool MainWindow::RequestStop()
Common::ScopeGuard confirm_lock([this] { m_stop_confirm_showing = false; });
const Core::State state = Core::GetState(Core::System::GetInstance());
const Core::State state = Core::GetState(m_system);
// Only pause the game, if NetPlay is not running
bool pause = !Settings::Instance().GetNetPlayClient();
if (pause)
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
Core::SetState(m_system, Core::State::Paused);
if (rendered_widget_was_active)
{
@ -980,7 +978,7 @@ bool MainWindow::RequestStop()
m_render_widget->SetWaitingForMessageBox(false);
if (pause)
Core::SetState(Core::System::GetInstance(), state);
Core::SetState(m_system, state);
return false;
}
@ -1001,112 +999,8 @@ bool MainWindow::RequestStop()
// Unpause because gracefully shutting down needs the game to actually request a shutdown.
// TODO: Do not unpause in debug mode to allow debugging until the complete shutdown.
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
Core::SetState(Core::System::GetInstance(), Core::State::Running);
// Tell NetPlay about the power event
if (NetPlay::IsNetPlayRunning())
NetPlay::SendPowerButtonEvent();
return true;
}
ForceStop();
#ifdef Q_OS_WIN
// Allow windows to idle or turn off display again
SetThreadExecutionState(ES_CONTINUOUS);
#endif
return true;
}
bool MainWindow::RequestStopNetplay()
{
if (!Core::IsRunning(Core::System::GetInstance()))
{
Core::QueueHostJob([this](Core::System&) { OnStopComplete(); }, true);
return true;
}
const bool rendered_widget_was_active =
m_render_widget->isActiveWindow() && !m_render_widget->isFullScreen();
QWidget* confirm_parent = (!m_rendering_to_main && rendered_widget_was_active) ?
m_render_widget :
static_cast<QWidget*>(this);
const bool was_cursor_locked = m_render_widget->IsCursorLocked();
if (!m_render_widget->isFullScreen())
m_render_widget_geometry = m_render_widget->saveGeometry();
else
FullScreen();
if (Config::Get(Config::MAIN_CONFIRM_ON_STOP))
{
if (std::exchange(m_stop_confirm_showing, true))
return true;
Common::ScopeGuard confirm_lock([this] { m_stop_confirm_showing = false; });
const Core::State state = Core::GetState(Core::System::GetInstance());
// Only pause the game, if NetPlay is not running
bool pause = !Settings::Instance().GetNetPlayClient();
if (pause)
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
if (rendered_widget_was_active)
{
// We have to do this before creating the message box, otherwise we might receive the window
// activation event before we know we need to lock the cursor again.
m_render_widget->SetCursorLockedOnNextActivation(was_cursor_locked);
}
// This is to avoid any "race conditions" between the "Window Activate" message and the
// message box returning, which could break cursor locking depending on the order
m_render_widget->SetWaitingForMessageBox(true);
auto confirm = ModalMessageBox::question(
confirm_parent, tr("Quitter!"),
m_stop_requested ? tr("A user closed down their game from the netplay lobby. "
"This means the Netplay session has ended! "
"Do you want to stop the current emulation?") :
tr("A user closed down their game from the netplay lobby. "
"This means the Netplay session has ended! "
"Do you want to stop the current emulation?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal);
// If a user confirmed stopping the emulation, we do not capture the cursor again,
// even if the render widget will stay alive for a while.
// If a used rejected stopping the emulation, we instead capture the cursor again,
// and let them continue playing as if nothing had happened
// (assuming cursor locking is on).
if (confirm != QMessageBox::Yes)
{
m_render_widget->SetWaitingForMessageBox(false);
if (pause)
Core::SetState(Core::System::GetInstance(), state);
return false;
}
else
{
m_render_widget->SetCursorLockedOnNextActivation(false);
// This needs to be after SetCursorLockedOnNextActivation(false) as it depends on it
m_render_widget->SetWaitingForMessageBox(false);
}
}
OnStopRecording();
// TODO: Add Debugger shutdown
if (!m_stop_requested && UICommon::TriggerSTMPowerEvent())
{
m_stop_requested = true;
// Unpause because gracefully shutting down needs the game to actually request a shutdown.
// TODO: Do not unpause in debug mode to allow debugging until the complete shutdown.
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
Core::SetState(Core::System::GetInstance(), Core::State::Running);
if (Core::GetState(m_system) == Core::State::Paused)
Core::SetState(m_system, Core::State::Running);
// Tell NetPlay about the power event
if (NetPlay::IsNetPlayRunning())
@ -1125,21 +1019,20 @@ bool MainWindow::RequestStopNetplay()
void MainWindow::ForceStop()
{
Core::Stop(Core::System::GetInstance());
Core::Stop(m_system);
}
void MainWindow::Reset()
{
auto& system = Core::System::GetInstance();
auto& movie = system.GetMovie();
auto& movie = m_system.GetMovie();
if (movie.IsRecordingInput())
movie.SetReset(true);
system.GetProcessorInterface().ResetButton_Tap_FromUser();
m_system.GetProcessorInterface().ResetButton_Tap();
}
void MainWindow::FrameAdvance()
{
Core::DoFrameStep(Core::System::GetInstance());
Core::DoFrameStep(m_system);
}
void MainWindow::FullScreen()
@ -1230,7 +1123,7 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
}
// If we're running, only start a new game once we've stopped the last.
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (!Core::IsUninitialized(m_system))
{
if (!RequestStop())
return;
@ -1244,7 +1137,7 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
ShowRenderWidget();
// Boot up, show an error if it fails to load the game.
if (!BootManager::BootCore(Core::System::GetInstance(), std::move(parameters),
if (!BootManager::BootCore(m_system, std::move(parameters),
::GetWindowSystemInfo(m_render_widget->windowHandle())))
{
ModalMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok);
@ -1400,7 +1293,7 @@ void MainWindow::ShowSettingsWindow()
InstallHotkeyFilter(m_settings_window);
}
//SetQWidgetWindowDecorations(m_settings_window);
SetQWidgetWindowDecorations(m_settings_window);
m_settings_window->show();
m_settings_window->raise();
m_settings_window->activateWindow();
@ -1483,8 +1376,7 @@ void MainWindow::ShowFIFOPlayer()
{
if (!m_fifo_window)
{
m_fifo_window = new FIFOPlayerWindow(Core::System::GetInstance().GetFifoPlayer(),
Core::System::GetInstance().GetFifoRecorder());
m_fifo_window = new FIFOPlayerWindow(m_system.GetFifoPlayer(), m_system.GetFifoRecorder());
connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this,
[this](const QString& path) { StartGame(path, ScanForSecondDisc::No); });
}
@ -1530,7 +1422,7 @@ void MainWindow::StateLoad()
this, tr("Select a File"), dialog_path, tr("All Save States (*.sav *.s##);; All Files (*)"));
Config::SetBase(Config::MAIN_CURRENT_STATE_PATH, QFileInfo(path).dir().path().toStdString());
if (!path.isEmpty())
State::LoadAs(Core::System::GetInstance(), path.toStdString());
State::LoadAs(m_system, path.toStdString());
}
void MainWindow::StateSave()
@ -1542,47 +1434,47 @@ void MainWindow::StateSave()
this, tr("Select a File"), dialog_path, tr("All Save States (*.sav *.s##);; All Files (*)"));
Config::SetBase(Config::MAIN_CURRENT_STATE_PATH, QFileInfo(path).dir().path().toStdString());
if (!path.isEmpty())
State::SaveAs(Core::System::GetInstance(), path.toStdString());
State::SaveAs(m_system, path.toStdString());
}
void MainWindow::StateLoadSlot()
{
State::Load(Core::System::GetInstance(), m_state_slot);
State::Load(m_system, m_state_slot);
}
void MainWindow::StateSaveSlot()
{
State::Save(Core::System::GetInstance(), m_state_slot);
State::Save(m_system, m_state_slot);
}
void MainWindow::StateLoadSlotAt(int slot)
{
State::Load(Core::System::GetInstance(), slot);
State::Load(m_system, slot);
}
void MainWindow::StateLoadLastSavedAt(int slot)
{
State::LoadLastSaved(Core::System::GetInstance(), slot);
State::LoadLastSaved(m_system, slot);
}
void MainWindow::StateSaveSlotAt(int slot)
{
State::Save(Core::System::GetInstance(), slot);
State::Save(m_system, slot);
}
void MainWindow::StateLoadUndo()
{
State::UndoLoadState(Core::System::GetInstance());
State::UndoLoadState(m_system);
}
void MainWindow::StateSaveUndo()
{
State::UndoSaveState(Core::System::GetInstance());
State::UndoSaveState(m_system);
}
void MainWindow::StateSaveOldest()
{
State::SaveFirstSaved(Core::System::GetInstance());
State::SaveFirstSaved(m_system);
}
void MainWindow::SetStateSlot(int slot)
@ -1636,11 +1528,10 @@ void MainWindow::NetPlayInit()
m_netplay_discord = new DiscordHandler(this);
#endif
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::RequestStopNetplay);
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::ForceStop);
connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Host, this, &MainWindow::NetPlayHost);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::JoinBrowser, this, &MainWindow::NetPlayJoin);
#ifdef USE_DISCORD_PRESENCE
connect(m_netplay_discord, &DiscordHandler::Join, this, &MainWindow::NetPlayJoin);
@ -1655,7 +1546,7 @@ void MainWindow::NetPlayInit()
bool MainWindow::NetPlayJoin()
{
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (!Core::IsUninitialized(m_system))
{
ModalMessageBox::critical(nullptr, tr("Error"),
tr("Can't start a NetPlay Session while a game is still running!"));
@ -1722,7 +1613,7 @@ bool MainWindow::NetPlayJoin()
bool MainWindow::NetPlayHost(const UICommon::GameFile& game)
{
if (!Core::IsUninitialized(Core::System::GetInstance()))
if (!Core::IsUninitialized(m_system))
{
ModalMessageBox::critical(nullptr, tr("Error"),
tr("Can't start a NetPlay Session while a game is still running!"));
@ -1784,7 +1675,7 @@ void MainWindow::NetPlayQuit()
void MainWindow::UpdateScreenSaverInhibition()
{
const bool inhibit = Config::Get(Config::MAIN_DISABLE_SCREENSAVER) &&
(Core::GetState(Core::System::GetInstance()) == Core::State::Running);
(Core::GetState(m_system) == Core::State::Running);
if (inhibit == m_is_screensaver_inhibited)
return;
@ -1945,7 +1836,7 @@ void MainWindow::OnPlayRecording()
if (dtm_file.isEmpty())
return;
auto& movie = Core::System::GetInstance().GetMovie();
auto& movie = m_system.GetMovie();
if (!movie.IsReadOnly())
{
// let's make the read-only flag consistent at the start of a movie.
@ -1964,10 +1855,9 @@ void MainWindow::OnPlayRecording()
void MainWindow::OnStartRecording()
{
auto& system = Core::System::GetInstance();
auto& movie = system.GetMovie();
if (Core::GetState(system) == Core::State::Starting ||
Core::GetState(system) == Core::State::Stopping || movie.IsRecordingInput() ||
auto& movie = m_system.GetMovie();
if (Core::GetState(m_system) == Core::State::Starting ||
Core::GetState(m_system) == Core::State::Stopping || movie.IsRecordingInput() ||
movie.IsPlayingInput())
{
return;
@ -1999,14 +1889,14 @@ void MainWindow::OnStartRecording()
{
emit RecordingStatusChanged(true);
if (Core::IsUninitialized(system))
if (Core::IsUninitialized(m_system))
Play();
}
}
void MainWindow::OnStopRecording()
{
auto& movie = Core::System::GetInstance().GetMovie();
auto& movie = m_system.GetMovie();
if (movie.IsRecordingInput())
OnExportRecording();
if (movie.IsMovieActive())
@ -2016,13 +1906,12 @@ void MainWindow::OnStopRecording()
void MainWindow::OnExportRecording()
{
auto& system = Core::System::GetInstance();
const Core::CPUThreadGuard guard(system);
const Core::CPUThreadGuard guard(m_system);
QString dtm_file = DolphinFileDialog::getSaveFileName(
this, tr("Save Recording File As"), QString(), tr("Dolphin TAS Movies (*.dtm)"));
if (!dtm_file.isEmpty())
system.GetMovie().SaveRecording(dtm_file.toStdString());
m_system.GetMovie().SaveRecording(dtm_file.toStdString());
}
void MainWindow::OnActivateChat()
@ -2060,11 +1949,10 @@ void MainWindow::ShowTASInput()
}
}
auto& system = Core::System::GetInstance();
for (int i = 0; i < num_wii_controllers; i++)
{
if (Config::Get(Config::GetInfoForWiimoteSource(i)) == WiimoteSource::Emulated &&
(!Core::IsRunning(system) || system.IsWii()))
(!Core::IsRunning(m_system) || m_system.IsWii()))
{
SetQWidgetWindowDecorations(m_wii_tas_input_windows[i]);
m_wii_tas_input_windows[i]->show();
@ -2076,7 +1964,7 @@ void MainWindow::ShowTASInput()
void MainWindow::OnConnectWiiRemote(int id)
{
const Core::CPUThreadGuard guard(Core::System::GetInstance());
const Core::CPUThreadGuard guard(m_system);
if (const auto bt = WiiUtils::GetBluetoothEmuDevice())
{
const auto wm = bt->AccessWiimoteByIndex(id);
@ -2157,16 +2045,3 @@ void MainWindow::ShowRiivolutionBootWidget(const UICommon::GameFile& game)
AddRiivolutionPatches(boot_params.get(), std::move(w.GetPatches()));
StartGame(std::move(boot_params));
}
void MainWindow::ShowGeckoCodes()
{
if (!m_gecko_dialog)
{
m_gecko_dialog = new GeckoDialog(this);
InstallHotkeyFilter(m_gecko_dialog);
}
m_gecko_dialog->show();
m_gecko_dialog->raise();
m_gecko_dialog->activateWindow();
}

View file

@ -55,6 +55,11 @@ class WatchWidget;
class WiiTASInputWindow;
struct WindowSystemInfo;
namespace Core
{
class System;
}
namespace DiscIO
{
enum class Region;
@ -75,7 +80,7 @@ class MainWindow final : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(std::unique_ptr<BootParameters> boot_parameters,
explicit MainWindow(Core::System& system, std::unique_ptr<BootParameters> boot_parameters,
const std::string& movie_path);
~MainWindow();
@ -216,6 +221,8 @@ private:
QSize sizeHint() const override;
void ShowGeckoCodes();
Core::System& m_system;
#ifdef HAVE_XRANDR
std::unique_ptr<X11Utils::XRRConfiguration> m_xrr_config;
#endif

View file

@ -0,0 +1,22 @@
// Copyright 2024 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "DolphinQt/QtUtils/QtUtils.h"
#include <QDateTimeEdit>
namespace QtUtils
{
void ShowFourDigitYear(QDateTimeEdit* widget)
{
if (!widget->displayFormat().contains(QStringLiteral("yyyy")))
{
// Always show the full year, no matter what the locale specifies. Otherwise, two-digit years
// will always be interpreted as in the 21st century.
widget->setDisplayFormat(
widget->displayFormat().replace(QStringLiteral("yy"), QStringLiteral("yyyy")));
}
}
} // namespace QtUtils

View file

@ -0,0 +1,13 @@
// Copyright 2024 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
class QDateTimeEdit;
namespace QtUtils
{
void ShowFourDigitYear(QDateTimeEdit* widget);
}

View file

@ -24,6 +24,7 @@
#include "Core/System.h"
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
#include "DolphinQt/QtUtils/QtUtils.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h"
@ -168,13 +169,7 @@ void AdvancedPane::CreateLayout()
m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace(
QStringLiteral("mm"), QStringLiteral("mm:ss")));
if (!m_custom_rtc_datetime->displayFormat().contains(QStringLiteral("yyyy")))
{
// Always show the full year, no matter what the locale specifies. Otherwise, two-digit years
// will always be interpreted as in the 21st century.
m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace(
QStringLiteral("yy"), QStringLiteral("yyyy")));
}
QtUtils::ShowFourDigitYear(m_custom_rtc_datetime);
m_custom_rtc_datetime->setDateTimeRange(QDateTime({2000, 1, 1}, {0, 0, 0}, Qt::UTC),
QDateTime({2099, 12, 31}, {23, 59, 59}, Qt::UTC));
m_custom_rtc_datetime->setTimeSpec(Qt::UTC);

View file

@ -163,7 +163,7 @@ void AudioPane::CreateWidgets()
auto* misc_layout = new QGridLayout;
misc_box->setLayout(misc_layout);
m_speed_up_mute_enable = new QCheckBox(tr("Mute When Disabling Speed Limit."));
m_speed_up_mute_enable = new QCheckBox(tr("Mute When Disabling Speed Limit"));
m_speed_up_mute_enable->setToolTip(
tr("Mutes the audio when overriding the emulation speed limit (default hotkey: Tab)."));

View file

@ -17,6 +17,7 @@
#include "Core/IOS/USB/Emulated/Skylanders/Skylander.h"
#include "Core/System.h"
#include "DolphinQt/QtUtils/QtUtils.h"
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
SkylanderModifyDialog::SkylanderModifyDialog(QWidget* parent, u8 slot)
@ -168,8 +169,9 @@ void SkylanderModifyDialog::PopulateSkylanderOptions(QVBoxLayout* layout)
edit_nick->setValidator(
new QRegularExpressionValidator(QRegularExpression(QStringLiteral("^\\p{L}{0,15}$")), this));
edit_playtime->setValidator(new QIntValidator(0, INT_MAX, this));
edit_last_reset->setDisplayFormat(QStringLiteral("dd/MM/yyyy hh:mm"));
edit_last_placed->setDisplayFormat(QStringLiteral("dd/MM/yyyy hh:mm"));
QtUtils::ShowFourDigitYear(edit_last_reset);
QtUtils::ShowFourDigitYear(edit_last_placed);
edit_toy_code->setToolTip(tr("The toy code for this figure. Only available for real figures."));
edit_money->setToolTip(tr("The amount of money this Skylander has. Between 0 and 65000"));

Some files were not shown because too many files have changed in this diff Show more