Compare commits

..

2 Commits

Author SHA1 Message Date
ReinUsesLisp
8e9763f1e4 address feedback 2018-09-12 15:47:21 -03:00
ReinUsesLisp
d021ff111c gl_rasterizer: use ARB_multi_bind for uniform buffers 2018-09-12 15:47:21 -03:00
270 changed files with 2007 additions and 6118 deletions

4
.gitattributes vendored
View File

@@ -1,4 +0,0 @@
dist/languages/* linguist-vendored
dist/qt_themes/* linguist-vendored
externals/* linguist-vendored
*.h linguist-language=cpp

3
.gitmodules vendored
View File

@@ -31,6 +31,3 @@
[submodule "opus"]
path = externals/opus
url = https://github.com/ogniK5377/opus.git
[submodule "soundtouch"]
path = externals/soundtouch
url = https://github.com/citra-emu/ext-soundtouch.git

View File

@@ -24,24 +24,11 @@ matrix:
- os: osx
env: NAME="macos build"
sudo: false
osx_image: xcode10
osx_image: xcode9.3
install: "./.travis/macos/deps.sh"
script: "./.travis/macos/build.sh"
after_success: "./.travis/macos/upload.sh"
cache: ccache
- os: linux
env: NAME="MinGW build"
sudo: required
dist: trusty
services: docker
addons:
apt:
packages:
- p7zip-full
install: "./.travis/linux-mingw/deps.sh"
script: "./.travis/linux-mingw/build.sh"
after_success: "./.travis/linux-mingw/upload.sh"
cache: ccache
deploy:
provider: releases

View File

@@ -11,9 +11,6 @@ if [ -z $TRAVIS_TAG ]; then
RELEASE_NAME=head
else
RELEASE_NAME=$(echo $TRAVIS_TAG | cut -d- -f1)
if [ "$NAME" = "MinGW build" ]; then
RELEASE_NAME="${RELEASE_NAME}-mingw"
fi
fi
mv "$REV_NAME" $RELEASE_NAME

View File

@@ -1,3 +0,0 @@
#!/bin/bash -ex
mkdir "$HOME/.ccache" || true
docker run --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /yuzu/.travis/linux-mingw/docker.sh

View File

@@ -1,3 +0,0 @@
#!/bin/sh -ex
docker pull ubuntu:18.04

View File

@@ -1,59 +0,0 @@
#!/bin/bash -ex
cd /yuzu
MINGW_PACKAGES="sdl2-mingw-w64 qt5base-mingw-w64 qt5tools-mingw-w64 libsamplerate-mingw-w64 qt5multimedia-mingw-w64"
apt-get update
apt-get install -y gpg wget git python3-pip python ccache g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 mingw-w64-tools cmake
echo 'deb http://ppa.launchpad.net/tobydox/mingw-w64/ubuntu bionic main ' > /etc/apt/sources.list.d/extras.list
apt-key adv --keyserver keyserver.ubuntu.com --recv '72931B477E22FEFD47F8DECE02FE5F12ADDE29B2'
apt-get update
apt-get install -y ${MINGW_PACKAGES}
# fix a problem in current MinGW headers
wget -q https://raw.githubusercontent.com/Alexpux/mingw-w64/d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-headers/crt/errno.h -O /usr/x86_64-w64-mingw32/include/errno.h
# override Travis CI unreasonable ccache size
echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
# Dirty hack to trick unicorn makefile into believing we are in a MINGW system
mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname
chmod +x /bin/uname
# Dirty hack to trick unicorn makefile into believing we have cmd
echo '' >> /bin/cmd
chmod +x /bin/cmd
mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
make -j4
# Clean up the dirty hacks
rm /bin/uname && mv /bin/uname1 /bin/uname
rm /bin/cmd
ccache -s
echo "Tests skipped"
#ctest -VV -C Release
echo 'Prepare binaries...'
cd ..
mkdir package
QT_PLATFORM_DLL_PATH='/usr/x86_64-w64-mingw32/lib/qt5/plugins/platforms/'
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/
rm -f package/mediaservice/*d.dll
for i in package/*.exe; do
# we need to process pdb here, however, cv2pdb
# does not work here, so we just simply strip all the debug symbols
x86_64-w64-mingw32-strip "${i}"
done
pip3 install pefile
python3 .travis/linux-mingw/scan_dll.py package/*.exe "package/"

View File

@@ -1,106 +0,0 @@
import pefile
import sys
import re
import os
import queue
import shutil
# constant definitions
KNOWN_SYS_DLLS = ['WINMM.DLL', 'MSVCRT.DLL', 'VERSION.DLL', 'MPR.DLL',
'DWMAPI.DLL', 'UXTHEME.DLL', 'DNSAPI.DLL', 'IPHLPAPI.DLL']
# below is for Ubuntu 18.04 with specified PPA enabled, if you are using
# other distro or different repositories, change the following accordingly
DLL_PATH = [
'/usr/x86_64-w64-mingw32/bin/',
'/usr/x86_64-w64-mingw32/lib/',
'/usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/'
]
missing = []
def parse_imports(file_name):
results = []
pe = pefile.PE(file_name, fast_load=True)
pe.parse_data_directories()
for entry in pe.DIRECTORY_ENTRY_IMPORT:
current = entry.dll.decode()
current_u = current.upper() # b/c Windows is often case insensitive
# here we filter out system dlls
# dll w/ names like *32.dll are likely to be system dlls
if current_u.upper() not in KNOWN_SYS_DLLS and not re.match(string=current_u, pattern=r'.*32\.DLL'):
results.append(current)
return results
def parse_imports_recursive(file_name, path_list=[]):
q = queue.Queue() # create a FIFO queue
# file_name can be a string or a list for the convience
if isinstance(file_name, str):
q.put(file_name)
elif isinstance(file_name, list):
for i in file_name:
q.put(i)
full_list = []
while q.qsize():
current = q.get_nowait()
print('> %s' % current)
deps = parse_imports(current)
# if this dll does not have any import, ignore it
if not deps:
continue
for dep in deps:
# the dependency already included in the list, skip
if dep in full_list:
continue
# find the requested dll in the provided paths
full_path = find_dll(dep)
if not full_path:
missing.append(dep)
continue
full_list.append(dep)
q.put(full_path)
path_list.append(full_path)
return full_list
def find_dll(name):
for path in DLL_PATH:
for root, _, files in os.walk(path):
for f in files:
if name.lower() == f.lower():
return os.path.join(root, f)
def deploy(name, dst, dry_run=False):
dlls_path = []
parse_imports_recursive(name, dlls_path)
for dll_entry in dlls_path:
if not dry_run:
shutil.copy(dll_entry, dst)
else:
print('[Dry-Run] Copy %s to %s' % (dll_entry, dst))
print('Deploy completed.')
return dlls_path
def main():
if len(sys.argv) < 3:
print('Usage: %s [files to examine ...] [target deploy directory]')
return 1
to_deploy = sys.argv[1:-1]
tgt_dir = sys.argv[-1]
if not os.path.isdir(tgt_dir):
print('%s is not a directory.' % tgt_dir)
return 1
print('Scanning dependencies...')
deploy(to_deploy, tgt_dir)
if missing:
print('Following DLLs are not found: %s' % ('\n'.join(missing)))
return 0
if __name__ == '__main__':
main()

View File

@@ -1,13 +0,0 @@
#!/bin/bash -ex
. .travis/common/pre-upload.sh
REV_NAME="yuzu-windows-mingw-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
mkdir "$REV_NAME"
# get around the permission issues
cp -r package/* "$REV_NAME"
. .travis/common/post-upload.sh

View File

@@ -6,9 +6,7 @@ apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev
cd /yuzu
mkdir build && cd build
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -G Ninja
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -G Ninja
ninja
ccache -s
ctest -VV -C Release

View File

@@ -2,16 +2,14 @@
set -o pipefail
export MACOSX_DEPLOYMENT_TARGET=10.13
export MACOSX_DEPLOYMENT_TARGET=10.12
export Qt5_DIR=$(brew --prefix)/opt/qt5
export UNICORNDIR=$(pwd)/externals/unicorn
export PATH="/usr/local/opt/ccache/libexec:$PATH"
mkdir build && cd build
cmake --version
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
make -j4
ccache -s
ctest -VV -C Release

View File

@@ -123,6 +123,8 @@ else()
# Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors.
add_definitions(/DWIN32_LEAN_AND_MEAN)
# set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE)
# Tweak optimization settings
@@ -267,18 +269,10 @@ if (YUZU_USE_BUNDLED_UNICORN)
find_package(PythonInterp 2.7 REQUIRED)
if (MINGW)
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh cross-win64
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
else()
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
endif()
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
# ALL makes this custom target build every time
# but it won't actually build if LIBUNICORN_LIBRARY is up to date
add_custom_target(unicorn-build ALL
@@ -292,7 +286,6 @@ endif()
if (UNICORN_FOUND)
add_library(unicorn INTERFACE)
add_dependencies(unicorn unicorn-build)
target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
else()
@@ -438,12 +431,8 @@ enable_testing()
add_subdirectory(externals)
add_subdirectory(src)
# Set yuzu project or yuzu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not
if(ENABLE_QT)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
else()
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu-cmd)
endif()
# Set yuzu project as default StartUp Project in Visual Studio
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
# Installation instructions

View File

@@ -1,54 +0,0 @@
set(MINGW_PREFIX /usr/x86_64-w64-mingw32/)
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
# Actually a hack, w/o this will cause some strange errors
set(CMAKE_HOST_WIN32 TRUE)
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
set(SDL2_PATH ${MINGW_PREFIX})
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
# Specify the cross compiler
set(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc-posix)
set(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++-posix)
set(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
# Mingw tools
set(STRIP ${MINGW_TOOL_PREFIX}strip)
set(WINDRES ${MINGW_TOOL_PREFIX}windres)
set(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
# ccache wrapper
option(USE_CCACHE "Use ccache for compilation" OFF)
if(USE_CCACHE)
find_program(CCACHE ccache)
if(CCACHE)
message(STATUS "Using ccache found in PATH")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
else(CCACHE)
message(WARNING "USE_CCACHE enabled, but no ccache found")
endif(CCACHE)
endif(USE_CCACHE)
# Search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Echo modified cmake vars to screen for debugging purposes
if(NOT DEFINED ENV{MINGW_DEBUG_INFO})
message("")
message("Custom cmake vars: (blank = system default)")
message("-----------------------------------------")
message("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
message("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
message("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
message("* WINDRES : ${WINDRES}")
message("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
message("* STRIP : ${STRIP}")
message("* USE_CCACHE : ${USE_CCACHE}")
message("")
# So that the debug info only appears once
set(ENV{MINGW_DEBUG_INFO} SHOWN)
endif()

View File

@@ -50,9 +50,6 @@ add_subdirectory(open_source_archives EXCLUDE_FROM_ALL)
add_library(unicorn-headers INTERFACE)
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
# SoundTouch
add_subdirectory(soundtouch)
# Xbyak
if (ARCHITECTURE_x86_64)
# Defined before "dynarmic" above

Submodule externals/soundtouch deleted from 060181eaf2

View File

@@ -17,8 +17,6 @@ add_library(audio_core STATIC
sink_stream.h
stream.cpp
stream.h
time_stretch.cpp
time_stretch.h
$<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
)
@@ -26,7 +24,6 @@ add_library(audio_core STATIC
create_target_directory_groups(audio_core)
target_link_libraries(audio_core PUBLIC common core)
target_link_libraries(audio_core PRIVATE SoundTouch)
if(ENABLE_CUBEB)
target_link_libraries(audio_core PRIVATE cubeb)

View File

@@ -35,12 +35,12 @@ Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2)
: a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {}
void Filter::Process(std::vector<s16>& signal) {
const std::size_t num_frames = signal.size() / 2;
for (std::size_t i = 0; i < num_frames; i++) {
const size_t num_frames = signal.size() / 2;
for (size_t i = 0; i < num_frames; i++) {
std::rotate(in.begin(), in.end() - 1, in.end());
std::rotate(out.begin(), out.end() - 1, out.end());
for (std::size_t ch = 0; ch < channel_count; ch++) {
for (size_t ch = 0; ch < channel_count; ch++) {
in[0][ch] = signal[i * channel_count + ch];
out[0][ch] = b0 * in[0][ch] + b1 * in[1][ch] + b2 * in[2][ch] - a1 * out[1][ch] -
@@ -54,14 +54,14 @@ void Filter::Process(std::vector<s16>& signal) {
/// Calculates the appropriate Q for each biquad in a cascading filter.
/// @param total_count The total number of biquads to be cascaded.
/// @param index 0-index of the biquad to calculate the Q value for.
static double CascadingBiquadQ(std::size_t total_count, std::size_t index) {
static double CascadingBiquadQ(size_t total_count, size_t index) {
const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
return 1.0 / (2.0 * std::cos(pole));
}
CascadingFilter CascadingFilter::LowPass(double cutoff, std::size_t cascade_size) {
CascadingFilter CascadingFilter::LowPass(double cutoff, size_t cascade_size) {
std::vector<Filter> cascade(cascade_size);
for (std::size_t i = 0; i < cascade_size; i++) {
for (size_t i = 0; i < cascade_size; i++) {
cascade[i] = Filter::LowPass(cutoff, CascadingBiquadQ(cascade_size, i));
}
return CascadingFilter{std::move(cascade)};

View File

@@ -30,7 +30,7 @@ public:
void Process(std::vector<s16>& signal);
private:
static constexpr std::size_t channel_count = 2;
static constexpr size_t channel_count = 2;
/// Coefficients are in normalized form (a0 = 1.0).
double a1, a2, b0, b1, b2;
@@ -46,7 +46,7 @@ public:
/// Creates a cascading low-pass filter.
/// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0.
/// @param cascade_size Number of biquads in cascade.
static CascadingFilter LowPass(double cutoff, std::size_t cascade_size);
static CascadingFilter LowPass(double cutoff, size_t cascade_size);
/// Passthrough.
CascadingFilter();

View File

@@ -14,7 +14,7 @@
namespace AudioCore {
/// The Lanczos kernel
static double Lanczos(std::size_t a, double x) {
static double Lanczos(size_t a, double x) {
if (x == 0.0)
return 1.0;
const double px = M_PI * x;
@@ -37,15 +37,15 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
}
state.nyquist.Process(input);
constexpr std::size_t taps = InterpolationState::lanczos_taps;
const std::size_t num_frames = input.size() / 2;
constexpr size_t taps = InterpolationState::lanczos_taps;
const size_t num_frames = input.size() / 2;
std::vector<s16> output;
output.reserve(static_cast<std::size_t>(input.size() / ratio + 4));
output.reserve(static_cast<size_t>(input.size() / ratio + 4));
double& pos = state.position;
auto& h = state.history;
for (std::size_t i = 0; i < num_frames; ++i) {
for (size_t i = 0; i < num_frames; ++i) {
std::rotate(h.begin(), h.end() - 1, h.end());
h[0][0] = input[i * 2 + 0];
h[0][1] = input[i * 2 + 1];
@@ -53,7 +53,7 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
while (pos <= 1.0) {
double l = 0.0;
double r = 0.0;
for (std::size_t j = 0; j < h.size(); j++) {
for (size_t j = 0; j < h.size(); j++) {
l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
}

View File

@@ -12,8 +12,8 @@
namespace AudioCore {
struct InterpolationState {
static constexpr std::size_t lanczos_taps = 4;
static constexpr std::size_t history_size = lanczos_taps * 2 - 1;
static constexpr size_t lanczos_taps = 4;
static constexpr size_t history_size = lanczos_taps * 2 - 1;
double current_ratio = 0.0;
CascadingFilter nyquist;

View File

@@ -39,8 +39,7 @@ StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&&
sink->AcquireSinkStream(sample_rate, num_channels, name), std::move(name));
}
std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream,
std::size_t max_count) {
std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count) {
return stream->GetTagsAndReleaseBuffers(max_count);
}

View File

@@ -25,7 +25,7 @@ public:
Stream::ReleaseCallback&& release_callback);
/// Returns a vector of recently released buffers specified by tag for the specified stream
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count);
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count);
/// Starts an audio stream for playback
void StartStream(StreamPtr stream);

View File

@@ -3,12 +3,9 @@
// Refer to the license.txt file included.
#include "audio_core/algorithm/interpolate.h"
#include "audio_core/audio_out.h"
#include "audio_core/audio_renderer.h"
#include "audio_core/codec.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
#include "core/memory.h"
namespace AudioCore {
@@ -16,41 +13,6 @@ namespace AudioCore {
constexpr u32 STREAM_SAMPLE_RATE{48000};
constexpr u32 STREAM_NUM_CHANNELS{2};
class AudioRenderer::VoiceState {
public:
bool IsPlaying() const {
return is_in_use && info.play_state == PlayState::Started;
}
const VoiceOutStatus& GetOutStatus() const {
return out_status;
}
const VoiceInfo& GetInfo() const {
return info;
}
VoiceInfo& Info() {
return info;
}
void SetWaveIndex(std::size_t index);
std::vector<s16> DequeueSamples(std::size_t sample_count);
void UpdateState();
void RefreshBuffer();
private:
bool is_in_use{};
bool is_refresh_pending{};
std::size_t wave_index{};
std::size_t offset{};
Codec::ADPCMState adpcm_state{};
InterpolationState interp_state{};
std::vector<s16> samples;
VoiceOutStatus out_status{};
VoiceInfo info{};
};
AudioRenderer::AudioRenderer(AudioRendererParameter params,
Kernel::SharedPtr<Kernel::Event> buffer_event)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) {
@@ -65,8 +27,6 @@ AudioRenderer::AudioRenderer(AudioRendererParameter params,
QueueMixedBuffer(2);
}
AudioRenderer::~AudioRenderer() = default;
u32 AudioRenderer::GetSampleRate() const {
return worker_params.sample_rate;
}
@@ -79,10 +39,6 @@ u32 AudioRenderer::GetMixBufferCount() const {
return worker_params.mix_buffer_count;
}
Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
// Copy UpdateDataHeader struct
UpdateDataHeader config{};
@@ -96,8 +52,8 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
memory_pool_count * sizeof(MemoryPoolInfo));
// Copy VoiceInfo structs
std::size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size +
config.voice_resource_size};
size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size +
config.voice_resource_size};
for (auto& voice : voices) {
std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo));
offset += sizeof(VoiceInfo);
@@ -116,7 +72,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
// Update memory pool state
std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
for (std::size_t index = 0; index < memory_pool.size(); ++index) {
for (size_t index = 0; index < memory_pool.size(); ++index) {
if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
memory_pool[index].state = MemoryPoolStates::Attached;
} else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
@@ -137,7 +93,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
response_data.memory_pools_size);
// Copy output voice status
std::size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
for (const auto& voice : voices) {
std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(),
sizeof(VoiceOutStatus));
@@ -147,12 +103,12 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
return output_params;
}
void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
void AudioRenderer::VoiceState::SetWaveIndex(size_t index) {
wave_index = index & 3;
is_refresh_pending = true;
}
std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count) {
std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(size_t sample_count) {
if (!IsPlaying()) {
return {};
}
@@ -161,9 +117,9 @@ std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_co
RefreshBuffer();
}
const std::size_t max_size{samples.size() - offset};
const std::size_t dequeue_offset{offset};
std::size_t size{sample_count * STREAM_NUM_CHANNELS};
const size_t max_size{samples.size() - offset};
const size_t dequeue_offset{offset};
size_t size{sample_count * STREAM_NUM_CHANNELS};
if (size > max_size) {
size = max_size;
}
@@ -228,7 +184,7 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
case 1:
// 1 channel is upsampled to 2 channel
samples.resize(new_samples.size() * 2);
for (std::size_t index = 0; index < new_samples.size(); ++index) {
for (size_t index = 0; index < new_samples.size(); ++index) {
samples[index * 2] = new_samples[index];
samples[index * 2 + 1] = new_samples[index];
}
@@ -254,7 +210,7 @@ static constexpr s16 ClampToS16(s32 value) {
}
void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
constexpr std::size_t BUFFER_SIZE{512};
constexpr size_t BUFFER_SIZE{512};
std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels());
for (auto& voice : voices) {
@@ -262,7 +218,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
continue;
}
std::size_t offset{};
size_t offset{};
s64 samples_remaining{BUFFER_SIZE};
while (samples_remaining > 0) {
const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)};

View File

@@ -8,20 +8,16 @@
#include <memory>
#include <vector>
#include "audio_core/algorithm/interpolate.h"
#include "audio_core/audio_out.h"
#include "audio_core/codec.h"
#include "audio_core/stream.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/kernel/object.h"
namespace Kernel {
class Event;
}
#include "core/hle/kernel/event.h"
namespace AudioCore {
class AudioOut;
enum class PlayState : u8 {
Started = 0,
Stopped = 1,
@@ -162,23 +158,53 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
class AudioRenderer {
public:
AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
~AudioRenderer();
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers();
u32 GetSampleRate() const;
u32 GetSampleCount() const;
u32 GetMixBufferCount() const;
Stream::State GetStreamState() const;
private:
class VoiceState;
class VoiceState {
public:
bool IsPlaying() const {
return is_in_use && info.play_state == PlayState::Started;
}
const VoiceOutStatus& GetOutStatus() const {
return out_status;
}
const VoiceInfo& GetInfo() const {
return info;
}
VoiceInfo& Info() {
return info;
}
void SetWaveIndex(size_t index);
std::vector<s16> DequeueSamples(size_t sample_count);
void UpdateState();
void RefreshBuffer();
private:
bool is_in_use{};
bool is_refresh_pending{};
size_t wave_index{};
size_t offset{};
Codec::ADPCMState adpcm_state{};
InterpolationState interp_state{};
std::vector<s16> samples;
VoiceOutStatus out_status{};
VoiceInfo info{};
};
AudioRendererParameter worker_params;
Kernel::SharedPtr<Kernel::Event> buffer_event;
std::vector<VoiceState> voices;
std::unique_ptr<AudioOut> audio_out;
std::unique_ptr<AudioCore::AudioOut> audio_out;
AudioCore::StreamPtr stream;
};

View File

@@ -8,27 +8,27 @@
namespace AudioCore::Codec {
std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM_Coeff& coeff,
std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coeff& coeff,
ADPCMState& state) {
// GC-ADPCM with scale factor and variable coefficients.
// Frames are 8 bytes long containing 14 samples each.
// Samples are 4 bits (one nibble) long.
constexpr std::size_t FRAME_LEN = 8;
constexpr std::size_t SAMPLES_PER_FRAME = 14;
constexpr size_t FRAME_LEN = 8;
constexpr size_t SAMPLES_PER_FRAME = 14;
constexpr std::array<int, 16> SIGNED_NIBBLES = {
{0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
const std::size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME;
const std::size_t ret_size =
const size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME;
const size_t ret_size =
sample_count % 2 == 0 ? sample_count : sample_count + 1; // Ensure multiple of two.
std::vector<s16> ret(ret_size);
int yn1 = state.yn1, yn2 = state.yn2;
const std::size_t NUM_FRAMES =
const size_t NUM_FRAMES =
(sample_count + (SAMPLES_PER_FRAME - 1)) / SAMPLES_PER_FRAME; // Round up.
for (std::size_t framei = 0; framei < NUM_FRAMES; framei++) {
for (size_t framei = 0; framei < NUM_FRAMES; framei++) {
const int frame_header = data[framei * FRAME_LEN];
const int scale = 1 << (frame_header & 0xF);
const int idx = (frame_header >> 4) & 0x7;
@@ -53,9 +53,9 @@ std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM
return static_cast<s16>(val);
};
std::size_t outputi = framei * SAMPLES_PER_FRAME;
std::size_t datai = framei * FRAME_LEN + 1;
for (std::size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) {
size_t outputi = framei * SAMPLES_PER_FRAME;
size_t datai = framei * FRAME_LEN + 1;
for (size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) {
const s16 sample1 = decode_sample(SIGNED_NIBBLES[data[datai] >> 4]);
ret[outputi] = sample1;
outputi++;

View File

@@ -38,7 +38,7 @@ using ADPCM_Coeff = std::array<s16, 16>;
* @param state ADPCM state, this is updated with new state
* @return Decoded stereo signed PCM16 data, sample_count in length
*/
std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM_Coeff& coeff,
std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coeff& coeff,
ADPCMState& state);
}; // namespace AudioCore::Codec

