Compare commits

..

93 Commits

Author SHA1 Message Date
ameerj
4cee25281f main: Display the instruction set of the running title in the window name
Displays whether the currently running title uses 64-bit instructions or only 32-bit instructions.
2021-06-28 00:37:24 -04:00
Morph
4df04ad48a Merge pull request #6529 from ReinUsesLisp/reaper-fixups
buffer_cache,texture_cache: Misc fixups from the memory reaper
2021-06-27 09:33:58 -04:00
Morph
3bc7b0a587 Merge pull request #6532 from MerryMage/libusb-apple
libusb: Apple is a POSIX system
2021-06-27 00:30:47 -04:00
MerryMage
f54f29198f libusb: Apple is a POSIX system 2021-06-26 20:24:18 +01:00
bunnei
432fab7c4f Merge pull request #6526 from bunnei/doom-update
services: Misc. minor changes for latest SDK update.
2021-06-26 01:21:55 -07:00
bunnei
36d581ec73 hle: service: hwopus: OpenHardwareOpusDecoderEx: Remove unused buffer size. 2021-06-26 00:38:08 -07:00
ReinUsesLisp
9476309d53 buffer_cache: Only flush downloaded size
Fixes a regression unintentionally introduced by the garbage collector.
This makes regular memory downloads only flush the requested sizes.

This negatively affected Koei Tecmo games.
2021-06-26 03:29:34 -03:00
ReinUsesLisp
03abe8bf85 video_core: Enforce C4244
Enforce implicit integer casts to a smaller type as errors.
2021-06-26 03:29:34 -03:00
ReinUsesLisp
05bd50a1cf codec,vic: Disable warnings in ffmpeg headers 2021-06-26 03:29:31 -03:00
ReinUsesLisp
3ab5bf6454 vk_buffer_cache: Silence implicit cast warnings 2021-06-26 02:17:36 -03:00
ReinUsesLisp
b4894faeae buffer_cache/texture_cache: Make GC functions private 2021-06-26 02:17:36 -03:00
ReinUsesLisp
e79d02bf38 buffer_cache: Silence implicit cast warning 2021-06-26 02:17:36 -03:00
Ameer J
d9fb6dbd37 Merge pull request #6528 from ReinUsesLisp/device-memory
vulkan_device: Make device memory match the rest of the file
2021-06-25 17:07:24 -04:00
ReinUsesLisp
99b859db55 vulkan_device: Make device memory match the rest of the file
Match the style in the file.
2021-06-25 02:38:58 -03:00
bunnei
c805c0b395 Merge pull request #6496 from ameerj/astc-fixes
astc: Various robustness enhancements for the gpu decoder
2021-06-24 21:47:05 -07:00
bunnei
b9c2732121 Merge pull request #6519 from Wunkolo/mem-size-literal
common: Replace common_sizes into user-literals
2021-06-24 19:09:12 -07:00
bunnei
982be246ab hle: hle_helpers: Skip data payload offset checks on TIPC requests.
- TIPC does not use this.
2021-06-24 18:39:43 -07:00
bunnei
3565e32f4d hle: service: hwopus: Implement GetWorkBufferSizeEx and OpenHardwareOpusDecoderEx.
- This is used by the latest update of Doom Eternal.
2021-06-24 18:25:37 -07:00
bunnei
d1ba4a2db2 hle: service: aoc: Stub GetAddOnContentListChangedEventWithProcessId.
- This is used by the latest update of Doom Eternal.
2021-06-24 18:22:53 -07:00
bunnei
50d0cc2716 audio_core: common: Bump audio revision to 9.
- This is used in fw 12.x.x games.
2021-06-24 18:22:10 -07:00
Wunkolo
4569f39c7c common: Replace common_sizes into user-literals
Removes common_sizes.h in favor of having `_KiB`, `_MiB`, `_GiB`, etc
user-literals within literals.h.

To keep the global namespace clean, users will have to use:

```
using namespace Common::Literals;
```

