Compare commits
3 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98882c0f37 | ||
|
|
8d98406393 | ||
|
|
5c9c51a628 |
13
.travis.yml
13
.travis.yml
@@ -29,19 +29,6 @@ matrix:
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
docker pull ubuntu:18.04
|
||||
@@ -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/"
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -9,9 +9,7 @@ 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
|
||||
|
||||
@@ -269,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
|
||||
@@ -294,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()
|
||||
@@ -440,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
|
||||
|
||||
@@ -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()
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 171d11659d...959446573f
@@ -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{};
|
||||
|
||||
@@ -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(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{};
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -49,14 +48,9 @@ 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()};
|
||||
return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
|
||||
|
||||
@@ -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()>;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
|
||||
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,
|
||||
LOG_DEBUG(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));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <SoundTouch.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -183,6 +183,7 @@ 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) \
|
||||
|
||||
@@ -70,6 +70,7 @@ 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
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
@@ -30,7 +29,7 @@ class RingBuffer {
|
||||
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);
|
||||
static_assert(std::atomic<std::size_t>::is_always_lock_free);
|
||||
|
||||
public:
|
||||
/// Pushes slots into the ring buffer
|
||||
@@ -103,15 +102,8 @@ public:
|
||||
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
|
||||
alignas(128) std::atomic<std::size_t> m_read_index{0};
|
||||
alignas(128) std::atomic<std::size_t> m_write_index{0};
|
||||
|
||||
std::array<T, granularity * capacity> m_data;
|
||||
};
|
||||
|
||||
@@ -87,6 +87,14 @@ private:
|
||||
|
||||
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
|
||||
|
||||
@@ -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,9 +19,9 @@ public:
|
||||
std::array<u64, 31> cpu_registers;
|
||||
u64 sp;
|
||||
u64 pc;
|
||||
u64 pstate;
|
||||
std::array<u128, 32> vector_registers;
|
||||
u64 fpcr;
|
||||
u64 cpsr;
|
||||
std::array<u128, 32> fpu_registers;
|
||||
u64 fpscr;
|
||||
};
|
||||
|
||||
/// Runs the CPU until an event happens
|
||||
@@ -72,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;
|
||||
|
||||
/**
|
||||
@@ -130,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)
|
||||
|
||||
@@ -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 {
|
||||
@@ -81,17 +79,6 @@ 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);
|
||||
@@ -207,20 +194,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 {
|
||||
@@ -243,18 +239,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.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(static_cast<u32>(ctx.pstate));
|
||||
jit->SetVectors(ctx.vector_registers);
|
||||
jit->SetFpcr(static_cast<u32>(ctx.fpcr));
|
||||
jit->SetPstate(static_cast<u32>(ctx.cpsr));
|
||||
jit->SetVectors(ctx.fpu_registers);
|
||||
jit->SetFpcr(static_cast<u32>(ctx.fpscr));
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PrepareReschedule() {
|
||||
@@ -308,8 +304,8 @@ bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr va
|
||||
|
||||
bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::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]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -33,12 +29,14 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -22,10 +22,12 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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"
|
||||
@@ -67,8 +66,6 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
|
||||
scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
|
||||
}
|
||||
|
||||
Cpu::~Cpu() = default;
|
||||
|
||||
std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -43,7 +43,6 @@ class Cpu {
|
||||
public:
|
||||
Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
|
||||
std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index);
|
||||
~Cpu();
|
||||
|
||||
void RunLoop(bool tight_loop = true);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -41,8 +41,6 @@ std::string FormatPatchTypeName(PatchType 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);
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ std::string FormatPatchTypeName(PatchType type);
|
||||
class PatchManager {
|
||||
public:
|
||||
explicit PatchManager(u64 title_id);
|
||||
~PatchManager();
|
||||
|
||||
// Currently tracked ExeFS patches:
|
||||
// - Game Updates
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
ProgramMetadata::ProgramMetadata() = default;
|
||||
|
||||
ProgramMetadata::~ProgramMetadata() = default;
|
||||
|
||||
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
std::size_t total_size = static_cast<std::size_t>(file->GetSize());
|
||||
if (total_size < sizeof(Header))
|
||||
|
||||
@@ -36,9 +36,6 @@ enum class ProgramFilePermission : u64 {
|
||||
*/
|
||||
class ProgramMetadata {
|
||||
public:
|
||||
ProgramMetadata();
|
||||
~ProgramMetadata();
|
||||
|
||||
Loader::ResultStatus Load(VirtualFile file);
|
||||
|
||||
bool Is64BitProgram() const;
|
||||
|
||||
@@ -28,8 +28,6 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
|
||||
ivfc_offset = app_loader.ReadRomFSIVFCOffset();
|
||||
}
|
||||
|
||||
RomFSFactory::~RomFSFactory() = default;
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
|
||||
if (!updatable)
|
||||
return MakeResult<VirtualFile>(file);
|
||||
|
||||
@@ -30,7 +30,6 @@ enum class StorageId : u8 {
|
||||
class RomFSFactory {
|
||||
public:
|
||||
explicit RomFSFactory(Loader::AppLoader& app_loader);
|
||||
~RomFSFactory();
|
||||
|
||||
ResultVal<VirtualFile> OpenCurrentProcess();
|
||||
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
|
||||
|
||||
@@ -20,8 +20,6 @@ std::string SaveDataDescriptor::DebugInfo() const {
|
||||
|
||||
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {}
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) {
|
||||
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
|
||||
if (meta.zero_1 != 0) {
|
||||
@@ -87,10 +85,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
|
||||
|
||||
switch (space) {
|
||||
case SaveDataSpaceId::NandSystem:
|
||||
out = "/system/";
|
||||
out = "/system/save/";
|
||||
break;
|
||||
case SaveDataSpaceId::NandUser:
|
||||
out = "/user/";
|
||||
out = "/user/save/";
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
|
||||
@@ -98,12 +96,9 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
|
||||
|
||||
switch (type) {
|
||||
case SaveDataType::SystemSaveData:
|
||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
||||
return fmt::format("{}{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
||||
case SaveDataType::SaveData:
|
||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||
title_id);
|
||||
case SaveDataType::TemporaryStorage:
|
||||
return fmt::format("{}temp/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
|
||||
title_id);
|
||||
default:
|
||||
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
|
||||
|
||||
@@ -48,7 +48,6 @@ static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorr
|
||||
class SaveDataFactory {
|
||||
public:
|
||||
explicit SaveDataFactory(VirtualDir dir);
|
||||
~SaveDataFactory();
|
||||
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ enum class ContentRecordType : u8;
|
||||
class NSP : public ReadOnlyVfsDirectory {
|
||||
public:
|
||||
explicit NSP(VirtualFile file);
|
||||
~NSP() override;
|
||||
~NSP();
|
||||
|
||||
Loader::ResultStatus GetStatus() const;
|
||||
Loader::ResultStatus GetProgramStatus(u64 title_id) const;
|
||||
|
||||
@@ -27,8 +27,6 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
|
||||
}
|
||||
}
|
||||
|
||||
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
|
||||
|
||||
std::string ConcatenatedVfsFile::GetName() const {
|
||||
if (files.empty())
|
||||
return "";
|
||||
|
||||
@@ -22,8 +22,6 @@ class ConcatenatedVfsFile : public VfsFile {
|
||||
ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
|
||||
|
||||
public:
|
||||
~ConcatenatedVfsFile() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
std::size_t GetSize() const override;
|
||||
bool Resize(std::size_t new_size) override;
|
||||
|
||||
@@ -14,8 +14,6 @@ OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_,
|
||||
: file(file_), offset(offset_), size(size_), name(std::move(name_)),
|
||||
parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
|
||||
|
||||
OffsetVfsFile::~OffsetVfsFile() = default;
|
||||
|
||||
std::string OffsetVfsFile::GetName() const {
|
||||
return name.empty() ? file->GetName() : name;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ class OffsetVfsFile : public VfsFile {
|
||||
public:
|
||||
OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0,
|
||||
std::string new_name = "", VirtualDir new_parent = nullptr);
|
||||
~OffsetVfsFile() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
std::size_t GetSize() const override;
|
||||
|
||||
@@ -13,8 +13,6 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
|
||||
: files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
|
||||
name(std::move(name_)) {}
|
||||
|
||||
VectorVfsDirectory::~VectorVfsDirectory() = default;
|
||||
|
||||
std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
|
||||
return files;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
|
||||
std::vector<VirtualDir> dirs = {}, std::string name = "",
|
||||
VirtualDir parent = nullptr);
|
||||
~VectorVfsDirectory() override;
|
||||
|
||||
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||
|
||||
@@ -30,6 +30,9 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
|
||||
mbedtls_md_context_t context;
|
||||
mbedtls_md_init(&context);
|
||||
|
||||
const auto key_f = reinterpret_cast<const u8*>(key);
|
||||
const std::vector<u8> key_v(key_f, key_f + key_length);
|
||||
|
||||
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
|
||||
mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
|
||||
mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
|
||||
@@ -42,7 +45,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
|
||||
return true;
|
||||
}
|
||||
|
||||
NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
|
||||
NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NAXHeader>()) {
|
||||
std::string path = FileUtil::SanitizePath(file->GetFullPath());
|
||||
static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
|
||||
std::regex_constants::ECMAScript |
|
||||
@@ -62,15 +65,13 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m
|
||||
}
|
||||
|
||||
NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
|
||||
: header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
|
||||
: file(std::move(file_)), header(std::make_unique<NAXHeader>()) {
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
|
||||
Common::HexArrayToString(nca_id, false)));
|
||||
}
|
||||
|
||||
NAX::~NAX() = default;
|
||||
|
||||
Loader::ResultStatus NAX::Parse(std::string_view path) {
|
||||
if (file->ReadObject(header.get()) != sizeof(NAXHeader))
|
||||
return Loader::ResultStatus::ErrorBadNAXHeader;
|
||||
@@ -137,9 +138,9 @@ VirtualFile NAX::GetDecrypted() const {
|
||||
return dec_file;
|
||||
}
|
||||
|
||||
std::unique_ptr<NCA> NAX::AsNCA() const {
|
||||
std::shared_ptr<NCA> NAX::AsNCA() const {
|
||||
if (type == NAXContentType::NCA)
|
||||
return std::make_unique<NCA>(GetDecrypted());
|
||||
return std::make_shared<NCA>(GetDecrypted());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,13 +33,12 @@ class NAX : public ReadOnlyVfsDirectory {
|
||||
public:
|
||||
explicit NAX(VirtualFile file);
|
||||
explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id);
|
||||
~NAX() override;
|
||||
|
||||
Loader::ResultStatus GetStatus() const;
|
||||
|
||||
VirtualFile GetDecrypted() const;
|
||||
|
||||
std::unique_ptr<NCA> AsNCA() const;
|
||||
std::shared_ptr<NCA> AsNCA() const;
|
||||
|
||||
NAXContentType GetContentType() const;
|
||||
|
||||
@@ -61,7 +60,7 @@ private:
|
||||
|
||||
VirtualFile file;
|
||||
Loader::ResultStatus status;
|
||||
NAXContentType type{};
|
||||
NAXContentType type;
|
||||
|
||||
VirtualFile dec_file;
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ constexpr u32 MSG_WAITALL = 8;
|
||||
constexpr u32 LR_REGISTER = 30;
|
||||
constexpr u32 SP_REGISTER = 31;
|
||||
constexpr u32 PC_REGISTER = 32;
|
||||
constexpr u32 PSTATE_REGISTER = 33;
|
||||
constexpr u32 CPSR_REGISTER = 33;
|
||||
constexpr u32 UC_ARM64_REG_Q0 = 34;
|
||||
constexpr u32 FPCR_REGISTER = 66;
|
||||
constexpr u32 FPSCR_REGISTER = 66;
|
||||
|
||||
// TODO/WiP - Used while working on support for FPU
|
||||
constexpr u32 TODO_DUMMY_REG_997 = 997;
|
||||
@@ -116,7 +116,7 @@ constexpr char target_xml[] =
|
||||
|
||||
<reg name="pc" bitsize="64" type="code_ptr"/>
|
||||
|
||||
<flags id="pstate_flags" size="4">
|
||||
<flags id="cpsr_flags" size="4">
|
||||
<field name="SP" start="0" end="0"/>
|
||||
<field name="" start="1" end="1"/>
|
||||
<field name="EL" start="2" end="3"/>
|
||||
@@ -135,7 +135,7 @@ constexpr char target_xml[] =
|
||||
<field name="Z" start="30" end="30"/>
|
||||
<field name="N" start="31" end="31"/>
|
||||
</flags>
|
||||
<reg name="pstate" bitsize="32" type="pstate_flags"/>
|
||||
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
|
||||
</feature>
|
||||
<feature name="org.gnu.gdb.aarch64.fpu">
|
||||
</feature>
|
||||
@@ -227,10 +227,10 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
|
||||
return thread->context.sp;
|
||||
} else if (id == PC_REGISTER) {
|
||||
return thread->context.pc;
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
return thread->context.pstate;
|
||||
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
|
||||
return thread->context.vector_registers[id - UC_ARM64_REG_Q0][0];
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
return thread->context.cpsr;
|
||||
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
|
||||
return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -247,10 +247,10 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
|
||||
thread->context.sp = val;
|
||||
} else if (id == PC_REGISTER) {
|
||||
thread->context.pc = val;
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
thread->context.pstate = val;
|
||||
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
|
||||
thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
thread->context.cpsr = val;
|
||||
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
|
||||
thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,11 +781,11 @@ static void ReadRegister() {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
} else if (id == PC_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
IntToGdbHex(reply, (u32)RegRead(id, current_thread));
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
|
||||
} else {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
|
||||
@@ -811,7 +811,7 @@ static void ReadRegisters() {
|
||||
|
||||
bufptr += 16;
|
||||
|
||||
IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread)));
|
||||
IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread));
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
@@ -843,11 +843,11 @@ static void WriteRegister() {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == PC_REGISTER) {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else {
|
||||
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
|
||||
@@ -866,16 +866,16 @@ static void WriteRegisters() {
|
||||
if (command_buffer[0] != 'G')
|
||||
return SendReply("E01");
|
||||
|
||||
for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) {
|
||||
for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
|
||||
if (reg <= SP_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == PC_REGISTER) {
|
||||
RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == PSTATE_REGISTER) {
|
||||
RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
|
||||
} else if (reg == CPSR_REGISTER) {
|
||||
RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == FPCR_REGISTER) {
|
||||
} else if (reg == FPSCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
@@ -995,7 +995,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
|
||||
breakpoint.addr = addr;
|
||||
breakpoint.len = len;
|
||||
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
|
||||
static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}};
|
||||
static constexpr std::array<u8, 4> btrap{{0xd4, 0x20, 0x7d, 0x0}};
|
||||
Memory::WriteBlock(addr, btrap.data(), btrap.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
p.insert({addr, breakpoint});
|
||||
|
||||
@@ -290,6 +290,13 @@ public:
|
||||
Skip(CommandIdSize, false);
|
||||
}
|
||||
|
||||
ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
|
||||
u32 num_handles_to_move,
|
||||
ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) const {
|
||||
return ResponseBuilder{*context, normal_params_size, num_handles_to_copy,
|
||||
num_handles_to_move, flags};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Pop();
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -63,7 +62,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
|
||||
Handle requesting_thread_handle) {
|
||||
// The mutex address must be 4-byte aligned
|
||||
if ((address % sizeof(u32)) != 0) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||
}
|
||||
|
||||
SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
|
||||
@@ -101,7 +100,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
|
||||
ResultCode Mutex::Release(VAddr address) {
|
||||
// The mutex address must be 4-byte aligned
|
||||
if ((address % sizeof(u32)) != 0) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||
}
|
||||
|
||||
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/scheduler.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/memory.h"
|
||||
@@ -127,92 +125,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
||||
vm_manager.LogLayout();
|
||||
status = ProcessStatus::Running;
|
||||
|
||||
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
|
||||
}
|
||||
|
||||
void Process::PrepareForTermination() {
|
||||
status = ProcessStatus::Exited;
|
||||
|
||||
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
|
||||
for (auto& thread : thread_list) {
|
||||
if (thread->owner_process != this)
|
||||
continue;
|
||||
|
||||
if (thread == GetCurrentThread())
|
||||
continue;
|
||||
|
||||
// TODO(Subv): When are the other running/ready threads terminated?
|
||||
ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
|
||||
thread->status == ThreadStatus::WaitSynchAll,
|
||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||
|
||||
thread->Stop();
|
||||
}
|
||||
};
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
stop_threads(system.Scheduler(0)->GetThreadList());
|
||||
stop_threads(system.Scheduler(1)->GetThreadList());
|
||||
stop_threads(system.Scheduler(2)->GetThreadList());
|
||||
stop_threads(system.Scheduler(3)->GetThreadList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a free location for the TLS section of a thread.
|
||||
* @param tls_slots The TLS page array of the thread's owner process.
|
||||
* Returns a tuple of (page, slot, alloc_needed) where:
|
||||
* page: The index of the first allocated TLS page that has free slots.
|
||||
* slot: The index of the first free slot in the indicated page.
|
||||
* alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
|
||||
*/
|
||||
static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
|
||||
const std::vector<std::bitset<8>>& tls_slots) {
|
||||
// Iterate over all the allocated pages, and try to find one where not all slots are used.
|
||||
for (std::size_t page = 0; page < tls_slots.size(); ++page) {
|
||||
const auto& page_tls_slots = tls_slots[page];
|
||||
if (!page_tls_slots.all()) {
|
||||
// We found a page with at least one free slot, find which slot it is
|
||||
for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
|
||||
if (!page_tls_slots.test(slot)) {
|
||||
return std::make_tuple(page, slot, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_tuple(0, 0, true);
|
||||
}
|
||||
|
||||
VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
|
||||
auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
|
||||
|
||||
if (needs_allocation) {
|
||||
tls_slots.emplace_back(0); // The page is completely available at the start
|
||||
available_page = tls_slots.size() - 1;
|
||||
available_slot = 0; // Use the first slot in the new page
|
||||
|
||||
// Allocate some memory from the end of the linear heap for this region.
|
||||
auto& tls_memory = thread.GetTLSMemory();
|
||||
tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0);
|
||||
|
||||
vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
|
||||
|
||||
vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
||||
tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal);
|
||||
}
|
||||
|
||||
tls_slots[available_page].set(available_slot);
|
||||
|
||||
return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||
available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
void Process::FreeTLSSlot(VAddr tls_address) {
|
||||
const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR;
|
||||
const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
|
||||
const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
|
||||
tls_slots[tls_page].reset(tls_slot);
|
||||
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, this);
|
||||
}
|
||||
|
||||
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
|
||||
|
||||
@@ -131,16 +131,6 @@ public:
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/// Gets the current status of the process
|
||||
ProcessStatus GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Gets the unique ID that identifies this particular process.
|
||||
u32 GetProcessID() const {
|
||||
return process_id;
|
||||
}
|
||||
|
||||
/// Title ID corresponding to the process
|
||||
u64 program_id;
|
||||
|
||||
@@ -164,6 +154,11 @@ public:
|
||||
u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
|
||||
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
|
||||
u32 is_virtual_address_memory_enabled = 0;
|
||||
/// Current status of the process
|
||||
ProcessStatus status;
|
||||
|
||||
/// The ID of this process
|
||||
u32 process_id = 0;
|
||||
|
||||
/**
|
||||
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
||||
@@ -176,42 +171,13 @@ public:
|
||||
*/
|
||||
void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
|
||||
|
||||
/**
|
||||
* Prepares a process for termination by stopping all of its threads
|
||||
* and clearing any other resources.
|
||||
*/
|
||||
void PrepareForTermination();
|
||||
|
||||
void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Management
|
||||
|
||||
// Marks the next available region as used and returns the address of the slot.
|
||||
VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
|
||||
|
||||
// Frees a used TLS slot identified by the given address
|
||||
void FreeTLSSlot(VAddr tls_address);
|
||||
|
||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
||||
ResultCode HeapFree(VAddr target, u32 size);
|
||||
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
VMManager vm_manager;
|
||||
|
||||
private:
|
||||
explicit Process(KernelCore& kernel);
|
||||
~Process() override;
|
||||
|
||||
/// Current status of the process
|
||||
ProcessStatus status;
|
||||
|
||||
/// The ID of this process
|
||||
u32 process_id = 0;
|
||||
|
||||
// Memory used to back the allocations in the regular heap. A single vector is used to cover
|
||||
// the entire virtual address space extents that bound the allocations, including any holes.
|
||||
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
||||
@@ -231,6 +197,17 @@ private:
|
||||
std::vector<std::bitset<8>> tls_slots;
|
||||
|
||||
std::string name;
|
||||
|
||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
||||
ResultCode HeapFree(VAddr target, u32 size);
|
||||
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
private:
|
||||
explicit Process(KernelCore& kernel);
|
||||
~Process() override;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -169,7 +169,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
*process_id = process->GetProcessID();
|
||||
*process_id = process->process_id;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -280,10 +280,6 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
|
||||
"requesting_current_thread_handle=0x{:08X}",
|
||||
holding_thread_handle, mutex_addr, requesting_thread_handle);
|
||||
|
||||
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
|
||||
return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
|
||||
requesting_thread_handle);
|
||||
@@ -293,10 +289,6 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
|
||||
static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
|
||||
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
|
||||
|
||||
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
return Mutex::Release(mutex_addr);
|
||||
}
|
||||
|
||||
@@ -530,13 +522,35 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd
|
||||
|
||||
/// Exits the current process
|
||||
static void ExitProcess() {
|
||||
auto& current_process = Core::CurrentProcess();
|
||||
LOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id);
|
||||
|
||||
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
|
||||
ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
|
||||
ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running,
|
||||
"Process has already exited");
|
||||
|
||||
current_process->PrepareForTermination();
|
||||
Core::CurrentProcess()->status = ProcessStatus::Exited;
|
||||
|
||||
auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) {
|
||||
for (auto& thread : thread_list) {
|
||||
if (thread->owner_process != Core::CurrentProcess())
|
||||
continue;
|
||||
|
||||
if (thread == GetCurrentThread())
|
||||
continue;
|
||||
|
||||
// TODO(Subv): When are the other running/ready threads terminated?
|
||||
ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
|
||||
thread->status == ThreadStatus::WaitSynchAll,
|
||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||
|
||||
thread->Stop();
|
||||
}
|
||||
};
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
stop_threads(system.Scheduler(0)->GetThreadList());
|
||||
stop_threads(system.Scheduler(1)->GetThreadList());
|
||||
stop_threads(system.Scheduler(2)->GetThreadList());
|
||||
stop_threads(system.Scheduler(3)->GetThreadList());
|
||||
|
||||
// Kill the current thread
|
||||
GetCurrentThread()->Stop();
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
static inline u64 Param(int n) {
|
||||
return Core::CurrentArmInterface().GetReg(n);
|
||||
}
|
||||
#define PARAM(n) Core::CurrentArmInterface().GetReg(n)
|
||||
|
||||
/**
|
||||
* HLE a function return from the current ARM userland process
|
||||
@@ -30,23 +28,23 @@ static inline void FuncReturn(u64 res) {
|
||||
|
||||
template <ResultCode func(u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0)).raw);
|
||||
FuncReturn(func(PARAM(0)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)Param(0)).raw);
|
||||
FuncReturn(func((u32)PARAM(0)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)Param(0), (u32)Param(1)).raw);
|
||||
FuncReturn(func((u32)PARAM(0), (u32)PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, (u32)Param(1)).raw;
|
||||
u32 retval = func(¶m_1, (u32)PARAM(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -54,39 +52,39 @@ void SvcWrap() {
|
||||
template <ResultCode func(u32*, u64)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), (s32)Param(1)).raw);
|
||||
FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64)>
|
||||
void SvcWrap() {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw);
|
||||
FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw);
|
||||
FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), (u32)(PARAM(1) & 0xFFFFFFFF), PARAM(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32*, u64*)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u64 param_2 = 0;
|
||||
ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), ¶m_1, ¶m_2);
|
||||
ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), ¶m_1, ¶m_2);
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
Core::CurrentArmInterface().SetReg(2, param_2);
|
||||
FuncReturn(retval.raw);
|
||||
@@ -95,46 +93,46 @@ void SvcWrap() {
|
||||
template <ResultCode func(u64, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw);
|
||||
func(PARAM(0), PARAM(1), (u32)(PARAM(3) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw);
|
||||
FuncReturn(func((u32)PARAM(0), PARAM(1), (u32)PARAM(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), Param(2)).raw);
|
||||
FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw);
|
||||
FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw);
|
||||
FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, s64)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
ResultCode retval = func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3));
|
||||
ResultCode retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3));
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw);
|
||||
FuncReturn(func(PARAM(0), PARAM(1), (u32)PARAM(2), (s64)PARAM(3)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), Param(3)).raw;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -143,7 +141,7 @@ template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval =
|
||||
func(¶m_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF))
|
||||
func(¶m_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF))
|
||||
.raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
@@ -153,13 +151,13 @@ template <ResultCode func(MemoryInfo*, PageInfo*, u64)>
|
||||
void SvcWrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, Param(2)).raw;
|
||||
u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
|
||||
|
||||
Memory::Write64(Param(0), memory_info.base_address);
|
||||
Memory::Write64(Param(0) + 8, memory_info.size);
|
||||
Memory::Write32(Param(0) + 16, memory_info.type);
|
||||
Memory::Write32(Param(0) + 20, memory_info.attributes);
|
||||
Memory::Write32(Param(0) + 24, memory_info.permission);
|
||||
Memory::Write64(PARAM(0), memory_info.base_address);
|
||||
Memory::Write64(PARAM(0) + 8, memory_info.size);
|
||||
Memory::Write32(PARAM(0) + 16, memory_info.type);
|
||||
Memory::Write32(PARAM(0) + 20, memory_info.attributes);
|
||||
Memory::Write32(PARAM(0) + 24, memory_info.permission);
|
||||
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -167,7 +165,7 @@ void SvcWrap() {
|
||||
template <ResultCode func(u32*, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -176,7 +174,7 @@ template <ResultCode func(Handle*, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval =
|
||||
func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw;
|
||||
func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
@@ -184,14 +182,14 @@ void SvcWrap() {
|
||||
template <ResultCode func(u64, u32, s32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3))
|
||||
func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32, s32, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF),
|
||||
(s32)(Param(3) & 0xFFFFFFFF))
|
||||
FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF),
|
||||
(s32)(PARAM(3) & 0xFFFFFFFF))
|
||||
.raw);
|
||||
}
|
||||
|
||||
@@ -221,17 +219,20 @@ void SvcWrap() {
|
||||
|
||||
template <void func(s64)>
|
||||
void SvcWrap() {
|
||||
func((s64)Param(0));
|
||||
func((s64)PARAM(0));
|
||||
}
|
||||
|
||||
template <void func(u64, u64 len)>
|
||||
void SvcWrap() {
|
||||
func(Param(0), Param(1));
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template <void func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
func(Param(0), Param(1), Param(2));
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
#undef PARAM
|
||||
#undef FuncReturn
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -65,7 +65,10 @@ void Thread::Stop() {
|
||||
wait_objects.clear();
|
||||
|
||||
// Mark the TLS slot in the thread's page as free.
|
||||
owner_process->FreeTLSSlot(tls_address);
|
||||
const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||
const u64 tls_slot =
|
||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
|
||||
}
|
||||
|
||||
void WaitCurrentThread_Sleep() {
|
||||
@@ -174,6 +177,32 @@ void Thread::ResumeFromWait() {
|
||||
Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a free location for the TLS section of a thread.
|
||||
* @param tls_slots The TLS page array of the thread's owner process.
|
||||
* Returns a tuple of (page, slot, alloc_needed) where:
|
||||
* page: The index of the first allocated TLS page that has free slots.
|
||||
* slot: The index of the first free slot in the indicated page.
|
||||
* alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
|
||||
*/
|
||||
static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
|
||||
const std::vector<std::bitset<8>>& tls_slots) {
|
||||
// Iterate over all the allocated pages, and try to find one where not all slots are used.
|
||||
for (std::size_t page = 0; page < tls_slots.size(); ++page) {
|
||||
const auto& page_tls_slots = tls_slots[page];
|
||||
if (!page_tls_slots.all()) {
|
||||
// We found a page with at least one free slot, find which slot it is
|
||||
for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
|
||||
if (!page_tls_slots.test(slot)) {
|
||||
return std::make_tuple(page, slot, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_tuple(0, 0, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a thread context, making it ready to be scheduled and run by the CPU
|
||||
* @param context Thread context to reset
|
||||
@@ -188,8 +217,8 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
|
||||
context.cpu_registers[0] = arg;
|
||||
context.pc = entry_point;
|
||||
context.sp = stack_top;
|
||||
context.pstate = 0;
|
||||
context.fpcr = 0;
|
||||
context.cpsr = 0;
|
||||
context.fpscr = 0;
|
||||
}
|
||||
|
||||
ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
|
||||
@@ -235,7 +264,32 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
|
||||
thread->owner_process = owner_process;
|
||||
thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
|
||||
thread->scheduler->AddThread(thread, priority);
|
||||
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
|
||||
|
||||
// Find the next available TLS index, and mark it as used
|
||||
auto& tls_slots = owner_process->tls_slots;
|
||||
|
||||
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
||||
if (needs_allocation) {
|
||||
tls_slots.emplace_back(0); // The page is completely available at the start
|
||||
available_page = tls_slots.size() - 1;
|
||||
available_slot = 0; // Use the first slot in the new page
|
||||
|
||||
// Allocate some memory from the end of the linear heap for this region.
|
||||
const std::size_t offset = thread->tls_memory->size();
|
||||
thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
|
||||
|
||||
auto& vm_manager = owner_process->vm_manager;
|
||||
vm_manager.RefreshMemoryBlockMappings(thread->tls_memory.get());
|
||||
|
||||
vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
||||
thread->tls_memory, 0, Memory::PAGE_SIZE,
|
||||
MemoryState::ThreadLocal);
|
||||
}
|
||||
|
||||
// Mark the slot as used
|
||||
tls_slots[available_page].set(available_slot);
|
||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||
available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
|
||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||
// to initialize the context
|
||||
@@ -257,13 +311,13 @@ void Thread::BoostPriority(u32 priority) {
|
||||
}
|
||||
|
||||
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||
Process& owner_process) {
|
||||
SharedPtr<Process> owner_process) {
|
||||
// Setup page table so we can write to memory
|
||||
SetCurrentPageTable(&owner_process.vm_manager.page_table);
|
||||
SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
|
||||
|
||||
// Initialize new "main" thread
|
||||
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
|
||||
Memory::STACK_AREA_VADDR_END, &owner_process);
|
||||
Memory::STACK_AREA_VADDR_END, std::move(owner_process));
|
||||
|
||||
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
||||
|
||||
|
||||
@@ -62,9 +62,6 @@ enum class ThreadWakeupReason {
|
||||
|
||||
class Thread final : public WaitObject {
|
||||
public:
|
||||
using TLSMemory = std::vector<u8>;
|
||||
using TLSMemoryPtr = std::shared_ptr<TLSMemory>;
|
||||
|
||||
/**
|
||||
* Creates and returns a new thread. The new thread is immediately scheduled
|
||||
* @param kernel The kernel instance this thread will be created under.
|
||||
@@ -137,14 +134,6 @@ public:
|
||||
return thread_id;
|
||||
}
|
||||
|
||||
TLSMemoryPtr& GetTLSMemory() {
|
||||
return tls_memory;
|
||||
}
|
||||
|
||||
const TLSMemoryPtr& GetTLSMemory() const {
|
||||
return tls_memory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a thread from waiting
|
||||
*/
|
||||
@@ -280,7 +269,7 @@ private:
|
||||
explicit Thread(KernelCore& kernel);
|
||||
~Thread() override;
|
||||
|
||||
TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
|
||||
std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -292,7 +281,7 @@ private:
|
||||
* @return A shared pointer to the main thread
|
||||
*/
|
||||
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||
Process& owner_process);
|
||||
SharedPtr<Process> owner_process);
|
||||
|
||||
/**
|
||||
* Gets the current thread
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IProfile::Get, "Get"},
|
||||
{1, &IProfile::GetBase, "GetBase"},
|
||||
{10, &IProfile::GetImageSize, "GetImageSize"},
|
||||
{10, nullptr, "GetImageSize"},
|
||||
{11, &IProfile::LoadImage, "LoadImage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
@@ -93,14 +93,6 @@ private:
|
||||
rb.Push<u32>(jpeg_size);
|
||||
}
|
||||
|
||||
void GetImageSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
constexpr u32 jpeg_size = 107;
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(jpeg_size);
|
||||
}
|
||||
|
||||
const ProfileManager& profile_manager;
|
||||
UUID user_id; ///< The user id this profile refers to.
|
||||
};
|
||||
@@ -130,10 +122,11 @@ private:
|
||||
|
||||
void GetAccountId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
// Should return a nintendo account ID
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(1);
|
||||
// TODO(Subv): Find out what this actually does and implement it. Stub it as an error for
|
||||
// now since we do not implement NNID. Returning a bogus id here will cause games to send
|
||||
// invalid IPC requests after ListOpenUsers is called.
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const UUID& UUID::Generate() {
|
||||
ProfileManager::ProfileManager() {
|
||||
// TODO(ogniK): Create the default user we have for now until loading/saving users is added
|
||||
auto user_uuid = UUID{1, 0};
|
||||
ASSERT(CreateNewUser(user_uuid, Settings::values.username).IsSuccess());
|
||||
CreateNewUser(user_uuid, Settings::values.username);
|
||||
OpenUser(user_uuid);
|
||||
}
|
||||
|
||||
@@ -91,8 +91,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern
|
||||
/// specifically by allowing an std::string for the username. This is required specifically since
|
||||
/// we're loading a string straight from the config
|
||||
ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) {
|
||||
ProfileUsername username_output{};
|
||||
|
||||
ProfileUsername username_output;
|
||||
if (username.size() > username_output.size()) {
|
||||
std::copy_n(username.begin(), username_output.size(), username_output.begin());
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
#include "core/hle/service/pm/pm.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::AM {
|
||||
@@ -335,7 +334,7 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
|
||||
{51, nullptr, "SetVrModeEnabled"},
|
||||
{52, nullptr, "SwitchLcdBacklight"},
|
||||
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
|
||||
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
|
||||
{60, nullptr, "GetDefaultDisplayResolution"},
|
||||
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent,
|
||||
"GetDefaultDisplayResolutionChangeEvent"},
|
||||
{62, nullptr, "GetHdcpAuthenticationState"},
|
||||
@@ -394,21 +393,6 @@ void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLEReque
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode};
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -462,7 +446,7 @@ private:
|
||||
|
||||
std::memcpy(&buffer[offset], data.data(), data.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
@@ -478,7 +462,7 @@ private:
|
||||
|
||||
ctx.WriteBuffer(buffer.data() + offset, size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
@@ -568,7 +552,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
@@ -616,7 +600,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||
const u64 size{rp.Pop<u64>()};
|
||||
std::vector<u8> buffer(size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
|
||||
|
||||
|
||||
@@ -123,7 +123,6 @@ private:
|
||||
void GetOperationMode(Kernel::HLERequestContext& ctx);
|
||||
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
|
||||
void GetBootMode(Kernel::HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> event;
|
||||
};
|
||||
|
||||
@@ -190,7 +190,7 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
ctx.WriteBuffer(DefaultDevice);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1); // Amount of audio devices
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
{0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"},
|
||||
{1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"},
|
||||
{2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"},
|
||||
{3, &IAudioRenderer::GetAudioRendererState, "GetAudioRendererState"},
|
||||
{3, nullptr, "GetAudioRendererState"},
|
||||
{4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
|
||||
{5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
|
||||
{6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
|
||||
@@ -62,13 +62,6 @@ private:
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -144,7 +137,7 @@ private:
|
||||
constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
}
|
||||
@@ -158,7 +151,7 @@ private:
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -169,7 +162,7 @@ private:
|
||||
constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, path);
|
||||
if (dir == nullptr) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
return ResultCode(-1);
|
||||
}
|
||||
return MakeResult(dir);
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public:
|
||||
{64, nullptr, "DeactivateJoySixAxisSensor"},
|
||||
{65, nullptr, "GetJoySixAxisSensorLifoHandle"},
|
||||
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
|
||||
{67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
|
||||
{67, nullptr, "StopSixAxisSensor"},
|
||||
{68, nullptr, "IsSixAxisSensorFusionEnabled"},
|
||||
{69, nullptr, "EnableSixAxisSensorFusion"},
|
||||
{70, nullptr, "SetSixAxisSensorFusionParameters"},
|
||||
@@ -329,7 +329,7 @@ public:
|
||||
{80, nullptr, "GetGyroscopeZeroDriftMode"},
|
||||
{81, nullptr, "ResetGyroscopeZeroDriftMode"},
|
||||
{82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
|
||||
{91, &Hid::ActivateGesture, "ActivateGesture"},
|
||||
{91, nullptr, "ActivateGesture"},
|
||||
{100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
|
||||
{101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
|
||||
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
|
||||
@@ -338,7 +338,7 @@ public:
|
||||
{106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
|
||||
{107, &Hid::DisconnectNpad, "DisconnectNpad"},
|
||||
{108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
|
||||
{109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
|
||||
{109, nullptr, "ActivateNpadWithRevision"},
|
||||
{120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
|
||||
{121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
|
||||
{122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
|
||||
@@ -364,8 +364,8 @@ public:
|
||||
{208, nullptr, "GetActualVibrationGcErmCommand"},
|
||||
{209, nullptr, "BeginPermitVibrationSession"},
|
||||
{210, nullptr, "EndPermitVibrationSession"},
|
||||
{300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
|
||||
{301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
|
||||
{300, nullptr, "ActivateConsoleSixAxisSensor"},
|
||||
{301, nullptr, "StartConsoleSixAxisSensor"},
|
||||
{302, nullptr, "StopConsoleSixAxisSensor"},
|
||||
{303, nullptr, "ActivateSevenSixAxisSensor"},
|
||||
{304, nullptr, "StartSevenSixAxisSensor"},
|
||||
@@ -579,36 +579,6 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ActivateGesture(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
class HidDbg final : public ServiceFramework<HidDbg> {
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
|
||||
namespace Service::HID {
|
||||
@@ -9,28 +14,145 @@ namespace Service::HID {
|
||||
IRS::IRS() : ServiceFramework{"irs"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{302, nullptr, "ActivateIrsensor"},
|
||||
{303, nullptr, "DeactivateIrsensor"},
|
||||
{304, nullptr, "GetIrsensorSharedMemoryHandle"},
|
||||
{305, nullptr, "StopImageProcessor"},
|
||||
{306, nullptr, "RunMomentProcessor"},
|
||||
{307, nullptr, "RunClusteringProcessor"},
|
||||
{308, nullptr, "RunImageTransferProcessor"},
|
||||
{309, nullptr, "GetImageTransferProcessorState"},
|
||||
{310, nullptr, "RunTeraPluginProcessor"},
|
||||
{311, nullptr, "GetNpadIrCameraHandle"},
|
||||
{312, nullptr, "RunPointingProcessor"},
|
||||
{313, nullptr, "SuspendImageProcessor"},
|
||||
{314, nullptr, "CheckFirmwareVersion"},
|
||||
{315, nullptr, "SetFunctionLevel"},
|
||||
{316, nullptr, "RunImageTransferExProcessor"},
|
||||
{317, nullptr, "RunIrLedProcessor"},
|
||||
{318, nullptr, "StopImageProcessorAsync"},
|
||||
{319, nullptr, "ActivateIrsensorWithFunctionLevel"},
|
||||
{302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
|
||||
{303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
|
||||
{304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
|
||||
{305, &IRS::StopImageProcessor, "StopImageProcessor"},
|
||||
{306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
|
||||
{307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
|
||||
{308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
|
||||
{309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
|
||||
{310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
|
||||
{311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
|
||||
{312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
|
||||
{313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
|
||||
{314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
|
||||
{315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
|
||||
{316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
|
||||
{317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
|
||||
{318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
|
||||
{319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
shared_mem = Kernel::SharedMemory::Create(
|
||||
kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite,
|
||||
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory");
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(shared_mem);
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(CoreTiming::GetTicks());
|
||||
rb.PushRaw<u32>(0);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(device_handle);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
IRS::~IRS() = default;
|
||||
|
||||
@@ -4,14 +4,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class SharedMemory;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class IRS final : public ServiceFramework<IRS> {
|
||||
public:
|
||||
explicit IRS();
|
||||
~IRS() override;
|
||||
|
||||
private:
|
||||
void ActivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
||||
void StopImageProcessor(Kernel::HLERequestContext& ctx);
|
||||
void RunMomentProcessor(Kernel::HLERequestContext& ctx);
|
||||
void RunClusteringProcessor(Kernel::HLERequestContext& ctx);
|
||||
void RunImageTransferProcessor(Kernel::HLERequestContext& ctx);
|
||||
void GetImageTransferProcessorState(Kernel::HLERequestContext& ctx);
|
||||
void RunTeraPluginProcessor(Kernel::HLERequestContext& ctx);
|
||||
void GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx);
|
||||
void RunPointingProcessor(Kernel::HLERequestContext& ctx);
|
||||
void SuspendImageProcessor(Kernel::HLERequestContext& ctx);
|
||||
void CheckFirmwareVersion(Kernel::HLERequestContext& ctx);
|
||||
void SetFunctionLevel(Kernel::HLERequestContext& ctx);
|
||||
void RunImageTransferExProcessor(Kernel::HLERequestContext& ctx);
|
||||
void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
|
||||
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
|
||||
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
|
||||
const u32 device_handle{0xABCD};
|
||||
};
|
||||
|
||||
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
{1, &IRequest::GetResult, "GetResult"},
|
||||
{2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"},
|
||||
{3, &IRequest::Cancel, "Cancel"},
|
||||
{4, &IRequest::Submit, "Submit"},
|
||||
{4, nullptr, "Submit"},
|
||||
{5, nullptr, "SetRequirement"},
|
||||
{6, nullptr, "SetRequirementPreset"},
|
||||
{8, nullptr, "SetPriority"},
|
||||
@@ -61,12 +61,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Submit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetRequestState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -120,11 +114,10 @@ public:
|
||||
|
||||
private:
|
||||
void GetClientId(Kernel::HLERequestContext& ctx) {
|
||||
static constexpr u32 client_id = 1;
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
void CreateScanRequest(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -148,16 +141,10 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size");
|
||||
u128 uuid{};
|
||||
auto buffer = ctx.ReadBuffer();
|
||||
std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<INetworkProfile>();
|
||||
rb.PushRaw<u128>(uuid);
|
||||
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
}
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/service/nim/nim.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@@ -104,111 +100,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class IEnsureNetworkClockAvailabilityService final
|
||||
: public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
|
||||
public:
|
||||
IEnsureNetworkClockAvailabilityService()
|
||||
: ServiceFramework("IEnsureNetworkClockAvailabilityService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
|
||||
{1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
|
||||
"GetFinishNotificationEvent"},
|
||||
{2, &IEnsureNetworkClockAvailabilityService::GetResult, "GetResult"},
|
||||
{3, &IEnsureNetworkClockAvailabilityService::Cancel, "Cancel"},
|
||||
{4, &IEnsureNetworkClockAvailabilityService::IsProcessing, "IsProcessing"},
|
||||
{5, &IEnsureNetworkClockAvailabilityService::GetServerTime, "GetServerTime"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
finished_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"IEnsureNetworkClockAvailabilityService:FinishEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
Kernel::SharedPtr<Kernel::Event> finished_event;
|
||||
|
||||
void StartTask(Kernel::HLERequestContext& ctx) {
|
||||
// No need to connect to the internet, just finish the task straight away.
|
||||
finished_event->Signal();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(finished_event);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void GetResult(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void Cancel(Kernel::HLERequestContext& ctx) {
|
||||
finished_event->Clear();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void IsProcessing(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(0); // We instantly process the request
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void GetServerTime(Kernel::HLERequestContext& ctx) {
|
||||
const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<s64>(server_time);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
class NTC final : public ServiceFramework<NTC> {
|
||||
public:
|
||||
explicit NTC() : ServiceFramework{"ntc"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
|
||||
{100, &NTC::SuspendAutonomicTimeCorrection, "SuspendAutonomicTimeCorrection"},
|
||||
{101, &NTC::ResumeAutonomicTimeCorrection, "ResumeAutonomicTimeCorrection"},
|
||||
{0, nullptr, "OpenEnsureNetworkClockAvailabilityService"},
|
||||
{100, nullptr, "SuspendAutonomicTimeCorrection"},
|
||||
{101, nullptr, "ResumeAutonomicTimeCorrection"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
// TODO(ogniK): Do we need these?
|
||||
void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& sm) {
|
||||
|
||||
@@ -108,7 +108,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
auto client_port = service_manager->GetServicePort(name);
|
||||
if (client_port.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(client_port.Code());
|
||||
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw);
|
||||
if (name.length() == 0)
|
||||
@@ -121,7 +121,8 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT(session.Succeeded());
|
||||
if (session.Succeeded()) {
|
||||
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId());
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
IPC::ResponseBuilder rb =
|
||||
rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles);
|
||||
rb.Push(session.Code());
|
||||
rb.PushMoveObjects(std::move(session).Unwrap());
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ private:
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
u64 z_value = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
@@ -747,7 +747,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -761,7 +761,7 @@ private:
|
||||
|
||||
u64 layer_id = nv_flinger->CreateLayer(display);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
}
|
||||
@@ -772,7 +772,7 @@ private:
|
||||
u32 stack = rp.Pop<u32>();
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -780,7 +780,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
@@ -837,7 +837,7 @@ private:
|
||||
|
||||
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(nv_flinger->OpenDisplay(name));
|
||||
}
|
||||
@@ -847,7 +847,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -856,7 +856,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
@@ -874,7 +874,7 @@ private:
|
||||
u32 scaling_mode = rp.Pop<u32>();
|
||||
u64 unknown = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -882,7 +882,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
DisplayInfo display_info;
|
||||
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(1);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
@@ -903,7 +903,7 @@ private:
|
||||
u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
|
||||
}
|
||||
@@ -922,7 +922,7 @@ private:
|
||||
u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
|
||||
@@ -934,7 +934,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -945,7 +945,7 @@ private:
|
||||
|
||||
auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(vsync_event);
|
||||
}
|
||||
|
||||
@@ -11,20 +11,6 @@
|
||||
#include "core/loader/nca.h"
|
||||
|
||||
namespace Loader {
|
||||
namespace {
|
||||
FileType IdentifyTypeImpl(const FileSys::NAX& nax) {
|
||||
if (nax.GetStatus() != ResultStatus::Success) {
|
||||
return FileType::Error;
|
||||
}
|
||||
|
||||
const auto nca = nax.AsNCA();
|
||||
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
|
||||
return FileType::Error;
|
||||
}
|
||||
|
||||
return FileType::NAX;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
|
||||
: AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)),
|
||||
@@ -33,12 +19,14 @@ AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
|
||||
AppLoader_NAX::~AppLoader_NAX() = default;
|
||||
|
||||
FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) {
|
||||
const FileSys::NAX nax(file);
|
||||
return IdentifyTypeImpl(nax);
|
||||
}
|
||||
FileSys::NAX nax(file);
|
||||
|
||||
FileType AppLoader_NAX::GetFileType() {
|
||||
return IdentifyTypeImpl(*nax);
|
||||
if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr &&
|
||||
nax.AsNCA()->GetStatus() == ResultStatus::Success) {
|
||||
return FileType::NAX;
|
||||
}
|
||||
|
||||
return FileType::Error;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||
|
||||
@@ -31,7 +31,9 @@ public:
|
||||
*/
|
||||
static FileType IdentifyType(const FileSys::VirtualFile& file);
|
||||
|
||||
FileType GetFileType() override;
|
||||
FileType GetFileType() override {
|
||||
return IdentifyType(file);
|
||||
}
|
||||
|
||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||
|
||||
|
||||
@@ -32,18 +32,11 @@ static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect
|
||||
|
||||
struct NsoHeader {
|
||||
u32_le magic;
|
||||
u32_le version;
|
||||
INSERT_PADDING_WORDS(1);
|
||||
u8 flags;
|
||||
INSERT_PADDING_BYTES(0xc);
|
||||
std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order)
|
||||
u32_le bss_size;
|
||||
INSERT_PADDING_BYTES(0x1c);
|
||||
std::array<u32_le, 3> segments_compressed_size;
|
||||
|
||||
bool IsSegmentCompressed(size_t segment_num) const {
|
||||
ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num);
|
||||
return ((flags >> segment_num) & 1);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
|
||||
static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable.");
|
||||
@@ -112,11 +105,9 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
|
||||
Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
|
||||
std::vector<u8> program_image;
|
||||
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
||||
std::vector<u8> data =
|
||||
const std::vector<u8> compressed_data =
|
||||
file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
|
||||
if (nso_header.IsSegmentCompressed(i)) {
|
||||
data = DecompressSegment(data, nso_header.segments[i]);
|
||||
}
|
||||
std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]);
|
||||
program_image.resize(nso_header.segments[i].location);
|
||||
program_image.insert(program_image.end(), data.begin(), data.end());
|
||||
codeset->segments[i].addr = nso_header.segments[i].location;
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
@@ -239,41 +240,6 @@ enum class FlowCondition : u64 {
|
||||
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
||||
};
|
||||
|
||||
enum class ControlCode : u64 {
|
||||
F = 0,
|
||||
LT = 1,
|
||||
EQ = 2,
|
||||
LE = 3,
|
||||
GT = 4,
|
||||
NE = 5,
|
||||
GE = 6,
|
||||
Num = 7,
|
||||
Nan = 8,
|
||||
LTU = 9,
|
||||
EQU = 10,
|
||||
LEU = 11,
|
||||
GTU = 12,
|
||||
NEU = 13,
|
||||
GEU = 14,
|
||||
//
|
||||
OFF = 16,
|
||||
LO = 17,
|
||||
SFF = 18,
|
||||
LS = 19,
|
||||
HI = 20,
|
||||
SFT = 21,
|
||||
HS = 22,
|
||||
OFT = 23,
|
||||
CSM_TA = 24,
|
||||
CSM_TR = 25,
|
||||
CSM_MX = 26,
|
||||
FCSM_TA = 27,
|
||||
FCSM_TR = 28,
|
||||
FCSM_MX = 29,
|
||||
RLE = 30,
|
||||
RGT = 31,
|
||||
};
|
||||
|
||||
enum class PredicateResultMode : u64 {
|
||||
None = 0x0,
|
||||
NotZero = 0x3,
|
||||
@@ -305,38 +271,17 @@ enum class TextureProcessMode : u64 {
|
||||
LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL
|
||||
};
|
||||
|
||||
enum class TextureMiscMode : u64 {
|
||||
DC,
|
||||
AOFFI, // Uses Offset
|
||||
NDV,
|
||||
NODEP,
|
||||
MZ,
|
||||
PTP,
|
||||
};
|
||||
|
||||
enum class IpaInterpMode : u64 {
|
||||
Linear = 0,
|
||||
Perspective = 1,
|
||||
Flat = 2,
|
||||
Sc = 3,
|
||||
};
|
||||
|
||||
enum class IpaSampleMode : u64 {
|
||||
Default = 0,
|
||||
Centroid = 1,
|
||||
Offset = 2,
|
||||
};
|
||||
enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
|
||||
enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
|
||||
|
||||
struct IpaMode {
|
||||
IpaInterpMode interpolation_mode;
|
||||
IpaSampleMode sampling_mode;
|
||||
|
||||
bool operator==(const IpaMode& a) const {
|
||||
return std::tie(interpolation_mode, sampling_mode) ==
|
||||
std::tie(a.interpolation_mode, a.sampling_mode);
|
||||
inline bool operator==(const IpaMode& a) {
|
||||
return (a.interpolation_mode == interpolation_mode) && (a.sampling_mode == sampling_mode);
|
||||
}
|
||||
bool operator!=(const IpaMode& a) const {
|
||||
return !operator==(a);
|
||||
inline bool operator!=(const IpaMode& a) {
|
||||
return !((*this) == a);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -600,15 +545,6 @@ union Instruction {
|
||||
BitField<45, 2, PredOperation> op;
|
||||
} pset;
|
||||
|
||||
union {
|
||||
BitField<0, 3, u64> pred0;
|
||||
BitField<3, 3, u64> pred3;
|
||||
BitField<8, 5, ControlCode> cc; // flag in cc
|
||||
BitField<39, 3, u64> pred39;
|
||||
BitField<42, 1, u64> neg_pred39;
|
||||
BitField<45, 4, PredOperation> op; // op with pred39
|
||||
} csetp;
|
||||
|
||||
union {
|
||||
BitField<39, 3, u64> pred39;
|
||||
BitField<42, 1, u64> neg_pred;
|
||||
@@ -654,127 +590,42 @@ union Instruction {
|
||||
BitField<28, 1, u64> array;
|
||||
BitField<29, 2, TextureType> texture_type;
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 1, u64> dc_flag;
|
||||
BitField<54, 1, u64> aoffi_flag;
|
||||
BitField<55, 3, TextureProcessMode> process_mode;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ull << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
return process_mode;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
case TextureMiscMode::AOFFI:
|
||||
return aoffi_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tex;
|
||||
|
||||
union {
|
||||
BitField<22, 6, TextureQueryType> query_type;
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} txq;
|
||||
|
||||
union {
|
||||
BitField<28, 1, u64> array;
|
||||
BitField<29, 2, TextureType> texture_type;
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<35, 1, u64> ndv_flag;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ull << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return (ndv_flag != 0);
|
||||
case TextureMiscMode::NODEP:
|
||||
return (nodep_flag != 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tmml;
|
||||
|
||||
union {
|
||||
BitField<28, 1, u64> array;
|
||||
BitField<29, 2, TextureType> texture_type;
|
||||
BitField<35, 1, u64> ndv_flag;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 1, u64> dc_flag;
|
||||
BitField<54, 2, u64> info;
|
||||
BitField<56, 2, u64> component;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return ndv_flag != 0;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
case TextureMiscMode::AOFFI:
|
||||
return info == 1;
|
||||
case TextureMiscMode::PTP:
|
||||
return info == 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tld4;
|
||||
|
||||
union {
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<50, 1, u64> dc_flag;
|
||||
BitField<51, 1, u64> aoffi_flag;
|
||||
BitField<52, 2, u64> component;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
case TextureMiscMode::AOFFI:
|
||||
return aoffi_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} tld4s;
|
||||
|
||||
union {
|
||||
BitField<0, 8, Register> gpr0;
|
||||
BitField<28, 8, Register> gpr28;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<49, 1, u64> nodep;
|
||||
BitField<50, 3, u64> component_mask_selector;
|
||||
BitField<53, 4, u64> texture_info;
|
||||
|
||||
@@ -794,37 +645,6 @@ union Instruction {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
switch (texture_info) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 6:
|
||||
case 8:
|
||||
case 9:
|
||||
case 11:
|
||||
return TextureProcessMode::LZ;
|
||||
case 3:
|
||||
case 5:
|
||||
case 13:
|
||||
return TextureProcessMode::LL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TextureProcessMode::None;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return (texture_info >= 4 && texture_info <= 6) || texture_info == 9;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsArrayTexture() const {
|
||||
// TEXS only supports Texture2D arrays.
|
||||
return texture_info >= 7 && texture_info <= 9;
|
||||
@@ -853,7 +673,6 @@ union Instruction {
|
||||
} texs;
|
||||
|
||||
union {
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
BitField<53, 4, u64> texture_info;
|
||||
|
||||
TextureType GetTextureType() const {
|
||||
@@ -874,26 +693,6 @@ union Instruction {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
if (texture_info == 1 || texture_info == 5 || texture_info == 12)
|
||||
return TextureProcessMode::LL;
|
||||
return TextureProcessMode::LZ;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::AOFFI:
|
||||
return texture_info == 12 || texture_info == 4;
|
||||
case TextureMiscMode::MZ:
|
||||
return texture_info == 5;
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsArrayTexture() const {
|
||||
// TEXS only supports Texture2D arrays.
|
||||
return texture_info == 8;
|
||||
@@ -936,7 +735,6 @@ union Instruction {
|
||||
BitField<36, 5, u64> index;
|
||||
} cbuf36;
|
||||
|
||||
BitField<47, 1, u64> generates_cc;
|
||||
BitField<61, 1, u64> is_b_imm;
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
@@ -1061,7 +859,6 @@ public:
|
||||
ISET_IMM,
|
||||
PSETP,
|
||||
PSET,
|
||||
CSETP,
|
||||
XMAD_IMM,
|
||||
XMAD_CR,
|
||||
XMAD_RC,
|
||||
@@ -1298,7 +1095,6 @@ private:
|
||||
INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
|
||||
INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
|
||||
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
|
||||
INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
|
||||
INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
|
||||
INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
|
||||
INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
|
||||
|
||||
@@ -383,7 +383,7 @@ void RasterizerOpenGL::Clear() {
|
||||
bool use_stencil{};
|
||||
|
||||
OpenGLState clear_state;
|
||||
clear_state.draw.draw_framebuffer = framebuffer.handle;
|
||||
clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer;
|
||||
clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
|
||||
@@ -484,13 +484,8 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
GLintptr index_buffer_offset = 0;
|
||||
if (is_indexed) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Index);
|
||||
|
||||
// Adjust the index buffer offset so it points to the first desired index.
|
||||
auto index_start = regs.index_array.StartAddress();
|
||||
index_start += static_cast<size_t>(regs.index_array.first) *
|
||||
static_cast<size_t>(regs.index_array.FormatSizeInBytes());
|
||||
|
||||
index_buffer_offset = buffer_cache.UploadMemory(index_start, index_buffer_size);
|
||||
index_buffer_offset =
|
||||
buffer_cache.UploadMemory(regs.index_array.StartAddress(), index_buffer_size);
|
||||
}
|
||||
|
||||
SetupShaders();
|
||||
@@ -504,6 +499,10 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
if (is_indexed) {
|
||||
const GLint base_vertex{static_cast<GLint>(regs.vb_element_base)};
|
||||
|
||||
// Adjust the index buffer offset so it points to the first desired index.
|
||||
index_buffer_offset += static_cast<GLintptr>(regs.index_array.first) *
|
||||
static_cast<GLintptr>(regs.index_array.FormatSizeInBytes());
|
||||
|
||||
if (gpu.state.current_instance > 0) {
|
||||
glDrawElementsInstancedBaseVertexBaseInstance(
|
||||
primitive_mode, regs.index_array.count,
|
||||
|
||||
@@ -141,8 +141,8 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
|
||||
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // BC7U
|
||||
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8,
|
||||
ComponentType::Float, true}, // BC6H_UF16
|
||||
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
ComponentType::UNorm, true}, // BC6H_UF16
|
||||
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // BC6H_SF16
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
|
||||
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
|
||||
@@ -501,9 +501,6 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr,
|
||||
SurfaceParams::SurfaceTargetName(params.target));
|
||||
}
|
||||
|
||||
static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
|
||||
|
||||
@@ -137,27 +137,6 @@ struct SurfaceParams {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string SurfaceTargetName(SurfaceTarget target) {
|
||||
switch (target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
return "Texture1D";
|
||||
case SurfaceTarget::Texture2D:
|
||||
return "Texture2D";
|
||||
case SurfaceTarget::Texture3D:
|
||||
return "Texture3D";
|
||||
case SurfaceTarget::Texture1DArray:
|
||||
return "Texture1DArray";
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
return "Texture2DArray";
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
return "TextureCubemap";
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
return fmt::format("TextureUnknown({})", static_cast<u32>(target));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
||||
* "compressed width" and "compressed height", not the overall compression factor of a
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
#include "video_core/utils.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
@@ -84,7 +83,6 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
|
||||
shader.Create(program_result.first.c_str(), gl_type);
|
||||
program.Create(true, shader.handle);
|
||||
SetShaderUniformBlockBindings(program.handle);
|
||||
VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr);
|
||||
}
|
||||
|
||||
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
|
||||
|
||||
@@ -236,14 +236,6 @@ private:
|
||||
const std::string& suffix;
|
||||
};
|
||||
|
||||
enum class InternalFlag : u64 {
|
||||
ZeroFlag = 0,
|
||||
CarryFlag = 1,
|
||||
OverflowFlag = 2,
|
||||
NaNFlag = 3,
|
||||
Amount
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
|
||||
* of all registers (e.g. whether they are currently being used as Floats or Integers), and
|
||||
@@ -337,19 +329,13 @@ public:
|
||||
void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
|
||||
const std::string& value, u64 dest_num_components,
|
||||
u64 value_num_components, bool is_saturated = false,
|
||||
u64 dest_elem = 0, Register::Size size = Register::Size::Word,
|
||||
bool sets_cc = false) {
|
||||
u64 dest_elem = 0, Register::Size size = Register::Size::Word) {
|
||||
ASSERT_MSG(!is_saturated, "Unimplemented");
|
||||
|
||||
const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};
|
||||
|
||||
SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')',
|
||||
dest_num_components, value_num_components, dest_elem);
|
||||
|
||||
if (sets_cc) {
|
||||
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
|
||||
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,26 +352,6 @@ public:
|
||||
shader.AddLine(dest + " = " + src + ';');
|
||||
}
|
||||
|
||||
std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
|
||||
switch (cc) {
|
||||
case Tegra::Shader::ControlCode::NEU:
|
||||
return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetInternalFlag(const InternalFlag ii) const {
|
||||
const u32 code = static_cast<u32>(ii);
|
||||
return "internalFlag_" + std::to_string(code) + suffix;
|
||||
}
|
||||
|
||||
void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
|
||||
shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes code that does a output attribute assignment to register operation. Output attributes
|
||||
* are stored as floats, so this may require conversion.
|
||||
@@ -449,12 +415,6 @@ public:
|
||||
}
|
||||
declarations.AddNewLine();
|
||||
|
||||
for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
|
||||
const InternalFlag code = static_cast<InternalFlag>(ii);
|
||||
declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
|
||||
}
|
||||
declarations.AddNewLine();
|
||||
|
||||
for (const auto element : declr_input_attribute) {
|
||||
// TODO(bunnei): Use proper number of elements for these
|
||||
u32 idx =
|
||||
@@ -978,6 +938,8 @@ private:
|
||||
// TEXS has two destination registers and a swizzle. The first two elements in the swizzle
|
||||
// go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
|
||||
|
||||
ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented");
|
||||
|
||||
std::size_t written_components = 0;
|
||||
for (u32 component = 0; component < 4; ++component) {
|
||||
if (!instr.texs.IsComponentEnabled(component)) {
|
||||
@@ -1660,8 +1622,7 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
|
||||
1, instr.alu.saturate_d, 0, instr.conversion.dest_size,
|
||||
instr.generates_cc.Value() != 0);
|
||||
1, instr.alu.saturate_d, 0, instr.conversion.dest_size);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::I2F_R:
|
||||
@@ -1800,8 +1761,8 @@ private:
|
||||
Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective,
|
||||
Tegra::Shader::IpaSampleMode::Default};
|
||||
|
||||
u64 next_element = instr.attribute.fmt20.element;
|
||||
u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
|
||||
u32 next_element = instr.attribute.fmt20.element;
|
||||
u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
|
||||
|
||||
const auto LoadNextElement = [&](u32 reg_offset) {
|
||||
regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element,
|
||||
@@ -1865,8 +1826,8 @@ private:
|
||||
ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
|
||||
"Unaligned attribute loads are not supported");
|
||||
|
||||
u64 next_element = instr.attribute.fmt20.element;
|
||||
u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
|
||||
u32 next_element = instr.attribute.fmt20.element;
|
||||
u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
|
||||
|
||||
const auto StoreNextElement = [&](u32 reg_offset) {
|
||||
regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index),
|
||||
@@ -1892,13 +1853,6 @@ private:
|
||||
Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
|
||||
std::string coord;
|
||||
|
||||
ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
|
||||
switch (texture_type) {
|
||||
case Tegra::Shader::TextureType::Texture1D: {
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
@@ -1981,11 +1935,6 @@ private:
|
||||
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
|
||||
bool is_array{instr.texs.IsArrayTexture()};
|
||||
|
||||
ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
|
||||
switch (texture_type) {
|
||||
case Tegra::Shader::TextureType::Texture2D: {
|
||||
if (is_array) {
|
||||
@@ -2022,13 +1971,6 @@ private:
|
||||
ASSERT(instr.tlds.IsArrayTexture() == false);
|
||||
std::string coord;
|
||||
|
||||
ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ),
|
||||
"MZ is not implemented");
|
||||
|
||||
switch (instr.tlds.GetTextureType()) {
|
||||
case Tegra::Shader::TextureType::Texture2D: {
|
||||
if (instr.tlds.IsArrayTexture()) {
|
||||
@@ -2057,17 +1999,6 @@ private:
|
||||
ASSERT(instr.tld4.array == 0);
|
||||
std::string coord;
|
||||
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
|
||||
"NDV is not implemented");
|
||||
ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP),
|
||||
"PTP is not implemented");
|
||||
|
||||
switch (instr.tld4.texture_type) {
|
||||
case Tegra::Shader::TextureType::Texture2D: {
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
@@ -2105,13 +2036,6 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TLD4S: {
|
||||
ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
|
||||
"AOFFI is not implemented");
|
||||
ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC),
|
||||
"DC is not implemented");
|
||||
|
||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
|
||||
@@ -2124,9 +2048,6 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TXQ: {
|
||||
ASSERT_MSG(!instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
|
||||
// TODO: the new commits on the texture refactor, change the way samplers work.
|
||||
// Sadly, not all texture instructions specify the type of texture their sampler
|
||||
// uses. This must be fixed at a later instance.
|
||||
@@ -2147,11 +2068,6 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TMML: {
|
||||
ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
|
||||
"NODEP is not implemented");
|
||||
ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
|
||||
"NDV is not implemented");
|
||||
|
||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||
const bool is_array = instr.tmml.array != 0;
|
||||
@@ -2318,55 +2234,31 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::PredicateSetPredicate: {
|
||||
switch (opcode->GetId()) {
|
||||
case OpCode::Id::PSETP: {
|
||||
const std::string op_a =
|
||||
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
|
||||
const std::string op_b =
|
||||
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
||||
const std::string op_a =
|
||||
GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
|
||||
const std::string op_b =
|
||||
GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
|
||||
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
// We can't use the constant predicate as destination.
|
||||
ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
|
||||
|
||||
const std::string second_pred =
|
||||
GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
|
||||
const std::string second_pred =
|
||||
GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
|
||||
|
||||
const std::string combiner = GetPredicateCombiner(instr.psetp.op);
|
||||
const std::string combiner = GetPredicateCombiner(instr.psetp.op);
|
||||
|
||||
const std::string predicate =
|
||||
'(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
|
||||
const std::string predicate =
|
||||
'(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
|
||||
|
||||
// Set the primary predicate to the result of Predicate OP SecondPredicate
|
||||
SetPredicate(instr.psetp.pred3,
|
||||
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
// Set the primary predicate to the result of Predicate OP SecondPredicate
|
||||
SetPredicate(instr.psetp.pred3,
|
||||
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
|
||||
if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
||||
// if enabled
|
||||
SetPredicate(instr.psetp.pred0,
|
||||
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::CSETP: {
|
||||
const std::string pred =
|
||||
GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
|
||||
const std::string combiner = GetPredicateCombiner(instr.csetp.op);
|
||||
const std::string controlCode = regs.GetControlCode(instr.csetp.cc);
|
||||
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
SetPredicate(instr.csetp.pred3,
|
||||
'(' + controlCode + ") " + combiner + " (" + pred + ')');
|
||||
}
|
||||
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
SetPredicate(instr.csetp.pred0,
|
||||
"!(" + controlCode + ") " + combiner + " (" + pred + ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName());
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
||||
// if enabled
|
||||
SetPredicate(instr.psetp.pred0,
|
||||
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <iterator>
|
||||
#include <glad/glad.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
#include <array>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
using Regs = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
namespace TextureUnits {
|
||||
|
||||
struct TextureUnit {
|
||||
|
||||
@@ -74,7 +74,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidate || !persistent) {
|
||||
if (invalidate | !persistent) {
|
||||
GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
|
||||
(coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
|
||||
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
|
||||
@@ -161,26 +161,4 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe
|
||||
}
|
||||
}
|
||||
|
||||
static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr,
|
||||
std::string extra_info = "") {
|
||||
if (!GLAD_GL_KHR_debug) {
|
||||
return; // We don't need to throw an error as this is just for debugging
|
||||
}
|
||||
const std::string nice_addr = fmt::format("0x{:016x}", addr);
|
||||
std::string object_label;
|
||||
|
||||
switch (identifier) {
|
||||
case GL_TEXTURE:
|
||||
object_label = extra_info + "@" + nice_addr;
|
||||
break;
|
||||
case GL_PROGRAM:
|
||||
object_label = "ShaderProgram@" + nice_addr;
|
||||
break;
|
||||
default:
|
||||
object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
|
||||
break;
|
||||
}
|
||||
glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
|
||||
}
|
||||
|
||||
} // namespace VideoCore
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
WaitTreeItem::WaitTreeItem() = default;
|
||||
WaitTreeItem::~WaitTreeItem() = default;
|
||||
|
||||
@@ -89,7 +89,15 @@ bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* e
|
||||
}
|
||||
|
||||
void GameList::SearchField::setFilterResult(int visible, int total) {
|
||||
label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
|
||||
QString result_of_text = tr("of");
|
||||
QString result_text;
|
||||
if (total == 1) {
|
||||
result_text = tr("result");
|
||||
} else {
|
||||
result_text = tr("results");
|
||||
}
|
||||
label_filter_result->setText(
|
||||
QString("%1 %2 %3 %4").arg(visible).arg(result_of_text).arg(total).arg(result_text));
|
||||
}
|
||||
|
||||
void GameList::SearchField::clear() {
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
|
||||
picture = GetDefaultIcon(size);
|
||||
}
|
||||
picture = picture.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
picture = picture.scaled(size, size);
|
||||
|
||||
setData(picture, Qt::DecorationRole);
|
||||
}
|
||||
|
||||
@@ -120,15 +120,11 @@ void Config::ReadValues() {
|
||||
sdl2_config->Get("Data Storage", "nand_directory",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
|
||||
sdl2_config->Get("Data Storage", "sdmc_directory",
|
||||
sdl2_config->Get("Data Storage", "nand_directory",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
|
||||
|
||||
// System
|
||||
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
|
||||
Settings::values.username = sdl2_config->Get("System", "username", "yuzu");
|
||||
if (Settings::values.username.empty()) {
|
||||
Settings::values.username = "yuzu";
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
|
||||
|
||||
@@ -176,7 +176,7 @@ use_docked_mode =
|
||||
|
||||
# Sets the account username, max length is 32 characters
|
||||
# yuzu (default)
|
||||
username = yuzu
|
||||
username =
|
||||
|
||||
# Sets the systems language index
|
||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
|
||||
|
||||
@@ -20,10 +20,8 @@
|
||||
#include "common/string_util.h"
|
||||
#include "common/telemetry.h"
|
||||
#include "core/core.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/settings.h"
|
||||
#include "core/telemetry_session.h"
|
||||
@@ -31,6 +29,7 @@
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include "core/crypto/key_manager.h"
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -170,7 +169,6 @@ int main(int argc, char** argv) {
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||
Service::FileSystem::CreateFactories(system.GetFilesystem());
|
||||
|
||||
SCOPE_EXIT({ system.Shutdown(); });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user