View File

@@ -3,23 +3,27 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <atomic>
#include <cstring>
#include <mutex>
#include "audio_core/cubeb_sink.h"
#include "audio_core/stream.h"
#include "audio_core/time_stretch.h"
#include "common/logging/log.h"
#include "common/ring_buffer.h"
#include "core/settings.h"
namespace AudioCore {
class CubebSinkStream final : public SinkStream {
class SinkStreamImpl final : public SinkStream {
public:
CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
const std::string& name)
: ctx{ctx}, num_channels{std::min(num_channels_, 2u)}, time_stretch{sample_rate,
num_channels} {
SinkStreamImpl(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
const std::string& name)
: ctx{ctx}, num_channels{num_channels_} {
if (num_channels == 6) {
// 6-channel audio does not seem to work with cubeb + SDL, so we downsample this to 2
// channel for now
is_6_channel = true;
num_channels = 2;
}
cubeb_stream_params params{};
params.rate = sample_rate;
@@ -34,7 +38,7 @@ public:
if (cubeb_stream_init(ctx, &stream_backend, name.c_str(), nullptr, nullptr, output_device,
&params, std::max(512u, minimum_latency),
&CubebSinkStream::DataCallback, &CubebSinkStream::StateCallback,
&SinkStreamImpl::DataCallback, &SinkStreamImpl::StateCallback,
this) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream");
return;
@@ -46,7 +50,7 @@ public:
}
}
~CubebSinkStream() {
~SinkStreamImpl() {
if (!ctx) {
return;
}
@@ -58,32 +62,27 @@ public:
cubeb_stream_destroy(stream_backend);
}
void EnqueueSamples(u32 source_num_channels, const std::vector<s16>& samples) override {
if (source_num_channels > num_channels) {
// Downsample 6 channels to 2
std::vector<s16> buf;
buf.reserve(samples.size() * num_channels / source_num_channels);
for (std::size_t i = 0; i < samples.size(); i += source_num_channels) {
for (std::size_t ch = 0; ch < num_channels; ch++) {
buf.push_back(samples[i + ch]);
}
}
queue.Push(buf);
void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) override {
if (!ctx) {
return;
}
queue.Push(samples);
}
std::lock_guard lock{queue_mutex};
std::size_t SamplesInQueue(u32 num_channels) const override {
if (!ctx)
return 0;
queue.reserve(queue.size() + samples.size() * GetNumChannels());
return queue.Size() / num_channels;
}
void Flush() override {
should_flush = true;
if (is_6_channel) {
// Downsample 6 channels to 2
const size_t sample_count_copy_size = samples.size() * 2;
queue.reserve(sample_count_copy_size);
for (size_t i = 0; i < samples.size(); i += num_channels) {
queue.push_back(samples[i]);
queue.push_back(samples[i + 1]);
}
} else {
// Copy as-is
std::copy(samples.begin(), samples.end(), std::back_inserter(queue));
}
}
u32 GetNumChannels() const {
@@ -96,11 +95,10 @@ private:
cubeb* ctx{};
cubeb_stream* stream_backend{};
u32 num_channels{};
bool is_6_channel{};
Common::RingBuffer<s16, 0x10000> queue;
std::array<s16, 2> last_frame;
std::atomic<bool> should_flush{};
TimeStretcher time_stretch;
std::mutex queue_mutex;
std::vector<s16> queue;
static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
void* output_buffer, long num_frames);
@@ -119,10 +117,10 @@ CubebSink::CubebSink(std::string target_device_name) {
LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
} else {
const auto collection_end{collection.device + collection.count};
const auto device{
std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) {
return target_device_name == info.friendly_name;
})};
const auto device{std::find_if(collection.device, collection_end,
[&](const cubeb_device_info& device) {
return target_device_name == device.friendly_name;
})};
if (device != collection_end) {
output_device = device->devid;
}
@@ -146,59 +144,44 @@ CubebSink::~CubebSink() {
SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
const std::string& name) {
sink_streams.push_back(
std::make_unique<CubebSinkStream>(ctx, sample_rate, num_channels, output_device, name));
std::make_unique<SinkStreamImpl>(ctx, sample_rate, num_channels, output_device, name));
return *sink_streams.back();
}
long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
void* output_buffer, long num_frames) {
CubebSinkStream* impl = static_cast<CubebSinkStream*>(user_data);
long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
void* output_buffer, long num_frames) {
SinkStreamImpl* impl = static_cast<SinkStreamImpl*>(user_data);
u8* buffer = reinterpret_cast<u8*>(output_buffer);
if (!impl) {
return {};
}
const std::size_t num_channels = impl->GetNumChannels();
const std::size_t samples_to_write = num_channels * num_frames;
std::size_t samples_written;
std::lock_guard lock{impl->queue_mutex};
if (Settings::values.enable_audio_stretching) {
const std::vector<s16> in{impl->queue.Pop()};
const std::size_t num_in{in.size() / num_channels};
s16* const out{reinterpret_cast<s16*>(buffer)};
const std::size_t out_frames =
impl->time_stretch.Process(in.data(), num_in, out, num_frames);
samples_written = out_frames * num_channels;
const size_t frames_to_write{
std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))};
if (impl->should_flush) {
impl->time_stretch.Flush();
impl->should_flush = false;
}
} else {
samples_written = impl->queue.Pop(buffer, samples_to_write);
}
memcpy(buffer, impl->queue.data(), frames_to_write * sizeof(s16) * impl->GetNumChannels());
impl->queue.erase(impl->queue.begin(),
impl->queue.begin() + frames_to_write * impl->GetNumChannels());
if (samples_written >= num_channels) {
std::memcpy(&impl->last_frame[0], buffer + (samples_written - num_channels) * sizeof(s16),
num_channels * sizeof(s16));
}
// Fill the rest of the frames with last_frame
for (std::size_t i = samples_written; i < samples_to_write; i += num_channels) {
std::memcpy(buffer + i * sizeof(s16), &impl->last_frame[0], num_channels * sizeof(s16));
if (frames_to_write < num_frames) {
// Fill the rest of the frames with silence
memset(buffer + frames_to_write * sizeof(s16) * impl->GetNumChannels(), 0,
(num_frames - frames_to_write) * sizeof(s16) * impl->GetNumChannels());
}
return num_frames;
}
void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
std::vector<std::string> ListCubebSinkDevices() {
std::vector<std::string> device_list;
cubeb* ctx;
if (cubeb_init(&ctx, "yuzu Device Enumerator", nullptr) != CUBEB_OK) {
if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
return {};
}
@@ -207,7 +190,7 @@ std::vector<std::string> ListCubebSinkDevices() {
if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
} else {
for (std::size_t i = 0; i < collection.count; i++) {
for (size_t i = 0; i < collection.count; i++) {
const cubeb_device_info& device = collection.device[i];
if (device.friendly_name) {
device_list.emplace_back(device.friendly_name);

View File

@@ -21,12 +21,6 @@ public:
private:
struct NullSinkStreamImpl final : SinkStream {
void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
std::size_t SamplesInQueue(u32 /*num_channels*/) const override {
return 0;
}
void Flush() override {}
} null_sink_stream;
};

View File

@@ -24,7 +24,7 @@ const std::vector<SinkDetails> g_sink_details = {
[] { return std::vector<std::string>{"null"}; }},
};
const SinkDetails& GetSinkDetails(std::string_view sink_id) {
const SinkDetails& GetSinkDetails(std::string sink_id) {
auto iter =
std::find_if(g_sink_details.begin(), g_sink_details.end(),
[sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });

View File

@@ -6,8 +6,6 @@
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
@@ -32,6 +30,6 @@ struct SinkDetails {
extern const std::vector<SinkDetails> g_sink_details;
const SinkDetails& GetSinkDetails(std::string_view sink_id);
const SinkDetails& GetSinkDetails(std::string sink_id);
} // namespace AudioCore

View File

@@ -25,10 +25,6 @@ public:
* @param samples Samples in interleaved stereo PCM16 format.
*/
virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
virtual std::size_t SamplesInQueue(u32 num_channels) const = 0;
virtual void Flush() = 0;
};
using SinkStreamPtr = std::unique_ptr<SinkStream>;

View File

@@ -7,7 +7,6 @@
#include "audio_core/sink.h"
#include "audio_core/sink_details.h"
#include "audio_core/sink_stream.h"
#include "audio_core/stream.h"
#include "common/assert.h"
#include "common/logging/log.h"
@@ -18,7 +17,7 @@
namespace AudioCore {
constexpr std::size_t MaxAudioBufferCount{32};
constexpr size_t MaxAudioBufferCount{32};
u32 Stream::GetNumChannels() const {
switch (format) {
@@ -49,16 +48,11 @@ void Stream::Play() {
}
void Stream::Stop() {
state = State::Stopped;
ASSERT_MSG(false, "Unimplemented");
}
Stream::State Stream::GetState() const {
return state;
}
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
const size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
}
@@ -79,7 +73,6 @@ static void VolumeAdjustSamples(std::vector<s16>& samples) {
void Stream::PlayNextBuffer() {
if (!IsPlaying()) {
// Ensure we are in playing state before playing the next buffer
sink_stream.Flush();
return;
}
@@ -90,7 +83,6 @@ void Stream::PlayNextBuffer() {
if (queued_buffers.empty()) {
// No queued buffers - we are effectively paused
sink_stream.Flush();
return;
}
@@ -98,7 +90,6 @@ void Stream::PlayNextBuffer() {
queued_buffers.pop();
VolumeAdjustSamples(active_buffer->Samples());
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
@@ -128,9 +119,9 @@ bool Stream::ContainsBuffer(Buffer::Tag tag) const {
return {};
}
std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) {
std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(size_t max_count) {
std::vector<Buffer::Tag> tags;
for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
for (size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
tags.push_back(released_buffers.front()->GetTag());
released_buffers.pop();
}

View File

@@ -11,16 +11,13 @@
#include <queue>
#include "audio_core/buffer.h"
#include "audio_core/sink_stream.h"
#include "common/assert.h"
#include "common/common_types.h"
namespace CoreTiming {
struct EventType;
}
#include "core/core_timing.h"
namespace AudioCore {
class SinkStream;
/**
* Represents an audio stream, which is a sequence of queued buffers, to be outputed by AudioOut
*/
@@ -33,12 +30,6 @@ public:
Multi51Channel16,
};
/// Current state of the stream
enum class State {
Stopped,
Playing,
};
/// Callback function type, used to change guest state on a buffer being released
using ReleaseCallback = std::function<void()>;
@@ -58,7 +49,7 @@ public:
bool ContainsBuffer(Buffer::Tag tag) const;
/// Returns a vector of recently released buffers specified by tag
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(size_t max_count);
/// Returns true if the stream is currently playing
bool IsPlaying() const {
@@ -66,7 +57,7 @@ public:
}
/// Returns the number of queued buffers
std::size_t GetQueueSize() const {
size_t GetQueueSize() const {
return queued_buffers.size();
}
@@ -78,10 +69,13 @@ public:
/// Gets the number of channels
u32 GetNumChannels() const;
/// Get the state
State GetState() const;
private:
/// Current state of the stream
enum class State {
Stopped,
Playing,
};
/// Plays the next queued buffer in the audio stream, starting playback if necessary
void PlayNextBuffer();

View File

@@ -1,69 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cmath>
#include <cstddef>
#include "audio_core/time_stretch.h"
#include "common/logging/log.h"
namespace AudioCore {
TimeStretcher::TimeStretcher(u32 sample_rate, u32 channel_count)
: m_sample_rate(sample_rate), m_channel_count(channel_count) {
m_sound_touch.setChannels(channel_count);
m_sound_touch.setSampleRate(sample_rate);
m_sound_touch.setPitch(1.0);
m_sound_touch.setTempo(1.0);
}
void TimeStretcher::Clear() {
m_sound_touch.clear();
}
void TimeStretcher::Flush() {
m_sound_touch.flush();
}
std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
std::size_t num_out) {
const double time_delta = static_cast<double>(num_out) / m_sample_rate; // seconds
// We were given actual_samples number of samples, and num_samples were requested from us.
double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out);
const double max_latency = 1.0; // seconds
const double max_backlog = m_sample_rate * max_latency;
const double backlog_fullness = m_sound_touch.numSamples() / max_backlog;
if (backlog_fullness > 5.0) {
// Too many samples in backlog: Don't push anymore on
num_in = 0;
}
// We ideally want the backlog to be about 50% full.
// This gives some headroom both ways to prevent underflow and overflow.
// We tweak current_ratio to encourage this.
constexpr double tweak_time_scale = 0.05; // seconds
const double tweak_correction = (backlog_fullness - 0.5) * (time_delta / tweak_time_scale);
current_ratio *= std::pow(1.0 + 2.0 * tweak_correction, tweak_correction < 0 ? 3.0 : 1.0);
// This low-pass filter smoothes out variance in the calculated stretch ratio.
// The time-scale determines how responsive this filter is.
constexpr double lpf_time_scale = 2.0; // seconds
const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
// Place a lower limit of 5% speed. When a game boots up, there will be
// many silence samples. These do not need to be timestretched.
m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
m_sound_touch.setTempo(m_stretch_ratio);
LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio,
backlog_fullness);
m_sound_touch.putSamples(in, static_cast<u32>(num_in));
return m_sound_touch.receiveSamples(out, static_cast<u32>(num_out));
}
} // namespace AudioCore

View File

@@ -1,35 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <SoundTouch.h>
#include "common/common_types.h"
namespace AudioCore {
class TimeStretcher {
public:
TimeStretcher(u32 sample_rate, u32 channel_count);
/// @param in Input sample buffer
/// @param num_in Number of input frames in `in`
/// @param out Output sample buffer
/// @param num_out Desired number of output frames in `out`
/// @returns Actual number of frames written to `out`
std::size_t Process(const s16* in, std::size_t num_in, s16* out, std::size_t num_out);
void Clear();
void Flush();
private:
u32 m_sample_rate;
u32 m_channel_count;
soundtouch::SoundTouch m_sound_touch;
double m_stretch_ratio = 1.0;
};
} // namespace AudioCore

View File

@@ -71,7 +71,6 @@ add_library(common STATIC
param_package.cpp
param_package.h
quaternion.h
ring_buffer.h
scm_rev.cpp
scm_rev.h
scope_exit.h

View File

@@ -8,13 +8,13 @@
namespace Common {
template <typename T>
constexpr T AlignUp(T value, std::size_t size) {
constexpr T AlignUp(T value, size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value + (size - value % size) % size);
}
template <typename T>
constexpr T AlignDown(T value, std::size_t size) {
constexpr T AlignDown(T value, size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value - value % size);
}

View File

@@ -129,8 +129,8 @@ private:
public:
/// Constants to allow limited introspection of fields if needed
static constexpr std::size_t position = Position;
static constexpr std::size_t bits = Bits;
static constexpr size_t position = Position;
static constexpr size_t bits = Bits;
static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position;
/**

View File

@@ -170,14 +170,14 @@ public:
m_val |= (IntTy)1 << bit;
}
static BitSet AllTrue(std::size_t count) {
static BitSet AllTrue(size_t count) {
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
}
Ref operator[](std::size_t bit) {
Ref operator[](size_t bit) {
return Ref(this, (IntTy)1 << bit);
}
const Ref operator[](std::size_t bit) const {
const Ref operator[](size_t bit) const {
return (*const_cast<BitSet*>(this))[bit];
}
bool operator==(BitSet other) const {

View File

@@ -114,7 +114,7 @@ static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
return b;
}
static uint64 HashLen0to16(const char* s, std::size_t len) {
static uint64 HashLen0to16(const char* s, size_t len) {
if (len >= 8) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch64(s) + k2;
@@ -141,7 +141,7 @@ static uint64 HashLen0to16(const char* s, std::size_t len) {
// This probably works well for 16-byte strings as well, but it may be overkill
// in that case.
static uint64 HashLen17to32(const char* s, std::size_t len) {
static uint64 HashLen17to32(const char* s, size_t len) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch64(s) * k1;
uint64 b = Fetch64(s + 8);
@@ -170,7 +170,7 @@ static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint
}
// Return an 8-byte hash for 33 to 64 bytes.
static uint64 HashLen33to64(const char* s, std::size_t len) {
static uint64 HashLen33to64(const char* s, size_t len) {
uint64 mul = k2 + len * 2;
uint64 a = Fetch64(s) * k2;
uint64 b = Fetch64(s + 8);
@@ -191,7 +191,7 @@ static uint64 HashLen33to64(const char* s, std::size_t len) {
return b + x;
}
uint64 CityHash64(const char* s, std::size_t len) {
uint64 CityHash64(const char* s, size_t len) {
if (len <= 32) {
if (len <= 16) {
return HashLen0to16(s, len);
@@ -212,7 +212,7 @@ uint64 CityHash64(const char* s, std::size_t len) {
x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
len = (len - 1) & ~static_cast<std::size_t>(63);
len = (len - 1) & ~static_cast<size_t>(63);
do {
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
@@ -229,17 +229,17 @@ uint64 CityHash64(const char* s, std::size_t len) {
HashLen16(v.second, w.second) + x);
}
uint64 CityHash64WithSeed(const char* s, std::size_t len, uint64 seed) {
uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
return CityHash64WithSeeds(s, len, k2, seed);
}
uint64 CityHash64WithSeeds(const char* s, std::size_t len, uint64 seed0, uint64 seed1) {
uint64 CityHash64WithSeeds(const char* s, size_t len, uint64 seed0, uint64 seed1) {
return HashLen16(CityHash64(s, len) - seed0, seed1);
}
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
// of any length representable in signed long. Based on City and Murmur.
static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
uint64 a = Uint128Low64(seed);
uint64 b = Uint128High64(seed);
uint64 c = 0;
@@ -269,7 +269,7 @@ static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
return uint128(a ^ b, HashLen16(b, a));
}
uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
if (len < 128) {
return CityMurmur(s, len, seed);
}
@@ -313,7 +313,7 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
w.first *= 9;
v.first *= k0;
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
for (std::size_t tail_done = 0; tail_done < len;) {
for (size_t tail_done = 0; tail_done < len;) {
tail_done += 32;
y = Rotate(x + y, 42) * k0 + v.second;
w.first += Fetch64(s + len - tail_done + 16);
@@ -331,7 +331,7 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
}
uint128 CityHash128(const char* s, std::size_t len) {
uint128 CityHash128(const char* s, size_t len) {
return len >= 16
? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0))
: CityHash128WithSeed(s, len, uint128(k0, k1));

View File

@@ -63,7 +63,7 @@
#include <utility>
#include <stdint.h>
#include <stdlib.h> // for std::size_t.
#include <stdlib.h> // for size_t.
namespace Common {
@@ -77,22 +77,22 @@ inline uint64_t Uint128High64(const uint128& x) {
}
// Hash function for a byte array.
uint64_t CityHash64(const char* buf, std::size_t len);
uint64_t CityHash64(const char* buf, size_t len);
// Hash function for a byte array. For convenience, a 64-bit seed is also
// hashed into the result.
uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
uint64_t CityHash64WithSeed(const char* buf, size_t len, uint64_t seed);
// Hash function for a byte array. For convenience, two seeds are also
// hashed into the result.
uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0, uint64_t seed1);
uint64_t CityHash64WithSeeds(const char* buf, size_t len, uint64_t seed0, uint64_t seed1);
// Hash function for a byte array.
uint128 CityHash128(const char* s, std::size_t len);
uint128 CityHash128(const char* s, size_t len);
// Hash function for a byte array. For convenience, a 128-bit seed is also
// hashed into the result.
uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed);
// Hash 128 input bits down to 64 bits of output.
// This is intended to be a reasonably good hash function.

View File

@@ -33,8 +33,6 @@
#define NAND_DIR "nand"
#define SYSDATA_DIR "sysdata"
#define KEYS_DIR "keys"
#define LOAD_DIR "load"
#define DUMP_DIR "dump"
#define LOG_DIR "log"
// Filenames

View File

@@ -76,7 +76,7 @@ namespace FileUtil {
// Modifies argument.
static void StripTailDirSlashes(std::string& fname) {
if (fname.length() > 1) {
std::size_t i = fname.length();
size_t i = fname.length();
while (i > 0 && fname[i - 1] == DIR_SEP_CHR)
--i;
fname.resize(i);
@@ -201,7 +201,7 @@ bool CreateFullPath(const std::string& fullPath) {
return true;
}
std::size_t position = 0;
size_t position = 0;
while (true) {
// Find next sub path
position = fullPath.find(DIR_SEP_CHR, position);
@@ -299,7 +299,7 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
std::array<char, 1024> buffer;
while (!feof(input.get())) {
// read input
std::size_t rnum = fread(buffer.data(), sizeof(char), buffer.size(), input.get());
size_t rnum = fread(buffer.data(), sizeof(char), buffer.size(), input.get());
if (rnum != buffer.size()) {
if (ferror(input.get()) != 0) {
LOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
@@ -309,7 +309,7 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
}
// write output
std::size_t wnum = fwrite(buffer.data(), sizeof(char), rnum, output.get());
size_t wnum = fwrite(buffer.data(), sizeof(char), rnum, output.get());
if (wnum != rnum) {
LOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
@@ -705,8 +705,6 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
#endif
paths.emplace(UserPath::SDMCDir, user_path + SDMC_DIR DIR_SEP);
paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP);
// TODO: Put the logs in a better location for each OS
@@ -758,11 +756,11 @@ std::string GetNANDRegistrationDir(bool system) {
return GetUserPath(UserPath::NANDDir) + "user/Contents/registered/";
}
std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
}
std::size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
IOFile file(filename, text_file ? "r" : "rb");
if (!file.IsOpen())
@@ -831,7 +829,7 @@ std::vector<std::string> SplitPathComponents(std::string_view filename) {
std::string_view GetParentPath(std::string_view path) {
const auto name_bck_index = path.rfind('\\');
const auto name_fwd_index = path.rfind('/');
std::size_t name_index;
size_t name_index;
if (name_bck_index == std::string_view::npos || name_fwd_index == std::string_view::npos) {
name_index = std::min(name_bck_index, name_fwd_index);
@@ -870,7 +868,7 @@ std::string_view GetFilename(std::string_view path) {
}
std::string_view GetExtensionFromFilename(std::string_view name) {
const std::size_t index = name.rfind('.');
const size_t index = name.rfind('.');
if (index == std::string_view::npos) {
return {};

View File

@@ -29,8 +29,6 @@ enum class UserPath {
NANDDir,
RootDir,
SDMCDir,
LoadDir,
DumpDir,
SysDataDir,
UserDir,
};
@@ -145,9 +143,8 @@ const std::string& GetExeDirectory();
std::string AppDataRoamingDirectory();
#endif
std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
std::size_t ReadFileToString(bool text_file, const char* filename, std::string& str);
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
size_t ReadFileToString(bool text_file, const char* filename, std::string& str);
/**
* Splits the filename into 8.3 format
@@ -180,10 +177,10 @@ std::string_view RemoveTrailingSlash(std::string_view path);
// Creates a new vector containing indices [first, last) from the original.
template <typename T>
std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) {
std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t last) {
if (first >= last)
return {};
last = std::min<std::size_t>(last, vector.size());
last = std::min<size_t>(last, vector.size());
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
}
@@ -216,47 +213,47 @@ public:
bool Close();
template <typename T>
std::size_t ReadArray(T* data, std::size_t length) const {
size_t ReadArray(T* data, size_t length) const {
static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
if (!IsOpen()) {
return std::numeric_limits<std::size_t>::max();
return std::numeric_limits<size_t>::max();
}
return std::fread(data, sizeof(T), length, m_file);
}
template <typename T>
std::size_t WriteArray(const T* data, std::size_t length) {
size_t WriteArray(const T* data, size_t length) {
static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
if (!IsOpen()) {
return std::numeric_limits<std::size_t>::max();
return std::numeric_limits<size_t>::max();
}
return std::fwrite(data, sizeof(T), length, m_file);
}
template <typename T>
std::size_t ReadBytes(T* data, std::size_t length) const {
size_t ReadBytes(T* data, size_t length) const {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
return ReadArray(reinterpret_cast<char*>(data), length);
}
template <typename T>
std::size_t WriteBytes(const T* data, std::size_t length) {
size_t WriteBytes(const T* data, size_t length) {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
return WriteArray(reinterpret_cast<const char*>(data), length);
}
template <typename T>
std::size_t WriteObject(const T& object) {
size_t WriteObject(const T& object) {
static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer");
return WriteArray(&object, 1);
}
std::size_t WriteString(const std::string& str) {
size_t WriteString(const std::string& str) {
return WriteArray(str.c_str(), str.length());
}

View File

@@ -17,7 +17,7 @@ namespace Common {
* @param len Length of data (in bytes) to compute hash over
* @returns 64-bit hash value that was computed over the data block
*/
static inline u64 ComputeHash64(const void* data, std::size_t len) {
static inline u64 ComputeHash64(const void* data, size_t len) {
return CityHash64(static_cast<const char*>(data), len);
}
@@ -63,7 +63,7 @@ struct HashableStruct {
return !(*this == o);
};
std::size_t Hash() const {
size_t Hash() const {
return Common::ComputeStructHash64(state);
}
};

View File

@@ -18,7 +18,7 @@ u8 ToHexNibble(char c1) {
return 0;
}
std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
std::array<u8, 16> operator""_array16(const char* str, size_t len) {
if (len != 32) {
LOG_ERROR(Common,
"Attempting to parse string to array that is not of correct size (expected=32, "
@@ -29,7 +29,7 @@ std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
return HexStringToArray<16>(str);
}
std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
std::array<u8, 32> operator""_array32(const char* str, size_t len) {
if (len != 64) {
LOG_ERROR(Common,
"Attempting to parse string to array that is not of correct size (expected=64, "

View File

@@ -14,20 +14,20 @@ namespace Common {
u8 ToHexNibble(char c1);
template <std::size_t Size, bool le = false>
template <size_t Size, bool le = false>
std::array<u8, Size> HexStringToArray(std::string_view str) {
std::array<u8, Size> out{};
if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
for (size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
} else {
for (std::size_t i = 0; i < 2 * Size; i += 2)
for (size_t i = 0; i < 2 * Size; i += 2)
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
}
return out;
}
template <std::size_t Size>
template <size_t Size>
std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
std::string out;
for (u8 c : array)
@@ -35,7 +35,7 @@ std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
return out;
}
std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
std::array<u8, 0x10> operator"" _array16(const char* str, size_t len);
std::array<u8, 0x20> operator"" _array32(const char* str, size_t len);
} // namespace Common

View File

@@ -135,7 +135,7 @@ FileBackend::FileBackend(const std::string& filename)
void FileBackend::Write(const Entry& entry) {
// 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 = 50 * 1024L * 1024L;
constexpr size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L;
if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
return;
}
@@ -183,7 +183,6 @@ void FileBackend::Write(const Entry& entry) {
SUB(Service, FS) \
SUB(Service, GRC) \
SUB(Service, HID) \
SUB(Service, IRS) \
SUB(Service, LBL) \
SUB(Service, LDN) \
SUB(Service, LDR) \

View File

@@ -100,7 +100,7 @@ public:
private:
FileUtil::IOFile file;
std::size_t bytes_written;
size_t bytes_written;
};
void AddBackend(std::unique_ptr<Backend> backend);

View File

@@ -71,7 +71,7 @@ void Filter::ResetAll(Level level) {
}
void Filter::SetClassLevel(Class log_class, Level level) {
class_levels[static_cast<std::size_t>(log_class)] = level;
class_levels[static_cast<size_t>(log_class)] = level;
}
void Filter::ParseFilterString(std::string_view filter_view) {
@@ -93,8 +93,7 @@ void Filter::ParseFilterString(std::string_view filter_view) {
}
bool Filter::CheckMessage(Class log_class, Level level) const {
return static_cast<u8>(level) >=
static_cast<u8>(class_levels[static_cast<std::size_t>(log_class)]);
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
}
bool Filter::IsDebug() const {

View File

@@ -49,6 +49,6 @@ public:
bool IsDebug() const;
private:
std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels;
std::array<Level, static_cast<size_t>(Class::Count)> class_levels;
};
} // namespace Log

View File

@@ -70,7 +70,6 @@ enum class Class : ClassType {
Service_FS, ///< The FS (Filesystem) service
Service_GRC, ///< The game recording service
Service_HID, ///< The HID (Human interface device) service
Service_IRS, ///< The IRS service
Service_LBL, ///< The LBL (LCD backlight) service
Service_LDN, ///< The LDN (Local domain network) service
Service_LDR, ///< The loader service

View File

@@ -25,7 +25,7 @@
// This is purposely not a full wrapper for virtualalloc/mmap, but it
// provides exactly the primitive operations that Dolphin needs.
void* AllocateExecutableMemory(std::size_t size, bool low) {
void* AllocateExecutableMemory(size_t size, bool low) {
#if defined(_WIN32)
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
@@ -74,7 +74,7 @@ void* AllocateExecutableMemory(std::size_t size, bool low) {
return ptr;
}
void* AllocateMemoryPages(std::size_t size) {
void* AllocateMemoryPages(size_t size) {
#ifdef _WIN32
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
#else
@@ -90,7 +90,7 @@ void* AllocateMemoryPages(std::size_t size) {
return ptr;
}
void* AllocateAlignedMemory(std::size_t size, std::size_t alignment) {
void* AllocateAlignedMemory(size_t size, size_t alignment) {
#ifdef _WIN32
void* ptr = _aligned_malloc(size, alignment);
#else
@@ -109,7 +109,7 @@ void* AllocateAlignedMemory(std::size_t size, std::size_t alignment) {
return ptr;
}
void FreeMemoryPages(void* ptr, std::size_t size) {
void FreeMemoryPages(void* ptr, size_t size) {
if (ptr) {
#ifdef _WIN32
if (!VirtualFree(ptr, 0, MEM_RELEASE))
@@ -130,7 +130,7 @@ void FreeAlignedMemory(void* ptr) {
}
}
void WriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
@@ -140,7 +140,7 @@ void WriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
#endif
}
void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,

View File

@@ -7,13 +7,13 @@
#include <cstddef>
#include <string>
void* AllocateExecutableMemory(std::size_t size, bool low = true);
void* AllocateMemoryPages(std::size_t size);
void FreeMemoryPages(void* ptr, std::size_t size);
void* AllocateAlignedMemory(std::size_t size, std::size_t alignment);
void* AllocateExecutableMemory(size_t size, bool low = true);
void* AllocateMemoryPages(size_t size);
void FreeMemoryPages(void* ptr, size_t size);
void* AllocateAlignedMemory(size_t size, size_t alignment);
void FreeAlignedMemory(void* ptr);
void WriteProtectMemory(void* ptr, std::size_t size, bool executable = false);
void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute = false);
void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
std::string MemUsage();
inline int GetPageSize() {

View File

@@ -16,7 +16,7 @@
// Call directly after the command or use the error num.
// This function might change the error code.
std::string GetLastErrorMsg() {
static const std::size_t buff_size = 255;
static const size_t buff_size = 255;
char err_str[buff_size];
#ifdef _WIN32

View File

@@ -1,119 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <algorithm>
#include <array>
#include <atomic>
#include <cstddef>
#include <cstring>
#include <new>
#include <type_traits>
#include <vector>
#include "common/common_types.h"
namespace Common {
/// SPSC ring buffer
/// @tparam T Element type
/// @tparam capacity Number of slots in ring buffer
/// @tparam granularity Slot size in terms of number of elements
template <typename T, std::size_t capacity, std::size_t granularity = 1>
class RingBuffer {
/// A "slot" is made of `granularity` elements of `T`.
static constexpr std::size_t slot_size = granularity * sizeof(T);
// T must be safely memcpy-able and have a trivial default constructor.
static_assert(std::is_trivial_v<T>);
// Ensure capacity is sensible.
static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity);
static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two");
// Ensure lock-free.
static_assert(std::atomic_size_t::is_always_lock_free);
public:
/// Pushes slots into the ring buffer
/// @param new_slots Pointer to the slots to push
/// @param slot_count Number of slots to push
/// @returns The number of slots actually pushed
std::size_t Push(const void* new_slots, std::size_t slot_count) {
const std::size_t write_index = m_write_index.load();
const std::size_t slots_free = capacity + m_read_index.load() - write_index;
const std::size_t push_count = std::min(slot_count, slots_free);
const std::size_t pos = write_index % capacity;
const std::size_t first_copy = std::min(capacity - pos, push_count);
const std::size_t second_copy = push_count - first_copy;
const char* in = static_cast<const char*>(new_slots);
std::memcpy(m_data.data() + pos * granularity, in, first_copy * slot_size);
in += first_copy * slot_size;
std::memcpy(m_data.data(), in, second_copy * slot_size);
m_write_index.store(write_index + push_count);
return push_count;
}
std::size_t Push(const std::vector<T>& input) {
return Push(input.data(), input.size());
}
/// Pops slots from the ring buffer
/// @param output Where to store the popped slots
/// @param max_slots Maximum number of slots to pop
/// @returns The number of slots actually popped
std::size_t Pop(void* output, std::size_t max_slots = ~std::size_t(0)) {
const std::size_t read_index = m_read_index.load();
const std::size_t slots_filled = m_write_index.load() - read_index;
const std::size_t pop_count = std::min(slots_filled, max_slots);
const std::size_t pos = read_index % capacity;
const std::size_t first_copy = std::min(capacity - pos, pop_count);
const std::size_t second_copy = pop_count - first_copy;
char* out = static_cast<char*>(output);
std::memcpy(out, m_data.data() + pos * granularity, first_copy * slot_size);
out += first_copy * slot_size;
std::memcpy(out, m_data.data(), second_copy * slot_size);
m_read_index.store(read_index + pop_count);
return pop_count;
}
std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) {
std::vector<T> out(std::min(max_slots, capacity) * granularity);
const std::size_t count = Pop(out.data(), out.size() / granularity);
out.resize(count * granularity);
return out;
}
/// @returns Number of slots used
std::size_t Size() const {
return m_write_index.load() - m_read_index.load();
}
/// @returns Maximum size of ring buffer
constexpr std::size_t Capacity() const {
return capacity;
}
private:
// It is important to align the below variables for performance reasons:
// Having them on the same cache-line would result in false-sharing between them.
// TODO: Remove this ifdef whenever clang and GCC support
// std::hardware_destructive_interference_size.
#if defined(_MSC_VER) && _MSC_VER >= 1911
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
#else
alignas(128) std::atomic_size_t m_read_index{0};
alignas(128) std::atomic_size_t m_write_index{0};
#endif
std::array<T, granularity * capacity> m_data;
};
} // namespace Common

View File

@@ -37,7 +37,7 @@ std::string ToUpper(std::string str) {
}
// For Debugging. Read out an u8 array.
std::string ArrayToString(const u8* data, std::size_t size, int line_len, bool spaces) {
std::string ArrayToString(const u8* data, size_t size, int line_len, bool spaces) {
std::ostringstream oss;
oss << std::setfill('0') << std::hex;
@@ -60,7 +60,7 @@ std::string StringFromBuffer(const std::vector<u8>& data) {
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) {
const std::size_t s = str.find_first_not_of(" \t\r\n");
const size_t s = str.find_first_not_of(" \t\r\n");
if (str.npos != s)
return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1);
@@ -121,10 +121,10 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
if (full_path.empty())
return false;
std::size_t dir_end = full_path.find_last_of("/"
size_t dir_end = full_path.find_last_of("/"
// windows needs the : included for something like just "C:" to be considered a directory
#ifdef _WIN32
"\\:"
"\\:"
#endif
);
if (std::string::npos == dir_end)
@@ -132,7 +132,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
else
dir_end += 1;
std::size_t fname_end = full_path.rfind('.');
size_t fname_end = full_path.rfind('.');
if (fname_end < dir_end || std::string::npos == fname_end)
fname_end = full_path.size();
@@ -172,7 +172,7 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri
}
std::string TabsToSpaces(int tab_size, std::string in) {
std::size_t i = 0;
size_t i = 0;
while ((i = in.find('\t')) != std::string::npos) {
in.replace(i, 1, tab_size, ' ');
@@ -182,7 +182,7 @@ std::string TabsToSpaces(int tab_size, std::string in) {
}
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
std::size_t pos = 0;
size_t pos = 0;
if (src == dest)
return result;
@@ -280,22 +280,22 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
return {};
}
const std::size_t in_bytes = sizeof(T) * input.size();
const size_t in_bytes = sizeof(T) * input.size();
// Multiply by 4, which is the max number of bytes to encode a codepoint
const std::size_t out_buffer_size = 4 * in_bytes;
const size_t out_buffer_size = 4 * in_bytes;
std::string out_buffer(out_buffer_size, '\0');
auto src_buffer = &input[0];
std::size_t src_bytes = in_bytes;
size_t src_bytes = in_bytes;
auto dst_buffer = &out_buffer[0];
std::size_t dst_bytes = out_buffer.size();
size_t dst_bytes = out_buffer.size();
while (0 != src_bytes) {
std::size_t const iconv_result =
size_t const iconv_result =
iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes);
if (static_cast<std::size_t>(-1) == iconv_result) {
if (static_cast<size_t>(-1) == iconv_result) {
if (EILSEQ == errno || EINVAL == errno) {
// Try to skip the bad character
if (0 != src_bytes) {
@@ -326,22 +326,22 @@ std::u16string UTF8ToUTF16(const std::string& input) {
return {};
}
const std::size_t in_bytes = sizeof(char) * input.size();
const size_t in_bytes = sizeof(char) * input.size();
// Multiply by 4, which is the max number of bytes to encode a codepoint
const std::size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
std::u16string out_buffer(out_buffer_size, char16_t{});
char* src_buffer = const_cast<char*>(&input[0]);
std::size_t src_bytes = in_bytes;
size_t src_bytes = in_bytes;
char* dst_buffer = (char*)(&out_buffer[0]);
std::size_t dst_bytes = out_buffer.size();
size_t dst_bytes = out_buffer.size();
while (0 != src_bytes) {
std::size_t const iconv_result =
size_t const iconv_result =
iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes);
if (static_cast<std::size_t>(-1) == iconv_result) {
if (static_cast<size_t>(-1) == iconv_result) {
if (EILSEQ == errno || EINVAL == errno) {
// Try to skip the bad character
if (0 != src_bytes) {
@@ -381,8 +381,8 @@ std::string SHIFTJISToUTF8(const std::string& input) {
#endif
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len) {
std::size_t len = 0;
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len) {
size_t len = 0;
while (len < max_len && buffer[len] != '\0')
++len;

View File

@@ -19,7 +19,7 @@ std::string ToLower(std::string str);
/// Make a string uppercase
std::string ToUpper(std::string str);
std::string ArrayToString(const u8* data, std::size_t size, int line_len = 20, bool spaces = true);
std::string ArrayToString(const u8* data, size_t size, int line_len = 20, bool spaces = true);
std::string StringFromBuffer(const std::vector<u8>& data);
@@ -118,7 +118,7 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
* Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
* NUL-terminated then the string ends at max_len characters.
*/
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
/**
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's

View File

@@ -60,12 +60,12 @@ private:
class Barrier {
public:
explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {}
explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {}
/// Blocks until all "count" threads have called Sync()
void Sync() {
std::unique_lock<std::mutex> lk(mutex);
const std::size_t current_generation = generation;
const size_t current_generation = generation;
if (++waiting == count) {
generation++;
@@ -80,13 +80,21 @@ public:
private:
std::condition_variable condvar;
std::mutex mutex;
const std::size_t count;
std::size_t waiting;
std::size_t generation; // Incremented once each time the barrier is used
const size_t count;
size_t waiting;
size_t generation; // Incremented once each time the barrier is used
};
void SleepCurrentThread(int ms);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
// Use this function during a spin-wait to make the current thread
// relax while another thread is working. This may be more efficient
// than using events because event functions use kernel calls.
inline void YieldCPU() {
std::this_thread::yield();
}
void SetCurrentThreadName(const char* name);
} // namespace Common

View File

@@ -97,7 +97,7 @@ const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
Xbyak::util::xmm15,
});
constexpr std::size_t ABI_SHADOW_SPACE = 0x20;
constexpr size_t ABI_SHADOW_SPACE = 0x20;
#else
@@ -147,23 +147,22 @@ const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
Xbyak::util::r15,
});
constexpr std::size_t ABI_SHADOW_SPACE = 0;
constexpr size_t ABI_SHADOW_SPACE = 0;
#endif
inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
std::size_t needed_frame_size, s32* out_subtraction,
s32* out_xmm_offset) {
inline void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size,
s32* out_subtraction, s32* out_xmm_offset) {
int count = (regs & ABI_ALL_GPRS).Count();
rsp_alignment -= count * 8;
std::size_t subtraction = 0;
size_t subtraction = 0;
int xmm_count = (regs & ABI_ALL_XMMS).Count();
if (xmm_count) {
// If we have any XMMs to save, we must align the stack here.
subtraction = rsp_alignment & 0xF;
}
subtraction += 0x10 * xmm_count;
std::size_t xmm_base_subtraction = subtraction;
size_t xmm_base_subtraction = subtraction;
subtraction += needed_frame_size;
subtraction += ABI_SHADOW_SPACE;
// Final alignment.
@@ -174,9 +173,8 @@ inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
*out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
}
inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
std::size_t rsp_alignment,
std::size_t needed_frame_size = 0) {
inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
size_t rsp_alignment, size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
@@ -197,8 +195,7 @@ inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, B
}
inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
std::size_t rsp_alignment,
std::size_t needed_frame_size = 0) {
size_t rsp_alignment, size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);

View File

@@ -34,7 +34,7 @@ inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
template <typename T>
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
std::size_t addr = reinterpret_cast<std::size_t>(f);
size_t addr = reinterpret_cast<size_t>(f);
if (IsWithin2G(code, addr)) {
code.call(f);
} else {

View File

@@ -32,8 +32,6 @@ add_library(core STATIC
file_sys/control_metadata.h
file_sys/directory.h
file_sys/errors.h
file_sys/fsmitm_romfsbuild.cpp
file_sys/fsmitm_romfsbuild.h
file_sys/mode.h
file_sys/nca_metadata.cpp
file_sys/nca_metadata.h
@@ -61,13 +59,10 @@ add_library(core STATIC
file_sys/vfs.h
file_sys/vfs_concat.cpp
file_sys/vfs_concat.h
file_sys/vfs_layered.cpp
file_sys/vfs_layered.h
file_sys/vfs_offset.cpp
file_sys/vfs_offset.h
file_sys/vfs_real.cpp
file_sys/vfs_real.h
file_sys/vfs_static.h
file_sys/vfs_vector.cpp
file_sys/vfs_vector.h
file_sys/xts_archive.cpp

View File

@@ -6,14 +6,11 @@
#include <array>
#include "common/common_types.h"
namespace Kernel {
enum class VMAPermission : u8;
}
#include "core/hle/kernel/vm_manager.h"
namespace Core {
/// Generic ARMv8 CPU interface
/// Generic ARM11 CPU interface
class ARM_Interface : NonCopyable {
public:
virtual ~ARM_Interface() {}
@@ -22,16 +19,10 @@ public:
std::array<u64, 31> cpu_registers;
u64 sp;
u64 pc;
u32 pstate;
std::array<u8, 4> padding;
std::array<u128, 32> vector_registers;
u32 fpcr;
u32 fpsr;
u64 tpidr;
u64 cpsr;
std::array<u128, 32> fpu_registers;
u64 fpscr;
};
// Internally within the kernel, it expects the AArch64 version of the
// thread context to be 800 bytes in size.
static_assert(sizeof(ThreadContext) == 0x320);
/// Runs the CPU until an event happens
virtual void Run() = 0;
@@ -40,11 +31,11 @@ public:
virtual void Step() = 0;
/// Maps a backing memory region for the CPU
virtual void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
virtual void MapBackingMemory(VAddr address, size_t size, u8* memory,
Kernel::VMAPermission perms) = 0;
/// Unmaps a region of memory that was previously mapped using MapBackingMemory
virtual void UnmapMemory(VAddr address, std::size_t size) = 0;
virtual void UnmapMemory(VAddr address, size_t size) = 0;
/// Clear all instruction cache
virtual void ClearInstructionCache() = 0;
@@ -78,50 +69,42 @@ public:
*/
virtual void SetReg(int index, u64 value) = 0;
/**
* Gets the value of a specified vector register.
*
* @param index The index of the vector register.
* @return the value within the vector register.
*/
virtual u128 GetVectorReg(int index) const = 0;
virtual u128 GetExtReg(int index) const = 0;
virtual void SetExtReg(int index, u128 value) = 0;
/**
* Sets a given value into a vector register.
*
* @param index The index of the vector register.
* @param value The new value to place in the register.
* Gets the value of a VFP register
* @param index Register index (0-31)
* @return Returns the value in the register
*/
virtual void SetVectorReg(int index, u128 value) = 0;
virtual u32 GetVFPReg(int index) const = 0;
/**
* Get the current PSTATE register
* @return Returns the value of the PSTATE register
* Sets a VFP register to the given value
* @param index Register index (0-31)
* @param value Value to set register to
*/
virtual u32 GetPSTATE() const = 0;
virtual void SetVFPReg(int index, u32 value) = 0;
/**
* Set the current PSTATE register
* @param pstate Value to set PSTATE to
* Get the current CPSR register
* @return Returns the value of the CPSR register
*/
virtual void SetPSTATE(u32 pstate) = 0;
virtual u32 GetCPSR() const = 0;
/**
* Set the current CPSR register
* @param cpsr Value to set CPSR to
*/
virtual void SetCPSR(u32 cpsr) = 0;
virtual VAddr GetTlsAddress() const = 0;
virtual void SetTlsAddress(VAddr address) = 0;
/**
* Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
*
* @return the value within the register.
*/
virtual u64 GetTPIDR_EL0() const = 0;
/**
* Sets a new value within the TPIDR_EL0 (read/write software thread ID) register.
*
* @param value The new value to place in the register.
*/
virtual void SetTPIDR_EL0(u64 value) = 0;
/**
@@ -136,7 +119,6 @@ public:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
/// Clears the exclusive monitor's state.
virtual void ClearExclusiveState() = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)

View File

@@ -12,10 +12,8 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
namespace Core {
@@ -60,7 +58,7 @@ public:
Memory::Write64(vaddr + 8, value[1]);
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
void InterpreterFallback(u64 pc, size_t num_instructions) override {
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
@@ -81,20 +79,9 @@ public:
case Dynarmic::A64::Exception::SendEventLocal:
case Dynarmic::A64::Exception::Yield:
return;
case Dynarmic::A64::Exception::Breakpoint:
if (GDBStub::IsServerEnabled()) {
parent.jit->HaltExecution();
parent.SetPC(pc);
Kernel::Thread* thread = Kernel::GetCurrentThread();
parent.SaveContext(thread->context);
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
return;
}
[[fallthrough]];
default:
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
static_cast<std::size_t>(exception), pc);
static_cast<size_t>(exception), pc);
}
}
@@ -123,14 +110,13 @@ public:
}
ARM_Dynarmic& parent;
std::size_t num_interpreted_instructions = 0;
size_t num_interpreted_instructions = 0;
u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0;
};
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
auto& current_process = Core::CurrentProcess();
auto** const page_table = current_process->VMManager().page_table.pointers.data();
auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data();
Dynarmic::A64::UserConfig config;
@@ -139,7 +125,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
// Memory
config.page_table = reinterpret_cast<void**>(page_table);
config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth();
config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS;
config.silently_mirror_page_table = false;
// Multi-process state
@@ -171,11 +157,10 @@ void ARM_Dynarmic::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
std::size_t core_index)
ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index)
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} {
ThreadContext ctx{};
ThreadContext ctx;
inner_unicorn.SaveContext(ctx);
PageTableChanged();
LoadContext(ctx);
@@ -183,12 +168,12 @@ ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
ARM_Dynarmic::~ARM_Dynarmic() = default;
void ARM_Dynarmic::MapBackingMemory(u64 address, std::size_t size, u8* memory,
void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory,
Kernel::VMAPermission perms) {
inner_unicorn.MapBackingMemory(address, size, memory, perms);
}
void ARM_Dynarmic::UnmapMemory(u64 address, std::size_t size) {
void ARM_Dynarmic::UnmapMemory(u64 address, size_t size) {
inner_unicorn.UnmapMemory(address, size);
}
@@ -208,20 +193,29 @@ void ARM_Dynarmic::SetReg(int index, u64 value) {
jit->SetRegister(index, value);
}
u128 ARM_Dynarmic::GetVectorReg(int index) const {
u128 ARM_Dynarmic::GetExtReg(int index) const {
return jit->GetVector(index);
}
void ARM_Dynarmic::SetVectorReg(int index, u128 value) {
void ARM_Dynarmic::SetExtReg(int index, u128 value) {
jit->SetVector(index, value);
}
u32 ARM_Dynarmic::GetPSTATE() const {
u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const {
UNIMPLEMENTED();
return {};
}
void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) {
UNIMPLEMENTED();
}
u32 ARM_Dynarmic::GetCPSR() const {
return jit->GetPstate();
}
void ARM_Dynarmic::SetPSTATE(u32 pstate) {
jit->SetPstate(pstate);
void ARM_Dynarmic::SetCPSR(u32 cpsr) {
jit->SetPstate(cpsr);
}
u64 ARM_Dynarmic::GetTlsAddress() const {
@@ -244,22 +238,18 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
ctx.pstate = jit->GetPstate();
ctx.vector_registers = jit->GetVectors();
ctx.fpcr = jit->GetFpcr();
ctx.fpsr = jit->GetFpsr();
ctx.tpidr = cb->tpidr_el0;
ctx.cpsr = jit->GetPstate();
ctx.fpu_registers = jit->GetVectors();
ctx.fpscr = jit->GetFpcr();
}
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
jit->SetPstate(ctx.pstate);
jit->SetVectors(ctx.vector_registers);
jit->SetFpcr(ctx.fpcr);
jit->SetFpsr(ctx.fpsr);
SetTPIDR_EL0(ctx.tpidr);
jit->SetPstate(static_cast<u32>(ctx.cpsr));
jit->SetVectors(ctx.fpu_registers);
jit->SetFpcr(static_cast<u32>(ctx.fpscr));
}
void ARM_Dynarmic::PrepareReschedule() {
@@ -279,10 +269,10 @@ void ARM_Dynarmic::PageTableChanged() {
current_page_table = Memory::GetCurrentPageTable();
}
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(size_t core_count) : monitor(core_count) {}
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
void DynarmicExclusiveMonitor::SetExclusive(size_t core_index, VAddr addr) {
// Size doesn't actually matter.
monitor.Mark(core_index, addr, 16);
}
@@ -291,30 +281,30 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
monitor.Clear();
}
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
bool DynarmicExclusiveMonitor::ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 1,
[&] { Memory::Write8(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
bool DynarmicExclusiveMonitor::ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 2,
[&] { Memory::Write16(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
bool DynarmicExclusiveMonitor::ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 4,
[&] { Memory::Write32(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
bool DynarmicExclusiveMonitor::ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 8,
[&] { Memory::Write64(vaddr, value); });
}
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
bool DynarmicExclusiveMonitor::ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) {
return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
Memory::Write64(vaddr + 0, value[0]);
Memory::Write64(vaddr + 8, value[1]);
Memory::Write64(vaddr, value[0]);
Memory::Write64(vaddr, value[1]);
});
}

View File

@@ -12,10 +12,6 @@
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
namespace Memory {
struct PageTable;
}
namespace Core {
class ARM_Dynarmic_Callbacks;
@@ -23,22 +19,24 @@ class DynarmicExclusiveMonitor;
class ARM_Dynarmic final : public ARM_Interface {
public:
ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, std::size_t core_index);
ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index);
~ARM_Dynarmic();
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
void MapBackingMemory(VAddr address, size_t size, u8* memory,
Kernel::VMAPermission perms) override;
void UnmapMemory(u64 address, std::size_t size) override;
void UnmapMemory(u64 address, size_t size) override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
u128 GetVectorReg(int index) const override;
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
u128 GetExtReg(int index) const override;
void SetExtReg(int index, u128 value) override;
u32 GetVFPReg(int index) const override;
void SetVFPReg(int index, u32 value) override;
u32 GetCPSR() const override;
void Run() override;
void Step() override;
void SetCPSR(u32 cpsr) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
@@ -61,7 +59,7 @@ private:
std::unique_ptr<Dynarmic::A64::Jit> jit;
ARM_Unicorn inner_unicorn;
std::size_t core_index;
size_t core_index;
std::shared_ptr<DynarmicExclusiveMonitor> exclusive_monitor;
Memory::PageTable* current_page_table = nullptr;
@@ -69,17 +67,17 @@ private:
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
explicit DynarmicExclusiveMonitor(std::size_t core_count);
explicit DynarmicExclusiveMonitor(size_t core_count);
~DynarmicExclusiveMonitor();
void SetExclusive(std::size_t core_index, VAddr addr) override;
void SetExclusive(size_t core_index, VAddr addr) override;
void ClearExclusive() override;
bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) override;
bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) override;
bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override;
bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) override;
bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) override;
bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) override;
bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) override;
bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) override;
private:
friend class ARM_Dynarmic;

View File

@@ -12,14 +12,14 @@ class ExclusiveMonitor {
public:
virtual ~ExclusiveMonitor();
virtual void SetExclusive(std::size_t core_index, VAddr addr) = 0;
virtual void SetExclusive(size_t core_index, VAddr addr) = 0;
virtual void ClearExclusive() = 0;
virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
virtual bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) = 0;
virtual bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) = 0;
virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0;
virtual bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) = 0;
virtual bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) = 0;
virtual bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) = 0;
virtual bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) = 0;
virtual bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) = 0;
};
} // namespace Core

View File

@@ -90,12 +90,12 @@ ARM_Unicorn::~ARM_Unicorn() {
CHECKED(uc_close(uc));
}
void ARM_Unicorn::MapBackingMemory(VAddr address, std::size_t size, u8* memory,
void ARM_Unicorn::MapBackingMemory(VAddr address, size_t size, u8* memory,
Kernel::VMAPermission perms) {
CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory));
}
void ARM_Unicorn::UnmapMemory(VAddr address, std::size_t size) {
void ARM_Unicorn::UnmapMemory(VAddr address, size_t size) {
CHECKED(uc_mem_unmap(uc, address, size));
}
@@ -131,24 +131,33 @@ void ARM_Unicorn::SetReg(int regn, u64 val) {
CHECKED(uc_reg_write(uc, treg, &val));
}
u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
u128 ARM_Unicorn::GetExtReg(int /*index*/) const {
UNIMPLEMENTED();
static constexpr u128 res{};
return res;
}
void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
void ARM_Unicorn::SetExtReg(int /*index*/, u128 /*value*/) {
UNIMPLEMENTED();
}
u32 ARM_Unicorn::GetPSTATE() const {
u32 ARM_Unicorn::GetVFPReg(int /*index*/) const {
UNIMPLEMENTED();
return {};
}
void ARM_Unicorn::SetVFPReg(int /*index*/, u32 /*value*/) {
UNIMPLEMENTED();
}
u32 ARM_Unicorn::GetCPSR() const {
u64 nzcv{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
return static_cast<u32>(nzcv);
}
void ARM_Unicorn::SetPSTATE(u32 pstate) {
u64 nzcv = pstate;
void ARM_Unicorn::SetCPSR(u32 cpsr) {
u64 nzcv = cpsr;
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
}
@@ -210,7 +219,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.cpsr));
for (auto i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
@@ -225,7 +234,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) {
for (int i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = &ctx.vector_registers[i];
tregs[i] = &ctx.fpu_registers[i];
}
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
@@ -237,7 +246,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.cpsr));
for (int i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
@@ -252,7 +261,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) {
for (auto i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = (void*)&ctx.vector_registers[i];
tregs[i] = (void*)&ctx.fpu_registers[i];
}
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));

View File

@@ -15,17 +15,19 @@ class ARM_Unicorn final : public ARM_Interface {
public:
ARM_Unicorn();
~ARM_Unicorn();
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
void MapBackingMemory(VAddr address, size_t size, u8* memory,
Kernel::VMAPermission perms) override;
void UnmapMemory(VAddr address, std::size_t size) override;
void UnmapMemory(VAddr address, size_t size) override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
u128 GetVectorReg(int index) const override;
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
u128 GetExtReg(int index) const override;
void SetExtReg(int index, u128 value) override;
u32 GetVFPReg(int index) const override;
void SetVFPReg(int index, u32 value) override;
u32 GetCPSR() const override;
void SetCPSR(u32 cpsr) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;

View File

@@ -64,7 +64,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
if (concat.empty())
return nullptr;
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
return FileSys::ConcatenateFiles(concat, dir->GetName());
}
return vfs->OpenFile(path, FileSys::Mode::Read);
@@ -140,7 +140,7 @@ struct System::Impl {
cpu_barrier = std::make_shared<CpuBarrier>();
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
for (size_t index = 0; index < cpu_cores.size(); ++index) {
cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
}
@@ -161,7 +161,7 @@ struct System::Impl {
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
if (Settings::values.use_multi_core) {
for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
for (size_t index = 0; index < cpu_core_threads.size(); ++index) {
cpu_core_threads[index] =
std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
@@ -202,7 +202,7 @@ struct System::Impl {
return init_result;
}
const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())};
const Loader::ResultStatus load_result{app_loader->Load(kernel.CurrentProcess())};
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
Shutdown();
@@ -285,7 +285,7 @@ struct System::Impl {
std::shared_ptr<CpuBarrier> cpu_barrier;
std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
std::size_t active_core{}; ///< Active core, only used in single thread mode
size_t active_core{}; ///< Active core, only used in single thread mode
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -348,7 +348,7 @@ ARM_Interface& System::CurrentArmInterface() {
return CurrentCpuCore().ArmInterface();
}
std::size_t System::CurrentCoreIndex() {
size_t System::CurrentCoreIndex() {
return CurrentCpuCore().CoreIndex();
}
@@ -356,7 +356,7 @@ Kernel::Scheduler& System::CurrentScheduler() {
return *CurrentCpuCore().Scheduler();
}
const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(std::size_t core_index) {
const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) {
ASSERT(core_index < NUM_CPU_CORES);
return impl->cpu_cores[core_index]->Scheduler();
}
@@ -369,12 +369,12 @@ const Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() const {
return impl->kernel.CurrentProcess();
}
ARM_Interface& System::ArmInterface(std::size_t core_index) {
ARM_Interface& System::ArmInterface(size_t core_index) {
ASSERT(core_index < NUM_CPU_CORES);
return impl->cpu_cores[core_index]->ArmInterface();
}
Cpu& System::CpuCore(std::size_t core_index) {
Cpu& System::CpuCore(size_t core_index) {
ASSERT(core_index < NUM_CPU_CORES);
return *impl->cpu_cores[core_index];
}

View File

@@ -145,16 +145,16 @@ public:
ARM_Interface& CurrentArmInterface();
/// Gets the index of the currently running CPU core
std::size_t CurrentCoreIndex();
size_t CurrentCoreIndex();
/// Gets the scheduler for the CPU core that is currently running
Kernel::Scheduler& CurrentScheduler();
/// Gets an ARM interface to the CPU core with the specified index
ARM_Interface& ArmInterface(std::size_t core_index);
ARM_Interface& ArmInterface(size_t core_index);
/// Gets a CPU interface to the CPU core with the specified index
Cpu& CpuCore(std::size_t core_index);
Cpu& CpuCore(size_t core_index);
/// Gets the exclusive monitor
ExclusiveMonitor& Monitor();
@@ -172,7 +172,7 @@ public:
const VideoCore::RendererBase& Renderer() const;
/// Gets the scheduler for the CPU core with the specified index
const std::shared_ptr<Kernel::Scheduler>& Scheduler(std::size_t core_index);
const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index);
/// Provides a reference to the current process
Kernel::SharedPtr<Kernel::Process>& CurrentProcess();

View File

@@ -9,7 +9,6 @@
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
@@ -50,26 +49,24 @@ bool CpuBarrier::Rendezvous() {
}
Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index)
std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
: cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index);
arm_interface = std::make_shared<ARM_Dynarmic>(exclusive_monitor, core_index);
#else
arm_interface = std::make_unique<ARM_Unicorn>();
arm_interface = std::make_shared<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
arm_interface = std::make_unique<ARM_Unicorn>();
arm_interface = std::make_shared<ARM_Unicorn>();
}
scheduler = std::make_shared<Kernel::Scheduler>(*arm_interface);
scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
}
Cpu::~Cpu() = default;
std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(size_t num_cores) {
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
return std::make_shared<DynarmicExclusiveMonitor>(num_cores);

View File

@@ -6,10 +6,11 @@
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <memory>
#include <mutex>
#include <string>
#include "common/common_types.h"
#include "core/arm/exclusive_monitor.h"
namespace Kernel {
class Scheduler;
@@ -18,7 +19,6 @@ class Scheduler;
namespace Core {
class ARM_Interface;
class ExclusiveMonitor;
constexpr unsigned NUM_CPU_CORES{4};
@@ -42,8 +42,7 @@ private:
class Cpu {
public:
Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index);
~Cpu();
std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index);
void RunLoop(bool tight_loop = true);
@@ -67,21 +66,21 @@ public:
return core_index == 0;
}
std::size_t CoreIndex() const {
size_t CoreIndex() const {
return core_index;
}
static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores);
static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(size_t num_cores);
private:
void Reschedule();
std::unique_ptr<ARM_Interface> arm_interface;
std::shared_ptr<ARM_Interface> arm_interface;
std::shared_ptr<CpuBarrier> cpu_barrier;
std::shared_ptr<Kernel::Scheduler> scheduler;
std::atomic<bool> reschedule_pending = false;
std::size_t core_index;
size_t core_index;
};
} // namespace Core

View File

@@ -10,9 +10,9 @@
namespace Core::Crypto {
namespace {
std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
std::vector<u8> CalculateNintendoTweak(size_t sector_id) {
std::vector<u8> out(0x10);
for (std::size_t i = 0xF; i <= 0xF; --i) {
for (size_t i = 0xF; i <= 0xF; --i) {
out[i] = sector_id & 0xFF;
sector_id >>= 8;
}
@@ -20,14 +20,11 @@ std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
}
} // Anonymous namespace
static_assert(static_cast<std::size_t>(Mode::CTR) ==
static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_CTR),
static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR),
"CTR has incorrect value.");
static_assert(static_cast<std::size_t>(Mode::ECB) ==
static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_ECB),
static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB),
"ECB has incorrect value.");
static_assert(static_cast<std::size_t>(Mode::XTS) ==
static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_XTS),
static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS),
"XTS has incorrect value.");
// Structure to hide mbedtls types from header file
@@ -36,7 +33,7 @@ struct CipherContext {
mbedtls_cipher_context_t decryption_context;
};
template <typename Key, std::size_t KeySize>
template <typename Key, size_t KeySize>
Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
: ctx(std::make_unique<CipherContext>()) {
mbedtls_cipher_init(&ctx->encryption_context);
@@ -57,26 +54,26 @@ Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
//"Failed to set key on mbedtls ciphers.");
}
template <typename Key, std::size_t KeySize>
template <typename Key, size_t KeySize>
AESCipher<Key, KeySize>::~AESCipher() {
mbedtls_cipher_free(&ctx->encryption_context);
mbedtls_cipher_free(&ctx->decryption_context);
}
template <typename Key, std::size_t KeySize>
template <typename Key, size_t KeySize>
void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
"Failed to set IV on mbedtls ciphers.");
}
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
template <typename Key, size_t KeySize>
void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) const {
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
mbedtls_cipher_reset(context);
std::size_t written = 0;
size_t written = 0;
if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
mbedtls_cipher_update(context, src, size, dest, &written);
if (written != size) {
@@ -93,8 +90,8 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
return;
}
for (std::size_t offset = 0; offset < size; offset += block_size) {
auto length = std::min<std::size_t>(block_size, size - offset);
for (size_t offset = 0; offset < size; offset += block_size) {
auto length = std::min<size_t>(block_size, size - offset);
mbedtls_cipher_update(context, src + offset, length, dest + offset, &written);
if (written != length) {
if (length < block_size) {
@@ -113,12 +110,12 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
mbedtls_cipher_finish(context, nullptr, nullptr);
}
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8* dest,
std::size_t sector_id, std::size_t sector_size, Op op) {
template <typename Key, size_t KeySize>
void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id,
size_t sector_size, Op op) {
ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size.");
for (std::size_t i = 0; i < size; i += sector_size) {
for (size_t i = 0; i < size; i += sector_size) {
SetIV(CalculateNintendoTweak(sector_id++));
Transcode<u8, u8>(src + i, sector_size, dest + i, op);
}

View File

@@ -25,7 +25,7 @@ enum class Op {
Decrypt,
};
template <typename Key, std::size_t KeySize = sizeof(Key)>
template <typename Key, size_t KeySize = sizeof(Key)>
class AESCipher {
static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8.");
static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256.");
@@ -38,25 +38,25 @@ public:
void SetIV(std::vector<u8> iv);
template <typename Source, typename Dest>
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
void Transcode(const Source* src, size_t size, Dest* dest, Op op) const {
static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
"Transcode source and destination types must be trivially copyable.");
Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op);
}
void Transcode(const u8* src, std::size_t size, u8* dest, Op op) const;
void Transcode(const u8* src, size_t size, u8* dest, Op op) const;
template <typename Source, typename Dest>
void XTSTranscode(const Source* src, std::size_t size, Dest* dest, std::size_t sector_id,
std::size_t sector_size, Op op) {
void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id,
size_t sector_size, Op op) {
static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
"XTSTranscode source and destination types must be trivially copyable.");
XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id,
sector_size, op);
}
void XTSTranscode(const u8* src, std::size_t size, u8* dest, std::size_t sector_id,
std::size_t sector_size, Op op);
void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size,
Op op);
private:
std::unique_ptr<CipherContext> ctx;

View File

@@ -8,12 +8,11 @@
namespace Core::Crypto {
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
std::size_t base_offset)
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset)
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
iv(16, 0) {}
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
if (length == 0)
return 0;
@@ -29,7 +28,7 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset);
UpdateIV(base_offset + offset - sector_offset);
cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt);
std::size_t read = 0x10 - sector_offset;
size_t read = 0x10 - sector_offset;
if (length + sector_offset < 0x10) {
std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));
@@ -44,9 +43,9 @@ void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
iv.assign(iv_.cbegin(), iv_.cbegin() + length);
}
void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
void CTREncryptionLayer::UpdateIV(size_t offset) const {
offset >>= 4;
for (std::size_t i = 0; i < 8; ++i) {
for (size_t i = 0; i < 8; ++i) {
iv[16 - i - 1] = offset & 0xFF;
offset >>= 8;
}

View File

@@ -14,20 +14,20 @@ namespace Core::Crypto {
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
class CTREncryptionLayer : public EncryptionLayer {
public:
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset);
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
size_t Read(u8* data, size_t length, size_t offset) const override;
void SetIV(const std::vector<u8>& iv);
private:
std::size_t base_offset;
size_t base_offset;
// Must be mutable as operations modify cipher contexts.
mutable AESCipher<Key128> cipher;
mutable std::vector<u8> iv;
void UpdateIV(std::size_t offset) const;
void UpdateIV(size_t offset) const;
};
} // namespace Core::Crypto

View File

@@ -12,11 +12,11 @@ std::string EncryptionLayer::GetName() const {
return base->GetName();
}
std::size_t EncryptionLayer::GetSize() const {
size_t EncryptionLayer::GetSize() const {
return base->GetSize();
}
bool EncryptionLayer::Resize(std::size_t new_size) {
bool EncryptionLayer::Resize(size_t new_size) {
return false;
}
@@ -32,7 +32,7 @@ bool EncryptionLayer::IsReadable() const {
return true;
}
std::size_t EncryptionLayer::Write(const u8* data, std::size_t length, std::size_t offset) {
size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) {
return 0;
}

View File

@@ -15,15 +15,15 @@ class EncryptionLayer : public FileSys::VfsFile {
public:
explicit EncryptionLayer(FileSys::VirtualFile base);
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override = 0;
size_t Read(u8* data, size_t length, size_t offset) const override = 0;
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
size_t GetSize() const override;
bool Resize(size_t new_size) override;
std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
size_t Write(const u8* data, size_t length, size_t offset) override;
bool Rename(std::string_view name) override;
protected:

View File

@@ -54,7 +54,7 @@ boost::optional<Key128> DeriveSDSeed() {
return boost::none;
std::array<u8, 0x10> buffer{};
std::size_t offset = 0;
size_t offset = 0;
for (; offset + 0x10 < save_43.GetSize(); ++offset) {
save_43.Seek(offset, SEEK_SET);
save_43.ReadBytes(buffer.data(), buffer.size());
@@ -105,7 +105,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManag
// Combine sources and seed
for (auto& source : sd_key_sources) {
for (std::size_t i = 0; i < source.size(); ++i)
for (size_t i = 0; i < source.size(); ++i)
source[i] ^= sd_seed[i & 0xF];
}
@@ -207,7 +207,7 @@ Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
return s256_keys.at({id, field1, field2});
}
template <std::size_t Size>
template <size_t Size>
void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname,
const std::array<u8, Size>& key) {
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);

View File

@@ -108,7 +108,7 @@ private:
void LoadFromFile(const std::string& filename, bool is_title_keys);
void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
const std::string& filename, bool title);
template <std::size_t Size>
template <size_t Size>
void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key);
static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;

View File

@@ -14,7 +14,7 @@ constexpr u64 XTS_SECTOR_SIZE = 0x4000;
XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_)
: EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {}
std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
if (length == 0)
return 0;
@@ -46,7 +46,7 @@ std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
block.resize(XTS_SECTOR_SIZE);
cipher.XTSTranscode(block.data(), block.size(), block.data(),
(offset - sector_offset) / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt);
const std::size_t read = XTS_SECTOR_SIZE - sector_offset;
const size_t read = XTS_SECTOR_SIZE - sector_offset;
if (length + sector_offset < XTS_SECTOR_SIZE) {
std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));

View File

@@ -15,7 +15,7 @@ class XTSEncryptionLayer : public EncryptionLayer {
public:
XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key);
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
size_t Read(u8* data, size_t length, size_t offset) const override;
private:
// Must be mutable as operations modify cipher contexts.

View File

@@ -2,14 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <fmt/format.h>
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/registered_cache.h"
namespace FileSys {
BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_)
: nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
BISFactory::BISFactory(VirtualDir nand_root_)
: nand_root(std::move(nand_root_)),
sysnand_cache(std::make_shared<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
usrnand_cache(std::make_shared<RegisteredCache>(
@@ -25,11 +24,4 @@ std::shared_ptr<RegisteredCache> BISFactory::GetUserNANDContents() const {
return usrnand_cache;
}
VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
// LayeredFS doesn't work on updates and title id-less homebrew
if (title_id == 0 || (title_id & 0x800) > 0)
return nullptr;
return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
}
} // namespace FileSys

View File

@@ -17,17 +17,14 @@ class RegisteredCache;
/// registered caches.
class BISFactory {
public:
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root);
explicit BISFactory(VirtualDir nand_root);
~BISFactory();
std::shared_ptr<RegisteredCache> GetSystemNANDContents() const;
std::shared_ptr<RegisteredCache> GetUserNANDContents() const;
VirtualDir GetModificationLoadRoot(u64 title_id) const;
private:
VirtualDir nand_root;
VirtualDir load_root;
std::shared_ptr<RegisteredCache> sysnand_cache;
std::shared_ptr<RegisteredCache> usrnand_cache;

View File

@@ -41,14 +41,13 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
for (XCIPartition partition :
{XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
auto raw = main_hfs.GetFile(partition_names[static_cast<std::size_t>(partition)]);
auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]);
if (raw != nullptr)
partitions[static_cast<std::size_t>(partition)] =
std::make_shared<PartitionFilesystem>(raw);
partitions[static_cast<size_t>(partition)] = std::make_shared<PartitionFilesystem>(raw);
}
secure_partition = std::make_shared<NSP>(
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]));
main_hfs.GetFile(partition_names[static_cast<size_t>(XCIPartition::Secure)]));
const auto secure_ncas = secure_partition->GetNCAsCollapsed();
std::copy(secure_ncas.begin(), secure_ncas.end(), std::back_inserter(ncas));
@@ -93,7 +92,7 @@ Loader::ResultStatus XCI::GetProgramNCAStatus() const {
}
VirtualDir XCI::GetPartition(XCIPartition partition) const {
return partitions[static_cast<std::size_t>(partition)];
return partitions[static_cast<size_t>(partition)];
}
std::shared_ptr<NSP> XCI::GetSecurePartitionNSP() const {
@@ -169,11 +168,11 @@ bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
}
Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
if (partitions[static_cast<std::size_t>(part)] == nullptr) {
if (partitions[static_cast<size_t>(part)] == nullptr) {
return Loader::ResultStatus::ErrorXCIMissingPartition;
}
for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) {
for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
if (file->GetExtension() != "nca")
continue;
auto nca = std::make_shared<NCA>(file);
@@ -188,7 +187,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
} else {
const u16 error_id = static_cast<u16>(nca->GetStatus());
LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})",
partition_names[static_cast<std::size_t>(part)], nca->GetName(), error_id,
partition_names[static_cast<size_t>(part)], nca->GetName(), error_id,
nca->GetStatus());
}
}

View File

@@ -298,11 +298,11 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
auto section = sections[i];
if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
const std::size_t base_offset =
const size_t base_offset =
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER;
ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset;
const std::size_t romfs_offset = base_offset + ivfc_offset;
const std::size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size;
const size_t romfs_offset = base_offset + ivfc_offset;
const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size;
auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset);
auto dec = Decrypt(section, raw, romfs_offset);
@@ -463,8 +463,6 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
status = Loader::ResultStatus::Success;
}
NCA::~NCA() = default;
Loader::ResultStatus NCA::GetStatus() const {
return status;
}

View File

@@ -81,8 +81,6 @@ class NCA : public ReadOnlyVfsDirectory {
public:
explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
u64 bktr_base_ivfc_offset = 0);
~NCA() override;
Loader::ResultStatus GetStatus() const;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;

View File

@@ -8,14 +8,6 @@
namespace FileSys {
const std::array<const char*, 15> LANGUAGE_NAMES = {
"AmericanEnglish", "BritishEnglish", "Japanese",
"French", "German", "LatinAmericanSpanish",
"Spanish", "Italian", "Dutch",
"CanadianFrench", "Portugese", "Russian",
"Korean", "Taiwanese", "Chinese",
};
std::string LanguageEntry::GetApplicationName() const {
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200);
}
@@ -28,20 +20,18 @@ NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
file->ReadObject(raw.get());
}
NACP::~NACP() = default;
const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
if (language != Language::Default) {
return raw->language_entries.at(static_cast<u8>(language));
}
} else {
for (const auto& language_entry : raw->language_entries) {
if (!language_entry.GetApplicationName().empty())
return language_entry;
}
for (const auto& language_entry : raw->language_entries) {
if (!language_entry.GetApplicationName().empty())
return language_entry;
// Fallback to English
return GetLanguageEntry(Language::AmericanEnglish);
}
// Fallback to English
return GetLanguageEntry(Language::AmericanEnglish);
}
std::string NACP::GetApplicationName(Language language) const {

View File

@@ -66,15 +66,18 @@ enum class Language : u8 {
Default = 255,
};
extern const std::array<const char*, 15> LANGUAGE_NAMES;
static constexpr std::array<const char*, 15> LANGUAGE_NAMES = {
"AmericanEnglish", "BritishEnglish", "Japanese",
"French", "German", "LatinAmericanSpanish",
"Spanish", "Italian", "Dutch",
"CanadianFrench", "Portugese", "Russian",
"Korean", "Taiwanese", "Chinese"};
// A class representing the format used by NX metadata files, typically named Control.nacp.
// These store application name, dev name, title id, and other miscellaneous data.
class NACP {
public:
explicit NACP(VirtualFile file);
~NACP();
const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const;
std::string GetApplicationName(Language language = Language::Default) const;
std::string GetDeveloperName(Language language = Language::Default) const;

View File

@@ -25,7 +25,7 @@ enum EntryType : u8 {
struct Entry {
Entry(std::string_view view, EntryType entry_type, u64 entry_size)
: type{entry_type}, file_size{entry_size} {
const std::size_t copy_size = view.copy(filename, std::size(filename) - 1);
const size_t copy_size = view.copy(filename, std::size(filename) - 1);
filename[copy_size] = '\0';
}

View File

@@ -1,366 +0,0 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Adapted by DarkLordZach for use/interaction with yuzu
*
* Modifications Copyright 2018 yuzu emulator team
* Licensed under GPLv2 or any later version
* Refer to the license.txt file included.
*/
#include <cstring>
#include "common/alignment.h"
#include "common/assert.h"
#include "core/file_sys/fsmitm_romfsbuild.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_vector.h"
namespace FileSys {
constexpr u64 FS_MAX_PATH = 0x301;
constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF;
constexpr u32 ROMFS_FILEPARTITION_OFS = 0x200;
// Types for building a RomFS.
struct RomFSHeader {
u64 header_size;
u64 dir_hash_table_ofs;
u64 dir_hash_table_size;
u64 dir_table_ofs;
u64 dir_table_size;
u64 file_hash_table_ofs;
u64 file_hash_table_size;
u64 file_table_ofs;
u64 file_table_size;
u64 file_partition_ofs;
};
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
struct RomFSDirectoryEntry {
u32 parent;
u32 sibling;
u32 child;
u32 file;
u32 hash;
u32 name_size;
};
static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size.");
struct RomFSFileEntry {
u32 parent;
u32 sibling;
u64 offset;
u64 size;
u32 hash;
u32 name_size;
};
static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size.");
struct RomFSBuildFileContext;
struct RomFSBuildDirectoryContext {
std::string path;
u32 cur_path_ofs = 0;
u32 path_len = 0;
u32 entry_offset = 0;
std::shared_ptr<RomFSBuildDirectoryContext> parent;
std::shared_ptr<RomFSBuildDirectoryContext> child;
std::shared_ptr<RomFSBuildDirectoryContext> sibling;
std::shared_ptr<RomFSBuildFileContext> file;
};
struct RomFSBuildFileContext {
std::string path;
u32 cur_path_ofs = 0;
u32 path_len = 0;
u32 entry_offset = 0;
u64 offset = 0;
u64 size = 0;
std::shared_ptr<RomFSBuildDirectoryContext> parent;
std::shared_ptr<RomFSBuildFileContext> sibling;
VirtualFile source;
};
static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) {
u32 hash = parent ^ 123456789;
for (u32 i = 0; i < path_len; i++) {
hash = (hash >> 5) | (hash << 27);
hash ^= path[start + i];
}
return hash;
}
static u64 romfs_get_hash_table_count(u64 num_entries) {
if (num_entries < 3) {
return 3;
}
if (num_entries < 19) {
return num_entries | 1;
}
u64 count = num_entries;
while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 ||
count % 11 == 0 || count % 13 == 0 || count % 17 == 0) {
count++;
}
return count;
}
void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs,
std::shared_ptr<RomFSBuildDirectoryContext> parent) {
std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
VirtualDir dir;
if (parent->path_len == 0)
dir = root_romfs;
else
dir = root_romfs->GetDirectoryRelative(parent->path);
const auto entries = dir->GetEntries();
for (const auto& kv : entries) {
if (kv.second == VfsEntryType::Directory) {
const auto child = std::make_shared<RomFSBuildDirectoryContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
if (AddDirectory(parent, child)) {
child_dirs.push_back(child);
}
} else {
const auto child = std::make_shared<RomFSBuildFileContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
child->source = root_romfs->GetFileRelative(child->path);
child->size = child->source->GetSize();
AddFile(parent, child);
}
}
for (auto& child : child_dirs) {
this->VisitDirectory(root_romfs, child);
}
}
bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) {
// Check whether it's already in the known directories.
const auto existing = directories.find(dir_ctx->path);
if (existing != directories.end())
return false;
// Add a new directory.
num_dirs++;
dir_table_size +=
sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
dir_ctx->parent = parent_dir_ctx;
directories.emplace(dir_ctx->path, dir_ctx);
return true;
}
bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
std::shared_ptr<RomFSBuildFileContext> file_ctx) {
// Check whether it's already in the known files.
const auto existing = files.find(file_ctx->path);
if (existing != files.end()) {
return false;
}
// Add a new file.
num_files++;
file_table_size +=
sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
file_ctx->parent = parent_dir_ctx;
files.emplace(file_ctx->path, file_ctx);
return true;
}
RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_)) {
root = std::make_shared<RomFSBuildDirectoryContext>();
root->path = "\0";
directories.emplace(root->path, root);
num_dirs = 1;
dir_table_size = 0x18;
VisitDirectory(base, root);
}
RomFSBuildContext::~RomFSBuildContext() = default;
std::map<u64, VirtualFile> RomFSBuildContext::Build() {
const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
dir_hash_table_size = 4 * dir_hash_table_entry_count;
file_hash_table_size = 4 * file_hash_table_entry_count;
// Assign metadata pointers
RomFSHeader header{};
std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY);
std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY);
std::vector<u8> dir_table(dir_table_size);
std::vector<u8> file_table(file_table_size);
std::shared_ptr<RomFSBuildFileContext> cur_file;
// Determine file offsets.
u32 entry_offset = 0;
std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr;
for (const auto& it : files) {
cur_file = it.second;
file_partition_size = Common::AlignUp(file_partition_size, 16);
cur_file->offset = file_partition_size;
file_partition_size += cur_file->size;
cur_file->entry_offset = entry_offset;
entry_offset += sizeof(RomFSFileEntry) +
Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
prev_file = cur_file;
}
// Assign deferred parent/sibling ownership.
for (auto it = files.rbegin(); it != files.rend(); ++it) {
cur_file = it->second;
cur_file->sibling = cur_file->parent->file;
cur_file->parent->file = cur_file;
}
std::shared_ptr<RomFSBuildDirectoryContext> cur_dir;
// Determine directory offsets.
entry_offset = 0;
for (const auto& it : directories) {
cur_dir = it.second;
cur_dir->entry_offset = entry_offset;
entry_offset += sizeof(RomFSDirectoryEntry) +
Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
}
// Assign deferred parent/sibling ownership.
for (auto it = directories.rbegin(); it->second != root; ++it) {
cur_dir = it->second;
cur_dir->sibling = cur_dir->parent->child;
cur_dir->parent->child = cur_dir;
}
std::map<u64, VirtualFile> out;
// Populate file tables.
for (const auto& it : files) {
cur_file = it.second;
RomFSFileEntry cur_entry{};
cur_entry.parent = cur_file->parent->entry_offset;
cur_entry.sibling =
cur_file->sibling == nullptr ? ROMFS_ENTRY_EMPTY : cur_file->sibling->entry_offset;
cur_entry.offset = cur_file->offset;
cur_entry.size = cur_file->size;
const auto name_size = cur_file->path_len - cur_file->cur_path_ofs;
const auto hash = romfs_calc_path_hash(cur_file->parent->entry_offset, cur_file->path,
cur_file->cur_path_ofs, name_size);
cur_entry.hash = file_hash_table[hash % file_hash_table_entry_count];
file_hash_table[hash % file_hash_table_entry_count] = cur_file->entry_offset;
cur_entry.name_size = name_size;
out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source);
std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
Common::AlignUp(cur_entry.name_size, 4));
std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry),
cur_file->path.data() + cur_file->cur_path_ofs, name_size);
}
// Populate dir tables.
for (const auto& it : directories) {
cur_dir = it.second;
RomFSDirectoryEntry cur_entry{};
cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset;
cur_entry.sibling =
cur_dir->sibling == nullptr ? ROMFS_ENTRY_EMPTY : cur_dir->sibling->entry_offset;
cur_entry.child =
cur_dir->child == nullptr ? ROMFS_ENTRY_EMPTY : cur_dir->child->entry_offset;
cur_entry.file = cur_dir->file == nullptr ? ROMFS_ENTRY_EMPTY : cur_dir->file->entry_offset;
const auto name_size = cur_dir->path_len - cur_dir->cur_path_ofs;
const auto hash = romfs_calc_path_hash(cur_dir == root ? 0 : cur_dir->parent->entry_offset,
cur_dir->path, cur_dir->cur_path_ofs, name_size);
cur_entry.hash = dir_hash_table[hash % dir_hash_table_entry_count];
dir_hash_table[hash % dir_hash_table_entry_count] = cur_dir->entry_offset;
cur_entry.name_size = name_size;
std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry,
sizeof(RomFSDirectoryEntry));
std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0,
Common::AlignUp(cur_entry.name_size, 4));
std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry),
cur_dir->path.data() + cur_dir->cur_path_ofs, name_size);
}
// Set header fields.
header.header_size = sizeof(RomFSHeader);
header.file_hash_table_size = file_hash_table_size;
header.file_table_size = file_table_size;
header.dir_hash_table_size = dir_hash_table_size;
header.dir_table_size = dir_table_size;
header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
std::vector<u8> header_data(sizeof(RomFSHeader));
std::memcpy(header_data.data(), &header, header_data.size());
out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size +
dir_table_size);
std::size_t index = 0;
std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32));
index += dir_hash_table.size() * sizeof(u32);
std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size());
index += dir_table.size();
std::memcpy(metadata.data() + index, file_hash_table.data(),
file_hash_table.size() * sizeof(u32));
index += file_hash_table.size() * sizeof(u32);
std::memcpy(metadata.data() + index, file_table.data(), file_table.size());
out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata)));
return out;
}
} // namespace FileSys

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Adapted by DarkLordZach for use/interaction with yuzu
*
* Modifications Copyright 2018 yuzu emulator team
* Licensed under GPLv2 or any later version
* Refer to the license.txt file included.
*/
#pragma once
#include <map>
#include <memory>
#include <string>
#include <boost/detail/container_fwd.hpp>
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
namespace FileSys {
struct RomFSBuildDirectoryContext;
struct RomFSBuildFileContext;
struct RomFSDirectoryEntry;
struct RomFSFileEntry;
class RomFSBuildContext {
public:
explicit RomFSBuildContext(VirtualDir base);
~RomFSBuildContext();
// This finalizes the context.
std::map<u64, VirtualFile> Build();
private:
VirtualDir base;
std::shared_ptr<RomFSBuildDirectoryContext> root;
std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories;
std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files;
u64 num_dirs = 0;
u64 num_files = 0;
u64 dir_table_size = 0;
u64 file_table_size = 0;
u64 dir_hash_table_size = 0;
u64 file_hash_table_size = 0;
u64 file_partition_size = 0;
void VisitDirectory(VirtualDir filesys, std::shared_ptr<RomFSBuildDirectoryContext> parent);
bool AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx);
bool AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
std::shared_ptr<RomFSBuildFileContext> file_ctx);
};
} // namespace FileSys