to access these literals.
2021-06-24 09:27:40 -07:00
bunnei
4dc2f5a341 Merge pull request #6522 from Morph1984/pragma
general: Add missing #pragma once directives
2021-06-24 08:53:27 -07:00
Morph
eed0d1f33b general: Add missing #pragma once directives 2021-06-24 07:20:57 -04:00
Chloe
f216a9432b Add missing includes (#6521)
* Add missing includes

* Add array
2021-06-24 03:24:17 -04:00
Schplee
5ed87152c3 Fix bold tag 2021-06-23 23:37:03 -07:00
Schplee
373bc6512d Fix typo in Readme 2021-06-23 23:35:46 -07:00
Schplee
496327490f Update Readme 2021-06-23 23:32:41 -07:00
bunnei
1b09d6628b Merge pull request #6517 from lioncash/fmtlib
externals: Update fmt to 8.0.0
2021-06-23 15:31:04 -07:00
bunnei
809e5fd523 Merge pull request #6504 from Kelebek1/samples-played
[audout] Implement GetAudioOutPlayedSampleCount
2021-06-23 11:31:12 -07:00
Lioncash
d0b1f2bd05 General: Resolve fmt specifiers to adhere to 8.0.0 API where applicable
Also removes some deprecated API usages.
2021-06-23 13:48:21 -04:00
bunnei
d8d9bb0dfb Merge pull request #6518 from lioncash/func
maxwell3d: Add missing return in default SizeInBytes() case
2021-06-23 09:43:00 -07:00
Lioncash
be6844c1ed maxwell3d: Add missing return in default SizeInBytes() case
We were returning '1' in ComponentCount()'s default case but were
neglecting to do the same with SizeInBytes().
2021-06-23 11:50:40 -04:00
Lioncash
c3fe071723 externals: Update dynarmic to allow fmt compilation to succeed 2021-06-23 09:31:59 -04:00
Mai M
17fff10e06 Merge pull request #6465 from FernandoS27/sex-on-the-beach
GPU: Implement a garbage collector for GPU Caches (project Reaper+)
2021-06-23 08:03:01 -04:00
Lioncash
8593e6f1e6 externals: Update fmt to 8.0.0
Keeps us up to date with the latest major release.

Also allows compilers that support it to perform compile-time format
string checking.
2021-06-23 02:43:36 -04:00
Mai M
20f474b09a Merge pull request #6508 from ReinUsesLisp/bootmanager-stop-token
bootmanager: Use std::stop_source for stopping emulation
2021-06-23 02:35:42 -04:00
Morph
c1a9fa9db7 Merge pull request #6514 from OZtistic/master
Simple resizing of Per-Game configuration window and removal of useless Help question mark button in the title bar
2021-06-22 23:19:13 -04:00
Mai M
d6b51e5e21 Merge pull request #6512 from ReinUsesLisp/wait-detached-stasks
common/detached_tasks: Wait for tasks before shutting down
2021-06-22 22:20:14 -04:00
Mai M
95b4c78b07 Merge pull request #6509 from ReinUsesLisp/mouse-datarace
input_common/mouse_input: Fix data race
2021-06-22 22:19:34 -04:00
Mai M
4ec7d79174 Merge pull request #6510 from ReinUsesLisp/npad-data-race
npad: Fix data race when updating devices
2021-06-22 22:17:57 -04:00
OZtistic
36aacf62ad Simple resizing of the Per-Game configuration window and removal of useless Help question mark button in the title bar 2021-06-23 12:02:10 +10:00
bunnei
0308a2679e Merge pull request #6493 from Morph1984/fs-nodiscard
common: fs: Miscellaneous changes
2021-06-22 17:21:59 -07:00
bunnei
255f8d22d7 Merge pull request #6472 from Morph1984/spl
service: spl: Implement general SPL service
2021-06-22 15:43:10 -07:00
bunnei
791d3d1bea Merge pull request #6483 from Morph1984/get-tz-file
service: time: Use GetFileRelative to get files within subdirectories
2021-06-22 14:25:41 -07:00
Fernando Sahmkow
f9b940a442 Reaper: Set minimum cleaning limit on OGL. 2021-06-22 22:07:17 +02:00
Morph
2fa207058b common: fs: Add a description of a regular file in IsFile
This provides a more concrete example of what a regular file is and isn't.
2021-06-22 15:07:51 -04:00
Morph
0394893354 vfs_real: Fix Mode to FileAccessMode conversion
These enforce requiring the file to exist prior to opening.
2021-06-22 15:07:51 -04:00
Morph
76b2313b25 common: fs: Amend IsFile check in FileOpen / (Write/Append)StringToFile
This check was preventing files with the Write or Append file access modes from being created, as per the documented behavior in FileAccessMode.
This amends the check to test for the existence of a filesystem object prior to checking whether it is a regular file.
Thanks to liushuyu for pointing out that removing the check altogether would not guard against attempting to open non-regular files such as directories, symlinks, FIFO (pipes), sockets, block devices, or character devices.
The documentation has also been updated for these functions to clarify that a file refers to a regular file.
2021-06-22 15:06:58 -04:00
Morph
cf0b9d1de2 common: fs: file: Remove [[nodiscard]] attribute from Flush
Similarly, Flush() is typically called to attempt to flush a file into the disk. In the one case where this is used, we do not care whether the flush has succeeded or not, making [[nodiscard]] unnecessary.
2021-06-22 13:36:24 -04:00
Morph
81b1b71993 common: fs: Remove [[nodiscard]] attribute on Remove* functions
There are a lot of scenarios where we don't particularly care whether or not the removal operation and just simply attempt a removal.

As such, removing the [[nodiscard]] attribute is best for these functions.
2021-06-22 13:36:24 -04:00
bunnei
faf57c183f Merge pull request #6506 from ReinUsesLisp/master-semaphore-jthread
vk_master_semaphore: Use jthread for debug thread
2021-06-22 08:44:25 -07:00
bunnei
0e2c1a5739 Merge pull request #6495 from lat9nq/mingw-vista-style
ci: windows: Copy the Qt styles directory when packaging
2021-06-22 08:39:28 -07:00
Mai M
698add8541 Merge pull request #6511 from ReinUsesLisp/core-is-powered-data-race
core: Make is_powered_on atomic
2021-06-22 04:28:38 -04:00
Rodrigo Locatti
c9c8537643 core: Make is_powered_on atomic
Fixes potential data races when shutting down.
2021-06-22 04:33:07 -03:00
Rodrigo Locatti
1ca9a13e50 common/detached_tasks: Wait for tasks before shutting down
If this is not waited on, the synchronization primitives are destroyed
whe main exits and the detached task ends up signalling garbage and not
properly finishing.
2021-06-22 04:27:44 -03:00
Rodrigo Locatti
15cc561d12 npad: Fix data race when updating devices
Add a lock to avoid data races.
This reduces the number of -fsanitize=thread errors significantly.
2021-06-22 03:16:21 -03:00
Rodrigo Locatti
0a39163a90 input_common/mouse_input: Fix data race
Fix data race using std::jthread and std::stop_token.
2021-06-22 02:31:39 -03:00
bunnei
2a7a65c944 Merge pull request #6481 from Morph1984/missing-peak-set
kernel: Fix missing peak set in KResourceLimit::SetLimitValue
2021-06-21 22:16:48 -07:00
Kelebek1
ba3af04da1 Implement audout GetAudioOutPlayedSampleCount
Used in Ninja Gaiden games.
2021-06-22 04:39:17 +01:00
ReinUsesLisp
4009ae1da2 bootmanager: Use std::stop_source for stopping emulation
Use its std::stop_token to abort shader cache loading.

Using std::stop_token instead of std::atomic_bool allows the usage of
other utilities like std::stop_callback.
2021-06-22 00:04:57 -03:00
ReinUsesLisp
cf116a28a6 vk_master_semaphore: Use jthread for debug thread 2021-06-21 19:56:07 -03:00
bunnei
0485b8e84b Merge pull request #6499 from FernandoS27/we-were-on-a-break
Update dynarmic and add new unsafe CPU option.
2021-06-21 14:56:08 -07:00
bunnei
2a3d3d3895 Merge pull request #6475 from ameerj/unlimit-fps
nvflinger: Add experimental toggle to disable buffer swap interval limits
2021-06-21 11:58:12 -07:00
Mai M
83ac715e76 Merge pull request #6486 from CaptV0rt3x/httplib
externals: httplib: replace custom httplib header with upstream as submodule
2021-06-21 11:56:33 -04:00
Fernando Sahmkow
2298508465 Update dynarmic and add new unsafe CPU option. 2021-06-20 20:40:02 +02:00
Fernando Sahmkow
569a1962c0 Reaper: Guarantee correct deletion. 2021-06-20 19:11:41 +02:00
Fernando Sahmkow
865dd615ca Reaper: Upgrade label from unsafe to experimental as no regressions are known now. 2021-06-20 12:35:19 +02:00
ameerj
851c76233d util_shaders: Specify ASTC decoder memory barrier bits 2021-06-19 11:16:25 -04:00
ameerj
ace20ba4a4 astc_decoder.comp: Remove unnecessary LUT SSBOs
We can move them to instead be compile time constants within the shader.
2021-06-19 10:56:13 -04:00
ameerj
31b125ef57 astc: Various robustness enhancements for the gpu decoder
These changes should help in reducing crashes/drivers panics that may
occur due to synchronization issues between the shader completion and
later access of the decoded texture.
2021-06-19 09:00:33 -04:00
lat9nq
ad8aab915b ci: windows: Copy the styles directory when packaging
Qt can make use of qwindowsvistastyle.dll if present, and our MinGW
container has the library, but it was not being copied during the
packaging process. Thus, yuzu looked like a Windows 98 application when
using the PR-verify artifacts.

This copies over the DLL during packaging, for that sweet-sweet Windows
Vista style.

In addition, set the Qt plugins path instead of the plugins/platforms
path. This way we can use the directory directly, rather than appending
a `..` everytime we need something just outside of it.
2021-06-19 05:24:56 -04:00
Morph
03da34b330 Merge pull request #6494 from lat9nq/mingw-fix-fastmem
host_memory: Correct MEM_RESERVE_PLACEHOLDER
2021-06-19 04:40:58 -04:00
lat9nq
9a06b85b24 host_memory: Correct MEM_RESERVE_PLACEHOLDER
Microsoft defines `MEM_RESERVE_PLACEHOLDER` as `0x00040000`, but our
manually imported version of it drops the last zero.
2021-06-19 04:38:33 -04:00
Vortex
e704da9192 externals: httplib: replace custom httplib header with upstream as submodule.
This also includes a minor change to web_service.cpp - to fix compatibility with upstream changes.
2021-06-19 02:18:58 +05:30
Mai M
3870ba670f Merge pull request #6484 from CaptV0rt3x/discord-rpc
update submodule discord-rpc to latest [now deprecated]
2021-06-18 15:18:15 -04:00
Vortex
8a83e3412a update submodule discord-rpc to latest [now deprecated] 2021-06-18 23:13:17 +05:30
Morph
fd5ef1970c service: time: Use GetFileRelative to get files within subdirectories
The timezone info file can be within subdirectories (such as Asia/Tokyo), use GetFileRelative instead of GetFile to get files within subdirectories.
2021-06-18 11:25:26 -04:00
Rodrigo Locatti
bb18a6533d Merge pull request #6478 from ameerj/vk-layer-settings
vulkan_debug_callback: Skip logging known false-positive validation errors
2021-06-18 10:10:49 -03:00
Morph
1a5eceeb9c kernel: Fix missing peak set in KResourceLimit::SetLimitValue 2021-06-18 07:27:48 -04:00
ameerj
0b172d12c0 vulkan_debug_callback: Skip logging known false-positive validation errors
Avoids overwhelming the log with validation errors that are not applicable
2021-06-17 22:16:32 -04:00
Fernando Sahmkow
719a6dd5a1 Reaper: Correct size calculation on Vulkan. 2021-06-17 08:48:41 +02:00
Fernando Sahmkow
ca6f47c686 Reaper: Change memory restrictions on TC depending on host memory on VK. 2021-06-17 00:29:48 +02:00
Fernando Sahmkow
0dd98842bf Reaper: Address Feedback. 2021-06-16 21:35:03 +02:00
Fernando Sahmkow
954ad2a61e Reaper: Setup settings and final tuning. 2021-06-16 21:35:03 +02:00
Fernando Sahmkow
d8ad6aa187 Reaper: Tune it up to be an smart GC. 2021-06-16 21:35:02 +02:00
ReinUsesLisp
a11bc4a382 Initial Reaper Setup
WIP
2021-06-16 21:35:02 +02:00
ReinUsesLisp
5b1efe522e vulkan_memory_allocator: Release allocations with no commits 2021-06-16 21:35:01 +02:00
Morph
4a4e304319 spl: Mark the other functions as unimplemented 2021-06-16 01:46:45 -04:00
Morph
8ba83c4c2a spl: Implement spl::GetConfig 2021-06-16 01:46:45 -04:00
Morph
e4318a1914 hle: api_version: Add HLE API version constants 2021-06-16 01:46:45 -04:00
Morph
ded36b8688 spl: Add the general SPL interface 2021-06-16 01:46:45 -04:00
Morph
faf11fe46d spl: Add SPL types 2021-06-16 01:46:45 -04:00
Morph
95f203b7c7 spl: Add SPL result codes 2021-06-16 01:07:58 -04:00
128 changed files with 1570 additions and 7322 deletions

View File

@@ -18,19 +18,20 @@ cd ..
mkdir package
if [ -d "/usr/x86_64-w64-mingw32/lib/qt5/plugins/platforms/" ]; then
QT_PLATFORM_DLL_PATH='/usr/x86_64-w64-mingw32/lib/qt5/plugins/platforms/'
QT_PLUGINS_PATH='/usr/x86_64-w64-mingw32/lib/qt5/plugins'
else
#fallback to qt
QT_PLATFORM_DLL_PATH='/usr/x86_64-w64-mingw32/lib/qt/plugins/platforms/'
QT_PLUGINS_PATH='/usr/x86_64-w64-mingw32/lib/qt/plugins'
fi
find build/ -name "yuzu*.exe" -exec cp {} 'package' \;
# copy Qt plugins
mkdir package/platforms
cp "${QT_PLATFORM_DLL_PATH}/qwindows.dll" package/platforms/
cp -rv "${QT_PLATFORM_DLL_PATH}/../mediaservice/" package/
cp -rv "${QT_PLATFORM_DLL_PATH}/../imageformats/" package/
cp -v "${QT_PLUGINS_PATH}/platforms/qwindows.dll" package/platforms/
cp -rv "${QT_PLUGINS_PATH}/mediaservice/" package/
cp -rv "${QT_PLUGINS_PATH}/imageformats/" package/
cp -rv "${QT_PLUGINS_PATH}/styles/" package/
rm -f package/mediaservice/*d.dll
for i in package/*.exe; do

5
.gitmodules vendored
View File

@@ -18,7 +18,7 @@
url = https://github.com/libusb/libusb.git
[submodule "discord-rpc"]
path = externals/discord-rpc
url = https://github.com/discordapp/discord-rpc.git
url = https://github.com/discord/discord-rpc.git
[submodule "Vulkan-Headers"]
path = externals/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git
@@ -43,3 +43,6 @@
[submodule "SDL"]
path = externals/SDL
url = https://github.com/libsdl-org/SDL.git
[submodule "externals/cpp-httplib"]
path = externals/cpp-httplib
url = https://github.com/yhirose/cpp-httplib.git

View File

@@ -172,7 +172,7 @@ macro(yuzu_find_packages)
set(REQUIRED_LIBS
# Cmake Pkg Prefix Version Conan Pkg
"Catch2 2.13 catch2/2.13.0"
"fmt 7.1 fmt/7.1.2"
"fmt 8.0 fmt/8.0.0"
"lz4 1.8 lz4/1.9.2"
"nlohmann_json 3.8 nlohmann_json/3.8.0"
"ZLIB 1.2 zlib/1.2.11"

View File

@@ -1,43 +1,80 @@
yuzu emulator
=============
[![Travis CI Build Status](https://travis-ci.com/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.com/yuzu-emu/yuzu)
[![Azure Mainline CI Build Status](https://dev.azure.com/yuzu-emu/yuzu/_apis/build/status/yuzu%20mainline?branchName=master)](https://dev.azure.com/yuzu-emu/yuzu/)
[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.com/invite/u77vRWY)
<h1 align="center">
<br>
<a href="https://yuzu-emu.org/"><img src="https://raw.githubusercontent.com/yuzu-emu/yuzu-assets/master/icons/icon.png" alt="yuzu" width="200"></a>
<br>
<b>yuzu</b>
<br>
</h1>
yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/).
<h4 align="center"><b>yuzu</b> is the world's most popular, open-source, Nintendo Switch emulator — started by the creators of <a href="https://citra-emu.org" target="_blank">Citra</a>.
<br>
It is written in C++ with portability in mind, and we actively maintain builds for Windows and Linux.
</h4>
It is written in C++ with portability in mind, with builds actively maintained for Windows and Linux. The emulator is capable of running several commercial games.
<p align="center">
<a href="https://dev.azure.com/yuzu-emu/yuzu/">
<img src="https://dev.azure.com/yuzu-emu/yuzu/_apis/build/status/yuzu%20mainline?branchName=master"
alt="Azure Mainline CI Build Status">
</a>
<a href="https://discord.com/invite/u77vRWY">
<img src="https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white"
alt="Discord">
</a>
</p>
yuzu only emulates a subset of Switch hardware and therefore most commercial games **do not** run at full speed or are not fully functional.
<p align="center">
<a href="#compatibility">Compatibility</a> |
<a href="#development">Development</a> |
<a href="#building">Building</a> |
<a href="#download">Download</a> |
<a href="#support">Support</a> |
<a href="#license">License</a>
</p>
Do you want to check which games are compatible and which ones are not? Please visit our [Compatibility page](https://yuzu-emu.org/game/)!
## Compatibility
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
The emulator is capable of running most commercial games at full speed, provided you meet the [necessary hardware requirements](https://yuzu-emu.org/help/quickstart/#hardware-requirements).
Check out our [website](https://yuzu-emu.org/)!
For a full list of games yuzu support, please visit our [Compatibility page](https://yuzu-emu.org/game/)
For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY).
Check out our [website](https://yuzu-emu.org/) for the latest news on exciting features, monthly progress reports, and more!
### Development
## Development
Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted.
Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted. For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY).
If you want to contribute please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator.
If you want to contribute, please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information).
You can also contact any of the developers on Discord in order to know about the current state of the emulator.
If you want to contribute to the user interface translation, please check out the [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize translation work there, and periodically upstream translations.
If you want to contribute to the user interface translation project, please check out the [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize translation work there, and periodically upstream translations.
### Building
## Building
* __Windows__: [Windows Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Windows)
* __Linux__: [Linux Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Linux)
## Download
### Support
We happily accept monetary donations, or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
You can download the latest releases automatically via the installer on our [downloads](https://yuzu-emu.org/downloads/) page.
## Support
If you enjoy the project and want to support us financially, check out our Patreon!
<a href="https://www.patreon.com/yuzuteam">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
</a>
Any donations received will go towards things like:
* Switch consoles to explore and reverse-engineer the hardware
* Switch games for testing, reverse-engineering, and implementing new features
* Web hosting and infrastructure setup
* Software licenses (e.g. Visual Studio, IDA Pro, etc.)
* Additional hardware (e.g. GPUs as-needed to improve rendering support, other peripherals to add support for, etc.)
We also more than gladly accept used Switch consoles, preferably ones with firmware 3.0.0 or lower! If you would like to give yours away, don't hesitate to join our [Discord](https://discord.gg/VXqngT3) and talk to bunnei. You may also contact: donations@yuzu-emu.org.
If you wish to support us a different way, please join our [Discord](https://discord.gg/u77vRWY) and talk to bunnei. You may also contact: donations@yuzu-emu.org.
## License
yuzu is licensed under the GPLv2 (or any later version). Refer to the [license.txt](https://github.com/yuzu-emu/yuzu/blob/master/license.txt) file.

View File

@@ -115,7 +115,7 @@ if (ENABLE_WEB_SERVICE)
# httplib
add_library(httplib INTERFACE)
target_include_directories(httplib INTERFACE ./httplib)
target_include_directories(httplib INTERFACE ./cpp-httplib)
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
if (WIN32)

1
externals/cpp-httplib vendored Submodule

Submodule externals/cpp-httplib added at 9648f950f5

View File

@@ -1,15 +0,0 @@
From https://github.com/yhirose/cpp-httplib/tree/ff5677ad197947177c158fe857caff4f0e242045 with https://github.com/yhirose/cpp-httplib/pull/701
MIT License
===
cpp-httplib
A C++11 header-only HTTP library.
It's extremely easy to setup. Just include httplib.h file in your code!
Inspired by Sinatra and express.
© 2017 Yuji Hirose

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux"))
if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR APPLE)
set(LIBUSB_FOUND ON CACHE BOOL "libusb is present" FORCE)
set(LIBUSB_VERSION "1.0.24" CACHE STRING "libusb version string" FORCE)

View File

@@ -15,7 +15,7 @@ constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
constexpr ResultCode ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
} // namespace Audren
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8');
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '9');
constexpr std::size_t MAX_MIX_BUFFERS = 24;
constexpr std::size_t MAX_BIQUAD_FILTERS = 2;
constexpr std::size_t MAX_CHANNEL_COUNT = 6;

View File

@@ -4,6 +4,8 @@
#pragma once
#include <array>
#include <vector>
#include "audio_core/common.h"
#include "common/common_funcs.h"
#include "common/common_types.h"

View File

@@ -107,9 +107,12 @@ void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
active_buffer = queued_buffers.front();
queued_buffers.pop();
VolumeAdjustSamples(active_buffer->GetSamples(), game_volume);
auto& samples = active_buffer->GetSamples();
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
VolumeAdjustSamples(samples, game_volume);
sink_stream.EnqueueSamples(GetNumChannels(), samples);
played_samples += samples.size();
const auto buffer_release_ns = GetBufferReleaseNS(*active_buffer);

View File

@@ -89,6 +89,11 @@ public:
return sample_rate;
}
/// Gets the number of samples played so far
[[nodiscard]] u64 GetPlayedSampleCount() const {
return played_samples;
}
/// Gets the number of channels
[[nodiscard]] u32 GetNumChannels() const;
@@ -106,6 +111,7 @@ private:
[[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
u32 sample_rate; ///< Sample rate of the stream
u64 played_samples{}; ///< The current played sample count
Format format; ///< Format of the stream
float game_volume = 1.0f; ///< The volume the game currently has set
ReleaseCallback release_callback; ///< Buffer release callback for the stream

View File

@@ -110,7 +110,6 @@ add_library(common STATIC
cityhash.cpp
cityhash.h
common_funcs.h
common_sizes.h
common_types.h
concepts.h
div_ceil.h
@@ -134,6 +133,7 @@ add_library(common STATIC
host_memory.cpp
host_memory.h
intrusive_red_black_tree.h
literals.h
logging/backend.cpp
logging/backend.h
logging/filter.cpp

View File

@@ -1,43 +0,0 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <limits>
#include "common/common_types.h"
namespace Common {
enum : u64 {
Size_1_KB = 0x400ULL,
Size_64_KB = 64ULL * Size_1_KB,
Size_128_KB = 128ULL * Size_1_KB,
Size_1_MB = 0x100000ULL,
Size_2_MB = 2ULL * Size_1_MB,
Size_4_MB = 4ULL * Size_1_MB,
Size_5_MB = 5ULL * Size_1_MB,
Size_14_MB = 14ULL * Size_1_MB,
Size_32_MB = 32ULL * Size_1_MB,
Size_33_MB = 33ULL * Size_1_MB,
Size_128_MB = 128ULL * Size_1_MB,
Size_448_MB = 448ULL * Size_1_MB,
Size_507_MB = 507ULL * Size_1_MB,
Size_562_MB = 562ULL * Size_1_MB,
Size_1554_MB = 1554ULL * Size_1_MB,
Size_2048_MB = 2048ULL * Size_1_MB,
Size_2193_MB = 2193ULL * Size_1_MB,
Size_3285_MB = 3285ULL * Size_1_MB,
Size_4916_MB = 4916ULL * Size_1_MB,
Size_1_GB = 0x40000000ULL,
Size_2_GB = 2ULL * Size_1_GB,
Size_4_GB = 4ULL * Size_1_GB,
Size_6_GB = 6ULL * Size_1_GB,
Size_8_GB = 8ULL * Size_1_GB,
Size_64_GB = 64ULL * Size_1_GB,
Size_512_GB = 512ULL * Size_1_GB,
Size_Invalid = std::numeric_limits<u64>::max(),
};
} // namespace Common

View File

@@ -21,6 +21,8 @@ void DetachedTasks::WaitForAllTasks() {
}
DetachedTasks::~DetachedTasks() {
WaitForAllTasks();
std::unique_lock lock{mutex};
ASSERT(count == 0);
instance = nullptr;

View File

@@ -172,7 +172,7 @@ std::string ReadStringFromFile(const std::filesystem::path& path, FileType type)
size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
std::string_view string) {
if (!IsFile(path)) {
if (Exists(path) && !IsFile(path)) {
return 0;
}
@@ -183,7 +183,7 @@ size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
size_t AppendStringToFile(const std::filesystem::path& path, FileType type,
std::string_view string) {
if (!IsFile(path)) {
if (Exists(path) && !IsFile(path)) {
return 0;
}

View File

@@ -49,7 +49,7 @@ void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::op
/**
* Reads an entire file at path and returns a string of the contents read from the file.
* If the filesystem object at path is not a file, this function returns an empty string.
* If the filesystem object at path is not a regular file, this function returns an empty string.
*
* @param path Filesystem path
* @param type File type
@@ -72,7 +72,8 @@ template <typename Path>
/**
* Writes a string to a file at path and returns the number of characters successfully written.
* If a file already exists at path, its contents will be erased.
* If the filesystem object at path is not a file, this function returns 0.
* If a file does not exist at path, it creates and opens a new empty file for writing.
* If the filesystem object at path exists and is not a regular file, this function returns 0.
*
* @param path Filesystem path
* @param type File type
@@ -95,7 +96,8 @@ template <typename Path>
/**
* Appends a string to a file at path and returns the number of characters successfully written.
* If the filesystem object at path is not a file, this function returns 0.
* If a file does not exist at path, it creates and opens a new empty file for appending.
* If the filesystem object at path exists and is not a regular file, this function returns 0.
*
* @param path Filesystem path
* @param type File type
@@ -394,11 +396,11 @@ public:
[[nodiscard]] size_t WriteString(std::span<const char> string) const;
/**
* Flushes any unwritten buffered data into the file.
* Attempts to flush any unwritten buffered data into the file and flush the file into the disk.
*
* @returns True if the flush was successful, false otherwise.
*/
[[nodiscard]] bool Flush() const;
bool Flush() const;
/**
* Resizes the file to a given size.

View File

@@ -135,8 +135,9 @@ std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, File
return nullptr;
}
if (!IsFile(path)) {
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file",
if (Exists(path) && !IsFile(path)) {
LOG_ERROR(Common_Filesystem,
"Filesystem object at path={} exists and is not a regular file",
PathToUTF8String(path));
return nullptr;
}

View File

@@ -48,18 +48,18 @@ template <typename Path>
*
* Failures occur when:
* - Input path is not valid
* - Filesystem object at path is not a file
* - Filesystem object at path is not a regular file
* - Filesystem at path is read only
*
* @param path Filesystem path
*
* @returns True if file removal succeeds or file does not exist, false otherwise.
*/
[[nodiscard]] bool RemoveFile(const std::filesystem::path& path);
bool RemoveFile(const std::filesystem::path& path);
#ifdef _WIN32
template <typename Path>
[[nodiscard]] bool RemoveFile(const Path& path) {
bool RemoveFile(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) {
return RemoveFile(ToU8String(path));
} else {
@@ -74,7 +74,7 @@ template <typename Path>
* Failures occur when:
* - One or both input path(s) is not valid
* - Filesystem object at old_path does not exist
* - Filesystem object at old_path is not a file
* - Filesystem object at old_path is not a regular file
* - Filesystem object at new_path exists
* - Filesystem at either path is read only
*
@@ -110,8 +110,8 @@ template <typename Path1, typename Path2>
*
* Failures occur when:
* - Input path is not valid
* - Filesystem object at path is not a file
* - The file is not opened
* - Filesystem object at path exists and is not a regular file
* - The file is not open
*
* @param path Filesystem path
* @param mode File access mode
@@ -251,11 +251,11 @@ template <typename Path>
*
* @returns True if directory removal succeeds or directory does not exist, false otherwise.
*/
[[nodiscard]] bool RemoveDir(const std::filesystem::path& path);
bool RemoveDir(const std::filesystem::path& path);
#ifdef _WIN32
template <typename Path>
[[nodiscard]] bool RemoveDir(const Path& path) {
bool RemoveDir(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) {
return RemoveDir(ToU8String(path));
} else {
@@ -276,11 +276,11 @@ template <typename Path>
*
* @returns True if the directory and all of its contents are removed successfully, false otherwise.
*/
[[nodiscard]] bool RemoveDirRecursively(const std::filesystem::path& path);
bool RemoveDirRecursively(const std::filesystem::path& path);
#ifdef _WIN32
template <typename Path>
[[nodiscard]] bool RemoveDirRecursively(const Path& path) {
bool RemoveDirRecursively(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) {
return RemoveDirRecursively(ToU8String(path));
} else {
@@ -301,11 +301,11 @@ template <typename Path>
*
* @returns True if all of the directory's contents are removed successfully, false otherwise.
*/
[[nodiscard]] bool RemoveDirContentsRecursively(const std::filesystem::path& path);
bool RemoveDirContentsRecursively(const std::filesystem::path& path);
#ifdef _WIN32
template <typename Path>
[[nodiscard]] bool RemoveDirContentsRecursively(const Path& path) {
bool RemoveDirContentsRecursively(const Path& path) {
if constexpr (IsChar<typename Path::value_type>) {
return RemoveDirContentsRecursively(ToU8String(path));
} else {
@@ -435,11 +435,13 @@ template <typename Path>
#endif
/**
* Returns whether a filesystem object at path is a file.
* Returns whether a filesystem object at path is a regular file.
* A regular file is a file that stores text or binary data.
* It is not a directory, symlink, FIFO, socket, block device, or character device.
*
* @param path Filesystem path
*
* @returns True if a filesystem object at path is a file, false otherwise.
* @returns True if a filesystem object at path is a regular file, false otherwise.
*/
[[nodiscard]] bool IsFile(const std::filesystem::path& path);

View File

@@ -53,8 +53,9 @@ template <typename ContiguousContainer>
std::string out;
out.reserve(std::size(data) * pad_width);
const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}");
for (const u8 c : data) {
out += fmt::format(upper ? "{:02X}" : "{:02x}", c);
out += fmt::format(format_str, c);
}
return out;

View File

@@ -34,7 +34,7 @@ constexpr size_t HugePageSize = 0x200000;
// Manually imported for MinGW compatibility
#ifndef MEM_RESERVE_PLACEHOLDER
#define MEM_RESERVE_PLACEHOLDER 0x0004000
#define MEM_RESERVE_PLACEHOLDER 0x00040000
#endif
#ifndef MEM_REPLACE_PLACEHOLDER
#define MEM_REPLACE_PLACEHOLDER 0x00004000

31
src/common/literals.h Normal file
View File

@@ -0,0 +1,31 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace Common::Literals {
constexpr u64 operator""_KiB(unsigned long long int x) {
return 1024ULL * x;
}
constexpr u64 operator""_MiB(unsigned long long int x) {
return 1024_KiB * x;
}
constexpr u64 operator""_GiB(unsigned long long int x) {
return 1024_MiB * x;
}
constexpr u64 operator""_TiB(unsigned long long int x) {
return 1024_GiB * x;
}
constexpr u64 operator""_PiB(unsigned long long int x) {
return 1024_TiB * x;
}
} // namespace Common::Literals

View File

@@ -19,6 +19,8 @@
#include "common/assert.h"
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/literals.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
@@ -98,8 +100,8 @@ private:
write_logs(entry);
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case
// where a system is repeatedly spamming logs even on close.
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
// case where a system is repeatedly spamming logs even on close.
const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
int logs_written = 0;
while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) {
@@ -159,7 +161,7 @@ FileBackend::FileBackend(const std::filesystem::path& filename) {
// Existence checks are done within the functions themselves.
// We don't particularly care if these succeed or not.
void(FS::RemoveFile(old_filename));
FS::RemoveFile(old_filename);
void(FS::RenameFile(filename, old_filename));
file =
@@ -169,10 +171,11 @@ FileBackend::FileBackend(const std::filesystem::path& filename) {
FileBackend::~FileBackend() = default;
void FileBackend::Write(const Entry& entry) {
using namespace Common::Literals;
// prevent logs from going over the maximum size (in case its spamming and the user doesn't
// know)
constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024;
constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024;
constexpr std::size_t MAX_BYTES_WRITTEN = 100_MiB;
constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1_GiB;
if (!file->IsOpen()) {
return;
@@ -186,7 +189,7 @@ void FileBackend::Write(const Entry& entry) {
bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n'));
if (entry.log_level >= Level::Error) {
void(file->Flush());
file->Flush();
}
}

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include "common/common_types.h"

View File

@@ -59,6 +59,7 @@ void LogSettings() {
log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue());
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
log_setting("Audio_OutputEngine", values.sink_id);
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
@@ -122,6 +123,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.cpu_accuracy.SetGlobal(true);
values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
@@ -141,6 +143,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.use_assembly_shaders.SetGlobal(true);
values.use_asynchronous_shaders.SetGlobal(true);
values.use_fast_gpu_time.SetGlobal(true);
values.use_caches_gc.SetGlobal(true);
values.bg_red.SetGlobal(true);
values.bg_green.SetGlobal(true);
values.bg_blue.SetGlobal(true);

View File

@@ -129,6 +129,7 @@ struct Values {
Setting<bool> cpuopt_unsafe_unfuse_fma;
Setting<bool> cpuopt_unsafe_reduce_fp_error;
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr;
Setting<bool> cpuopt_unsafe_inaccurate_nan;
Setting<bool> cpuopt_unsafe_fastmem_check;
@@ -153,6 +154,7 @@ struct Values {
Setting<bool> use_assembly_shaders;
Setting<bool> use_asynchronous_shaders;
Setting<bool> use_fast_gpu_time;
Setting<bool> use_caches_gc;
Setting<float> bg_red;
Setting<float> bg_green;

View File

@@ -139,6 +139,7 @@ add_library(core STATIC
frontend/input.h
hardware_interrupt_manager.cpp
hardware_interrupt_manager.h
hle/api_version.h
hle/ipc.h
hle/ipc_helpers.h
hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -550,6 +551,8 @@ add_library(core STATIC
hle/service/spl/module.h
hle/service/spl/spl.cpp
hle/service/spl/spl.h
hle/service/spl/spl_results.h
hle/service/spl/spl_types.h
hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h
hle/service/time/clock_types.h

View File

@@ -8,6 +8,7 @@
#include <dynarmic/interface/A32/config.h>
#include <dynarmic/interface/A32/context.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
@@ -22,6 +23,8 @@
namespace Core {
using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
@@ -143,8 +146,8 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 400 * 1024 * 1024;
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Safe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
@@ -186,6 +189,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
}
if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}

View File

@@ -7,6 +7,7 @@
#include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/A64/config.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
@@ -24,6 +25,7 @@
namespace Core {
using Vector = Dynarmic::A64::Vector;
using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
@@ -184,8 +186,8 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 400 * 1024 * 1024;
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Safe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {

View File

@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <array>
#include <atomic>
#include <memory>
#include <utility>
@@ -377,7 +378,7 @@ struct System::Impl {
std::unique_ptr<Core::DeviceMemory> device_memory;
Core::Memory::Memory memory;
CpuManager cpu_manager;
bool is_powered_on = false;
std::atomic_bool is_powered_on{};
bool exit_lock = false;
Reporter reporter;
@@ -463,7 +464,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
}
bool System::IsPoweredOn() const {
return impl->is_powered_on;
return impl->is_powered_on.load(std::memory_order::relaxed);
}
void System::PrepareReschedule() {

View File

@@ -835,7 +835,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
"key_area_key_ocean_{:02X}",
"key_area_key_system_{:02X}",
};
WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);
WriteKeyToFile(category, fmt::format(fmt::runtime(kak_names.at(field2)), field1), key);
} else if (id == S128KeyType::Master) {
WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key);
} else if (id == S128KeyType::Package1) {

View File

@@ -58,14 +58,17 @@ static bool FollowsNcaIdFormat(std::string_view name) {
static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
bool within_two_digit, bool cnmt_suffix) {
if (!within_two_digit)
return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca",
Common::HexToString(nca_id, second_hex_upper));
if (!within_two_digit) {
const auto format_str = fmt::runtime(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca");
return fmt::format(format_str, Common::HexToString(nca_id, second_hex_upper));
}
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0],
Common::HexToString(nca_id, second_hex_upper));
const auto format_str =
fmt::runtime(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca");
return fmt::format(format_str, hash[0], Common::HexToString(nca_id, second_hex_upper));
}
static std::string GetCNMTName(TitleType type, u64 title_id) {

View File

@@ -4,47 +4,29 @@
#include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/vfs_vector.h"
#include "core/hle/api_version.h"
namespace FileSys::SystemArchive {
namespace SystemVersionData {
// This section should reflect the best system version to describe yuzu's HLE api.
// TODO(DarkLordZach): Update when HLE gets better.
constexpr u8 VERSION_MAJOR = 11;
constexpr u8 VERSION_MINOR = 0;
constexpr u8 VERSION_MICRO = 1;
constexpr u8 REVISION_MAJOR = 1;
constexpr u8 REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
constexpr char DISPLAY_VERSION[] = "11.0.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
} // namespace SystemVersionData
std::string GetLongDisplayVersion() {
return SystemVersionData::DISPLAY_TITLE;
return HLE::ApiVersion::DISPLAY_TITLE;
}
VirtualDir SystemVersion() {
VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
file->WriteObject(SystemVersionData::VERSION_MAJOR, 0);
file->WriteObject(SystemVersionData::VERSION_MINOR, 1);
file->WriteObject(SystemVersionData::VERSION_MICRO, 2);
file->WriteObject(SystemVersionData::REVISION_MAJOR, 4);
file->WriteObject(SystemVersionData::REVISION_MINOR, 5);
file->WriteArray(SystemVersionData::PLATFORM_STRING,
std::min<u64>(sizeof(SystemVersionData::PLATFORM_STRING), 0x20ULL), 0x8);
file->WriteArray(SystemVersionData::VERSION_HASH,
std::min<u64>(sizeof(SystemVersionData::VERSION_HASH), 0x40ULL), 0x28);
file->WriteArray(SystemVersionData::DISPLAY_VERSION,
std::min<u64>(sizeof(SystemVersionData::DISPLAY_VERSION), 0x18ULL), 0x68);
file->WriteArray(SystemVersionData::DISPLAY_TITLE,
std::min<u64>(sizeof(SystemVersionData::DISPLAY_TITLE), 0x80ULL), 0x80);
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MICRO, 2);
file->WriteObject(HLE::ApiVersion::SDK_REVISION_MAJOR, 4);
file->WriteObject(HLE::ApiVersion::SDK_REVISION_MINOR, 5);
file->WriteArray(HLE::ApiVersion::PLATFORM_STRING,
std::min<u64>(sizeof(HLE::ApiVersion::PLATFORM_STRING), 0x20ULL), 0x8);
file->WriteArray(HLE::ApiVersion::VERSION_HASH,
std::min<u64>(sizeof(HLE::ApiVersion::VERSION_HASH), 0x40ULL), 0x28);
file->WriteArray(HLE::ApiVersion::DISPLAY_VERSION,
std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_VERSION), 0x18ULL), 0x68);
file->WriteArray(HLE::ApiVersion::DISPLAY_TITLE,
std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_TITLE), 0x80ULL), 0x80);
return std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{file},
std::vector<VirtualDir>{}, "data");
}

View File

@@ -24,17 +24,12 @@ constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) {
case Mode::Read:
return FS::FileAccessMode::Read;
case Mode::Write:
return FS::FileAccessMode::Write;
case Mode::ReadWrite:
return FS::FileAccessMode::ReadWrite;
case Mode::Append:
return FS::FileAccessMode::Append;
case Mode::ReadAppend:
return FS::FileAccessMode::ReadAppend;
case Mode::WriteAppend:
return FS::FileAccessMode::Append;
case Mode::All:
return FS::FileAccessMode::ReadAppend;
return FS::FileAccessMode::ReadWrite;
default:
return {};
}

View File

@@ -4,6 +4,7 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <tuple>

View File

@@ -0,0 +1,40 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
// This file contains yuzu's HLE API version constants.
namespace HLE::ApiVersion {
// Horizon OS version constants.
constexpr u8 HOS_VERSION_MAJOR = 11;
constexpr u8 HOS_VERSION_MINOR = 0;
constexpr u8 HOS_VERSION_MICRO = 1;
// NintendoSDK version constants.
constexpr u8 SDK_REVISION_MAJOR = 1;
constexpr u8 SDK_REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
constexpr char DISPLAY_VERSION[] = "11.0.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
// Atmosphere version constants.
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0;
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19;
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 4;
constexpr u32 GetTargetFirmware() {
return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 |
u32{HOS_VERSION_MICRO} << 8 | 0U;
}
} // namespace HLE::ApiVersion

View File

@@ -345,8 +345,12 @@ public:
explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) {
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
Skip(ctx.GetDataPayloadOffset(), false);
// TIPC does not have data payload offset
if (!ctx.IsTipc()) {
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
Skip(ctx.GetDataPayloadOffset(), false);
}
// Skip the u64 command id, it's already stored in the context
static constexpr u32 CommandIdSize = 2;
Skip(CommandIdSize, false);

View File

@@ -4,7 +4,8 @@
#include <random>
#include "common/common_sizes.h"
#include "common/literals.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
#include "core/hle/kernel/k_trace.h"
@@ -25,6 +26,8 @@ constexpr const std::size_t RequiredNonSecureSystemMemorySize =
namespace {
using namespace Common::Literals;
u32 GetMemoryModeForInit() {
return 0x01;
}
@@ -57,11 +60,11 @@ size_t KSystemControl::Init::GetIntendedMemorySize() {
switch (GetMemorySizeForInit()) {
case Smc::MemorySize_4GB:
default: // All invalid modes should go to 4GB.
return Common::Size_4_GB;
return 4_GiB;
case Smc::MemorySize_6GB:
return Common::Size_6_GB;
return 6_GiB;
case Smc::MemorySize_8GB:
return Common::Size_8_GB;
return 8_GiB;
}
}
@@ -79,17 +82,17 @@ std::size_t KSystemControl::Init::GetApplicationPoolSize() {
switch (GetMemoryArrangeForInit()) {
case Smc::MemoryArrangement_4GB:
default:
return Common::Size_3285_MB;
return 3285_MiB;
case Smc::MemoryArrangement_4GBForAppletDev:
return Common::Size_2048_MB;
return 2048_MiB;
case Smc::MemoryArrangement_4GBForSystemDev:
return Common::Size_3285_MB;
return 3285_MiB;
case Smc::MemoryArrangement_6GB:
return Common::Size_4916_MB;
return 4916_MiB;
case Smc::MemoryArrangement_6GBForAppletDev:
return Common::Size_3285_MB;
return 3285_MiB;
case Smc::MemoryArrangement_8GB:
return Common::Size_4916_MB;
return 4916_MiB;
}
}();
@@ -103,22 +106,22 @@ size_t KSystemControl::Init::GetAppletPoolSize() {
switch (GetMemoryArrangeForInit()) {
case Smc::MemoryArrangement_4GB:
default:
return Common::Size_507_MB;
return 507_MiB;
case Smc::MemoryArrangement_4GBForAppletDev:
return Common::Size_1554_MB;
return 1554_MiB;
case Smc::MemoryArrangement_4GBForSystemDev:
return Common::Size_448_MB;
return 448_MiB;
case Smc::MemoryArrangement_6GB:
return Common::Size_562_MB;
return 562_MiB;
case Smc::MemoryArrangement_6GBForAppletDev:
return Common::Size_2193_MB;
return 2193_MiB;
case Smc::MemoryArrangement_8GB:
return Common::Size_2193_MB;
return 2193_MiB;
}
}();
// Return (possibly) adjusted size.
constexpr size_t ExtraSystemMemoryForAtmosphere = Common::Size_33_MB;
constexpr size_t ExtraSystemMemoryForAtmosphere = 33_MiB;
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
}

View File

@@ -5,34 +5,37 @@
#include <array>
#include "common/assert.h"
#include "common/common_sizes.h"
#include "common/literals.h"
#include "core/hle/kernel/k_address_space_info.h"
namespace Kernel {
namespace {
using namespace Common::Literals;
constexpr u64 Size_Invalid = UINT64_MAX;
// clang-format off
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
{ .bit_width = 32, .address = 2_MiB , .size = 1_GiB - 2_MiB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = 1_GiB , .size = 4_GiB - 1_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, },
}};
// clang-format on
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
return index < AddressSpaceInfos.size() &&
AddressSpaceInfos[index].address != Common::Size_Invalid;
return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Size_Invalid;
}
using IndexArray =

View File

@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/alignment.h"
#include "common/literals.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_system_control.h"
@@ -12,8 +13,10 @@ namespace Kernel {
namespace {
using namespace Common::Literals;
constexpr size_t CarveoutAlignment = 0x20000;
constexpr size_t CarveoutSizeMax = (512ULL * 1024 * 1024) - CarveoutAlignment;
constexpr size_t CarveoutSizeMax = (512_MiB) - CarveoutAlignment;
bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
// Above firmware 2.0.0, the PMC is not mappable.

View File

@@ -7,8 +7,7 @@
#include <utility>
#include "common/alignment.h"
#include "common/common_sizes.h"
#include "common/common_types.h"
#include "common/literals.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_region.h"
#include "core/hle/kernel/k_memory_region_type.h"
@@ -16,20 +15,22 @@
namespace Kernel {
constexpr std::size_t L1BlockSize = Common::Size_1_GB;
constexpr std::size_t L2BlockSize = Common::Size_2_MB;
using namespace Common::Literals;
constexpr std::size_t L1BlockSize = 1_GiB;
constexpr std::size_t L2BlockSize = 2_MiB;
constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
}
constexpr std::size_t MainMemorySize = Common::Size_4_GB;
constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
constexpr std::size_t MainMemorySize = 4_GiB;
constexpr std::size_t MainMemorySizeMax = 8_GiB;
constexpr std::size_t ReservedEarlyDramSize = 0x60000;
constexpr std::size_t ReservedEarlyDramSize = 384_KiB;
constexpr std::size_t DramPhysicalAddress = 0x80000000;
constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
constexpr std::size_t KernelAslrAlignment = 2_MiB;
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
@@ -40,7 +41,7 @@ constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceE
constexpr std::size_t KernelVirtualAddressSpaceSize =
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
constexpr std::size_t KernelVirtualAddressCodeSize = 392_KiB;
constexpr std::size_t KernelVirtualAddressCodeEnd =
KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
@@ -53,14 +54,14 @@ constexpr std::size_t KernelPhysicalAddressSpaceSize =
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
constexpr std::size_t KernelInitialPageHeapSize = 128_KiB;
constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
constexpr std::size_t KernelSlabHeapDataSize = 5_MiB;
constexpr std::size_t KernelSlabHeapGapsSize = 2_MiB - 64_KiB;
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
constexpr std::size_t KernelSlabHeapAdditionalSize = 416_KiB;
constexpr std::size_t KernelResourceSize =
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;

View File

@@ -4,6 +4,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/literals.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_address_space_info.h"
@@ -23,6 +24,8 @@ namespace Kernel {
namespace {
using namespace Common::Literals;
constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) {
switch (as_type) {
case FileSys::ProgramAddressSpaceType::Is32Bit:
@@ -89,7 +92,7 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_
}
// Set code regions and determine remaining
constexpr std::size_t RegionAlignment{2 * 1024 * 1024};
constexpr std::size_t RegionAlignment{2_MiB};
VAddr process_code_start{};
VAddr process_code_end{};
std::size_t stack_region_size{};

View File

@@ -79,6 +79,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
R_UNLESS(current_values[index] <= value, ResultInvalidState);
limit_values[index] = value;
peak_values[index] = current_values[index];
return ResultSuccess;
}

View File

@@ -4,9 +4,13 @@
#pragma once
#include "common/common_funcs.h"
namespace Kernel {
using namespace Common::Literals;
constexpr bool IsKTraceEnabled = false;
constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16 * 1024 * 1024 : 0;
constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16_MiB : 0;
} // namespace Kernel

View File

@@ -12,7 +12,6 @@
#include <utility>
#include "common/assert.h"
#include "common/common_sizes.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/thread.h"
@@ -180,7 +179,7 @@ struct KernelCore::Impl {
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
// Reserve secure applet memory, introduced in firmware 5.0.0
constexpr u64 secure_applet_memory_size{Common::Size_4_MB};
constexpr u64 secure_applet_memory_size{4_MiB};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size));
@@ -320,8 +319,8 @@ struct KernelCore::Impl {
const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
// Setup the containing kernel region.
constexpr size_t KernelRegionSize = Common::Size_1_GB;
constexpr size_t KernelRegionAlign = Common::Size_1_GB;
constexpr size_t KernelRegionSize = 1_GiB;
constexpr size_t KernelRegionAlign = 1_GiB;
constexpr VAddr kernel_region_start =
Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
size_t kernel_region_size = KernelRegionSize;
@@ -368,7 +367,7 @@ struct KernelCore::Impl {
// Decide on the actual size for the misc region.
constexpr size_t MiscRegionAlign = KernelAslrAlignment;
constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
constexpr size_t MiscRegionMinimumSize = 32_MiB;
const size_t misc_region_size = Common::AlignUp(
std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
ASSERT(misc_region_size > 0);
@@ -381,7 +380,7 @@ struct KernelCore::Impl {
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
// Setup the stack region.
constexpr size_t StackRegionSize = Common::Size_14_MB;
constexpr size_t StackRegionSize = 14_MiB;
constexpr size_t StackRegionAlign = KernelAslrAlignment;
const VAddr stack_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
@@ -414,7 +413,7 @@ struct KernelCore::Impl {
slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
// Setup the temp region.
constexpr size_t TempRegionSize = Common::Size_128_MB;
constexpr size_t TempRegionSize = 128_MiB;
constexpr size_t TempRegionAlign = KernelAslrAlignment;
const VAddr temp_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
@@ -470,7 +469,7 @@ struct KernelCore::Impl {
// Determine size available for kernel page table heaps, requiring > 8 MB.
const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
ASSERT(page_table_heap_size / 4_MiB > 2);
// Insert a physical region for the kernel page table heap region
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
@@ -495,7 +494,7 @@ struct KernelCore::Impl {
ASSERT(linear_extents.GetEndAddress() != 0);
// Setup the linear mapping region.
constexpr size_t LinearRegionAlign = Common::Size_1_GB;
constexpr size_t LinearRegionAlign = 1_GiB;
const PAddr aligned_linear_phys_start =
Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
const size_t linear_region_size =

View File

@@ -117,7 +117,7 @@ AOC_U::AOC_U(Core::System& system_)
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
{10, nullptr, "GetAddOnContentListChangedEventWithProcessId"},
{10, &AOC_U::GetAddOnContentListChangedEventWithProcessId, "GetAddOnContentListChangedEventWithProcessId"},
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
{110, nullptr, "CreateContentsServiceManager"},
@@ -257,6 +257,14 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(aoc_change_event.GetReadableEvent());
}
void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(aoc_change_event.GetReadableEvent());
}
void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");

View File

@@ -28,6 +28,7 @@ private:
void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx);
void PrepareAddOnContent(Kernel::HLERequestContext& ctx);
void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
void GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx);
void CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);

View File

@@ -58,7 +58,7 @@ public:
{7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
{8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
{9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
{10, nullptr, "GetAudioOutPlayedSampleCount"},
{10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"},
{11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"},
{12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
{13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
@@ -186,6 +186,14 @@ private:
rb.Push(static_cast<u32>(stream->GetQueueSize()));
}
void GetAudioOutPlayedSampleCount(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(stream->GetPlayedSampleCount());
}
void FlushAudioOutBuffers(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");

View File

@@ -253,7 +253,11 @@ void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(worker_buffer_sz);
}
void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
void HwOpus::GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx) {
GetWorkBufferSize(ctx);
}
void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
@@ -291,14 +295,47 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
}
void HwOpus::OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
LOG_CRITICAL(Audio, "called sample_rate={}, channel_count={}", sample_rate, channel_count);
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
sample_rate == 12000 || sample_rate == 8000,
"Invalid sample rate");
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
const int num_stereo_streams = channel_count == 2 ? 1 : 0;
const auto mapping_table = CreateMappingTable(channel_count);
int error = 0;
OpusDecoderPtr decoder{
opus_multistream_decoder_create(sample_rate, static_cast<int>(channel_count), 1,
num_stereo_streams, mapping_table.data(), &error)};
if (error != OPUS_OK || decoder == nullptr) {
LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
rb.Push(ResultUnknown);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHardwareOpusDecoderManager>(
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
}
HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
static const FunctionInfo functions[] = {
{0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"},
{0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
{1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
{2, nullptr, "OpenOpusDecoderForMultiStream"},
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
{4, nullptr, "OpenHardwareOpusDecoderEx"},
{5, nullptr, "GetWorkBufferSizeEx"},
{4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
{7, nullptr, "GetWorkBufferSizeForMultiStreamEx"},
};

View File

@@ -18,8 +18,10 @@ public:
~HwOpus() override;
private:
void OpenOpusDecoder(Kernel::HLERequestContext& ctx);
void OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx);
void OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx);
void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
void GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Audio

View File

@@ -313,7 +313,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
void(Common::FS::RemoveFile(zip_path));
Common::FS::RemoveFile(zip_path);
}
HandleDownloadDisplayResult(applet_manager, res);
@@ -445,7 +445,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
void(Common::FS::RemoveFile(bin_file_path));
Common::FS::RemoveFile(bin_file_path);
}
HandleDownloadDisplayResult(applet_manager, res);

View File

@@ -314,6 +314,8 @@ void Controller_NPad::OnInit() {
void Controller_NPad::OnLoadInputDevices() {
const auto& players = Settings::values.players.GetValue();
std::lock_guard lock{mutex};
for (std::size_t i = 0; i < players.size(); ++i) {
std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
@@ -348,6 +350,8 @@ void Controller_NPad::OnRelease() {
}
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
std::lock_guard lock{mutex};
const auto controller_idx = NPadIdToIndex(npad_id);
const auto controller_type = connected_controllers[controller_idx].type;
if (!connected_controllers[controller_idx].is_connected) {

View File

@@ -6,6 +6,8 @@
#include <array>
#include <atomic>
#include <mutex>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/quaternion.h"
@@ -563,6 +565,8 @@ private:
using MotionArray = std::array<
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
10>;
std::mutex mutex;
ButtonArray buttons;
StickArray sticks;
VibrationArray vibrations;

View File

@@ -4,6 +4,8 @@
#pragma once
#include <array>
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/uuid.h"

View File

@@ -149,10 +149,10 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
std::string function_name = info == nullptr ? fmt::format("{}", ctx.GetCommand()) : info->name;
fmt::memory_buffer buf;
fmt::format_to(buf, "function '{}': port='{}' cmd_buf={{[0]=0x{:X}", function_name,
service_name, cmd_buf[0]);
fmt::format_to(std::back_inserter(buf), "function '{}': port='{}' cmd_buf={{[0]=0x{:X}",
function_name, service_name, cmd_buf[0]);
for (int i = 1; i <= 8; ++i) {
fmt::format_to(buf, ", [{}]=0x{:X}", i, cmd_buf[i]);
fmt::format_to(std::back_inserter(buf), ", [{}]=0x{:X}", i, cmd_buf[i]);
}
buf.push_back('}');

View File

@@ -9,7 +9,7 @@ namespace Service::SPL {
CSRNG::CSRNG(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "csrng") {
static const FunctionInfo functions[] = {
{0, &CSRNG::GetRandomBytes, "GetRandomBytes"},
{0, &CSRNG::GenerateRandomBytes, "GenerateRandomBytes"},
};
RegisterHandlers(functions);
}

View File

@@ -10,6 +10,7 @@
#include <vector>
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/hle/api_version.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/module.h"
@@ -24,7 +25,46 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu
Module::Interface::~Interface() = default;
void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto config_item = rp.PopEnum<ConfigItem>();
// This should call svcCallSecureMonitor with the appropriate args.
// Since we do not have it implemented yet, we will use this for now.
const auto smc_result = GetConfigImpl(config_item);
const auto result_code = smc_result.Code();
if (smc_result.Failed()) {
LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item,
result_code.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result_code);
}
LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item,
result_code.raw, *smc_result);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result_code);
rb.Push(*smc_result);
}
void Module::Interface::ModularExponentiate(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("ModularExponentiate is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::SetConfig(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("SetConfig is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SPL, "called");
const std::size_t size = ctx.GetWriteBufferSize();
@@ -39,6 +79,88 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void Module::Interface::IsDevelopment(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("IsDevelopment is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::SetBootReason(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("SetBootReason is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
void Module::Interface::GetBootReason(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("GetBootReason is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
switch (config_item) {
case ConfigItem::DisableProgramVerification:
case ConfigItem::DramId:
case ConfigItem::SecurityEngineInterruptNumber:
case ConfigItem::FuseVersion:
case ConfigItem::HardwareType:
case ConfigItem::HardwareState:
case ConfigItem::IsRecoveryBoot:
case ConfigItem::DeviceId:
case ConfigItem::BootReason:
case ConfigItem::MemoryMode:
case ConfigItem::IsDevelopmentFunctionEnabled:
case ConfigItem::KernelConfiguration:
case ConfigItem::IsChargerHiZModeEnabled:
case ConfigItem::QuestState:
case ConfigItem::RegulatorType:
case ConfigItem::DeviceUniqueKeyGeneration:
case ConfigItem::Package2Hash:
return ResultSecureMonitorNotImplemented;
case ConfigItem::ExosphereApiVersion:
// Get information about the current exosphere version.
return MakeResult((u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware())));
case ConfigItem::ExosphereNeedsReboot:
// We are executing, so we aren't in the process of rebooting.
return MakeResult(u64{0});
case ConfigItem::ExosphereNeedsShutdown:
// We are executing, so we aren't in the process of shutting down.
return MakeResult(u64{0});
case ConfigItem::ExosphereGitCommitHash:
// Get information about the current exosphere git commit hash.
return MakeResult(u64{0});
case ConfigItem::ExosphereHasRcmBugPatch:
// Get information about whether this unit has the RCM bug patched.
return MakeResult(u64{0});
case ConfigItem::ExosphereBlankProdInfo:
// Get whether this unit should simulate a "blanked" PRODINFO.
return MakeResult(u64{0});
case ConfigItem::ExosphereAllowCalWrites:
// Get whether this unit should allow writing to the calibration partition.
return MakeResult(u64{0});
case ConfigItem::ExosphereEmummcType:
// Get what kind of emummc this unit has active.
return MakeResult(u64{0});
case ConfigItem::ExospherePayloadAddress:
// Gets the physical address of the reboot payload buffer, if one exists.
return ResultSecureMonitorNotInitialized;
case ConfigItem::ExosphereLogConfiguration:
// Get the log configuration.
return MakeResult(u64{0});
case ConfigItem::ExosphereForceEnableUsb30:
// Get whether usb 3.0 should be force-enabled.
return MakeResult(u64{0});
default:
return ResultSecureMonitorInvalidArgument;
}
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager);

View File

@@ -6,6 +6,8 @@
#include <random>
#include "core/hle/service/service.h"
#include "core/hle/service/spl/spl_results.h"
#include "core/hle/service/spl/spl_types.h"
namespace Core {
class System;
@@ -21,12 +23,21 @@ public:
const char* name);
~Interface() override;
void GetRandomBytes(Kernel::HLERequestContext& ctx);
// General
void GetConfig(Kernel::HLERequestContext& ctx);
void ModularExponentiate(Kernel::HLERequestContext& ctx);
void SetConfig(Kernel::HLERequestContext& ctx);
void GenerateRandomBytes(Kernel::HLERequestContext& ctx);
void IsDevelopment(Kernel::HLERequestContext& ctx);
void SetBootReason(Kernel::HLERequestContext& ctx);
void GetBootReason(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
private:
ResultVal<u64> GetConfigImpl(ConfigItem config_item) const;
std::mt19937 rng;
};
};

View File

@@ -10,13 +10,13 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
{11, nullptr, "IsDevelopment"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{0, &SPL::GetConfig, "GetConfig"},
{1, &SPL::ModularExponentiate, "ModularExponentiate"},
{5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, &SPL::IsDevelopment, "IsDevelopment"},
{24, &SPL::SetBootReason, "SetBootReason"},
{25, &SPL::GetBootReason, "GetBootReason"},
};
// clang-format on
@@ -27,22 +27,22 @@ SPL_MIG::SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:mig") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{0, &SPL::GetConfig, "GetConfig"},
{1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"},
{5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, &SPL::IsDevelopment, "IsDevelopment"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{24, &SPL::SetBootReason, "SetBootReason"},
{25, &SPL::GetBootReason, "GetBootReason"},
};
// clang-format on
@@ -53,16 +53,16 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:fs") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{0, &SPL::GetConfig, "GetConfig"},
{1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
{5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{9, nullptr, "ImportLotusKey"},
{10, nullptr, "DecryptLotusMessage"},
{11, nullptr, "IsDevelopment"},
{11, &SPL::IsDevelopment, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
@@ -71,8 +71,8 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{24, &SPL::SetBootReason, "SetBootReason"},
{25, &SPL::GetBootReason, "GetBootReason"},
{31, nullptr, "GetPackage2Hash"},
};
// clang-format on
@@ -84,14 +84,14 @@ SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:ssl") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{0, &SPL::GetConfig, "GetConfig"},
{1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
{11, nullptr, "IsDevelopment"},
{5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, &SPL::IsDevelopment, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
@@ -99,8 +99,8 @@ SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{24, &SPL::SetBootReason, "SetBootReason"},
{25, &SPL::GetBootReason, "GetBootReason"},
{26, nullptr, "DecryptAndStoreSslClientCertKey"},
{27, nullptr, "ModularExponentiateWithSslClientCertKey"},
};
@@ -113,14 +113,14 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:es") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{0, &SPL::GetConfig, "GetConfig"},
{1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"},
{5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, &SPL::IsDevelopment, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
@@ -131,8 +131,8 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{24, &SPL::SetBootReason, "SetBootReason"},
{25, &SPL::GetBootReason, "GetBootReason"},
{28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
{29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
{31, nullptr, "PrepareEsArchiveKey"},
@@ -147,14 +147,14 @@ SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:manu") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{0, &SPL::GetConfig, "GetConfig"},
{1, &SPL::ModularExponentiate, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
{11, nullptr, "IsDevelopment"},
{5, &SPL::SetConfig, "SetConfig"},
{7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"},
{11, &SPL::IsDevelopment, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
@@ -162,8 +162,8 @@ SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_)
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{24, &SPL::SetBootReason, "SetBootReason"},
{25, &SPL::GetBootReason, "GetBootReason"},
{30, nullptr, "ReencryptDeviceUniqueData"},
};
// clang-format on

View File

@@ -0,0 +1,31 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::SPL {
// Description 0 - 99
constexpr ResultCode ResultSecureMonitorError{ErrorModule::SPL, 0};
constexpr ResultCode ResultSecureMonitorNotImplemented{ErrorModule::SPL, 1};
constexpr ResultCode ResultSecureMonitorInvalidArgument{ErrorModule::SPL, 2};
constexpr ResultCode ResultSecureMonitorBusy{ErrorModule::SPL, 3};
constexpr ResultCode ResultSecureMonitorNoAsyncOperation{ErrorModule::SPL, 4};
constexpr ResultCode ResultSecureMonitorInvalidAsyncOperation{ErrorModule::SPL, 5};
constexpr ResultCode ResultSecureMonitorNotPermitted{ErrorModule::SPL, 6};
constexpr ResultCode ResultSecureMonitorNotInitialized{ErrorModule::SPL, 7};
constexpr ResultCode ResultInvalidSize{ErrorModule::SPL, 100};
constexpr ResultCode ResultUnknownSecureMonitorError{ErrorModule::SPL, 101};
constexpr ResultCode ResultDecryptionFailed{ErrorModule::SPL, 102};
constexpr ResultCode ResultOutOfKeySlots{ErrorModule::SPL, 104};
constexpr ResultCode ResultInvalidKeySlot{ErrorModule::SPL, 105};
constexpr ResultCode ResultBootReasonAlreadySet{ErrorModule::SPL, 106};
constexpr ResultCode ResultBootReasonNotSet{ErrorModule::SPL, 107};
constexpr ResultCode ResultInvalidArgument{ErrorModule::SPL, 108};
} // namespace Service::SPL

View File

@@ -0,0 +1,232 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <span>
#include "common/bit_field.h"
#include "common/common_types.h"
namespace Service::SPL {
constexpr size_t AES_128_KEY_SIZE = 0x10;
namespace Smc {
enum class FunctionId : u32 {
SetConfig = 0xC3000401,
GetConfig = 0xC3000002,
GetResult = 0xC3000003,
GetResultData = 0xC3000404,
ModularExponentiate = 0xC3000E05,
GenerateRandomBytes = 0xC3000006,
GenerateAesKek = 0xC3000007,
LoadAesKey = 0xC3000008,
ComputeAes = 0xC3000009,
GenerateSpecificAesKey = 0xC300000A,
ComputeCmac = 0xC300040B,
ReencryptDeviceUniqueData = 0xC300D60C,
DecryptDeviceUniqueData = 0xC300100D,
ModularExponentiateWithStorageKey = 0xC300060F,
PrepareEsDeviceUniqueKey = 0xC3000610,
LoadPreparedAesKey = 0xC3000011,
PrepareCommonEsTitleKey = 0xC3000012,
// Deprecated functions.
LoadEsDeviceKey = 0xC300100C,
DecryptAndStoreGcKey = 0xC300100E,
// Atmosphere functions.
AtmosphereIramCopy = 0xF0000201,
AtmosphereReadWriteRegister = 0xF0000002,
AtmosphereGetEmummcConfig = 0xF0000404,
};
enum class CipherMode {
CbcEncrypt = 0,
CbcDecrypt = 1,
Ctr = 2,
};
enum class DeviceUniqueDataMode {
DecryptDeviceUniqueData = 0,
DecryptAndStoreGcKey = 1,
DecryptAndStoreEsDeviceKey = 2,
DecryptAndStoreSslKey = 3,
DecryptAndStoreDrmDeviceCertKey = 4,
};
enum class ModularExponentiateWithStorageKeyMode {
Gc = 0,
Ssl = 1,
DrmDeviceCert = 2,
};
enum class EsCommonKeyType {
TitleKey = 0,
ArchiveKey = 1,
};
struct AsyncOperationKey {
u64 value;
};
} // namespace Smc
enum class HardwareType {
Icosa = 0,
Copper = 1,
Hoag = 2,
Iowa = 3,
Calcio = 4,
Aula = 5,
};
enum class SocType {
Erista = 0,
Mariko = 1,
};
enum class HardwareState {
Development = 0,
Production = 1,
};
enum class MemoryArrangement {
Standard = 0,
StandardForAppletDev = 1,
StandardForSystemDev = 2,
Expanded = 3,
ExpandedForAppletDev = 4,
// Note: Dynamic is not official.
// Atmosphere uses it to maintain compatibility with firmwares prior to 6.0.0,
// which removed the explicit retrieval of memory arrangement from PM.
Dynamic = 5,
Count,
};
enum class BootReason {
Unknown = 0,
AcOk = 1,
OnKey = 2,
RtcAlarm1 = 3,
RtcAlarm2 = 4,
};
struct BootReasonValue {
union {
u32 value{};
BitField<0, 8, u32> power_intr;
BitField<8, 8, u32> rtc_intr;
BitField<16, 8, u32> nv_erc;
BitField<24, 8, u32> boot_reason;
};
};
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
struct AesKey {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "AesKey definition!");
struct IvCtr {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "IvCtr definition!");
struct Cmac {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "Cmac definition!");
struct AccessKey {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "AccessKey definition!");
struct KeySource {
std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{};
std::span<u8> AsBytes() {
return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE};
}
std::span<const u8> AsBytes() const {
return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE};
}
};
static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "KeySource definition!");
enum class ConfigItem : u32 {
// Standard config items.
DisableProgramVerification = 1,
DramId = 2,
SecurityEngineInterruptNumber = 3,
FuseVersion = 4,
HardwareType = 5,
HardwareState = 6,
IsRecoveryBoot = 7,
DeviceId = 8,
BootReason = 9,
MemoryMode = 10,
IsDevelopmentFunctionEnabled = 11,
KernelConfiguration = 12,
IsChargerHiZModeEnabled = 13,
QuestState = 14,
RegulatorType = 15,
DeviceUniqueKeyGeneration = 16,
Package2Hash = 17,
// Extension config items for exosphere.
ExosphereApiVersion = 65000,
ExosphereNeedsReboot = 65001,
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010,
};
} // namespace Service::SPL

View File

@@ -125,7 +125,7 @@ ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& locati
return ERROR_TIME_NOT_FOUND;
}
vfs_file = zoneinfo_dir->GetFile(location_name);
vfs_file = zoneinfo_dir->GetFileRelative(location_name);
if (!vfs_file) {
LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
time_zone_binary_titleid, location_name);

View File

@@ -2,25 +2,23 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <stop_token>
#include <thread>
#include "common/settings.h"
#include "input_common/mouse/mouse_input.h"
namespace MouseInput {
Mouse::Mouse() {
update_thread = std::thread(&Mouse::UpdateThread, this);
update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
}
Mouse::~Mouse() {
update_thread_running = false;
if (update_thread.joinable()) {
update_thread.join();
}
}
Mouse::~Mouse() = default;
void Mouse::UpdateThread() {
void Mouse::UpdateThread(std::stop_token stop_token) {
constexpr int update_time = 10;
while (update_thread_running) {
while (!stop_token.stop_requested()) {
for (MouseInfo& info : mouse_info) {
const Common::Vec3f angular_direction{
-info.tilt_direction.y,

View File

@@ -6,6 +6,7 @@
#include <array>
#include <mutex>
#include <stop_token>
#include <thread>
#include "common/common_types.h"
@@ -85,7 +86,7 @@ public:
[[nodiscard]] const MouseData& GetMouseState(std::size_t button) const;
private:
void UpdateThread();
void UpdateThread(std::stop_token stop_token);
void UpdateYuzuSettings();
void StopPanning();
@@ -105,12 +106,11 @@ private:
u16 buttons{};
u16 toggle_buttons{};
u16 lock_buttons{};
std::thread update_thread;
std::jthread update_thread;
MouseButton last_button{MouseButton::Undefined};
std::array<MouseInfo, 7> mouse_info;
Common::SPSCQueue<MouseStatus> mouse_queue;
bool configuring{false};
bool update_thread_running{true};
int mouse_panning_timout{};
};
} // namespace MouseInput

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <memory>
#include <mutex>
#include <utility>

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
#include "input_common/touch_from_button.h"

View File

@@ -5,11 +5,13 @@
#include <catch2/catch.hpp>
#include "common/host_memory.h"
#include "common/literals.h"
using Common::HostMemory;
using namespace Common::Literals;
static constexpr size_t VIRTUAL_SIZE = 1ULL << 39;
static constexpr size_t BACKING_SIZE = 4ULL * 1024 * 1024 * 1024;
static constexpr size_t BACKING_SIZE = 4_GiB;
TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
{ HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); }

View File

@@ -293,6 +293,7 @@ endif()
if (MSVC)
target_compile_options(video_core PRIVATE
/we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
/we4244 # 'var' : conversion from integer to 'type', possible loss of data
/we4456 # Declaration of 'identifier' hides previous local declaration
/we4457 # Declaration of 'identifier' hides function parameter
/we4458 # Declaration of 'identifier' hides class member

View File

@@ -256,6 +256,16 @@ public:
stream_score += score;
}
/// Sets the new frame tick
void SetFrameTick(u64 new_frame_tick) noexcept {
frame_tick = new_frame_tick;
}
/// Returns the new frame tick
[[nodiscard]] u64 FrameTick() const noexcept {
return frame_tick;
}
/// Returns the likeliness of this being a stream buffer
[[nodiscard]] int StreamScore() const noexcept {
return stream_score;
@@ -586,6 +596,7 @@ private:
RasterizerInterface* rasterizer = nullptr;
VAddr cpu_addr = 0;
Words words;
u64 frame_tick = 0;
BufferFlagBits flags{};
int stream_score = 0;
};

View File

@@ -18,6 +18,7 @@
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "common/literals.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "common/settings.h"
@@ -47,8 +48,11 @@ constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
constexpr u32 NUM_STORAGE_BUFFERS = 16;
constexpr u32 NUM_STAGES = 5;
using namespace Common::Literals;
template <typename P>
class BufferCache {
// Page size for caching purposes.
// This is unrelated to the CPU page size and it can be changed as it seems optimal.
static constexpr u32 PAGE_BITS = 16;
@@ -65,6 +69,9 @@ class BufferCache {
static constexpr BufferId NULL_BUFFER_ID{0};
static constexpr u64 EXPECTED_MEMORY = 512_MiB;
static constexpr u64 CRITICAL_MEMORY = 1_GiB;
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
using Runtime = typename P::Runtime;
@@ -92,7 +99,7 @@ class BufferCache {
};
public:
static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = 4096;
static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = static_cast<u32>(4_KiB);
explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_,
Tegra::Engines::Maxwell3D& maxwell3d_,
@@ -188,6 +195,8 @@ private:
((cpu_addr + size) & ~Core::Memory::PAGE_MASK);
}
void RunGarbageCollector();
void BindHostIndexBuffer();
void BindHostVertexBuffers();
@@ -243,6 +252,8 @@ private:
template <bool insert>
void ChangeRegister(BufferId buffer_id);
void TouchBuffer(Buffer& buffer) const noexcept;
bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size);
bool SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size);
@@ -255,6 +266,10 @@ private:
void MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, std::span<BufferCopy> copies);
void DownloadBufferMemory(Buffer& buffer_id);
void DownloadBufferMemory(Buffer& buffer_id, VAddr cpu_addr, u64 size);
void DeleteBuffer(BufferId buffer_id);
void ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id);
@@ -319,6 +334,10 @@ private:
size_t immediate_buffer_capacity = 0;
std::unique_ptr<u8[]> immediate_buffer_alloc;
typename SlotVector<Buffer>::Iterator deletion_iterator;
u64 frame_tick = 0;
u64 total_used_memory = 0;
std::array<BufferId, ((1ULL << 39) >> PAGE_BITS)> page_table;
};
@@ -332,6 +351,28 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
gpu_memory{gpu_memory_}, cpu_memory{cpu_memory_}, runtime{runtime_} {
// Ensure the first slot is used for the null buffer
void(slot_buffers.insert(runtime, NullBufferParams{}));
deletion_iterator = slot_buffers.end();
}
template <class P>
void BufferCache<P>::RunGarbageCollector() {
const bool aggressive_gc = total_used_memory >= CRITICAL_MEMORY;
const u64 ticks_to_destroy = aggressive_gc ? 60 : 120;
int num_iterations = aggressive_gc ? 64 : 32;
for (; num_iterations > 0; --num_iterations) {
if (deletion_iterator == slot_buffers.end()) {
deletion_iterator = slot_buffers.begin();
}
++deletion_iterator;
if (deletion_iterator == slot_buffers.end()) {
break;
}
const auto [buffer_id, buffer] = *deletion_iterator;
if (buffer->FrameTick() + ticks_to_destroy < frame_tick) {
DownloadBufferMemory(*buffer);
DeleteBuffer(buffer_id);
}
}
}
template <class P>
@@ -349,6 +390,10 @@ void BufferCache<P>::TickFrame() {
const bool skip_preferred = hits * 256 < shots * 251;
uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0;
if (Settings::values.use_caches_gc.GetValue() && total_used_memory >= EXPECTED_MEMORY) {
RunGarbageCollector();
}
++frame_tick;
delayed_destruction_ring.Tick();
}
@@ -372,48 +417,7 @@ void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) {
template <class P>
void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) {
boost::container::small_vector<BufferCopy, 1> copies;
u64 total_size_bytes = 0;
u64 largest_copy = 0;
buffer.ForEachDownloadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
copies.push_back(BufferCopy{
.src_offset = range_offset,
.dst_offset = total_size_bytes,
.size = range_size,
});
total_size_bytes += range_size;
largest_copy = std::max(largest_copy, range_size);
});
if (total_size_bytes == 0) {
return;
}
MICROPROFILE_SCOPE(GPU_DownloadMemory);
if constexpr (USE_MEMORY_MAPS) {
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
const u8* const mapped_memory = download_staging.mapped_span.data();
const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
for (BufferCopy& copy : copies) {
// Modify copies to have the staging offset in mind
copy.dst_offset += download_staging.offset;
}
runtime.CopyBuffer(download_staging.buffer, buffer, copies_span);
runtime.Finish();
for (const BufferCopy& copy : copies) {
const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset;
// Undo the modified offset
const u64 dst_offset = copy.dst_offset - download_staging.offset;
const u8* copy_mapped_memory = mapped_memory + dst_offset;
cpu_memory.WriteBlockUnsafe(copy_cpu_addr, copy_mapped_memory, copy.size);
}
} else {
const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
for (const BufferCopy& copy : copies) {
buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset;
cpu_memory.WriteBlockUnsafe(copy_cpu_addr, immediate_buffer.data(), copy.size);
}
}
DownloadBufferMemory(buffer, cpu_addr, size);
});
}
@@ -640,6 +644,7 @@ bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
template <class P>
void BufferCache<P>::BindHostIndexBuffer() {
Buffer& buffer = slot_buffers[index_buffer.buffer_id];
TouchBuffer(buffer);
const u32 offset = buffer.Offset(index_buffer.cpu_addr);
const u32 size = index_buffer.size;
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
@@ -658,6 +663,7 @@ void BufferCache<P>::BindHostVertexBuffers() {
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
const Binding& binding = vertex_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer);
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
if (!flags[Dirty::VertexBuffer0 + index]) {
continue;
@@ -693,6 +699,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
const VAddr cpu_addr = binding.cpu_addr;
const u32 size = binding.size;
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer);
const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
size <= uniform_buffer_skip_cache_size &&
!buffer.IsRegionGpuModified(cpu_addr, size);
@@ -744,6 +751,7 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
ForEachEnabledBit(enabled_storage_buffers[stage], [&](u32 index) {
const Binding& binding = storage_buffers[stage][index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -766,6 +774,7 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
const Binding& binding = transform_feedback_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -784,6 +793,7 @@ void BufferCache<P>::BindHostComputeUniformBuffers() {
ForEachEnabledBit(enabled_compute_uniform_buffers, [&](u32 index) {
const Binding& binding = compute_uniform_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -803,6 +813,7 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
ForEachEnabledBit(enabled_compute_storage_buffers, [&](u32 index) {
const Binding& binding = compute_storage_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -1101,6 +1112,7 @@ BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) {
const OverlapResult overlap = ResolveOverlaps(cpu_addr, wanted_size);
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size);
TouchBuffer(slot_buffers[new_buffer_id]);
for (const BufferId overlap_id : overlap.ids) {
JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap);
}
@@ -1122,8 +1134,14 @@ template <class P>
template <bool insert>
void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
const Buffer& buffer = slot_buffers[buffer_id];
const auto size = buffer.SizeBytes();
if (insert) {
total_used_memory += Common::AlignUp(size, 1024);
} else {
total_used_memory -= Common::AlignUp(size, 1024);
}
const VAddr cpu_addr_begin = buffer.CpuAddr();
const VAddr cpu_addr_end = cpu_addr_begin + buffer.SizeBytes();
const VAddr cpu_addr_end = cpu_addr_begin + size;
const u64 page_begin = cpu_addr_begin / PAGE_SIZE;
const u64 page_end = Common::DivCeil(cpu_addr_end, PAGE_SIZE);
for (u64 page = page_begin; page != page_end; ++page) {
@@ -1135,6 +1153,11 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
}
}
template <class P>
void BufferCache<P>::TouchBuffer(Buffer& buffer) const noexcept {
buffer.SetFrameTick(frame_tick);
}
template <class P>
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) {
if (buffer.CpuAddr() == 0) {
@@ -1211,6 +1234,57 @@ void BufferCache<P>::MappedUploadMemory(Buffer& buffer, u64 total_size_bytes,
runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
}
template <class P>
void BufferCache<P>::DownloadBufferMemory(Buffer& buffer) {
DownloadBufferMemory(buffer, buffer.CpuAddr(), buffer.SizeBytes());
}
template <class P>
void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 size) {
boost::container::small_vector<BufferCopy, 1> copies;
u64 total_size_bytes = 0;
u64 largest_copy = 0;
buffer.ForEachDownloadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
copies.push_back(BufferCopy{
.src_offset = range_offset,
.dst_offset = total_size_bytes,
.size = range_size,
});
total_size_bytes += range_size;
largest_copy = std::max(largest_copy, range_size);
});
if (total_size_bytes == 0) {
return;
}
MICROPROFILE_SCOPE(GPU_DownloadMemory);
if constexpr (USE_MEMORY_MAPS) {
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
const u8* const mapped_memory = download_staging.mapped_span.data();
const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
for (BufferCopy& copy : copies) {
// Modify copies to have the staging offset in mind
copy.dst_offset += download_staging.offset;
}
runtime.CopyBuffer(download_staging.buffer, buffer, copies_span);
runtime.Finish();
for (const BufferCopy& copy : copies) {
const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset;
// Undo the modified offset
const u64 dst_offset = copy.dst_offset - download_staging.offset;
const u8* copy_mapped_memory = mapped_memory + dst_offset;
cpu_memory.WriteBlockUnsafe(copy_cpu_addr, copy_mapped_memory, copy.size);
}
} else {
const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
for (const BufferCopy& copy : copies) {
buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset;
cpu_memory.WriteBlockUnsafe(copy_cpu_addr, immediate_buffer.data(), copy.size);
}
}
}
template <class P>
void BufferCache<P>::DeleteBuffer(BufferId buffer_id) {
const auto scalar_replace = [buffer_id](Binding& binding) {
@@ -1236,6 +1310,7 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id) {
Unregister(buffer_id);
delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id]));
slot_buffers.erase(buffer_id);
NotifyBufferDeletion();
}

View File

@@ -14,10 +14,18 @@ extern "C" {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4242) // conversion from 'type' to 'type', possible loss of data
#pragma warning(disable : 4244) // conversion from 'type' to 'type', possible loss of data
#endif
#include <libavcodec/avcodec.h>
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}
namespace Tegra {

View File

@@ -3,7 +3,28 @@
// Refer to the license.txt file included.
#include <array>
extern "C" {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4244) // conversion from 'type' to 'type', possible loss of data
#pragma warning(push)
#endif
#include <libswscale/swscale.h>
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}
#include "common/assert.h"
#include "common/logging/log.h"
#include "video_core/command_classes/nvdec.h"
#include "video_core/command_classes/vic.h"
#include "video_core/engines/maxwell_3d.h"
@@ -11,10 +32,6 @@
#include "video_core/memory_manager.h"
#include "video_core/textures/decoders.h"
extern "C" {
#include <libswscale/swscale.h>
}
namespace Tegra {
Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_)

View File

@@ -242,6 +242,7 @@ public:
return 4;
default:
UNREACHABLE();
return 1;
}
}

View File

@@ -11,12 +11,8 @@
#define UNIFORM(n)
#define BINDING_INPUT_BUFFER 0
#define BINDING_ENC_BUFFER 1
#define BINDING_6_TO_8_BUFFER 2
#define BINDING_7_TO_8_BUFFER 3
#define BINDING_8_TO_8_BUFFER 4
#define BINDING_BYTE_TO_16_BUFFER 5
#define BINDING_SWIZZLE_BUFFER 6
#define BINDING_OUTPUT_IMAGE 7
#define BINDING_SWIZZLE_BUFFER 2
#define BINDING_OUTPUT_IMAGE 3
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
@@ -26,10 +22,6 @@
#define BINDING_SWIZZLE_BUFFER 0
#define BINDING_INPUT_BUFFER 1
#define BINDING_ENC_BUFFER 2
#define BINDING_6_TO_8_BUFFER 3
#define BINDING_7_TO_8_BUFFER 4
#define BINDING_8_TO_8_BUFFER 5
#define BINDING_BYTE_TO_16_BUFFER 6
#define BINDING_OUTPUT_IMAGE 0
#endif
@@ -76,19 +68,6 @@ layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
EncodingData encoding_values[];
};
// ASTC Precompiled tables
layout(binding = BINDING_6_TO_8_BUFFER, std430) readonly buffer REPLICATE_6_BIT_TO_8 {
uint REPLICATE_6_BIT_TO_8_TABLE[];
};
layout(binding = BINDING_7_TO_8_BUFFER, std430) readonly buffer REPLICATE_7_BIT_TO_8 {
uint REPLICATE_7_BIT_TO_8_TABLE[];
};
layout(binding = BINDING_8_TO_8_BUFFER, std430) readonly buffer REPLICATE_8_BIT_TO_8 {
uint REPLICATE_8_BIT_TO_8_TABLE[];
};
layout(binding = BINDING_BYTE_TO_16_BUFFER, std430) readonly buffer REPLICATE_BYTE_TO_16 {
uint REPLICATE_BYTE_TO_16_TABLE[];
};
layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
@@ -139,6 +118,19 @@ const uint REPLICATE_4_BIT_TO_6_TABLE[16] =
const uint REPLICATE_5_BIT_TO_6_TABLE[32] =
uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 33, 35, 37, 39, 41, 43, 45,
47, 49, 51, 53, 55, 57, 59, 61, 63);
const uint REPLICATE_6_BIT_TO_8_TABLE[64] =
uint[](0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 65, 69, 73, 77, 81, 85, 89,
93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162,
166, 170, 174, 178, 182, 186, 190, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235,
239, 243, 247, 251, 255);
const uint REPLICATE_7_BIT_TO_8_TABLE[128] =
uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44,
46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88,
90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126,
129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163,
165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199,
201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235,
237, 239, 241, 243, 245, 247, 249, 251, 253, 255);
// Input ASTC texture globals
uint current_index = 0;
@@ -207,8 +199,7 @@ uint Replicate(uint val, uint num_bits, uint to_bit) {
}
uvec4 ReplicateByteTo16(uvec4 value) {
return uvec4(REPLICATE_BYTE_TO_16_TABLE[value.x], REPLICATE_BYTE_TO_16_TABLE[value.y],
REPLICATE_BYTE_TO_16_TABLE[value.z], REPLICATE_BYTE_TO_16_TABLE[value.w]);
return value * 0x101;
}
uint ReplicateBitTo7(uint value) {
@@ -236,7 +227,7 @@ uint FastReplicateTo8(uint value, uint num_bits) {
case 7:
return REPLICATE_7_BIT_TO_8_TABLE[value];
case 8:
return REPLICATE_8_BIT_TO_8_TABLE[value];
return value;
}
return Replicate(value, num_bits, 8);
}
@@ -1327,6 +1318,9 @@ void main() {
offset += swizzle;
const ivec3 coord = ivec3(gl_GlobalInvocationID * uvec3(block_dims, 1));
if (any(greaterThanEqual(coord, imageSize(dest_image)))) {
return;
}
uint block_index =
pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;

View File

@@ -4,10 +4,10 @@
#pragma once
#include <atomic>
#include <functional>
#include <optional>
#include <span>
#include <stop_token>
#include "common/common_types.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/gpu.h"
@@ -123,7 +123,7 @@ public:
virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
/// Initialize disk cached resources for the game being emulated
virtual void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
const DiskResourceLoadCallback& callback) {}
/// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.

View File

@@ -454,7 +454,7 @@ private:
template <typename... Args>
void AddExpression(std::string_view text, Args&&... args) {
shader_source += fmt::format(text, std::forward<Args>(args)...);
shader_source += fmt::format(fmt::runtime(text), std::forward<Args>(args)...);
}
template <typename... Args>

View File

@@ -351,7 +351,7 @@ void RasterizerOpenGL::SetupShaders(bool is_indexed) {
}
}
void RasterizerOpenGL::LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
shader_cache.LoadDiskCache(title_id, stop_loading, callback);
}

View File

@@ -94,7 +94,7 @@ public:
const Tegra::Engines::Fermi2D::Config& copy_config) override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) override;
/// Returns true when there are commands queued to the OpenGL server.

View File

@@ -331,7 +331,7 @@ ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer_,
ShaderCacheOpenGL::~ShaderCacheOpenGL() = default;
void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
disk_cache.BindTitleID(title_id);
const std::optional transferable = disk_cache.LoadTransferable();
@@ -372,7 +372,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop
const auto scope = context->Acquire();
for (std::size_t i = begin; i < end; ++i) {
if (stop_loading) {
if (stop_loading.stop_requested()) {
return;
}
const auto& entry = (*transferable)[i];
@@ -435,7 +435,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop
precompiled_cache_altered = true;
return;
}
if (stop_loading) {
if (stop_loading.stop_requested()) {
return;
}

View File

@@ -127,7 +127,7 @@ public:
~ShaderCacheOpenGL() override;
/// Loads disk cache for the current game
void LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
void LoadDiskCache(u64 title_id, std::stop_token stop_loading,
const VideoCore::DiskResourceLoadCallback& callback);
/// Gets the current specified shader stage program

View File

@@ -96,7 +96,7 @@ public:
// etc).
template <typename... Args>
void AddLine(std::string_view text, Args&&... args) {
AddExpression(fmt::format(text, std::forward<Args>(args)...));
AddExpression(fmt::format(fmt::runtime(text), std::forward<Args>(args)...));
AddNewLine();
}

View File

@@ -12,12 +12,15 @@
#include <glad/glad.h>
#include "common/common_types.h"
#include "common/literals.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
namespace OpenGL {
using namespace Common::Literals;
class StreamBuffer {
static constexpr size_t STREAM_BUFFER_SIZE = 64 * 1024 * 1024;
static constexpr size_t STREAM_BUFFER_SIZE = 64_MiB;
static constexpr size_t NUM_SYNCS = 16;
static constexpr size_t REGION_SIZE = STREAM_BUFFER_SIZE / NUM_SYNCS;
static constexpr size_t MAX_ALIGNMENT = 256;

View File

@@ -737,6 +737,8 @@ Image::Image(TextureCacheRuntime& runtime, const VideoCommon::ImageInfo& info_,
}
}
Image::~Image() = default;
void Image::UploadMemory(const ImageBufferMap& map,
std::span<const VideoCommon::BufferImageCopy> copies) {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, map.buffer);

View File

@@ -143,6 +143,14 @@ public:
explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr,
VAddr cpu_addr);
~Image();
Image(const Image&) = delete;
Image& operator=(const Image&) = delete;
Image(Image&&) = default;
Image& operator=(Image&&) = default;
void UploadMemory(const ImageBufferMap& map,
std::span<const VideoCommon::BufferImageCopy> copies);
@@ -235,6 +243,7 @@ struct TextureCacheParams {
static constexpr bool ENABLE_VALIDATION = true;
static constexpr bool FRAMEBUFFER_BLITS = true;
static constexpr bool HAS_EMULATED_COPIES = true;
static constexpr bool HAS_DEVICE_MEMORY_INFO = false;
using Runtime = OpenGL::TextureCacheRuntime;
using Image = OpenGL::Image;

View File

@@ -69,7 +69,8 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
swizzle_table_buffer.Create();
astc_buffer.Create();
glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_BUFFER_DATA), &ASTC_BUFFER_DATA, 0);
glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_ENCODINGS_VALUES), &ASTC_ENCODINGS_VALUES,
0);
}
UtilShaders::~UtilShaders() = default;
@@ -79,12 +80,6 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
static constexpr GLuint BINDING_INPUT_BUFFER = 1;
static constexpr GLuint BINDING_ENC_BUFFER = 2;
static constexpr GLuint BINDING_6_TO_8_BUFFER = 3;
static constexpr GLuint BINDING_7_TO_8_BUFFER = 4;
static constexpr GLuint BINDING_8_TO_8_BUFFER = 5;
static constexpr GLuint BINDING_BYTE_TO_16_BUFFER = 6;
static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
const Extent2D tile_size{
@@ -93,21 +88,7 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
};
program_manager.BindHostCompute(astc_decoder_program.handle);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, encoding_values),
sizeof(AstcBufferData::encoding_values));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_6_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_6_to_8),
sizeof(AstcBufferData::replicate_6_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_7_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_7_to_8),
sizeof(AstcBufferData::replicate_7_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_8_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_8_to_8),
sizeof(AstcBufferData::replicate_8_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_BYTE_TO_16_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_byte_to_16),
sizeof(AstcBufferData::replicate_byte_to_16));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle);
glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
glUniform2ui(1, tile_size.width, tile_size.height);
@@ -137,6 +118,12 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
}
// Precautionary barrier to ensure the compute shader is done decoding prior to texture access.
// GL_TEXTURE_FETCH_BARRIER_BIT and GL_SHADER_IMAGE_ACCESS_BARRIER_BIT are used in a separate
// glMemoryBarrier call by the texture cache runtime
glMemoryBarrier(GL_UNIFORM_BARRIER_BIT | GL_COMMAND_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT |
GL_TEXTURE_UPDATE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT |
GL_SHADER_STORAGE_BARRIER_BIT | GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
program_manager.RestoreGuestCompute();
}

View File

@@ -55,8 +55,9 @@ size_t BytesPerIndex(VkIndexType index_type) {
template <typename T>
std::array<T, 6> MakeQuadIndices(u32 quad, u32 first) {
std::array<T, 6> indices{0, 1, 2, 0, 2, 3};
std::ranges::transform(indices, indices.begin(),
[quad, first](u32 index) { return first + index + quad * 4; });
for (T& index : indices) {
index = static_cast<T>(first + index + quad * 4);
}
return indices;
}
} // Anonymous namespace

View File

@@ -30,19 +30,16 @@
namespace Vulkan {
using Tegra::Texture::SWIZZLE_TABLE;
using Tegra::Texture::ASTC::EncodingsValues;
using Tegra::Texture::ASTC::ASTC_ENCODINGS_VALUES;
using namespace Tegra::Texture::ASTC;
namespace {
constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
constexpr u32 ASTC_BINDING_ENC_BUFFER = 1;
constexpr u32 ASTC_BINDING_6_TO_8_BUFFER = 2;
constexpr u32 ASTC_BINDING_7_TO_8_BUFFER = 3;
constexpr u32 ASTC_BINDING_8_TO_8_BUFFER = 4;
constexpr u32 ASTC_BINDING_BYTE_TO_16_BUFFER = 5;
constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 6;
constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 7;
constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 2;
constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 3;
constexpr size_t ASTC_NUM_BINDINGS = 4;
VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
return {
@@ -71,7 +68,7 @@ std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBinding
}};
}
std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
std::array<VkDescriptorSetLayoutBinding, ASTC_NUM_BINDINGS> BuildASTCDescriptorSetBindings() {
return {{
{
.binding = ASTC_BINDING_INPUT_BUFFER,
@@ -87,34 +84,6 @@ std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_6_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_7_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_8_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_BYTE_TO_16_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_SWIZZLE_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
@@ -143,7 +112,8 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
};
}
std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateTemplateEntry() {
std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS>
BuildASTCPassDescriptorUpdateTemplateEntry() {
return {{
{
.dstBinding = ASTC_BINDING_INPUT_BUFFER,
@@ -161,38 +131,6 @@ std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateT
.offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_6_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_6_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_7_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_7_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_8_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_8_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_BYTE_TO_16_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_BYTE_TO_16_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
.dstArrayElement = 0,
@@ -222,15 +160,6 @@ struct AstcPushConstants {
u32 block_height_mask;
};
struct AstcBufferData {
decltype(SWIZZLE_TABLE) swizzle_table_buffer = SWIZZLE_TABLE;
decltype(EncodingsValues) encoding_values = EncodingsValues;
decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
} constexpr ASTC_BUFFER_DATA;
} // Anonymous namespace
VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
@@ -423,7 +352,7 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
ASTCDecoderPass::~ASTCDecoderPass() = default;
void ASTCDecoderPass::MakeDataBuffer() {
constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_BUFFER_DATA) + sizeof(SWIZZLE_TABLE);
constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_ENCODINGS_VALUES) + sizeof(SWIZZLE_TABLE);
data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -437,9 +366,10 @@ void ASTCDecoderPass::MakeDataBuffer() {
data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
std::memcpy(staging_ref.mapped_span.data(), &ASTC_BUFFER_DATA, sizeof(ASTC_BUFFER_DATA));
std::memcpy(staging_ref.mapped_span.data(), &ASTC_ENCODINGS_VALUES,
sizeof(ASTC_ENCODINGS_VALUES));
// Tack on the swizzle table at the end of the buffer
std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_BUFFER_DATA), &SWIZZLE_TABLE,
std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_ENCODINGS_VALUES), &SWIZZLE_TABLE,
sizeof(SWIZZLE_TABLE));
scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
@@ -509,18 +439,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
update_descriptor_queue.Acquire();
update_descriptor_queue.AddBuffer(map.buffer, input_offset,
image.guest_size_bytes - swizzle.buffer_offset);
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, encoding_values),
sizeof(AstcBufferData::encoding_values));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_6_to_8),
sizeof(AstcBufferData::replicate_6_to_8));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_7_to_8),
sizeof(AstcBufferData::replicate_7_to_8));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_8_to_8),
sizeof(AstcBufferData::replicate_8_to_8));
update_descriptor_queue.AddBuffer(*data_buffer,
offsetof(AstcBufferData, replicate_byte_to_16),
sizeof(AstcBufferData::replicate_byte_to_16));
update_descriptor_queue.AddBuffer(*data_buffer, sizeof(AstcBufferData),
update_descriptor_queue.AddBuffer(*data_buffer, 0, sizeof(ASTC_ENCODINGS_VALUES));
update_descriptor_queue.AddBuffer(*data_buffer, sizeof(ASTC_ENCODINGS_VALUES),
sizeof(SWIZZLE_TABLE));
update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
@@ -569,6 +489,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, image_barrier);
});
scheduler.Finish();
}
} // namespace Vulkan

