In the unit test I'm adding in the next commit, I want to call
MemoryManager::Init, but initializing all the hardware that
MemoryManager::InitMMIO calls into would be cumbersome.
Calling MemoryManager::InitMMIO from MemoryManager::Init was a bit
strange anyway. Because MemoryManager::Init is called about halfway
through HW::Init, some of the hardware that MemoryManager::InitMMIO
calls into isn't initialized yet.
Most systems that Dolphin runs on have a page size of 4 KiB, which
conveniently matches the page size of the GameCube and Wii. But there
are also systems that use larger page sizes, notably Apple CPUs with
16 KiB page sizes. To let us create host mappings on such systems, this
commit implements combining guest mappings into host page sized mappings
wherever possible.
For this to work for a given mapping, not only do four (in the case of
16 KiB) guest mappings have to exist adjacent to each other, but the
corresponding translated addresses also have to be adjacent, and the
lowest bits of the addresses have to match. When I tested a few games,
the following percentages of guest mappings met these criteria:
Spider-Man 2: 0%-12%
Rogue Squadron 2: 39%-42%
Rogue Squadron 3: 28%-41%
So while 16 KiB systems don't get as much of a performance improvement
as 4 KiB systems, they do still get some improvement.
Removing and readding every page table mapping every time something
changes in the page table is very slow. Instead, let's generate a diff
and ask Memmap to update only the diff.
Page table mappings are only used when DR is set, so if page tables are
updated when DR isn't set, we can wait with updating page table mappings
until DR gets set. This lets us batch page table updates in the Disney
Trio of Destruction, improving performance when the games are loading
data. It doesn't help much for GameCube games, because those run tlbie
with DR set.
The PowerPCState struct has had its members slightly reordered. I had to
put pagetable_update_pending less than 4 KiB from the start so AArch64's
LDRB (immediate) can access it, and I also took the opportunity to move
some other members around to cut down on padding.
Previously we've only been setting up fastmem mappings for block address
translation, but now we also do it for page address translation. This
increases performance when games access memory using page tables, but
decreases performance when games set up page tables.
The tlbie instruction is used as an indication that the mappings need to
be updated.
There are some accuracy downsides:
* The TLB is now effectively infinitely large, which matters if games
don't use tlbie when modifying page tables.
* The R and C bits for page table entries get set pessimistically rather
than when the page is actually accessed.
No games are known to be broken by these inaccuracies, but unfortunately
the second inaccuracy causes a large performance regression in Rogue
Squadron 3. You still get the old, more accurate behavior if Enable
Write-Back Cache is on.
It turns out that it is possible to create a login alias in RetroAchievements
such that you can log in with a username that doesn't match your display name.
AchievementManager was treating this as a synchronization error, but this is
desired behavior, so this removes the check.
Remove unused vector `controller_names` from `LoadConfig` and
`SaveConfig`. The vector has names added to it but they're never used.
Prior to d03f9032c1 these vectors were
passed to `DynamicInputTextureManager::GenerateTextures`, but that
commit removed those calls.
Yellow squiggly lines begone!
Done automatically on .cpp files through `run-clang-tidy`, with manual corrections to the mistakes.
If an import is directly used, but is technically unnecessary since it's recursively imported by something else, it is *not* removed.
The tool doesn't touch .h files, so I did some of them by hand while fixing errors due to old recursive imports.
Not everything is removed, but the cleanup should be substantial enough.
Because this done on Linux, code that isn't used on it is mostly untouched.
(Hopefully no open PR is depending on these imports...)
This improves my PC's performance on RS2 Hoth by... 0.1% or so, which I
think is within the margin of error. But this change also cuts down on
boilerplate.
If the call to `Open` a perf map fails don't set `s_is_enabled` (though
it could already be true if you're also using VTUNE) and don't call
`std::setvbuf` with a null stream.
Also fix a typo in a comment (`if` -> `in`)
If all inputs to an fmadds instruction (including cousins like fmsubs,
fnmadd...) are single-precision, then the result is identical between a
double-precision calculation with an error-free transform (whether the
calculation is fused or not) and a single-precision FMA instruction
(must be fused). So as a performance optimization in JitArm64, if we
were going to use double precision with EFT but the inputs are singles,
instead we'll use a normal single-precision FMA instruction without
anything extra. This lets us skip both the EFT and double-to-single
conversions.
Also renaming `inaccurate_fma` to `nonfused` because it's confusing that
`inaccurate_fma` and `m_accurate_fmadds` have such similar names
despite controlling separate things.
If result_reg is set to a temporary register instead of VD because of
accurate NaNs, there's no need to allocate a secondary temporary
register because of inaccurate FMA.
TextureCacheBase::LoadImpl has a hot path where the passed-in
TextureInfo never gets used. Instead of passing in a TextureInfo, let's
pass in the stage and create the TextureInfo from the stage if needed.
This unlocks somewhere above an additional 4% performance boost in the
Hoth level of Rogue Squadron 2 on my PC. Performance varies, making it
difficult for me to measure, so treat this as a very approximate number.
When we're emulating single-precision FMA using an FMA instruction,
there's no precision benefit from using a double-precision instruction,
assuming all inputs are single-precision. But when we're emulating
single-precision FMA using separate multiplication and addition
instructions, there is.
This change increases the precision of inaccurate FMA to the same level
as Jit64, which matters since the only reason we have the inaccurate
FMA mode is for sync compatibility with Jit64.
The check only happened if `USE_VTUNE` wasn't defined, and in that case
it was immediately followed by the same check again.
The check used to avoid an unnecessary call to `StringFromFormatV` in
certain circumstances, but that call was removed in
be81fe86e1.
Building on macOS with a recent CMake version would result in the
following error:
CMake Error at Source/Core/MacUpdater/CMakeLists.txt:48 (add_custom_command):
The following keywords are not supported when using
add_custom_command(TARGET): DEPENDS
As it turns out, this form of `add_custom_command` does not accept
DEPENDS, but versions of CMake prior to 3.31 silently dropped it.
The TextureInfo constructor creates a vector of MipLevels. This could be
good for performance if MipLevels are accessed very often for each
TextureInfo, but that's not the case. Dolphin creates thousands of
TextureInfos per second that it never accesses the mipmap levels of
because there's a hit in the texture cache, and in the uncommon case of
a texture cache miss, the mipmap levels only get looped through once.
To make the common case of texture cache hits as fast as possible, let's
not create a vector in the TextureInfo constructor. This commit
implements a custom iterator for MipLevels instead.
In my testing on the Death Star level of Rogue Squadron 2, this speeds
up TextureInfo::FromStage by 200%, giving an overall emulation speedup
of a bit over 1%. Results on the Hoth level are even better, with
TextureInfo::FromStage being close to 300% faster and overall emulation
being over 4% faster. (Single core, no GPU texture decoding.)
Profiling Dolphin using Heaptrack, this turns out to be the cause of
more than half of all temporary allocations. Though since it's in a
separate thread, I suppose it wasn't affecting performance very much.
Combined with the previous commit, this brings the TrampolineInfo struct
down to 48 bytes. This matters, because Jit64 has a big
std::unordered_map where it stores many megabytes of TrampolineInfo
entries.
The key saving comes from shrinking the len member from u32 to u16. It
should be safe to even turn it into a u8, but going that far brings no
additional savings due to how the padding works out.
By moving members of the OpArg struct around, we can cut down on how
much padding the struct needs. Now it has a size of 16 bytes, small
enough for function calls to pass it in two registers instead of on the
stack.
Re-added a line of code from a cancelled PR (that I thought was in
main already) that RetroAchievements uses to properly synchronize
memory reads and writes with the emulator frames. This appears to
fix some pretty major freezing and deadlocks in the RA dev tools.
CMake support for c++23 was added in 3.20.
Remove statements explicitly setting the following policies to NEW.
These policies were introduced in or before 3.20, and now that 3.20 is
the minimum version they will automatically have the NEW behavior.
Policy: Introduced in
CMP0079: 3.13
CMP0084: 3.14
CMP0091: 3.15
CMP0092: 3.15
CMP0099: 3.17
CMP0117: 3.20
Disable scanning c++ source files for module imports (introduced as
CMP0155 in 3.28) since we don't use modules and that policy triggers
build errors with Clang if the clang-scan-deps tool isn't installed.
cpp-ipc is explicitely only available on Windows, Linux, QNX, and FreeBSD. Trying to build dolphin on any another BSD such as OpenBSD or Haiku currently leads to failure because of this.
During my quest to rid Dolphin of the memory-unsafe GetPointer function,
I didn't realize that DSPHLE had its own set of memory access functions
that were essentially duplicating the standard ones. This commit gets
rid of them and replaces calls to them with calls to MemoryManager.
Move the constructor and destructor after the definition of the class
`Internal`.
This fixes an error generated by Clang from the destructor of
`std::unique_ptr<Internal>` when setting the standard version to c++23:
`invalid application of 'sizeof' to an incomplete type 'Metal::ObjectCache::Internal'`.
Fix an error generated by Clang from the destructor of
`std::unique_ptr<FileInfo> m_file_info` when setting the standard
version to c++23:
`invalid application of 'sizeof' to an incomplete type 'DiscIO::FileInfo'`
* This fixes some UI elements (3-dot menu background, status bar when scrolling down in settings) not following Material You colors.
* It doesn't cause any issues on Android versions without dynamic colors (tested on Android 9, 11, 16)
Signed-off-by: Leonardo Ledda <leonardoledda@gmail.com>
Checked on hardware that this bias was not added because I had assumed the other way around would be true, forgot to ask about making a PR for this when I initially had done so
If we're on an x64 CPU that doesn't have the MOVBE extension, trying to
SwapAndStore a host register results in that register's value getting
clobbered with the swapped value. Jit64::stX and Jit64::stXx detect this
case, and if necessary, emit a MOV to a register that's fine to clobber.
This logic was broken by the merge of PR 12134. Jit64::stX and
Jit64::stXx were assuming that if RegCache::IsImm returns true for a
guest register, calling RegCache::Use or RegCache::BindOrImm for that
guest register would result in an immediate. However, PR 12134 made it
possible for a guest register to have both a host register and an
immediate in the register cache at the same time. When this happens,
RegCache::IsImm returns true, yet RegCache::Use and RegCache::BindForImm
return an RCOpArg whose Location returns a host register. (To make it
extra confusing, RCOpArg::IsImm calls RegCache::IsImm if the RCOpArg
came from RegCache, so RCOpArg::IsImm returns true!)
To fix this, in cases where Jit64::stX and Jit64::stXx explicitly need
an immediate to avoid having to emit an extra MOV, let's call
RegCache::Imm32 so that we're certain that we're getting an immediate.
This fixes an issue on older x64 CPUs that manifested as e.g. completely
broken graphics in Spyro: Enter the Dragonfly.
The constant propagation PR made it so that a guest register can be
present in the register cache as both a host register and an immediate
at the same time. If such a guest register is requested from the
register cache, the register cache prefers returning it as a host
register. However, RCOpArg::IsImm still returns true in this case. This
is confusing, especially since OpArg::IsImm does not return true if the
RCOpArg is converted into an OpArg.
This commit makes RCOpArg::IsImm check whether RCOpArg::Location returns
an immediate, so that RCOpArg::IsImm returns false when a host register
is being used. Code that wants to know whether an immediate exists in
the register cache rather than whether an immediate is currently being
used should call RegCache::IsImm instead.
Recently came across a strange issue where Dolphin would hard crash in most games with this error:
```sh
/usr/include/c++/15.2.1/optional:1165: constexpr const _Tp* std::optional<_Tp>::operator->() const [with _Tp = InputCommon::ImagePixelData]: Assertion 'this->_M_is_engaged()' failed.
```
The culprit turned out to be accessing `host_key_image` which is an `std::optional` thay may return `std::nullopt`. I'm not sure why this issue started occuring for me since I've had no issue with my Dynamic Input Textures in the past? But this fixes a crash if the image fails to load.
Aside from being unnecessary, on Windows the flag prevents two instances
of Dolphin (one instance from before 2509-371 when the flag was
introduced and the other after) from running the same ROM
simultaneously.
Attempting to do so generated the false error `"[Rom]" is an invalid
GCM/ISO file, or is not a GC/Wii ISO.` followed by `Failed to init core`
and emulation shutdown on the second instance to start the game. Fixing
the incorrect error message is a task I'm deferring to another PR.
The problem didn't happen when both instances were 2509-371 or later,
but I ran into it while bisecting an issue and it'd be nice to avoid
that problem in the future.
We have an optimization where the guest carry flag is kept in the host
carry flag between certain back-to-back pairs of integer instructions.
If the second instruction falls back to the interpreter, then
FallBackToInterpreter should flush the carry flag to m_ppc_state,
otherwise the interpreter reads a stale carry flag and at some later
point Jit64 trips the "Attempt to modify flags while flags locked!"
assertion.
An alternative solution would be to not store the guest carry flag in
the host carry flag to begin with if we know the next instruction is
going to fall back to the interpreter, but knowing that in advance is
non-trivial. Since interpreter fallbacks aren't exactly intended to be
super optimized, I went for the flushing solution instead, which is how
JitArm64 already works. In most cases, the emitted code shouldn't even
differ between these two solutions.
Note that the problematic situation only happens if the first integer
instruction doesn't fall back to the interpreter but the second one
does. This used to be impossible because there's no "JIT disable"
setting that's granular enough to disable some integer instructions but
not all, but with the constant propagation PR, it's possible if constant
propagation is able to entirely evaluate the first instruction but not
the second.
This makes SetUID take more emulated time giving the host more time to actually do the work.
The Wii menu "Data Management" -> "Save Data" -> "Wii" screen is no longer nearly as hard to emulate at full speed.
Constructing the UIDSys from the filesystem is a major bottleneck in the Wii menu "Data Management" -> "Save Data" -> "Wii" screen and this change makes it about twice as fast.
Call `UseNoImm` instead of `Use` on parameter `a` of `MultiplyImmediate`
since `Ra` gets passed to `IMUL` which asserts that parameter is not an
immediate.
This fixes a build error when `-DENABLE_TESTS=ON` and `-DUSE_RETRO_ACHIEVEMENTS=OFF` are both set together, since AchievementManager is also behind an ifdef.
There was a LINUX check added in b3bdad4, but this should be removed as this change applies to all Qt supported platforms. Simply put, GuiPrivate CMake files were introduced in Qt 6.9 and are now enforced in Qt 6.10 and are not platform-dependent.
Having it be static leads to a race condition if two different threads
call RunOnCPUThread with wait_for_completion set to true. (There's
currently nobody calling RunOnCPUThread from anything other than the
host thread, so this hasn't led to any consequences yet.)
This is an Android port of 7ed61c50a1. It looks like we don't have
descriptions for any of the RetroAchievements settings in the Android
GUI, so I haven't added descriptions for these two new settings either.
LoginDialog sets these to gone when a login starts or fails. Whether we
use gone or invisible needs to be consistent between LoginDialog and the
XML file, otherwise we'll blank space that shows up or disappears when
login starts or fails.
The optimizations for subfcx introduced in #13852 also apply to subfx.
Rather than duplicating the logic, we merge the handlers, like we did
in #10120 for x86.
We only use this class in one in one single function since its introduction with 12aa1071cb in 2021. If we do need it elsewhere we can always bring it back.