View File

@@ -11,11 +11,11 @@
namespace FileSys {
bool operator>=(TitleType lhs, TitleType rhs) {
return static_cast<std::size_t>(lhs) >= static_cast<std::size_t>(rhs);
return static_cast<size_t>(lhs) >= static_cast<size_t>(rhs);
}
bool operator<=(TitleType lhs, TitleType rhs) {
return static_cast<std::size_t>(lhs) <= static_cast<std::size_t>(rhs);
return static_cast<size_t>(lhs) <= static_cast<size_t>(rhs);
}
CNMT::CNMT(VirtualFile file) {
@@ -51,8 +51,6 @@ CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentReco
: header(std::move(header)), opt_header(std::move(opt_header)),
content_records(std::move(content_records)), meta_records(std::move(meta_records)) {}
CNMT::~CNMT() = default;
u64 CNMT::GetTitleID() const {
return header.title_id;
}

View File

@@ -87,7 +87,6 @@ public:
explicit CNMT(VirtualFile file);
CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
std::vector<MetaRecord> meta_records);
~CNMT();
u64 GetTitleID() const;
u32 GetTitleVersion() const;

View File

@@ -22,11 +22,11 @@ BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock rel
base_romfs(std::move(base_romfs_)), bktr_romfs(std::move(bktr_romfs_)),
encrypted(is_encrypted_), key(key_), base_offset(base_offset_), ivfc_offset(ivfc_offset_),
section_ctr(section_ctr_) {
for (std::size_t i = 0; i < relocation.number_buckets - 1; ++i) {
for (size_t i = 0; i < relocation.number_buckets - 1; ++i) {
relocation_buckets[i].entries.push_back({relocation.base_offsets[i + 1], 0, 0});
}
for (std::size_t i = 0; i < subsection.number_buckets - 1; ++i) {
for (size_t i = 0; i < subsection.number_buckets - 1; ++i) {
subsection_buckets[i].entries.push_back({subsection_buckets[i + 1].entries[0].address_patch,
{0},
subsection_buckets[i + 1].entries[0].ctr});
@@ -37,7 +37,7 @@ BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock rel
BKTR::~BKTR() = default;
std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
size_t BKTR::Read(u8* data, size_t length, size_t offset) const {
// Read out of bounds.
if (offset >= relocation.size)
return 0;
@@ -69,14 +69,14 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
std::vector<u8> iv(16);
auto subsection_ctr = subsection.ctr;
auto offset_iv = section_offset + base_offset;
for (std::size_t i = 0; i < section_ctr.size(); ++i)
for (size_t i = 0; i < section_ctr.size(); ++i)
iv[i] = section_ctr[0x8 - i - 1];
offset_iv >>= 4;
for (std::size_t i = 0; i < sizeof(u64); ++i) {
for (size_t i = 0; i < sizeof(u64); ++i) {
iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF);
offset_iv >>= 8;
}
for (std::size_t i = 0; i < sizeof(u32); ++i) {
for (size_t i = 0; i < sizeof(u32); ++i) {
iv[0x7 - i] = static_cast<u8>(subsection_ctr & 0xFF);
subsection_ctr >>= 8;
}
@@ -110,8 +110,8 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
}
template <bool Subsection, typename BlockType, typename BucketType>
std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block,
BucketType buckets) const {
std::pair<size_t, size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block,
BucketType buckets) const {
if constexpr (Subsection) {
const auto last_bucket = buckets[block.number_buckets - 1];
if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch)
@@ -120,18 +120,18 @@ std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockTyp
ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block.");
}
std::size_t bucket_id = std::count_if(
block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets,
[&offset](u64 base_offset) { return base_offset <= offset; });
size_t bucket_id = std::count_if(block.base_offsets.begin() + 1,
block.base_offsets.begin() + block.number_buckets,
[&offset](u64 base_offset) { return base_offset <= offset; });
const auto bucket = buckets[bucket_id];
if (bucket.number_entries == 1)
return {bucket_id, 0};
std::size_t low = 0;
std::size_t mid = 0;
std::size_t high = bucket.number_entries - 1;
size_t low = 0;
size_t mid = 0;
size_t high = bucket.number_entries - 1;
while (low <= high) {
mid = (low + high) / 2;
if (bucket.entries[mid].address_patch > offset) {
@@ -179,11 +179,11 @@ std::string BKTR::GetName() const {
return base_romfs->GetName();
}
std::size_t BKTR::GetSize() const {
size_t BKTR::GetSize() const {
return relocation.size;
}
bool BKTR::Resize(std::size_t new_size) {
bool BKTR::Resize(size_t new_size) {
return false;
}
@@ -199,7 +199,7 @@ bool BKTR::IsReadable() const {
return true;
}
std::size_t BKTR::Write(const u8* data, std::size_t length, std::size_t offset) {
size_t BKTR::Write(const u8* data, size_t length, size_t offset) {
return 0;
}

View File

@@ -98,13 +98,13 @@ public:
Core::Crypto::Key128 key, u64 base_offset, u64 ivfc_offset, std::array<u8, 8> section_ctr);
~BKTR() override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
size_t Read(u8* data, size_t length, size_t offset) const override;
std::string GetName() const override;
std::size_t GetSize() const override;
size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
bool Resize(size_t new_size) override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
@@ -112,14 +112,14 @@ public:
bool IsReadable() const override;
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
size_t Write(const u8* data, size_t length, size_t offset) override;
bool Rename(std::string_view name) override;
private:
template <bool Subsection, typename BlockType, typename BucketType>
std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, BlockType block,
BucketType buckets) const;
std::pair<size_t, size_t> SearchBucketEntry(u64 offset, BlockType block,
BucketType buckets) const;
RelocationEntry GetRelocationEntry(u64 offset) const;
RelocationEntry GetNextRelocationEntry(u64 offset) const;

View File

@@ -42,21 +42,21 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
std::size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
std::size_t metadata_size =
size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
size_t metadata_size =
sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size;
// Actually read in now...
std::vector<u8> file_data = file->ReadBytes(metadata_size);
const std::size_t total_size = file_data.size();
const size_t total_size = file_data.size();
if (total_size != metadata_size) {
status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
return;
}
std::size_t entries_offset = sizeof(Header);
std::size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size);
size_t entries_offset = sizeof(Header);
size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size);
content_offset = strtab_offset + pfs_header.strtab_size;
for (u16 i = 0; i < pfs_header.num_entries; i++) {
FSEntry entry;
@@ -72,8 +72,6 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
status = Loader::ResultStatus::Success;
}
PartitionFilesystem::~PartitionFilesystem() = default;
Loader::ResultStatus PartitionFilesystem::GetStatus() const {
return status;
}

View File

@@ -25,8 +25,6 @@ namespace FileSys {
class PartitionFilesystem : public ReadOnlyVfsDirectory {
public:
explicit PartitionFilesystem(std::shared_ptr<VfsFile> file);
~PartitionFilesystem() override;
Loader::ResultStatus GetStatus() const;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
@@ -81,7 +79,7 @@ private:
Header pfs_header{};
bool is_hfs = false;
std::size_t content_offset = 0;
size_t content_offset = 0;
std::vector<VirtualFile> pfs_files;
std::vector<VirtualDir> pfs_dirs;

View File

@@ -11,7 +11,6 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_layered.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
@@ -22,7 +21,7 @@ constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
std::array<u8, sizeof(u32)> bytes{};
bytes[0] = version % SINGLE_BYTE_MODULUS;
for (std::size_t i = 1; i < bytes.size(); ++i) {
for (size_t i = 1; i < bytes.size(); ++i) {
version /= SINGLE_BYTE_MODULUS;
bytes[i] = version % SINGLE_BYTE_MODULUS;
}
@@ -32,19 +31,16 @@ std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
}
constexpr std::array<const char*, 2> PATCH_TYPE_NAMES{
constexpr std::array<const char*, 1> PATCH_TYPE_NAMES{
"Update",
"LayeredFS",
};
std::string FormatPatchTypeName(PatchType type) {
return PATCH_TYPE_NAMES.at(static_cast<std::size_t>(type));
return PATCH_TYPE_NAMES.at(static_cast<size_t>(type));
}
PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
PatchManager::~PatchManager() = default;
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
@@ -68,44 +64,6 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
return exefs;
}
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) {
return;
}
auto extracted = ExtractRomFS(romfs);
if (extracted == nullptr) {
return;
}
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
layers.reserve(patch_dirs.size() + 1);
for (const auto& subdir : patch_dirs) {
auto romfs_dir = subdir->GetSubdirectory("romfs");
if (romfs_dir != nullptr)
layers.push_back(std::move(romfs_dir));
}
layers.push_back(std::move(extracted));
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
if (layered == nullptr) {
return;
}
auto packed = CreateRomFS(std::move(layered));
if (packed == nullptr) {
return;
}
LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully");
romfs = std::move(packed);
}
VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
ContentRecordType type) const {
LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id,
@@ -129,9 +87,6 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
}
}
// LayeredFS
ApplyLayeredFS(romfs, title_id, type);
return romfs;
}
@@ -157,10 +112,6 @@ std::map<PatchType, std::string> PatchManager::GetPatchVersionNames() const {
}
}
const auto lfs_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
if (lfs_dir != nullptr && lfs_dir->GetSize() > 0)
out.insert_or_assign(PatchType::LayeredFS, "");
return out;
}

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