View File

@@ -2,8 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <atomic>
#include <chrono>
#include <thread>
#include "common/settings.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
@@ -12,8 +11,6 @@
namespace Vulkan {
using namespace std::chrono_literals;
MasterSemaphore::MasterSemaphore(const Device& device) {
static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR,
@@ -34,9 +31,9 @@ MasterSemaphore::MasterSemaphore(const Device& device) {
// Validation layers have a bug where they fail to track resource usage when using timeline
// semaphores and synchronizing with GetSemaphoreCounterValueKHR. To workaround this issue, have
// a separate thread waiting for each timeline semaphore value.
debug_thread = std::thread([this] {
debug_thread = std::jthread([this](std::stop_token stop_token) {
u64 counter = 0;
while (!shutdown) {
while (!stop_token.stop_requested()) {
if (semaphore.Wait(counter, 10'000'000)) {
++counter;
}
@@ -44,13 +41,6 @@ MasterSemaphore::MasterSemaphore(const Device& device) {
});
}
MasterSemaphore::~MasterSemaphore() {
shutdown = true;
// This thread might not be started
if (debug_thread.joinable()) {
debug_thread.join();
}
}
MasterSemaphore::~MasterSemaphore() = default;
} // namespace Vulkan

View File

@@ -65,11 +65,10 @@ public:
}
private:
vk::Semaphore semaphore; ///< Timeline semaphore.
std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
std::atomic<u64> current_tick{1}; ///< Current logical tick.
std::atomic<bool> shutdown{false}; ///< True when the object is being destroyed.
std::thread debug_thread; ///< Debug thread to workaround validation layer bugs.
vk::Semaphore semaphore; ///< Timeline semaphore.
std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
std::atomic<u64> current_tick{1}; ///< Current logical tick.
std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs.
};
} // namespace Vulkan

View File

@@ -12,6 +12,7 @@
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/vulkan_common/vulkan_device.h"
@@ -19,12 +20,15 @@
namespace Vulkan {
namespace {
using namespace Common::Literals;
// Maximum potential alignment of a Vulkan buffer
constexpr VkDeviceSize MAX_ALIGNMENT = 256;
// Maximum size to put elements in the stream buffer
constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8 * 1024 * 1024;
constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
// Stream buffer size in bytes
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
constexpr VkMemoryPropertyFlags HOST_FLAGS =

View File

@@ -10,6 +10,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/vulkan_common/vulkan_device.h"
@@ -19,6 +20,8 @@ namespace Vulkan {
namespace {
using namespace Common::Literals;
constexpr VkBufferUsageFlags BUFFER_USAGE =
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
@@ -26,7 +29,7 @@ constexpr VkBufferUsageFlags BUFFER_USAGE =
constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
constexpr u64 PREFERRED_STREAM_BUFFER_SIZE = 256 * 1024 * 1024;
constexpr u64 PREFERRED_STREAM_BUFFER_SIZE = 256_MiB;
/// Find a memory type with the passed requirements
std::optional<u32> FindMemoryType(const VkPhysicalDeviceMemoryProperties& properties,

View File

@@ -818,6 +818,10 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
});
}
u64 TextureCacheRuntime::GetDeviceLocalMemory() const {
return device.GetDeviceLocalMemory();
}
Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_,
VAddr cpu_addr_)
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler},
@@ -876,6 +880,8 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
}
}
Image::~Image() = default;
void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
// TODO: Move this to another API
scheduler->RequestOutsideRenderPassOperationContext();

View File

@@ -97,6 +97,8 @@ struct TextureCacheRuntime {
// All known Vulkan drivers can natively handle BGR textures
return true;
}
u64 GetDeviceLocalMemory() const;
};
class Image : public VideoCommon::ImageBase {
@@ -104,6 +106,14 @@ public:
explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr,
VAddr cpu_addr);
~Image();
Image(const Image&) = delete;
Image& operator=(const Image&) = delete;
Image(Image&&) = default;
Image& operator=(Image&&) = default;
void UploadMemory(const StagingBufferRef& map,
std::span<const VideoCommon::BufferImageCopy> copies);
@@ -257,6 +267,7 @@ struct TextureCacheParams {
static constexpr bool ENABLE_VALIDATION = true;
static constexpr bool FRAMEBUFFER_BLITS = false;
static constexpr bool HAS_EMULATED_COPIES = false;
static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
using Runtime = Vulkan::TextureCacheRuntime;
using Image = Vulkan::Image;

View File

@@ -283,4 +283,11 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
}
u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format) {
constexpr u64 RGBA8_PIXEL_SIZE = 4;
const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
return (base_size * base_block_size) / BytesPerBlock(format);
}
} // namespace VideoCore::Surface

