Compare commits
93 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cee25281f | ||
|
|
4df04ad48a | ||
|
|
3bc7b0a587 | ||
|
|
f54f29198f | ||
|
|
432fab7c4f | ||
|
|
36d581ec73 | ||
|
|
9476309d53 | ||
|
|
03abe8bf85 | ||
|
|
05bd50a1cf | ||
|
|
3ab5bf6454 | ||
|
|
b4894faeae | ||
|
|
e79d02bf38 | ||
|
|
d9fb6dbd37 | ||
|
|
99b859db55 | ||
|
|
c805c0b395 | ||
|
|
b9c2732121 | ||
|
|
982be246ab | ||
|
|
3565e32f4d | ||
|
|
d1ba4a2db2 | ||
|
|
50d0cc2716 | ||
|
|
4569f39c7c | ||
|
|
4dc2f5a341 | ||
|
|
eed0d1f33b | ||
|
|
f216a9432b | ||
|
|
5ed87152c3 | ||
|
|
373bc6512d | ||
|
|
496327490f | ||
|
|
1b09d6628b | ||
|
|
809e5fd523 | ||
|
|
d0b1f2bd05 | ||
|
|
d8d9bb0dfb | ||
|
|
be6844c1ed | ||
|
|
c3fe071723 | ||
|
|
17fff10e06 | ||
|
|
8593e6f1e6 | ||
|
|
20f474b09a | ||
|
|
c1a9fa9db7 | ||
|
|
d6b51e5e21 | ||
|
|
95b4c78b07 | ||
|
|
4ec7d79174 | ||
|
|
36aacf62ad | ||
|
|
0308a2679e | ||
|
|
255f8d22d7 | ||
|
|
791d3d1bea | ||
|
|
f9b940a442 | ||
|
|
2fa207058b | ||
|
|
0394893354 | ||
|
|
76b2313b25 | ||
|
|
cf0b9d1de2 | ||
|
|
81b1b71993 | ||
|
|
faf57c183f | ||
|
|
0e2c1a5739 | ||
|
|
698add8541 | ||
|
|
c9c8537643 | ||
|
|
1ca9a13e50 | ||
|
|
15cc561d12 | ||
|
|
0a39163a90 | ||
|
|
2a7a65c944 | ||
|
|
ba3af04da1 | ||
|
|
4009ae1da2 | ||
|
|
cf116a28a6 | ||
|
|
0485b8e84b | ||
|
|
2a3d3d3895 | ||
|
|
83ac715e76 | ||
|
|
2298508465 | ||
|
|
569a1962c0 | ||
|
|
865dd615ca | ||
|
|
851c76233d | ||
|
|
ace20ba4a4 | ||
|
|
31b125ef57 | ||
|
|
ad8aab915b | ||
|
|
03da34b330 | ||
|
|
9a06b85b24 | ||
|
|
e704da9192 | ||
|
|
3870ba670f | ||
|
|
8a83e3412a | ||
|
|
fd5ef1970c | ||
|
|
bb18a6533d | ||
|
|
1a5eceeb9c | ||
|
|
0b172d12c0 | ||
|
|
719a6dd5a1 | ||
|
|
ca6f47c686 | ||
|
|
0dd98842bf | ||
|
|
954ad2a61e | ||
|
|
d8ad6aa187 | ||
|
|
a11bc4a382 | ||
|
|
5b1efe522e | ||
|
|
4a4e304319 | ||
|
|
8ba83c4c2a | ||
|
|
e4318a1914 | ||
|
|
ded36b8688 | ||
|
|
faf11fe46d | ||
|
|
95f203b7c7 |
@@ -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
5
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
77
README.md
77
README.md
@@ -1,43 +1,80 @@
|
||||
yuzu emulator
|
||||
=============
|
||||
[](https://travis-ci.com/yuzu-emu/yuzu)
|
||||
[](https://dev.azure.com/yuzu-emu/yuzu/)
|
||||
[](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.
|
||||
|
||||
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
@@ -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
1
externals/cpp-httplib
vendored
Submodule
Submodule externals/cpp-httplib added at 9648f950f5
2
externals/discord-rpc
vendored
2
externals/discord-rpc
vendored
Submodule externals/discord-rpc updated: e32d001809...963aa9f3e5
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 0c12614d1a...7946868af4
15
externals/httplib/README.md
vendored
15
externals/httplib/README.md
vendored
@@ -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
|
||||
6714
externals/httplib/httplib.h
vendored
6714
externals/httplib/httplib.h
vendored
File diff suppressed because it is too large
Load Diff
2
externals/libusb/CMakeLists.txt
vendored
2
externals/libusb/CMakeLists.txt
vendored
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -21,6 +21,8 @@ void DetachedTasks::WaitForAllTasks() {
|
||||
}
|
||||
|
||||
DetachedTasks::~DetachedTasks() {
|
||||
WaitForAllTasks();
|
||||
|
||||
std::unique_lock lock{mutex};
|
||||
ASSERT(count == 0);
|
||||
instance = nullptr;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
31
src/common/literals.h
Normal 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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
40
src/core/hle/api_version.h
Normal file
40
src/core/hle/api_version.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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"},
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/uuid.h"
|
||||
|
||||
@@ -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('}');
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
31
src/core/hle/service/spl/spl_results.h
Normal file
31
src/core/hle/service/spl/spl_results.h
Normal 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
|
||||
232
src/core/hle/service/spl/spl_types.h
Normal file
232
src/core/hle/service/spl/spl_types.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_)
|
||||
|
||||
@@ -242,6 +242,7 @@ public:
|
||||
return 4;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user