View File

@@ -462,4 +462,6 @@ bool IsPixelFormatSRGB(PixelFormat format);
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format);
} // namespace VideoCore::Surface

View File

@@ -113,6 +113,43 @@ void ImageBase::InsertView(const ImageViewInfo& view_info, ImageViewId image_vie
image_view_ids.push_back(image_view_id);
}
bool ImageBase::IsSafeDownload() const noexcept {
// Skip images that were not modified from the GPU
if (False(flags & ImageFlagBits::GpuModified)) {
return false;
}
// Skip images that .are. modified from the CPU
// We don't want to write sensitive data from the guest
if (True(flags & ImageFlagBits::CpuModified)) {
return false;
}
if (info.num_samples > 1) {
LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented");
return false;
}
return true;
}
void ImageBase::CheckBadOverlapState() {
if (False(flags & ImageFlagBits::BadOverlap)) {
return;
}
if (!overlapping_images.empty()) {
return;
}
flags &= ~ImageFlagBits::BadOverlap;
}
void ImageBase::CheckAliasState() {
if (False(flags & ImageFlagBits::Alias)) {
return;
}
if (!aliased_images.empty()) {
return;
}
flags &= ~ImageFlagBits::Alias;
}
void AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_id) {
static constexpr auto OPTIONS = RelaxedOptions::Size | RelaxedOptions::Format;
ASSERT(lhs.info.type == rhs.info.type);

View File

@@ -25,6 +25,12 @@ enum class ImageFlagBits : u32 {
Strong = 1 << 5, ///< Exists in the image table, the dimensions are can be trusted
Registered = 1 << 6, ///< True when the image is registered
Picked = 1 << 7, ///< Temporary flag to mark the image as picked
// Garbage Collection Flags
BadOverlap = 1 << 8, ///< This image overlaps other but doesn't fit, has higher
///< garbage collection priority
Alias = 1 << 9, ///< This image has aliases and has priority on garbage
///< collection
};
DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
@@ -44,11 +50,16 @@ struct ImageBase {
void InsertView(const ImageViewInfo& view_info, ImageViewId image_view_id);
[[nodiscard]] bool IsSafeDownload() const noexcept;
[[nodiscard]] bool Overlaps(VAddr overlap_cpu_addr, size_t overlap_size) const noexcept {
const VAddr overlap_end = overlap_cpu_addr + overlap_size;
return cpu_addr < overlap_end && overlap_cpu_addr < cpu_addr_end;
}
void CheckBadOverlapState();
void CheckAliasState();
ImageInfo info;
u32 guest_size_bytes = 0;
@@ -72,6 +83,7 @@ struct ImageBase {
std::vector<SubresourceBase> slice_subresources;
std::vector<AliasedImage> aliased_images;
std::vector<ImageId> overlapping_images;
};
struct ImageAllocBase {

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