Compare commits

..

3 Commits

Author SHA1 Message Date
99c777a17b Android #159 2023-12-13 00:57:15 +00:00
cc0b79270e Merge PR 12335 2023-12-13 00:57:15 +00:00
a5bfa8e00f Merge PR 12237 2023-12-13 00:57:15 +00:00
175 changed files with 2178 additions and 5347 deletions

View File

@ -79,8 +79,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Install dependencies - name: Install dependencies
run: | run: |
# workaround for https://github.com/actions/setup-python/issues/577 brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd
brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd || brew link --overwrite python@3.12
- name: Build - name: Build
run: | run: |
mkdir build mkdir build

View File

@ -142,9 +142,6 @@ if (YUZU_USE_BUNDLED_VCPKG)
if (ENABLE_WEB_SERVICE) if (ENABLE_WEB_SERVICE)
list(APPEND VCPKG_MANIFEST_FEATURES "web-service") list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
endif() endif()
if (ANDROID)
list(APPEND VCPKG_MANIFEST_FEATURES "android")
endif()
include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake) include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "") elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")
@ -305,7 +302,7 @@ find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED) find_package(zstd 1.5 REQUIRED)
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
find_package(Vulkan 1.3.274 REQUIRED) find_package(Vulkan 1.3.256 REQUIRED)
endif() endif()
if (ENABLE_LIBUSB) if (ENABLE_LIBUSB)

View File

@ -1,5 +1,7 @@
| Pull Request | Commit | Title | Author | Merged? | | Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----| |----|----|----|----|----|
| [12237](https://github.com/yuzu-emu/yuzu//pull/12237) | [`a05c24242`](https://github.com/yuzu-emu/yuzu//pull/12237/files) | nce: implement instruction emulation for misaligned memory accesses | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12335](https://github.com/yuzu-emu/yuzu//pull/12335) | [`86d26914a`](https://github.com/yuzu-emu/yuzu//pull/12335/files) | android: Game Properties | [t895](https://github.com/t895/) | Yes |
End of merge log. You can find the original README.md below the break. End of merge log. You can find the original README.md below the break.

View File

@ -91,20 +91,18 @@ class GamesFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.apply { viewLifecycleOwner.lifecycleScope.apply {
launch { launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.isReloading.collect { gamesViewModel.isReloading.collect { binding.swipeRefresh.isRefreshing = it }
binding.swipeRefresh.isRefreshing = it
if (gamesViewModel.games.value.isEmpty() && !it) {
binding.noticeText.visibility = View.VISIBLE
} else {
binding.noticeText.visibility = View.INVISIBLE
}
}
} }
} }
launch { launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.games.collectLatest { gamesViewModel.games.collectLatest {
(binding.gridGames.adapter as GameAdapter).submitList(it) (binding.gridGames.adapter as GameAdapter).submitList(it)
if (it.isEmpty()) {
binding.noticeText.visibility = View.VISIBLE
} else {
binding.noticeText.visibility = View.GONE
}
} }
} }
} }

View File

@ -256,13 +256,11 @@
<string-array name="outputEngineEntries"> <string-array name="outputEngineEntries">
<item>@string/auto</item> <item>@string/auto</item>
<item>@string/oboe</item>
<item>@string/cubeb</item> <item>@string/cubeb</item>
<item>@string/string_null</item> <item>@string/string_null</item>
</string-array> </string-array>
<integer-array name="outputEngineValues"> <integer-array name="outputEngineValues">
<item>0</item> <item>0</item>
<item>4</item>
<item>1</item> <item>1</item>
<item>3</item> <item>3</item>
</integer-array> </integer-array>

View File

@ -503,7 +503,6 @@
<string name="theme_mode_dark">Dark</string> <string name="theme_mode_dark">Dark</string>
<!-- Audio output engines --> <!-- Audio output engines -->
<string name="oboe">oboe</string>
<string name="cubeb">cubeb</string> <string name="cubeb">cubeb</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->

View File

@ -253,17 +253,6 @@ if (ENABLE_SDL2)
target_compile_definitions(audio_core PRIVATE HAVE_SDL2) target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
endif() endif()
if (ANDROID)
target_sources(audio_core PRIVATE
sink/oboe_sink.cpp
sink/oboe_sink.h
)
# FIXME: this port seems broken, it cannot be imported with find_package(oboe REQUIRED)
target_link_libraries(audio_core PRIVATE "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/liboboe.a")
target_compile_definitions(audio_core PRIVATE HAVE_OBOE)
endif()
if (YUZU_USE_PRECOMPILED_HEADERS) if (YUZU_USE_PRECOMPILED_HEADERS)
target_precompile_headers(audio_core PRIVATE precompiled_headers.h) target_precompile_headers(audio_core PRIVATE precompiled_headers.h)
endif() endif()

View File

@ -253,9 +253,8 @@ CubebSink::~CubebSink() {
#endif #endif
} }
SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels_, SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) { const std::string& name, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>( SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>(
ctx, device_channels, system_channels, output_device, input_device, name, type, system)); ctx, device_channels, system_channels, output_device, input_device, name, type, system));

View File

@ -1,223 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <span>
#include <vector>
#include <oboe/Oboe.h>
#include "audio_core/common/common.h"
#include "audio_core/sink/oboe_sink.h"
#include "audio_core/sink/sink_stream.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "core/core.h"
namespace AudioCore::Sink {
class OboeSinkStream final : public SinkStream,
public oboe::AudioStreamDataCallback,
public oboe::AudioStreamErrorCallback {
public:
explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
u32 system_channels_)
: SinkStream(system_, type_) {
name = name_;
system_channels = system_channels_;
this->OpenStream();
}
~OboeSinkStream() override {
LOG_INFO(Audio_Sink, "Destroyed Oboe stream");
}
void Finalize() override {
this->Stop();
m_stream.reset();
}
void Start(bool resume = false) override {
if (!m_stream || !paused) {
return;
}
paused = false;
if (m_stream->start() != oboe::Result::OK) {
LOG_CRITICAL(Audio_Sink, "Error starting Oboe stream");
}
}
void Stop() override {
if (!m_stream || paused) {
return;
}
this->SignalPause();
if (m_stream->stop() != oboe::Result::OK) {
LOG_CRITICAL(Audio_Sink, "Error stopping Oboe stream");
}
}
public:
static s32 QueryChannelCount(oboe::Direction direction) {
std::shared_ptr<oboe::AudioStream> temp_stream;
oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
ASSERT(result == oboe::Result::OK);
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
}
protected:
oboe::DataCallbackResult onAudioReady(oboe::AudioStream*, void* audio_data,
s32 num_buffer_frames) override {
const size_t num_channels = this->GetDeviceChannels();
const size_t frame_size = num_channels;
const size_t num_frames = static_cast<size_t>(num_buffer_frames);
if (type == StreamType::In) {
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(audio_data),
num_frames * frame_size};
this->ProcessAudioIn(input_buffer, num_frames);
} else {
std::span<s16> output_buffer{reinterpret_cast<s16*>(audio_data),
num_frames * frame_size};
this->ProcessAudioOutAndRender(output_buffer, num_frames);
}
return oboe::DataCallbackResult::Continue;
}
void onErrorAfterClose(oboe::AudioStream*, oboe::Result) override {
LOG_INFO(Audio_Sink, "Audio stream closed, reinitializing");
if (this->OpenStream()) {
m_stream->start();
}
}
private:
static oboe::AudioStreamBuilder* ConfigureBuilder(oboe::AudioStreamBuilder& builder,
oboe::Direction direction) {
// TODO: investigate callback delay issues when using AAudio
return builder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
->setAudioApi(oboe::AudioApi::OpenSLES)
->setDirection(direction)
->setSampleRate(TargetSampleRate)
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
->setFormat(oboe::AudioFormat::I16)
->setFormatConversionAllowed(true)
->setUsage(oboe::Usage::Game)
->setBufferCapacityInFrames(TargetSampleCount * 2);
}
bool OpenStream() {
const auto direction = [&]() {
switch (type) {
case StreamType::In:
return oboe::Direction::Input;
case StreamType::Out:
case StreamType::Render:
return oboe::Direction::Output;
default:
ASSERT(false);
return oboe::Direction::Output;
}
}();
const auto expected_channels = QueryChannelCount(direction);
const auto expected_mask = [&]() {
switch (expected_channels) {
case 1:
return oboe::ChannelMask::Mono;
case 2:
return oboe::ChannelMask::Stereo;
case 6:
return oboe::ChannelMask::CM5Point1;
default:
ASSERT(false);
return oboe::ChannelMask::Unspecified;
}
}();
oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)
->setChannelCount(expected_channels)
->setChannelMask(expected_mask)
->setChannelConversionAllowed(true)
->setDataCallback(this)
->setErrorCallback(this)
->openStream(m_stream);
ASSERT(result == oboe::Result::OK);
return result == oboe::Result::OK && this->SetStreamProperties();
}
bool SetStreamProperties() {
ASSERT(m_stream);
m_stream->setBufferSizeInFrames(TargetSampleCount * 2);
device_channels = m_stream->getChannelCount();
const auto sample_rate = m_stream->getSampleRate();
const auto buffer_capacity = m_stream->getBufferCapacityInFrames();
const auto stream_backend =
m_stream->getAudioApi() == oboe::AudioApi::AAudio ? "AAudio" : "OpenSLES";
LOG_INFO(Audio_Sink, "Opened Oboe {} stream with {} channels sample rate {} capacity {}",
stream_backend, device_channels, sample_rate, buffer_capacity);
return true;
}
std::shared_ptr<oboe::AudioStream> m_stream{};
};
OboeSink::OboeSink() {
// TODO: This is not generally knowable
// The channel count is distinct based on direction and can change
device_channels = OboeSinkStream::QueryChannelCount(oboe::Direction::Output);
}
OboeSink::~OboeSink() = default;
SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) {
SinkStreamPtr& stream = sink_streams.emplace_back(
std::make_unique<OboeSinkStream>(system, type, name, system_channels));
return stream.get();
}
void OboeSink::CloseStream(SinkStream* to_remove) {
sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
}
void OboeSink::CloseStreams() {
sink_streams.clear();
}
f32 OboeSink::GetDeviceVolume() const {
if (sink_streams.empty()) {
return 1.0f;
}
return sink_streams.front()->GetDeviceVolume();
}
void OboeSink::SetDeviceVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetDeviceVolume(volume);
}
}
void OboeSink::SetSystemVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetSystemVolume(volume);
}
}
} // namespace AudioCore::Sink

View File

@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <list>
#include <string>
#include "audio_core/sink/sink.h"
namespace Core {
class System;
}
namespace AudioCore::Sink {
class SinkStream;
class OboeSink final : public Sink {
public:
explicit OboeSink();
~OboeSink() override;
/**
* Create a new sink stream.
*
* @param system - Core system.
* @param system_channels - Number of channels the audio system expects.
* May differ from the device's channel count.
* @param name - Name of this stream.
* @param type - Type of this stream, render/in/out.
*
* @return A pointer to the created SinkStream
*/
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) override;
/**
* Close a given stream.
*
* @param stream - The stream to close.
*/
void CloseStream(SinkStream* stream) override;
/**
* Close all streams.
*/
void CloseStreams() override;
/**
* Get the device volume. Set from calls to the IAudioDevice service.
*
* @return Volume of the device.
*/
f32 GetDeviceVolume() const override;
/**
* Set the device volume. Set from calls to the IAudioDevice service.
*
* @param volume - New volume of the device.
*/
void SetDeviceVolume(f32 volume) override;
/**
* Set the system volume. Comes from the audio system using this stream.
*
* @param volume - New volume of the system.
*/
void SetSystemVolume(f32 volume) override;
private:
/// List of streams managed by this sink
std::list<SinkStreamPtr> sink_streams{};
};
} // namespace AudioCore::Sink

View File

@ -168,9 +168,8 @@ SDLSink::SDLSink(std::string_view target_device_name) {
SDLSink::~SDLSink() = default; SDLSink::~SDLSink() = default;
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_, SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string&, StreamType type) { const std::string&, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>( SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(
device_channels, system_channels, output_device, input_device, type, system)); device_channels, system_channels, output_device, input_device, type, system));
return stream.get(); return stream.get();

View File

@ -85,21 +85,9 @@ public:
*/ */
virtual void SetSystemVolume(f32 volume) = 0; virtual void SetSystemVolume(f32 volume) = 0;
/**
* Get the number of channels the game has set, can be different to the host hardware's support.
* Either 2 or 6.
*
* @return Number of device channels.
*/
u32 GetSystemChannels() const {
return system_channels;
}
protected: protected:
/// Number of device channels supported by the hardware /// Number of device channels supported by the hardware
u32 device_channels{2}; u32 device_channels{2};
/// Number of channels the game is sending
u32 system_channels{2};
}; };
using SinkPtr = std::unique_ptr<Sink>; using SinkPtr = std::unique_ptr<Sink>;

View File

@ -7,9 +7,6 @@
#include <vector> #include <vector>
#include "audio_core/sink/sink_details.h" #include "audio_core/sink/sink_details.h"
#ifdef HAVE_OBOE
#include "audio_core/sink/oboe_sink.h"
#endif
#ifdef HAVE_CUBEB #ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h" #include "audio_core/sink/cubeb_sink.h"
#endif #endif
@ -39,16 +36,6 @@ struct SinkDetails {
// sink_details is ordered in terms of desirability, with the best choice at the top. // sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = { constexpr SinkDetails sink_details[] = {
#ifdef HAVE_OBOE
SinkDetails{
Settings::AudioEngine::Oboe,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<OboeSink>();
},
[](bool capture) { return std::vector<std::string>{"Default"}; },
[]() { return true; },
},
#endif
#ifdef HAVE_CUBEB #ifdef HAVE_CUBEB
SinkDetails{ SinkDetails{
Settings::AudioEngine::Cubeb, Settings::AudioEngine::Cubeb,

View File

@ -40,36 +40,29 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
if (system_channels == 6 && device_channels == 2) { if (system_channels == 6 && device_channels == 2) {
// We're given 6 channels, but our device only outputs 2, so downmix. // We're given 6 channels, but our device only outputs 2, so downmix.
// Front = 1.0 static constexpr std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f};
// Center = 0.596
// LFE = 0.354
// Back = 0.707
static constexpr std::array<f32, 4> down_mix_coeff{1.0, 0.596f, 0.354f, 0.707f};
for (u32 read_index = 0, write_index = 0; read_index < samples.size(); for (u32 read_index = 0, write_index = 0; read_index < samples.size();
read_index += system_channels, write_index += device_channels) { read_index += system_channels, write_index += device_channels) {
const auto fl =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::FrontLeft)]);
const auto fr =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::FrontRight)]);
const auto c =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::Center)]);
const auto lfe =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::LFE)]);
const auto bl =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::BackLeft)]);
const auto br =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::BackRight)]);
const auto left_sample{ const auto left_sample{
static_cast<s32>((fl * down_mix_coeff[0] + c * down_mix_coeff[1] + ((Common::FixedPoint<49, 15>(
lfe * down_mix_coeff[2] + bl * down_mix_coeff[3]) * samples[read_index + static_cast<u32>(Channels::FrontLeft)]) *
volume)}; down_mix_coeff[0] +
samples[read_index + static_cast<u32>(Channels::Center)] * down_mix_coeff[1] +
samples[read_index + static_cast<u32>(Channels::LFE)] * down_mix_coeff[2] +
samples[read_index + static_cast<u32>(Channels::BackLeft)] * down_mix_coeff[3]) *
volume)
.to_int()};
const auto right_sample{ const auto right_sample{
static_cast<s32>((fr * down_mix_coeff[0] + c * down_mix_coeff[1] + ((Common::FixedPoint<49, 15>(
lfe * down_mix_coeff[2] + br * down_mix_coeff[3]) * samples[read_index + static_cast<u32>(Channels::FrontRight)]) *
volume)}; down_mix_coeff[0] +
samples[read_index + static_cast<u32>(Channels::Center)] * down_mix_coeff[1] +
samples[read_index + static_cast<u32>(Channels::LFE)] * down_mix_coeff[2] +
samples[read_index + static_cast<u32>(Channels::BackRight)] * down_mix_coeff[3]) *
volume)
.to_int()};
samples[write_index + static_cast<u32>(Channels::FrontLeft)] = samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
static_cast<s16>(std::clamp(left_sample, min, max)); static_cast<s16>(std::clamp(left_sample, min, max));

View File

@ -123,12 +123,6 @@ namespace Common {
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24; return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
} }
[[nodiscard]] constexpr u64 MakeMagic(char a, char b, char c, char d, char e, char f, char g,
char h) {
return u64(a) << 0 | u64(b) << 8 | u64(c) << 16 | u64(d) << 24 | u64(e) << 32 | u64(f) << 40 |
u64(g) << 48 | u64(h) << 56;
}
// std::size() does not support zero-size C arrays. We're fixing that. // std::size() does not support zero-size C arrays. We're fixing that.
template <class C> template <class C>
constexpr auto Size(const C& c) -> decltype(c.size()) { constexpr auto Size(const C& c) -> decltype(c.size()) {

View File

@ -354,36 +354,18 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
return path; return path;
} }
template <typename F> std::vector<std::string> SplitPathComponents(std::string_view filename) {
static void ForEachPathComponent(std::string_view filename, F&& cb) { std::string copy(filename);
const char* component_begin = filename.data(); std::replace(copy.begin(), copy.end(), '\\', '/');
const char* const end = component_begin + filename.size(); std::vector<std::string> out;
for (const char* it = component_begin; it != end; ++it) {
const char c = *it;
if (c == '\\' || c == '/') {
if (component_begin != it) {
cb(std::string_view{component_begin, it});
}
component_begin = it + 1;
}
}
if (component_begin != end) {
cb(std::string_view{component_begin, end});
}
}
std::vector<std::string_view> SplitPathComponents(std::string_view filename) { std::stringstream stream(copy);
std::vector<std::string_view> components; std::string item;
ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); }); while (std::getline(stream, item, '/')) {
out.push_back(std::move(item));
}
return components; return out;
}
std::vector<std::string> SplitPathComponentsCopy(std::string_view filename) {
std::vector<std::string> components;
ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); });
return components;
} }
std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
@ -418,9 +400,9 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
return std::string(RemoveTrailingSlash(path)); return std::string(RemoveTrailingSlash(path));
} }
std::string GetParentPath(std::string_view path) { std::string_view GetParentPath(std::string_view path) {
if (path.empty()) { if (path.empty()) {
return std::string(path); return path;
} }
#ifdef ANDROID #ifdef ANDROID
@ -439,7 +421,7 @@ std::string GetParentPath(std::string_view path) {
name_index = std::max(name_bck_index, name_fwd_index); name_index = std::max(name_bck_index, name_fwd_index);
} }
return std::string(path.substr(0, name_index)); return path.substr(0, name_index);
} }
std::string_view GetPathWithoutTop(std::string_view path) { std::string_view GetPathWithoutTop(std::string_view path) {

View File

@ -289,11 +289,7 @@ enum class DirectorySeparator {
// Splits the path on '/' or '\' and put the components into a vector // Splits the path on '/' or '\' and put the components into a vector
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" } // i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
[[nodiscard]] std::vector<std::string_view> SplitPathComponents(std::string_view filename); [[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
// Splits the path on '/' or '\' and put the components into a vector
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
[[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename);
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows // depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
@ -302,7 +298,7 @@ enum class DirectorySeparator {
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
// Gets all of the text up to the last '/' or '\' in the path. // Gets all of the text up to the last '/' or '\' in the path.
[[nodiscard]] std::string GetParentPath(std::string_view path); [[nodiscard]] std::string_view GetParentPath(std::string_view path);
// Gets all of the text after the first '/' or '\' in the path. // Gets all of the text after the first '/' or '\' in the path.
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path); [[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);

View File

@ -11,6 +11,10 @@
#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
#ifdef ANDROID
#include <android/sharedmem.h>
#endif
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
@ -189,11 +193,6 @@ public:
} }
} }
bool ClearBackingRegion(size_t physical_offset, size_t length) {
// TODO: This does not seem to be possible on Windows.
return false;
}
void EnableDirectMappedAddress() { void EnableDirectMappedAddress() {
// TODO // TODO
UNREACHABLE(); UNREACHABLE();
@ -443,7 +442,9 @@ public:
} }
// Backing memory initialization // Backing memory initialization
#if defined(__FreeBSD__) && __FreeBSD__ < 13 #ifdef ANDROID
fd = ASharedMemory_create("HostMemory", backing_size);
#elif defined(__FreeBSD__) && __FreeBSD__ < 13
// XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
fd = shm_open(SHM_ANON, O_RDWR, 0600); fd = shm_open(SHM_ANON, O_RDWR, 0600);
#else #else
@ -454,6 +455,7 @@ public:
throw std::bad_alloc{}; throw std::bad_alloc{};
} }
#ifndef ANDROID
// Defined to extend the file with zeros // Defined to extend the file with zeros
int ret = ftruncate(fd, backing_size); int ret = ftruncate(fd, backing_size);
if (ret != 0) { if (ret != 0) {
@ -461,6 +463,7 @@ public:
strerror(errno)); strerror(errno));
throw std::bad_alloc{}; throw std::bad_alloc{};
} }
#endif
backing_base = static_cast<u8*>( backing_base = static_cast<u8*>(
mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
@ -549,19 +552,6 @@ public:
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
} }
bool ClearBackingRegion(size_t physical_offset, size_t length) {
#ifdef __linux__
// Set MADV_REMOVE on backing map to destroy it instantly.
// This also deletes the area from the backing file.
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
return true;
#else
return false;
#endif
}
void EnableDirectMappedAddress() { void EnableDirectMappedAddress() {
virtual_base = nullptr; virtual_base = nullptr;
} }
@ -633,10 +623,6 @@ public:
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {} void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
return false;
}
void EnableDirectMappedAddress() {} void EnableDirectMappedAddress() {}
u8* backing_base{nullptr}; u8* backing_base{nullptr};
@ -712,12 +698,6 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool w
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
} }
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
std::memset(backing_base + physical_offset, fill_value, length);
}
}
void HostMemory::EnableDirectMappedAddress() { void HostMemory::EnableDirectMappedAddress() {
if (impl) { if (impl) {
impl->EnableDirectMappedAddress(); impl->EnableDirectMappedAddress();

View File

@ -48,8 +48,6 @@ public:
void EnableDirectMappedAddress(); void EnableDirectMappedAddress();
void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value);
[[nodiscard]] u8* BackingBasePointer() noexcept { [[nodiscard]] u8* BackingBasePointer() noexcept {
return backing_base; return backing_base;
} }

View File

@ -82,15 +82,16 @@ enum class AudioEngine : u32 {
Cubeb, Cubeb,
Sdl2, Sdl2,
Null, Null,
Oboe,
}; };
template <> template <>
inline std::vector<std::pair<std::string, AudioEngine>> inline std::vector<std::pair<std::string, AudioEngine>>
EnumMetadata<AudioEngine>::Canonicalizations() { EnumMetadata<AudioEngine>::Canonicalizations() {
return { return {
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2}, {"auto", AudioEngine::Auto},
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe}, {"cubeb", AudioEngine::Cubeb},
{"sdl2", AudioEngine::Sdl2},
{"null", AudioEngine::Null},
}; };
} }

View File

@ -549,11 +549,6 @@ add_library(core STATIC
hle/service/hid/xcd.cpp hle/service/hid/xcd.cpp
hle/service/hid/xcd.h hle/service/hid/xcd.h
hle/service/hid/errors.h hle/service/hid/errors.h
hle/service/hid/controllers/types/debug_pad_types.h
hle/service/hid/controllers/types/keyboard_types.h
hle/service/hid/controllers/types/mouse_types.h
hle/service/hid/controllers/types/npad_types.h
hle/service/hid/controllers/types/touch_types.h
hle/service/hid/controllers/applet_resource.cpp hle/service/hid/controllers/applet_resource.cpp
hle/service/hid/controllers/applet_resource.h hle/service/hid/controllers/applet_resource.h
hle/service/hid/controllers/console_six_axis.cpp hle/service/hid/controllers/console_six_axis.cpp
@ -574,15 +569,14 @@ add_library(core STATIC
hle/service/hid/controllers/palma.h hle/service/hid/controllers/palma.h
hle/service/hid/controllers/seven_six_axis.cpp hle/service/hid/controllers/seven_six_axis.cpp
hle/service/hid/controllers/seven_six_axis.h hle/service/hid/controllers/seven_six_axis.h
hle/service/hid/controllers/shared_memory_format.h
hle/service/hid/controllers/shared_memory_holder.cpp
hle/service/hid/controllers/shared_memory_holder.h
hle/service/hid/controllers/six_axis.cpp hle/service/hid/controllers/six_axis.cpp
hle/service/hid/controllers/six_axis.h hle/service/hid/controllers/six_axis.h
hle/service/hid/controllers/stubbed.cpp hle/service/hid/controllers/stubbed.cpp
hle/service/hid/controllers/stubbed.h hle/service/hid/controllers/stubbed.h
hle/service/hid/controllers/touchscreen.cpp hle/service/hid/controllers/touchscreen.cpp
hle/service/hid/controllers/touchscreen.h hle/service/hid/controllers/touchscreen.h
hle/service/hid/controllers/xpad.cpp
hle/service/hid/controllers/xpad.h
hle/service/hid/hidbus/hidbus_base.cpp hle/service/hid/hidbus/hidbus_base.cpp
hle/service/hid/hidbus/hidbus_base.h hle/service/hid/hidbus/hidbus_base.h
hle/service/hid/hidbus/ringcon.cpp hle/service/hid/hidbus/ringcon.cpp
@ -790,12 +784,6 @@ add_library(core STATIC
hle/service/service.h hle/service/service.h
hle/service/set/set.cpp hle/service/set/set.cpp
hle/service/set/set.h hle/service/set/set.h
hle/service/set/appln_settings.cpp
hle/service/set/appln_settings.h
hle/service/set/device_settings.cpp
hle/service/set/device_settings.h
hle/service/set/private_settings.cpp
hle/service/set/private_settings.h
hle/service/set/set_cal.cpp hle/service/set/set_cal.cpp
hle/service/set/set_cal.h hle/service/set/set_cal.h
hle/service/set/set_fd.cpp hle/service/set/set_fd.cpp
@ -804,8 +792,6 @@ add_library(core STATIC
hle/service/set/set_sys.h hle/service/set/set_sys.h
hle/service/set/settings.cpp hle/service/set/settings.cpp
hle/service/set/settings.h hle/service/set/settings.h
hle/service/set/system_settings.cpp
hle/service/set/system_settings.h
hle/service/sm/sm.cpp hle/service/sm/sm.cpp
hle/service/sm/sm.h hle/service/sm/sm.h
hle/service/sm/sm_controller.cpp hle/service/sm/sm_controller.cpp

View File

@ -9,7 +9,7 @@
namespace Core { namespace Core {
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const { void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const {
Kernel::Svc::ThreadContext ctx; Kernel::Svc::ThreadContext ctx;
this->GetContext(ctx); this->GetContext(ctx);

View File

@ -95,7 +95,7 @@ public:
virtual void SignalInterrupt(Kernel::KThread* thread) = 0; virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
// Stack trace generation. // Stack trace generation.
void LogBacktrace(Kernel::KProcess* process) const; void LogBacktrace(const Kernel::KProcess* process) const;
// Debug functionality. // Debug functionality.
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;

View File

@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
0x7100000000ULL, 0x7100000000ULL,
}; };
void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) { void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
auto modules = FindModules(process); auto modules = FindModules(process);
const bool is_64 = process->Is64Bit(); const bool is_64 = process->Is64Bit();
@ -118,7 +118,7 @@ void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>
} }
} }
std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process, std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out; std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory(); auto& memory = process->GetMemory();
@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
return out; return out;
} }
std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process, std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out; std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory(); auto& memory = process->GetMemory();
@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
} // namespace } // namespace
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) { std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
auto* process = thread->GetOwnerProcess(); const auto* process = thread->GetOwnerProcess();
if (process->Is64Bit()) { if (process->Is64Bit()) {
return GetNameFromThreadType64(process->GetMemory(), *thread); return GetNameFromThreadType64(process->GetMemory(), *thread);
} else { } else {
@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
return cur_addr - 1; return cur_addr - 1;
} }
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) { Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
Loader::AppLoader::Modules modules; Loader::AppLoader::Modules modules;
auto& page_table = process->GetPageTable(); auto& page_table = process->GetPageTable();
@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
return modules; return modules;
} }
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) { Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) {
// Do we have any loaded executable sections? // Do we have any loaded executable sections?
auto modules = FindModules(process); auto modules = FindModules(process);
@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres
} }
} }
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process, std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
if (process->Is64Bit()) { if (process->Is64Bit()) {
return GetAArch64Backtrace(process, ctx); return GetAArch64Backtrace(process, ctx);

View File

@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
std::string_view GetThreadWaitReason(const Kernel::KThread* thread); std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
std::string GetThreadState(const Kernel::KThread* thread); std::string GetThreadState(const Kernel::KThread* thread);
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process); Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process);
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base); Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process); Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process);
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size); void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
@ -28,7 +28,7 @@ struct BacktraceEntry {
std::string name; std::string name;
}; };
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process, std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx); const Kernel::Svc::ThreadContext& ctx);
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread); std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);

View File

@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public: public:
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process) explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()), : m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled || m_check_memory_access{m_debugger_enabled ||
@ -169,7 +169,7 @@ public:
ArmDynarmic32& m_parent; ArmDynarmic32& m_parent;
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
Kernel::KProcess* m_process{}; const Kernel::KProcess* m_process{};
const bool m_debugger_enabled{}; const bool m_debugger_enabled{};
const bool m_check_memory_access{}; const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U; static constexpr u64 MinimumRunCycles = 10000U;
@ -370,7 +370,7 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context); this->SetContext(m_breakpoint_context);
} }
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process, ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)), m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),

View File

@ -20,7 +20,7 @@ class System;
class ArmDynarmic32 final : public ArmInterface { class ArmDynarmic32 final : public ArmInterface {
public: public:
ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process, ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic32() override; ~ArmDynarmic32() override;

View File

@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public: public:
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process) explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()), : m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled || m_check_memory_access{m_debugger_enabled ||
@ -216,7 +216,7 @@ public:
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
u64 m_tpidrro_el0{}; u64 m_tpidrro_el0{};
u64 m_tpidr_el0{}; u64 m_tpidr_el0{};
Kernel::KProcess* m_process{}; const Kernel::KProcess* m_process{};
const bool m_debugger_enabled{}; const bool m_debugger_enabled{};
const bool m_check_memory_access{}; const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U; static constexpr u64 MinimumRunCycles = 10000U;
@ -399,7 +399,7 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context); this->SetContext(m_breakpoint_context);
} }
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process, ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} { m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {

View File

@ -25,7 +25,7 @@ class System;
class ArmDynarmic64 final : public ArmInterface { class ArmDynarmic64 final : public ArmInterface {
public: public:
ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process, ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic64() override; ~ArmDynarmic64() override;

View File

@ -39,7 +39,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
} }
using namespace Common::Literals; using namespace Common::Literals;
constexpr u32 StackSize = 128_KiB; constexpr u32 StackSize = 32_KiB;
} // namespace } // namespace

View File

@ -5,6 +5,8 @@
#include "common/bit_cast.h" #include "common/bit_cast.h"
#include "core/arm/nce/interpreter_visitor.h" #include "core/arm/nce/interpreter_visitor.h"
#include <dynarmic/frontend/A64/decoder/a64.h>
namespace Core { namespace Core {
template <u32 BitSize> template <u32 BitSize>
@ -247,7 +249,6 @@ bool InterpreterVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
return false; return false;
} }
// Size in bytes
const u64 size = 4 << opc.ZeroExtend(); const u64 size = 4 << opc.ZeroExtend();
const u64 offset = imm19.SignExtend<u64>() << 2; const u64 offset = imm19.SignExtend<u64>() << 2;
const u64 address = this->GetPc() + offset; const u64 address = this->GetPc() + offset;
@ -529,7 +530,7 @@ bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale,
} }
case MemOp::Load: { case MemOp::Load: {
u128 data{}; u128 data{};
m_memory.ReadBlock(address, &data, datasize / 8); m_memory.ReadBlock(address, &data, datasize);
this->SetVec(Vt, data); this->SetVec(Vt, data);
break; break;
} }

View File

@ -4,15 +4,9 @@
#pragma once #pragma once
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#include <dynarmic/frontend/A64/a64_types.h> #include <dynarmic/frontend/A64/a64_types.h>
#include <dynarmic/frontend/A64/decoder/a64.h>
#include <dynarmic/frontend/imm.h> #include <dynarmic/frontend/imm.h>
#pragma GCC diagnostic pop
namespace Core { namespace Core {
class VisitorBase { class VisitorBase {

View File

@ -28,6 +28,7 @@
#include "core/file_sys/savedata_factory.h" #include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
@ -129,8 +130,11 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl { struct System::Impl {
explicit Impl(System& system) explicit Impl(System& system)
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {} cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
time_manager{system}, gpu_dirty_memory_write_manager{} {
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
}
void Initialize(System& system) { void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>(); device_memory = std::make_unique<Core::DeviceMemory>();
@ -237,17 +241,17 @@ struct System::Impl {
debugger = std::make_unique<Debugger>(system, port); debugger = std::make_unique<Debugger>(system, port);
} }
void InitializeKernel(System& system) { SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK"); LOG_DEBUG(Core, "initialized OK");
// Setting changes may require a full system reinitialization (e.g., disabling multicore). // Setting changes may require a full system reinitialization (e.g., disabling multicore).
ReinitializeIfNecessary(system); ReinitializeIfNecessary(system);
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
kernel.Initialize(); kernel.Initialize();
cpu_manager.Initialize(); cpu_manager.Initialize();
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
/// Reset all glue registrations /// Reset all glue registrations
arp_manager.ResetAll(); arp_manager.ResetAll();
@ -296,9 +300,17 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader; return SystemResultStatus::ErrorGetLoader;
} }
InitializeKernel(system); SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
// Create the application process. telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Create the process.
auto main_process = Kernel::KProcess::Create(system.Kernel()); auto main_process = Kernel::KProcess::Create(system.Kernel());
Kernel::KProcess::Register(system.Kernel(), main_process); Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.AppendNewProcess(main_process); kernel.AppendNewProcess(main_process);
@ -311,18 +323,7 @@ struct System::Impl {
return static_cast<SystemResultStatus>( return static_cast<SystemResultStatus>(
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
} }
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
AddGlueRegistrationForProcess(*app_loader, *main_process); AddGlueRegistrationForProcess(*app_loader, *main_process);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Initialize cheat engine // Initialize cheat engine
if (cheat_engine) { if (cheat_engine) {
@ -425,6 +426,7 @@ struct System::Impl {
cpu_manager.Shutdown(); cpu_manager.Shutdown();
debugger.reset(); debugger.reset();
kernel.Shutdown(); kernel.Shutdown();
memory.Reset();
Network::RestartSocketOperations(); Network::RestartSocketOperations();
if (auto room_member = room_network.GetRoomMember().lock()) { if (auto room_member = room_network.GetRoomMember().lock()) {
@ -505,6 +507,7 @@ struct System::Impl {
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core; std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
std::unique_ptr<Core::DeviceMemory> device_memory; std::unique_ptr<Core::DeviceMemory> device_memory;
std::unique_ptr<AudioCore::AudioCore> audio_core; std::unique_ptr<AudioCore::AudioCore> audio_core;
Core::Memory::Memory memory;
Core::HID::HIDCore hid_core; Core::HID::HIDCore hid_core;
Network::RoomNetwork room_network; Network::RoomNetwork room_network;
@ -564,6 +567,9 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_write_manager{};
std::deque<std::vector<u8>> user_channel; std::deque<std::vector<u8>> user_channel;
}; };
@ -646,12 +652,29 @@ void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index); impl->kernel.PrepareReschedule(core_index);
} }
Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
/// Provides a constant reference to the current gou dirty memory manager.
const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
size_t System::GetCurrentHostThreadID() const { size_t System::GetCurrentHostThreadID() const {
return impl->kernel.GetCurrentHostThreadID(); return impl->kernel.GetCurrentHostThreadID();
} }
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); for (auto& manager : impl->gpu_dirty_memory_write_manager) {
manager.Gather(callback);
}
} }
PerfStatsResults System::GetAndResetPerfStats() { PerfStatsResults System::GetAndResetPerfStats() {
@ -700,12 +723,20 @@ const Kernel::KProcess* System::ApplicationProcess() const {
return impl->kernel.ApplicationProcess(); return impl->kernel.ApplicationProcess();
} }
ExclusiveMonitor& System::Monitor() {
return impl->kernel.GetExclusiveMonitor();
}
const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
}
Memory::Memory& System::ApplicationMemory() { Memory::Memory& System::ApplicationMemory() {
return impl->kernel.ApplicationProcess()->GetMemory(); return impl->memory;
} }
const Core::Memory::Memory& System::ApplicationMemory() const { const Core::Memory::Memory& System::ApplicationMemory() const {
return impl->kernel.ApplicationProcess()->GetMemory(); return impl->memory;
} }
Tegra::GPU& System::GPU() { Tegra::GPU& System::GPU() {

View File

@ -116,6 +116,7 @@ class CpuManager;
class Debugger; class Debugger;
class DeviceMemory; class DeviceMemory;
class ExclusiveMonitor; class ExclusiveMonitor;
class GPUDirtyMemoryManager;
class PerfStats; class PerfStats;
class Reporter; class Reporter;
class SpeedLimiter; class SpeedLimiter;
@ -224,6 +225,12 @@ public:
/// Prepare the core emulation for a reschedule /// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index); void PrepareReschedule(u32 core_index);
/// Provides a reference to the gou dirty memory manager.
[[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
/// Provides a constant reference to the current gou dirty memory manager.
[[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
[[nodiscard]] size_t GetCurrentHostThreadID() const; [[nodiscard]] size_t GetCurrentHostThreadID() const;
@ -243,6 +250,12 @@ public:
/// Gets a const reference to the underlying CPU manager /// Gets a const reference to the underlying CPU manager
[[nodiscard]] const CpuManager& GetCpuManager() const; [[nodiscard]] const CpuManager& GetCpuManager() const;
/// Gets a reference to the exclusive monitor
[[nodiscard]] ExclusiveMonitor& Monitor();
/// Gets a constant reference to the exclusive monitor
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance. /// Gets a mutable reference to the system memory instance.
[[nodiscard]] Core::Memory::Memory& ApplicationMemory(); [[nodiscard]] Core::Memory::Memory& ApplicationMemory();

View File

@ -166,10 +166,6 @@ u32 ProgramMetadata::GetSystemResourceSize() const {
return npdm_header.system_resource_size; return npdm_header.system_resource_size;
} }
PoolPartition ProgramMetadata::GetPoolPartition() const {
return acid_header.pool_partition;
}
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
return aci_kernel_capabilities; return aci_kernel_capabilities;
} }
@ -205,7 +201,7 @@ void ProgramMetadata::Print() const {
// Begin ACID printing (potential perms, signed) // Begin ACID printing (potential perms, signed)
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO"); LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);

View File

@ -34,13 +34,6 @@ enum class ProgramFilePermission : u64 {
Everything = 1ULL << 63, Everything = 1ULL << 63,
}; };
enum class PoolPartition : u32 {
Application = 0,
Applet = 1,
System = 2,
SystemNonSecure = 3,
};
/** /**
* Helper which implements an interface to parse Program Description Metadata (NPDM) * Helper which implements an interface to parse Program Description Metadata (NPDM)
* Data can either be loaded from a file path or with data and an offset into it. * Data can either be loaded from a file path or with data and an offset into it.
@ -79,7 +72,6 @@ public:
u64 GetTitleID() const; u64 GetTitleID() const;
u64 GetFilesystemPermissions() const; u64 GetFilesystemPermissions() const;
u32 GetSystemResourceSize() const; u32 GetSystemResourceSize() const;
PoolPartition GetPoolPartition() const;
const KernelCapabilityDescriptors& GetKernelCapabilities() const; const KernelCapabilityDescriptors& GetKernelCapabilities() const;
const std::array<u8, 0x10>& GetName() const { const std::array<u8, 0x10>& GetName() const {
return npdm_header.application_name; return npdm_header.application_name;
@ -124,9 +116,8 @@ private:
union { union {
u32 flags; u32 flags;
BitField<0, 1, u32> production_flag; BitField<0, 1, u32> is_retail;
BitField<1, 1, u32> unqualified_approval; BitField<1, 31, u32> flags_unk;
BitField<2, 4, PoolPartition> pool_partition;
}; };
u64_le title_id_min; u64_le title_id_min;
u64_le title_id_max; u64_le title_id_max;

View File

@ -201,6 +201,8 @@ std::string VfsFile::GetFullPath() const {
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const { VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
auto vec = Common::FS::SplitPathComponents(path); auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
if (vec.empty()) { if (vec.empty()) {
return nullptr; return nullptr;
} }
@ -235,6 +237,8 @@ VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const { VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
auto vec = Common::FS::SplitPathComponents(path); auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
if (vec.empty()) { if (vec.empty()) {
// TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
// because of const-ness // because of const-ness
@ -299,6 +303,8 @@ std::size_t VfsDirectory::GetSize() const {
VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) { VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) {
auto vec = Common::FS::SplitPathComponents(path); auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
if (vec.empty()) { if (vec.empty()) {
return nullptr; return nullptr;
} }
@ -328,6 +334,8 @@ VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) { VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) {
auto vec = Common::FS::SplitPathComponents(path); auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
if (vec.empty()) { if (vec.empty()) {
return nullptr; return nullptr;
} }

View File

@ -268,7 +268,7 @@ void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference)
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
const std::string& path_, Mode perms_, std::optional<u64> size_) const std::string& path_, Mode perms_, std::optional<u64> size_)
: base(base_), reference(std::move(reference_)), path(path_), : base(base_), reference(std::move(reference_)), path(path_),
parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)), parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)),
size(size_), perms(perms_) {} size(size_), perms(perms_) {}
RealVfsFile::~RealVfsFile() { RealVfsFile::~RealVfsFile() {
@ -276,7 +276,7 @@ RealVfsFile::~RealVfsFile() {
} }
std::string RealVfsFile::GetName() const { std::string RealVfsFile::GetName() const {
return path_components.empty() ? "" : std::string(path_components.back()); return path_components.back();
} }
std::size_t RealVfsFile::GetSize() const { std::size_t RealVfsFile::GetSize() const {
@ -375,7 +375,7 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
: base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)), : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) { path_components(FS::SplitPathComponents(path)), perms(perms_) {
if (!FS::Exists(path) && True(perms & Mode::Write)) { if (!FS::Exists(path) && True(perms & Mode::Write)) {
void(FS::CreateDirs(path)); void(FS::CreateDirs(path));
} }
@ -464,7 +464,7 @@ bool RealVfsDirectory::IsReadable() const {
} }
std::string RealVfsDirectory::GetName() const { std::string RealVfsDirectory::GetName() const {
return path_components.empty() ? "" : std::string(path_components.back()); return path_components.back();
} }
VirtualDir RealVfsDirectory::GetParentDirectory() const { VirtualDir RealVfsDirectory::GetParentDirectory() const {

View File

@ -20,9 +20,6 @@ InputInterpreter::InputInterpreter(Core::System& system)
InputInterpreter::~InputInterpreter() = default; InputInterpreter::~InputInterpreter() = default;
void InputInterpreter::PollInput() { void InputInterpreter::PollInput() {
if (npad == nullptr) {
return;
}
const auto button_state = npad->GetAndResetPressState(); const auto button_state = npad->GetAndResetPressState();
previous_index = current_index; previous_index = current_index;

View File

@ -4,7 +4,6 @@
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
@ -27,9 +26,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
return true; return true;
} }
bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) { bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) {
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor(); auto& monitor = system.Monitor();
const auto current_core = kernel.CurrentPhysicalCoreIndex(); const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
// NOTE: If scheduler lock is not held here, interrupt disable is required. // NOTE: If scheduler lock is not held here, interrupt disable is required.
// KScopedInterruptDisable di; // KScopedInterruptDisable di;
@ -67,10 +66,10 @@ bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address,
return true; return true;
} }
bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value, bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value,
s32 new_value) { s32 new_value) {
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor(); auto& monitor = system.Monitor();
const auto current_core = kernel.CurrentPhysicalCoreIndex(); const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
// NOTE: If scheduler lock is not held here, interrupt disable is required. // NOTE: If scheduler lock is not held here, interrupt disable is required.
// KScopedInterruptDisable di; // KScopedInterruptDisable di;
@ -160,7 +159,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
// Check the userspace value. // Check the userspace value.
s32 user_value{}; s32 user_value{};
R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1), R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1),
ResultInvalidCurrentMemory); ResultInvalidCurrentMemory);
R_UNLESS(user_value == value, ResultInvalidState); R_UNLESS(user_value == value, ResultInvalidState);
@ -220,7 +219,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
s32 user_value{}; s32 user_value{};
bool succeeded{}; bool succeeded{};
if (value != new_value) { if (value != new_value) {
succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value); succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value);
} else { } else {
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
} }
@ -263,7 +262,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
s32 user_value{}; s32 user_value{};
bool succeeded{}; bool succeeded{};
if (decrement) { if (decrement) {
succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value); succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value);
} else { } else {
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
} }

View File

@ -58,8 +58,9 @@ Result KClientPort::CreateSession(KClientSession** out) {
KSession* session{}; KSession* session{};
// Reserve a new session from the resource limit. // Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel), //! FIXME: we are reserving this from the wrong resource limit!
LimitableResource::SessionCountMax); KScopedResourceReservation session_reservation(
m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
// Allocate a session normally. // Allocate a session normally.

View File

@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
return true; return true;
} }
bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero, bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero,
u32 new_orr_mask) { u32 new_orr_mask) {
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor(); auto& monitor = system.Monitor();
const auto current_core = kernel.CurrentPhysicalCoreIndex(); const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
u32 expected{}; u32 expected{};
@ -208,7 +208,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true; can_access = true;
if (can_access) [[likely]] { if (can_access) [[likely]] {
UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag, UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask); Svc::HandleWaitMask);
} }
} }

View File

@ -30,7 +30,7 @@ public:
public: public:
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {} explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
Result Initialize(KProcess* owner, s32 size) { Result Initialize(s32 size) {
// Check that the table size is valid. // Check that the table size is valid.
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
@ -44,7 +44,6 @@ public:
m_next_linear_id = MinLinearId; m_next_linear_id = MinLinearId;
m_count = 0; m_count = 0;
m_free_head_index = -1; m_free_head_index = -1;
m_owner = owner;
// Free all entries. // Free all entries.
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
@ -91,8 +90,8 @@ public:
// Handle pseudo-handles. // Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) { if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) { if (handle == Svc::PseudoHandle::CurrentProcess) {
// TODO: this should be the current process //! FIXME: this is the wrong process!
auto* const cur_process = m_owner; auto* const cur_process = m_kernel.ApplicationProcess();
ASSERT(cur_process != nullptr); ASSERT(cur_process != nullptr);
return cur_process; return cur_process;
} }
@ -302,7 +301,6 @@ private:
private: private:
KernelCore& m_kernel; KernelCore& m_kernel;
KProcess* m_owner{};
std::array<EntryInfo, MaxTableSize> m_entry_infos{}; std::array<EntryInfo, MaxTableSize> m_entry_infos{};
std::array<KAutoObject*, MaxTableSize> m_objects{}; std::array<KAutoObject*, MaxTableSize> m_objects{};
mutable KSpinLock m_lock; mutable KSpinLock m_lock;

View File

@ -421,9 +421,8 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
} else { } else {
// Set all the allocated memory. // Set all the allocated memory.
for (const auto& block : *out) { for (const auto& block : *out) {
m_system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(block.GetAddress()) - std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern,
Core::DramMemoryMap::Base, block.GetSize());
block.GetSize(), fill_pattern);
} }
} }

View File

@ -81,11 +81,6 @@ void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size)
} }
} }
void ClearBackingRegion(Core::System& system, KPhysicalAddress addr, u64 size, u32 fill_value) {
system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(addr) - Core::DramMemoryMap::Base,
size, fill_value);
}
template <typename AddressType> template <typename AddressType>
Result InvalidateDataCache(AddressType addr, u64 size) { Result InvalidateDataCache(AddressType addr, u64 size) {
R_SUCCEED(); R_SUCCEED();
@ -1368,7 +1363,8 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
// Clear all the newly allocated pages. // Clear all the newly allocated pages.
for (const auto& it : pg) { for (const auto& it : pg) {
ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value); std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()),
static_cast<u32>(m_heap_fill_value), it.GetSize());
} }
// Lock the table. // Lock the table.
@ -1574,7 +1570,8 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
// Clear all pages. // Clear all pages.
for (const auto& it : pg) { for (const auto& it : pg) {
ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value); std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()),
static_cast<u32>(m_heap_fill_value), it.GetSize());
} }
// Map the pages. // Map the pages.
@ -2162,7 +2159,8 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
// Clear all the newly allocated pages. // Clear all the newly allocated pages.
for (const auto& it : pg) { for (const auto& it : pg) {
ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value); std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), m_heap_fill_value,
it.GetSize());
} }
// Map the pages. // Map the pages.

View File

@ -306,16 +306,12 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
params.code_address, params.code_num_pages * PageSize, params.code_address, params.code_num_pages * PageSize,
m_system_resource, res_limit, m_memory, 0)); m_system_resource, res_limit, this->GetMemory(), 0));
} }
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {
m_page_table.Finalize(); m_page_table.Finalize();
}; };
// Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
KMemoryState::Code), KMemoryState::Code),
@ -403,16 +399,12 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
params.code_address, code_size, m_system_resource, res_limit, params.code_address, code_size, m_system_resource, res_limit,
m_memory, aslr_space_start)); this->GetMemory(), aslr_space_start));
} }
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {
m_page_table.Finalize(); m_page_table.Finalize();
}; };
// Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
@ -1102,7 +1094,8 @@ void KProcess::UnpinThread(KThread* thread) {
Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids,
s32 max_out_count) { s32 max_out_count) {
auto& memory = this->GetMemory(); // TODO: use current memory reference
auto& memory = m_kernel.System().ApplicationMemory();
// Lock the list. // Lock the list.
KScopedLightLock lk(m_list_lock); KScopedLightLock lk(m_list_lock);
@ -1135,15 +1128,14 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
KProcess::KProcess(KernelCore& kernel) KProcess::KProcess(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
m_handle_table{kernel}, m_dirty_memory_managers{}, m_handle_table{kernel} {}
m_exclusive_monitor{}, m_memory{kernel.System()} {}
KProcess::~KProcess() = default; KProcess::~KProcess() = default;
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
KProcessAddress aslr_space_start, bool is_hbl) { KProcessAddress aslr_space_start, bool is_hbl) {
// Create a resource limit for the process. // Create a resource limit for the process.
const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition()); const auto physical_memory_size =
const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool); m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
auto* res_limit = auto* res_limit =
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
@ -1154,10 +1146,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
Svc::CreateProcessFlag flag{}; Svc::CreateProcessFlag flag{};
u64 code_address{}; u64 code_address{};
// Determine if we are an application. // We are an application.
if (pool == KMemoryManager::Pool::Application) {
flag |= Svc::CreateProcessFlag::IsApplication; flag |= Svc::CreateProcessFlag::IsApplication;
}
// If we are 64-bit, create as such. // If we are 64-bit, create as such.
if (metadata.Is64BitProgram()) { if (metadata.Is64BitProgram()) {
@ -1206,8 +1196,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
std::memcpy(params.name.data(), name.data(), sizeof(params.name)); std::memcpy(params.name.data(), name.data(), sizeof(params.name));
// Initialize for application process. // Initialize for application process.
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool, R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit,
aslr_space_start)); KMemoryManager::Pool::Application, aslr_space_start));
// Assign remaining properties. // Assign remaining properties.
m_is_hbl = is_hbl; m_is_hbl = is_hbl;
@ -1233,7 +1223,7 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
#ifdef HAS_NCE #ifdef HAS_NCE
if (this->IsApplication() && Settings::IsNceEnabled()) { if (Settings::IsNceEnabled()) {
auto& buffer = m_kernel.System().DeviceMemory().buffer; auto& buffer = m_kernel.System().DeviceMemory().buffer;
const auto& code = code_set.CodeSegment(); const auto& code = code_set.CodeSegment();
const auto& patch = code_set.PatchSegment(); const auto& patch = code_set.PatchSegment();
@ -1245,11 +1235,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
} }
void KProcess::InitializeInterfaces() { void KProcess::InitializeInterfaces() {
m_exclusive_monitor = this->GetMemory().SetCurrentPageTable(*this);
Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
#ifdef HAS_NCE #ifdef HAS_NCE
if (this->IsApplication() && Settings::IsNceEnabled()) { if (this->Is64Bit() && Settings::IsNceEnabled()) {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
} }
@ -1259,13 +1248,13 @@ void KProcess::InitializeInterfaces() {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>( m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
m_kernel.System(), m_kernel.IsMulticore(), this, m_kernel.System(), m_kernel.IsMulticore(), this,
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i); static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
} }
} else { } else {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>( m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
m_kernel.System(), m_kernel.IsMulticore(), this, m_kernel.System(), m_kernel.IsMulticore(), this,
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i); static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
} }
} }
} }
@ -1316,10 +1305,9 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
return true; return true;
} }
void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { Core::Memory::Memory& KProcess::GetMemory() const {
for (auto& manager : m_dirty_memory_managers) { // TODO: per-process memory
manager.Gather(callback); return m_kernel.System().ApplicationMemory();
}
} }
} // namespace Kernel } // namespace Kernel

View File

@ -7,7 +7,6 @@
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/file_sys/program_metadata.h" #include "core/file_sys/program_metadata.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/code_set.h" #include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_capabilities.h" #include "core/hle/kernel/k_capabilities.h"
@ -18,7 +17,6 @@
#include "core/hle/kernel/k_system_resource.h" #include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_local_page.h" #include "core/hle/kernel/k_thread_local_page.h"
#include "core/memory.h"
namespace Kernel { namespace Kernel {
@ -128,9 +126,6 @@ private:
#ifdef HAS_NCE #ifdef HAS_NCE
std::unordered_map<u64, u64> m_post_handlers{}; std::unordered_map<u64, u64> m_post_handlers{};
#endif #endif
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
Core::Memory::Memory m_memory;
private: private:
Result StartTermination(); Result StartTermination();
@ -507,15 +502,7 @@ public:
void InitializeInterfaces(); void InitializeInterfaces();
Core::Memory::Memory& GetMemory() { Core::Memory::Memory& GetMemory() const;
return m_memory;
}
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
Core::ExclusiveMonitor& GetExclusiveMonitor() const {
return *m_exclusive_monitor;
}
public: public:
// Overridden parent functions. // Overridden parent functions.
@ -552,7 +539,7 @@ private:
Result InitializeHandleTable(s32 size) { Result InitializeHandleTable(s32 size) {
// Try to initialize the handle table. // Try to initialize the handle table.
R_TRY(m_handle_table.Initialize(this, size)); R_TRY(m_handle_table.Initialize(size));
// We succeeded, so note that we did. // We succeeded, so note that we did.
m_is_handle_table_initialized = true; m_is_handle_table_initialized = true;

File diff suppressed because it is too large Load Diff

View File

@ -49,21 +49,14 @@ public:
bool IsSignaled() const override; bool IsSignaled() const override;
void OnClientClosed(); void OnClientClosed();
/// TODO: flesh these out to match the real kernel
Result OnRequest(KSessionRequest* request); Result OnRequest(KSessionRequest* request);
Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size, Result SendReply(bool is_hle = false);
KPhysicalAddress server_message_paddr, bool is_hle = false); Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
Result ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size,
KPhysicalAddress server_message_paddr,
std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
std::weak_ptr<Service::SessionRequestManager> manager = {}); std::weak_ptr<Service::SessionRequestManager> manager = {});
Result SendReplyHLE() { Result SendReplyHLE() {
R_RETURN(this->SendReply(0, 0, 0, true)); return SendReply(true);
}
Result ReceiveRequestHLE(std::shared_ptr<Service::HLERequestContext>* out_context,
std::weak_ptr<Service::SessionRequestManager> manager) {
R_RETURN(this->ReceiveRequest(0, 0, 0, out_context, manager));
} }
private: private:

View File

@ -33,7 +33,8 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
m_name = name; m_name = name;
// Set our owner process. // Set our owner process.
m_process = GetCurrentProcessPointer(m_kernel); //! FIXME: this is the wrong process!
m_process = m_kernel.ApplicationProcess();
m_process->Open(); m_process->Open();
// Set our port. // Set our port.

View File

@ -1422,7 +1422,8 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
} }
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) { Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
return GetCurrentProcess(kernel).GetMemory(); // TODO: per-process memory
return kernel.System().ApplicationMemory();
} }
KScopedDisableDispatch::~KScopedDisableDispatch() { KScopedDisableDispatch::~KScopedDisableDispatch() {

View File

@ -314,7 +314,11 @@ public:
m_current_core_id = core; m_current_core_id = core;
} }
KProcess* GetOwnerProcess() const { KProcess* GetOwnerProcess() {
return m_parent;
}
const KProcess* GetOwnerProcess() const {
return m_parent; return m_parent;
} }

View File

@ -68,6 +68,8 @@ struct KernelCore::Impl {
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
global_handle_table->Initialize(KHandleTable::MaxTableSize);
is_phantom_mode_for_singlecore = false; is_phantom_mode_for_singlecore = false;
@ -119,8 +121,13 @@ struct KernelCore::Impl {
next_user_process_id = KProcess::ProcessIdMin; next_user_process_id = KProcess::ProcessIdMin;
next_thread_id = 1; next_thread_id = 1;
global_handle_table->Finalize();
global_handle_table.reset();
preemption_event = nullptr; preemption_event = nullptr;
exclusive_monitor.reset();
// Cleanup persistent kernel objects // Cleanup persistent kernel objects
auto CleanupObject = [](KAutoObject* obj) { auto CleanupObject = [](KAutoObject* obj) {
if (obj) { if (obj) {
@ -128,6 +135,7 @@ struct KernelCore::Impl {
obj = nullptr; obj = nullptr;
} }
}; };
CleanupObject(hid_shared_mem);
CleanupObject(font_shared_mem); CleanupObject(font_shared_mem);
CleanupObject(irs_shared_mem); CleanupObject(irs_shared_mem);
CleanupObject(time_shared_mem); CleanupObject(time_shared_mem);
@ -184,6 +192,8 @@ struct KernelCore::Impl {
} }
void InitializePhysicalCores() { void InitializePhysicalCores() {
exclusive_monitor =
Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
const s32 core{static_cast<s32>(i)}; const s32 core{static_cast<s32>(i)};
@ -734,16 +744,22 @@ struct KernelCore::Impl {
void InitializeHackSharedMemory(KernelCore& kernel) { void InitializeHackSharedMemory(KernelCore& kernel) {
// Setup memory regions for emulated processes // Setup memory regions for emulated processes
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
constexpr std::size_t hid_size{0x40000};
constexpr std::size_t font_size{0x1100000}; constexpr std::size_t font_size{0x1100000};
constexpr std::size_t irs_size{0x8000}; constexpr std::size_t irs_size{0x8000};
constexpr std::size_t time_size{0x1000}; constexpr std::size_t time_size{0x1000};
constexpr std::size_t hidbus_size{0x1000}; constexpr std::size_t hidbus_size{0x1000};
hid_shared_mem = KSharedMemory::Create(system.Kernel());
font_shared_mem = KSharedMemory::Create(system.Kernel()); font_shared_mem = KSharedMemory::Create(system.Kernel());
irs_shared_mem = KSharedMemory::Create(system.Kernel()); irs_shared_mem = KSharedMemory::Create(system.Kernel());
time_shared_mem = KSharedMemory::Create(system.Kernel()); time_shared_mem = KSharedMemory::Create(system.Kernel());
hidbus_shared_mem = KSharedMemory::Create(system.Kernel()); hidbus_shared_mem = KSharedMemory::Create(system.Kernel());
hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
Svc::MemoryPermission::Read, hid_size);
KSharedMemory::Register(kernel, hid_shared_mem);
font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
Svc::MemoryPermission::Read, font_size); Svc::MemoryPermission::Read, font_size);
KSharedMemory::Register(kernel, font_shared_mem); KSharedMemory::Register(kernel, font_shared_mem);
@ -782,6 +798,10 @@ struct KernelCore::Impl {
std::shared_ptr<Core::Timing::EventType> preemption_event; std::shared_ptr<Core::Timing::EventType> preemption_event;
// This is the kernel's handle table or supervisor handle table which
// stores all the objects in place.
std::unique_ptr<KHandleTable> global_handle_table;
std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
std::unique_ptr<KObjectNameGlobalData> object_name_global_data; std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
@ -792,6 +812,7 @@ struct KernelCore::Impl {
std::mutex server_lock; std::mutex server_lock;
std::vector<std::unique_ptr<Service::ServerManager>> server_managers; std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
@ -868,6 +889,10 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
return impl->system_resource_limit; return impl->system_resource_limit;
} }
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
return impl->global_handle_table->GetObject<KThread>(handle);
}
void KernelCore::AppendNewProcess(KProcess* process) { void KernelCore::AppendNewProcess(KProcess* process) {
impl->process_list.push_back(process); impl->process_list.push_back(process);
} }
@ -941,6 +966,14 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
return *impl->hardware_timer; return *impl->hardware_timer;
} }
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
return *impl->exclusive_monitor;
}
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
return *impl->exclusive_monitor;
}
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
return *impl->global_object_list_container; return *impl->global_object_list_container;
} }
@ -1004,6 +1037,14 @@ u64 KernelCore::CreateNewUserProcessID() {
return impl->next_user_process_id++; return impl->next_user_process_id++;
} }
KHandleTable& KernelCore::GlobalHandleTable() {
return *impl->global_handle_table;
}
const KHandleTable& KernelCore::GlobalHandleTable() const {
return *impl->global_handle_table;
}
void KernelCore::RegisterCoreThread(std::size_t core_id) { void KernelCore::RegisterCoreThread(std::size_t core_id) {
impl->RegisterCoreThread(core_id); impl->RegisterCoreThread(core_id);
} }
@ -1149,6 +1190,14 @@ const KSystemResource& KernelCore::GetSystemSystemResource() const {
return *impl->sys_system_resource; return *impl->sys_system_resource;
} }
Kernel::KSharedMemory& KernelCore::GetHidSharedMem() {
return *impl->hid_shared_mem;
}
const Kernel::KSharedMemory& KernelCore::GetHidSharedMem() const {
return *impl->hid_shared_mem;
}
Kernel::KSharedMemory& KernelCore::GetFontSharedMem() { Kernel::KSharedMemory& KernelCore::GetFontSharedMem() {
return *impl->font_shared_mem; return *impl->font_shared_mem;
} }

View File

@ -116,6 +116,9 @@ public:
/// Retrieves a shared pointer to the system resource limit instance. /// Retrieves a shared pointer to the system resource limit instance.
KResourceLimit* GetSystemResourceLimit(); KResourceLimit* GetSystemResourceLimit();
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes. /// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(KProcess* process); void AppendNewProcess(KProcess* process);
@ -167,6 +170,10 @@ public:
/// Stops execution of 'id' core, in order to reschedule a new thread. /// Stops execution of 'id' core, in order to reschedule a new thread.
void PrepareReschedule(std::size_t id); void PrepareReschedule(std::size_t id);
Core::ExclusiveMonitor& GetExclusiveMonitor();
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
KAutoObjectWithListContainer& ObjectListContainer(); KAutoObjectWithListContainer& ObjectListContainer();
const KAutoObjectWithListContainer& ObjectListContainer() const; const KAutoObjectWithListContainer& ObjectListContainer() const;
@ -232,6 +239,12 @@ public:
/// Gets the system resource manager. /// Gets the system resource manager.
const KSystemResource& GetSystemSystemResource() const; const KSystemResource& GetSystemSystemResource() const;
/// Gets the shared memory object for HID services.
Kernel::KSharedMemory& GetHidSharedMem();
/// Gets the shared memory object for HID services.
const Kernel::KSharedMemory& GetHidSharedMem() const;
/// Gets the shared memory object for font services. /// Gets the shared memory object for font services.
Kernel::KSharedMemory& GetFontSharedMem(); Kernel::KSharedMemory& GetFontSharedMem();

View File

@ -18,13 +18,13 @@ public:
static constexpr inline u64 NullTag = 0; static constexpr inline u64 NullTag = 0;
public: public:
enum ReceiveListCountType : u32 { enum class ReceiveListCountType : u32 {
ReceiveListCountType_None = 0, None = 0,
ReceiveListCountType_ToMessageBuffer = 1, ToMessageBuffer = 1,
ReceiveListCountType_ToSingleBuffer = 2, ToSingleBuffer = 2,
ReceiveListCountType_CountOffset = 2, CountOffset = 2,
ReceiveListCountType_CountMax = 13, CountMax = 13,
}; };
private: private:
@ -591,16 +591,16 @@ public:
// Add the size of the receive list. // Add the size of the receive list.
const auto count = hdr.GetReceiveListCount(); const auto count = hdr.GetReceiveListCount();
switch (count) { switch (count) {
case MessageHeader::ReceiveListCountType_None: case MessageHeader::ReceiveListCountType::None:
break; break;
case MessageHeader::ReceiveListCountType_ToMessageBuffer: case MessageHeader::ReceiveListCountType::ToMessageBuffer:
break; break;
case MessageHeader::ReceiveListCountType_ToSingleBuffer: case MessageHeader::ReceiveListCountType::ToSingleBuffer:
msg_size += ReceiveListEntry::GetDataSize(); msg_size += ReceiveListEntry::GetDataSize();
break; break;
default: default:
msg_size += (static_cast<s32>(count) - msg_size += (static_cast<s32>(count) -
static_cast<s32>(MessageHeader::ReceiveListCountType_CountOffset)) * static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
ReceiveListEntry::GetDataSize(); ReceiveListEntry::GetDataSize();
break; break;
} }

View File

@ -118,6 +118,7 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED(); R_SUCCEED();
case InfoType::IsApplication: case InfoType::IsApplication:
LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
*result = process->IsApplication(); *result = process->IsApplication();
R_SUCCEED(); R_SUCCEED();

View File

@ -48,7 +48,8 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
}; };
// Send the reply. // Send the reply.
R_TRY(session->SendReply(message, buffer_size, message_paddr)); R_TRY(session->SendReply());
// R_TRY(session->SendReply(message, buffer_size, message_paddr));
} }
// Receive a message. // Receive a message.
@ -84,7 +85,8 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
if (R_SUCCEEDED(result)) { if (R_SUCCEEDED(result)) {
KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
if (session != nullptr) { if (session != nullptr) {
result = session->ReceiveRequest(message, buffer_size, message_paddr); // result = session->ReceiveRequest(message, buffer_size, message_paddr);
result = session->ReceiveRequest();
if (ResultNotFound == result) { if (ResultNotFound == result) {
continue; continue;
} }

View File

@ -38,9 +38,7 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126}; constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131}; constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132}; constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258};
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259}; constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260};
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519}; constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
} // namespace Kernel } // namespace Kernel

View File

@ -359,7 +359,7 @@ private:
void GetActiveChannelCount(HLERequestContext& ctx) { void GetActiveChannelCount(HLERequestContext& ctx) {
const auto& sink{system.AudioCore().GetOutputSink()}; const auto& sink{system.AudioCore().GetOutputSink()};
u32 channel_count{sink.GetSystemChannels()}; u32 channel_count{sink.GetDeviceChannels()};
LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count); LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);

View File

@ -89,7 +89,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F
crash_report += fmt::format(" ESR: {:016x}\n", info.esr); crash_report += fmt::format(" ESR: {:016x}\n", info.esr);
crash_report += fmt::format(" FAR: {:016x}\n", info.far); crash_report += fmt::format(" FAR: {:016x}\n", info.far);
crash_report += "\nBacktrace:\n"; crash_report += "\nBacktrace:\n";
for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); i++) { for (size_t i = 0; i < info.backtrace_size; i++) {
crash_report += crash_report +=
fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]); fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
} }

View File

@ -104,7 +104,11 @@ Result VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) con
const auto components = Common::FS::SplitPathComponents(path); const auto components = Common::FS::SplitPathComponents(path);
std::string relative_path; std::string relative_path;
for (const auto& component : components) { for (const auto& component : components) {
relative_path = Common::FS::SanitizePath(fmt::format("{}/{}", relative_path, component)); // Skip empty path components
if (component.empty()) {
continue;
}
relative_path = Common::FS::SanitizePath(relative_path + '/' + component);
auto new_dir = backing->CreateSubdirectory(relative_path); auto new_dir = backing->CreateSubdirectory(relative_path);
if (new_dir == nullptr) { if (new_dir == nullptr) {
// TODO(DarkLordZach): Find a better error code for this // TODO(DarkLordZach): Find a better error code for this

View File

@ -54,13 +54,6 @@ enum class ImageDirectoryId : u32 {
SdCard, SdCard,
}; };
enum class OpenDirectoryMode : u64 {
Directory = (1 << 0),
File = (1 << 1),
All = Directory | File
};
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode);
class FileSystemController { class FileSystemController {
public: public:
explicit FileSystemController(Core::System& system_); explicit FileSystemController(Core::System& system_);

View File

@ -259,7 +259,7 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
class IDirectory final : public ServiceFramework<IDirectory> { class IDirectory final : public ServiceFramework<IDirectory> {
public: public:
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode) explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
: ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IDirectory::Read, "Read"}, {0, &IDirectory::Read, "Read"},
@ -269,12 +269,8 @@ public:
// TODO(DarkLordZach): Verify that this is the correct behavior. // TODO(DarkLordZach): Verify that this is the correct behavior.
// Build entry index now to save time later. // Build entry index now to save time later.
if (True(mode & OpenDirectoryMode::Directory)) {
BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
}
if (True(mode & OpenDirectoryMode::File)) {
BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File); BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
} BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
} }
private: private:
@ -450,9 +446,11 @@ public:
const auto file_buffer = ctx.ReadBuffer(); const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer); const std::string name = Common::StringFromBuffer(file_buffer);
const auto mode = rp.PopRaw<OpenDirectoryMode>();
LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); // TODO(Subv): Implement this filter.
const u32 filter_flags = rp.Pop<u32>();
LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
FileSys::VirtualDir vfs_dir{}; FileSys::VirtualDir vfs_dir{};
auto result = backend.OpenDirectory(&vfs_dir, name); auto result = backend.OpenDirectory(&vfs_dir, name);
@ -462,7 +460,7 @@ public:
return; return;
} }
auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); auto directory = std::make_shared<IDirectory>(system, vfs_dir);
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);

View File

@ -4,7 +4,6 @@
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/hid/controllers/applet_resource.h" #include "core/hle/service/hid/controllers/applet_resource.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/errors.h"
namespace Service::HID { namespace Service::HID {
@ -24,24 +23,11 @@ Result AppletResource::CreateAppletResource(u64 aruid) {
return ResultAruidAlreadyRegistered; return ResultAruidAlreadyRegistered;
} }
auto& shared_memory = shared_memory_holder[index]; // TODO: Here shared memory is created for the process we don't quite emulate this part so
if (!shared_memory.IsMapped()) { // obtain this pointer from system
const Result result = shared_memory.Initialize(system); auto& shared_memory = system.Kernel().GetHidSharedMem();
if (result.IsError()) {
return result;
}
if (shared_memory.GetAddress() == nullptr) {
shared_memory.Finalize();
return ResultSharedMemoryNotInitialized;
}
}
auto* shared_memory_format = shared_memory.GetAddress(); data[index].shared_memory_handle = &shared_memory;
if (shared_memory_format != nullptr) {
shared_memory_format->Initialize();
}
data[index].shared_memory_format = shared_memory_format;
data[index].flag.is_assigned.Assign(true); data[index].flag.is_assigned.Assign(true);
// TODO: InitializeSixAxisControllerConfig(false); // TODO: InitializeSixAxisControllerConfig(false);
active_aruid = aruid; active_aruid = aruid;
@ -108,7 +94,7 @@ void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
if (index < AruidIndexMax) { if (index < AruidIndexMax) {
if (data[index].flag.is_assigned) { if (data[index].flag.is_assigned) {
data[index].shared_memory_format = nullptr; data[index].shared_memory_handle = nullptr;
data[index].flag.is_assigned.Assign(false); data[index].flag.is_assigned.Assign(false);
} }
} }
@ -134,7 +120,7 @@ void AppletResource::FreeAppletResourceId(u64 aruid) {
auto& aruid_data = data[index]; auto& aruid_data = data[index];
if (aruid_data.flag.is_assigned) { if (aruid_data.flag.is_assigned) {
aruid_data.shared_memory_format = nullptr; aruid_data.shared_memory_handle = nullptr;
aruid_data.flag.is_assigned.Assign(false); aruid_data.flag.is_assigned.Assign(false);
} }
} }
@ -149,18 +135,7 @@ Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle,
return ResultAruidNotRegistered; return ResultAruidNotRegistered;
} }
*out_handle = shared_memory_holder[index].GetHandle(); *out_handle = data[index].shared_memory_handle;
return ResultSuccess;
}
Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
u64 aruid) {
u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {
return ResultAruidNotRegistered;
}
*out_shared_memory_format = data[index].shared_memory_format;
return ResultSuccess; return ResultSuccess;
} }

View File

@ -8,7 +8,6 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/hid/controllers/shared_memory_holder.h"
namespace Core { namespace Core {
class System; class System;
@ -19,8 +18,6 @@ class KSharedMemory;
} }
namespace Service::HID { namespace Service::HID {
struct SharedMemoryFormat;
class AppletResource { class AppletResource {
public: public:
explicit AppletResource(Core::System& system_); explicit AppletResource(Core::System& system_);
@ -35,7 +32,6 @@ public:
u64 GetActiveAruid(); u64 GetActiveAruid();
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
u64 GetIndexFromAruid(u64 aruid); u64 GetIndexFromAruid(u64 aruid);
@ -84,13 +80,12 @@ private:
struct AruidData { struct AruidData {
DataStatusFlag flag{}; DataStatusFlag flag{};
u64 aruid{}; u64 aruid{};
SharedMemoryFormat* shared_memory_format{nullptr}; Kernel::KSharedMemory* shared_memory_handle{nullptr};
}; };
u64 active_aruid{}; u64 active_aruid{};
AruidRegisterList registration_list{}; AruidRegisterList registration_list{};
std::array<AruidData, AruidIndexMax> data{}; std::array<AruidData, AruidIndexMax> data{};
std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
s32 ref_counter{}; s32 ref_counter{};
Core::System& system; Core::System& system;

View File

@ -1,18 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_console.h" #include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/console_six_axis.h" #include "core/hle/service/hid/controllers/console_six_axis.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/memory.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory) : ControllerBase{hid_core_} {
: ControllerBase{hid_core_}, shared_memory{console_shared_memory} {
console = hid_core.GetEmulatedConsole(); console = hid_core.GetEmulatedConsole();
static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
"ConsoleSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
} }
ConsoleSixAxis::~ConsoleSixAxis() = default; ConsoleSixAxis::~ConsoleSixAxis() = default;
@ -28,10 +33,10 @@ void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
const auto motion_status = console->GetMotion(); const auto motion_status = console->GetMotion();
shared_memory.sampling_number++; shared_memory->sampling_number++;
shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
shared_memory.verticalization_error = motion_status.verticalization_error; shared_memory->verticalization_error = motion_status.verticalization_error;
shared_memory.gyro_bias = motion_status.gyro_bias; shared_memory->gyro_bias = motion_status.gyro_bias;
} }
} // namespace Service::HID } // namespace Service::HID

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "common/vector_math.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
namespace Core::HID { namespace Core::HID {
@ -10,12 +11,9 @@ class EmulatedConsole;
} // namespace Core::HID } // namespace Core::HID
namespace Service::HID { namespace Service::HID {
struct ConsoleSixAxisSensorSharedMemoryFormat;
class ConsoleSixAxis final : public ControllerBase { class ConsoleSixAxis final : public ControllerBase {
public: public:
explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory);
~ConsoleSixAxis() override; ~ConsoleSixAxis() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -28,7 +26,18 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private: private:
ConsoleSixAxisSensorSharedMemoryFormat& shared_memory; // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
struct ConsoleSharedMemory {
u64 sampling_number{};
bool is_seven_six_axis_sensor_at_rest{};
INSERT_PADDING_BYTES(3); // padding
f32 verticalization_error{};
Common::Vec3f gyro_bias{};
INSERT_PADDING_BYTES(4); // padding
};
static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
ConsoleSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedConsole* console = nullptr; Core::HID::EmulatedConsole* console = nullptr;
}; };
} // namespace Service::HID } // namespace Service::HID

View File

@ -39,6 +39,9 @@ public:
bool IsControllerActivated() const; bool IsControllerActivated() const;
static const std::size_t hid_entry_count = 17;
static const std::size_t shared_memory_size = 0x40000;
protected: protected:
bool is_activated{false}; bool is_activated{false};

View File

@ -1,19 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/common_types.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_controller.h" #include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/debug_pad.h" #include "core/hle/service/hid/controllers/debug_pad.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
DebugPadSharedMemoryFormat& debug_pad_shared_memory) : ControllerBase{hid_core_} {
: ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} { static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
"DebugPadSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
} }
@ -25,12 +30,12 @@ void DebugPad::OnRelease() {}
void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.debug_pad_lifo.buffer_count = 0; shared_memory->debug_pad_lifo.buffer_count = 0;
shared_memory.debug_pad_lifo.buffer_tail = 0; shared_memory->debug_pad_lifo.buffer_tail = 0;
return; return;
} }
const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state; const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1; next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.debug_pad_enabled) { if (Settings::values.debug_pad_enabled) {
@ -44,7 +49,7 @@ void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.r_stick = stick_state.right; next_state.r_stick = stick_state.right;
} }
shared_memory.debug_pad_lifo.WriteNextEntry(next_state); shared_memory->debug_pad_lifo.WriteNextEntry(next_state);
} }
} // namespace Service::HID } // namespace Service::HID

View File

@ -3,24 +3,21 @@
#pragma once #pragma once
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/debug_pad_types.h" #include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID { namespace Core::HID {
class HIDCore; class EmulatedController;
} struct DebugPadButton;
struct AnalogStickState;
namespace Core::Timing { } // namespace Core::HID
class CoreTiming;
}
namespace Service::HID { namespace Service::HID {
struct DebugPadSharedMemoryFormat;
class DebugPad final : public ControllerBase { class DebugPad final : public ControllerBase {
public: public:
explicit DebugPad(Core::HID::HIDCore& hid_core_, explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
DebugPadSharedMemoryFormat& debug_pad_shared_memory);
~DebugPad() override; ~DebugPad() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -33,8 +30,35 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private: private:
// This is nn::hid::DebugPadAttribute
struct DebugPadAttribute {
union {
u32 raw{};
BitField<0, 1, u32> connected;
};
};
static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
// This is nn::hid::DebugPadState
struct DebugPadState {
s64 sampling_number{};
DebugPadAttribute attribute{};
Core::HID::DebugPadButton pad_state{};
Core::HID::AnalogStickState r_stick{};
Core::HID::AnalogStickState l_stick{};
};
static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
struct DebugPadSharedMemory {
// This is nn::hid::detail::DebugPadLifo
Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
INSERT_PADDING_WORDS(0x4E);
};
static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
DebugPadState next_state{}; DebugPadState next_state{};
DebugPadSharedMemoryFormat& shared_memory; DebugPadSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedController* controller = nullptr; Core::HID::EmulatedController* controller = nullptr;
}; };
} // namespace Service::HID } // namespace Service::HID

View File

@ -1,15 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "common/math_util.h" #include "common/math_util.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/gesture.h" #include "core/hle/service/hid/controllers/gesture.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
// HW is around 700, value is set to 400 to make it easier to trigger with mouse // HW is around 700, value is set to 400 to make it easier to trigger with mouse
constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
constexpr f32 angle_threshold = 0.015f; // Threshold in radians constexpr f32 angle_threshold = 0.015f; // Threshold in radians
@ -21,15 +23,19 @@ constexpr f32 Square(s32 num) {
return static_cast<f32>(num * num); return static_cast<f32>(num * num);
} }
Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory) Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
: ControllerBase(hid_core_), shared_memory{gesture_shared_memory} { : ControllerBase(hid_core_) {
static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
"GestureSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
console = hid_core.GetEmulatedConsole(); console = hid_core.GetEmulatedConsole();
} }
Gesture::~Gesture() = default; Gesture::~Gesture() = default;
void Gesture::OnInit() { void Gesture::OnInit() {
shared_memory.gesture_lifo.buffer_count = 0; shared_memory->gesture_lifo.buffer_count = 0;
shared_memory.gesture_lifo.buffer_tail = 0; shared_memory->gesture_lifo.buffer_tail = 0;
force_update = true; force_update = true;
} }
@ -37,8 +43,8 @@ void Gesture::OnRelease() {}
void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.gesture_lifo.buffer_count = 0; shared_memory->gesture_lifo.buffer_count = 0;
shared_memory.gesture_lifo.buffer_tail = 0; shared_memory->gesture_lifo.buffer_tail = 0;
return; return;
} }
@ -46,7 +52,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
GestureProperties gesture = GetGestureProperties(); GestureProperties gesture = GetGestureProperties();
f32 time_difference = f32 time_difference =
static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) / static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
(1000 * 1000 * 1000); (1000 * 1000 * 1000);
// Only update if necessary // Only update if necessary
@ -54,7 +60,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return; return;
} }
last_update_timestamp = shared_memory.gesture_lifo.timestamp; last_update_timestamp = shared_memory->gesture_lifo.timestamp;
UpdateGestureSharedMemory(gesture, time_difference); UpdateGestureSharedMemory(gesture, time_difference);
} }
@ -97,7 +103,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
GestureType type = GestureType::Idle; GestureType type = GestureType::Idle;
GestureAttribute attributes{}; GestureAttribute attributes{};
const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state; const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
// Reset next state to default // Reset next state to default
next_state.sampling_number = last_entry.sampling_number + 1; next_state.sampling_number = last_entry.sampling_number + 1;
@ -127,7 +133,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
next_state.points = gesture.points; next_state.points = gesture.points;
last_gesture = gesture; last_gesture = gesture;
shared_memory.gesture_lifo.WriteNextEntry(next_state); shared_memory->gesture_lifo.WriteNextEntry(next_state);
} }
void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
@ -299,11 +305,11 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_
next_state.direction = GestureDirection::Up; next_state.direction = GestureDirection::Up;
} }
const GestureState& Gesture::GetLastGestureEntry() const { const Gesture::GestureState& Gesture::GetLastGestureEntry() const {
return shared_memory.gesture_lifo.ReadCurrentEntry().state; return shared_memory->gesture_lifo.ReadCurrentEntry().state;
} }
GestureProperties Gesture::GetGestureProperties() { Gesture::GestureProperties Gesture::GetGestureProperties() {
GestureProperties gesture; GestureProperties gesture;
std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),

View File

@ -4,22 +4,17 @@
#pragma once #pragma once
#include <array> #include <array>
#include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/point.h"
#include "core/hid/emulated_console.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/touch_types.h" #include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedConsole;
}
namespace Service::HID { namespace Service::HID {
struct GestureSharedMemoryFormat;
class Gesture final : public ControllerBase { class Gesture final : public ControllerBase {
public: public:
explicit Gesture(Core::HID::HIDCore& hid_core_, explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
GestureSharedMemoryFormat& gesture_shared_memory);
~Gesture() override; ~Gesture() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -32,6 +27,79 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private: private:
static constexpr size_t MAX_FINGERS = 16;
static constexpr size_t MAX_POINTS = 4;
// This is nn::hid::GestureType
enum class GestureType : u32 {
Idle, // Nothing touching the screen
Complete, // Set at the end of a touch event
Cancel, // Set when the number of fingers change
Touch, // A finger just touched the screen
Press, // Set if last type is touch and the finger hasn't moved
Tap, // Fast press then release
Pan, // All points moving together across the screen
Swipe, // Fast press movement and release of a single point
Pinch, // All points moving away/closer to the midpoint
Rotate, // All points rotating from the midpoint
};
// This is nn::hid::GestureDirection
enum class GestureDirection : u32 {
None,
Left,
Up,
Right,
Down,
};
// This is nn::hid::GestureAttribute
struct GestureAttribute {
union {
u32 raw{};
BitField<4, 1, u32> is_new_touch;
BitField<8, 1, u32> is_double_tap;
};
};
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
// This is nn::hid::GestureState
struct GestureState {
s64 sampling_number{};
s64 detection_count{};
GestureType type{GestureType::Idle};
GestureDirection direction{GestureDirection::None};
Common::Point<s32> pos{};
Common::Point<s32> delta{};
f32 vel_x{};
f32 vel_y{};
GestureAttribute attributes{};
f32 scale{};
f32 rotation_angle{};
s32 point_count{};
std::array<Common::Point<s32>, 4> points{};
};
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
struct GestureProperties {
std::array<Common::Point<s32>, MAX_POINTS> points{};
std::size_t active_points{};
Common::Point<s32> mid_point{};
s64 detection_count{};
u64 delta_time{};
f32 average_distance{};
f32 angle{};
};
struct GestureSharedMemory {
// This is nn::hid::detail::GestureLifo
Lifo<GestureState, hid_entry_count> gesture_lifo{};
static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
INSERT_PADDING_WORDS(0x3E);
};
static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
// Reads input from all available input engines // Reads input from all available input engines
void ReadTouchInput(); void ReadTouchInput();
@ -74,7 +142,7 @@ private:
GestureProperties GetGestureProperties(); GestureProperties GetGestureProperties();
GestureState next_state{}; GestureState next_state{};
GestureSharedMemoryFormat& shared_memory; GestureSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedConsole* console = nullptr; Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};

View File

@ -1,18 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/common_types.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_devices.h" #include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/keyboard.h" #include "core/hle/service/hid/controllers/keyboard.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
KeyboardSharedMemoryFormat& keyboard_shared_memory) : ControllerBase{hid_core_} {
: ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} { static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
"KeyboardSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
emulated_devices = hid_core.GetEmulatedDevices(); emulated_devices = hid_core.GetEmulatedDevices();
} }
@ -24,12 +29,12 @@ void Keyboard::OnRelease() {}
void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.keyboard_lifo.buffer_count = 0; shared_memory->keyboard_lifo.buffer_count = 0;
shared_memory.keyboard_lifo.buffer_tail = 0; shared_memory->keyboard_lifo.buffer_tail = 0;
return; return;
} }
const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state; const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1; next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.keyboard_enabled) { if (Settings::values.keyboard_enabled) {
@ -41,7 +46,7 @@ void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.attribute.is_connected.Assign(1); next_state.attribute.is_connected.Assign(1);
} }
shared_memory.keyboard_lifo.WriteNextEntry(next_state); shared_memory->keyboard_lifo.WriteNextEntry(next_state);
} }
} // namespace Service::HID } // namespace Service::HID

View File

@ -3,16 +3,20 @@
#pragma once #pragma once
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/keyboard_types.h" #include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
struct KeyboardModifier;
struct KeyboardKey;
} // namespace Core::HID
namespace Service::HID { namespace Service::HID {
struct KeyboardSharedMemoryFormat;
class Keyboard final : public ControllerBase { class Keyboard final : public ControllerBase {
public: public:
explicit Keyboard(Core::HID::HIDCore& hid_core_, explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
KeyboardSharedMemoryFormat& keyboard_shared_memory);
~Keyboard() override; ~Keyboard() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -25,8 +29,25 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private: private:
// This is nn::hid::detail::KeyboardState
struct KeyboardState {
s64 sampling_number{};
Core::HID::KeyboardModifier modifier{};
Core::HID::KeyboardAttribute attribute{};
Core::HID::KeyboardKey key{};
};
static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
struct KeyboardSharedMemory {
// This is nn::hid::detail::KeyboardLifo
Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
INSERT_PADDING_WORDS(0xA);
};
static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
KeyboardState next_state{}; KeyboardState next_state{};
KeyboardSharedMemoryFormat& shared_memory; KeyboardSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedDevices* emulated_devices = nullptr; Core::HID::EmulatedDevices* emulated_devices = nullptr;
}; };
} // namespace Service::HID } // namespace Service::HID

View File

@ -1,17 +1,22 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/common_types.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/hid/emulated_devices.h" #include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/mouse.h" #include "core/hle/service/hid/controllers/mouse.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory) Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
: ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} { static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
"MouseSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
emulated_devices = hid_core.GetEmulatedDevices(); emulated_devices = hid_core.GetEmulatedDevices();
} }
@ -22,14 +27,14 @@ void Mouse::OnRelease() {}
void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.mouse_lifo.buffer_count = 0; shared_memory->mouse_lifo.buffer_count = 0;
shared_memory.mouse_lifo.buffer_tail = 0; shared_memory->mouse_lifo.buffer_tail = 0;
return; return;
} }
next_state = {}; next_state = {};
const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state; const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1; next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.mouse_enabled) { if (Settings::values.mouse_enabled) {
@ -48,7 +53,7 @@ void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.button = mouse_button_state; next_state.button = mouse_button_state;
} }
shared_memory.mouse_lifo.WriteNextEntry(next_state); shared_memory->mouse_lifo.WriteNextEntry(next_state);
} }
} // namespace Service::HID } // namespace Service::HID

View File

@ -3,7 +3,9 @@
#pragma once #pragma once
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID { namespace Core::HID {
class EmulatedDevices; class EmulatedDevices;
@ -12,11 +14,9 @@ struct AnalogStickState;
} // namespace Core::HID } // namespace Core::HID
namespace Service::HID { namespace Service::HID {
struct MouseSharedMemoryFormat;
class Mouse final : public ControllerBase { class Mouse final : public ControllerBase {
public: public:
explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory); explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Mouse() override; ~Mouse() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -29,9 +29,17 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private: private:
struct MouseSharedMemory {
// This is nn::hid::detail::MouseLifo
Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
INSERT_PADDING_WORDS(0x2C);
};
static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
Core::HID::MouseState next_state{}; Core::HID::MouseState next_state{};
Core::HID::AnalogStickState last_mouse_wheel_state{}; Core::HID::AnalogStickState last_mouse_wheel_state{};
MouseSharedMemoryFormat& shared_memory; MouseSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedDevices* emulated_devices = nullptr; Core::HID::EmulatedDevices* emulated_devices = nullptr;
}; };
} // namespace Service::HID } // namespace Service::HID

View File

@ -17,12 +17,12 @@
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/hid/hid_util.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t NPAD_OFFSET = 0x9A00;
constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3,
Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6,
@ -30,12 +30,14 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
Core::HID::NpadIdType::Handheld, Core::HID::NpadIdType::Handheld,
}; };
NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_) KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} { : ControllerBase{hid_core_}, service_context{service_context_} {
static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
for (std::size_t i = 0; i < controller_data.size(); ++i) { for (std::size_t i = 0; i < controller_data.size(); ++i) {
auto& controller = controller_data[i]; auto& controller = controller_data[i];
controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state; controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>(
raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState))));
controller.device = hid_core.GetEmulatedControllerByIndex(i); controller.device = hid_core.GetEmulatedControllerByIndex(i);
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
Core::HID::DEFAULT_VIBRATION_VALUE; Core::HID::DEFAULT_VIBRATION_VALUE;
@ -615,7 +617,7 @@ void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
hold_type = joy_hold_type; hold_type = joy_hold_type;
} }
NpadJoyHoldType NPad::GetHoldType() const { NPad::NpadJoyHoldType NPad::GetHoldType() const {
return hold_type; return hold_type;
} }
@ -628,7 +630,7 @@ void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_m
handheld_activation_mode = activation_mode; handheld_activation_mode = activation_mode;
} }
NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
return handheld_activation_mode; return handheld_activation_mode;
} }
@ -636,7 +638,7 @@ void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
communication_mode = communication_mode_; communication_mode = communication_mode_;
} }
NpadCommunicationMode NPad::GetNpadCommunicationMode() const { NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
return communication_mode; return communication_mode;
} }
@ -976,27 +978,27 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
return ResultSuccess; return ResultSuccess;
} }
NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo; return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo;
} }
NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) { NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo; return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo;
} }
NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) { NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo; return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo;
} }
NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) { NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo; return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo;
} }
NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) { NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo; return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo;
} }
NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) { NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo; return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo;
} }
@ -1341,7 +1343,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
} }
} }
AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory; const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory;
return { return {

View File

@ -8,10 +8,12 @@
#include <mutex> #include <mutex>
#include <span> #include <span>
#include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/npad_types.h" #include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID { namespace Core::HID {
class EmulatedController; class EmulatedController;
@ -30,13 +32,10 @@ class ServiceContext;
union Result; union Result;
namespace Service::HID { namespace Service::HID {
struct NpadInternalState;
struct NpadSixAxisSensorLifo;
struct NpadSharedMemoryFormat;
class NPad final : public ControllerBase { class NPad final : public ControllerBase {
public: public:
explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_); KernelHelpers::ServiceContext& service_context_);
~NPad() override; ~NPad() override;
@ -49,6 +48,89 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
// This is nn::hid::NpadJoyHoldType
enum class NpadJoyHoldType : u64 {
Vertical = 0,
Horizontal = 1,
};
// This is nn::hid::NpadJoyAssignmentMode
enum class NpadJoyAssignmentMode : u32 {
Dual = 0,
Single = 1,
};
// This is nn::hid::NpadJoyDeviceType
enum class NpadJoyDeviceType : s64 {
Left = 0,
Right = 1,
};
// This is nn::hid::NpadHandheldActivationMode
enum class NpadHandheldActivationMode : u64 {
Dual = 0,
Single = 1,
None = 2,
MaxActivationMode = 3,
};
// This is nn::hid::system::AppletFooterUiAttributesSet
struct AppletFooterUiAttributes {
INSERT_PADDING_BYTES(0x4);
};
// This is nn::hid::system::AppletFooterUiType
enum class AppletFooterUiType : u8 {
None = 0,
HandheldNone = 1,
HandheldJoyConLeftOnly = 2,
HandheldJoyConRightOnly = 3,
HandheldJoyConLeftJoyConRight = 4,
JoyDual = 5,
JoyDualLeftOnly = 6,
JoyDualRightOnly = 7,
JoyLeftHorizontal = 8,
JoyLeftVertical = 9,
JoyRightHorizontal = 10,
JoyRightVertical = 11,
SwitchProController = 12,
CompatibleProController = 13,
CompatibleJoyCon = 14,
LarkHvc1 = 15,
LarkHvc2 = 16,
LarkNesLeft = 17,
LarkNesRight = 18,
Lucia = 19,
Verification = 20,
Lagon = 21,
};
using AppletFooterUiVariant = u8;
// This is "nn::hid::system::AppletDetailedUiType".
struct AppletDetailedUiType {
AppletFooterUiVariant ui_variant;
INSERT_PADDING_BYTES(0x2);
AppletFooterUiType footer;
};
static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
// This is nn::hid::NpadCommunicationMode
enum class NpadCommunicationMode : u64 {
Mode_5ms = 0,
Mode_10ms = 1,
Mode_15ms = 2,
Default = 3,
};
enum class NpadRevision : u32 {
Revision0 = 0,
Revision1 = 1,
Revision2 = 2,
Revision3 = 3,
};
using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>;
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const; Core::HID::NpadStyleTag GetSupportedStyleSet() const;
@ -106,12 +188,12 @@ public:
Result ResetIsSixAxisSensorDeviceNewlyAssigned( Result ResetIsSixAxisSensorDeviceNewlyAssigned(
const Core::HID::SixAxisSensorHandle& sixaxis_handle); const Core::HID::SixAxisSensorHandle& sixaxis_handle);
NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id); SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id); SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id); SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id); SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id); SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id); SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
@ -139,6 +221,214 @@ public:
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
private: private:
static constexpr std::size_t NPAD_COUNT = 10;
// This is nn::hid::detail::ColorAttribute
enum class ColorAttribute : u32 {
Ok = 0,
ReadError = 1,
NoController = 2,
};
static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
// This is nn::hid::detail::NpadFullKeyColorState
struct NpadFullKeyColorState {
ColorAttribute attribute{ColorAttribute::NoController};
Core::HID::NpadControllerColor fullkey{};
};
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
// This is nn::hid::detail::NpadJoyColorState
struct NpadJoyColorState {
ColorAttribute attribute{ColorAttribute::NoController};
Core::HID::NpadControllerColor left{};
Core::HID::NpadControllerColor right{};
};
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
// This is nn::hid::NpadAttribute
struct NpadAttribute {
union {
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected;
BitField<3, 1, u32> is_left_wired;
BitField<4, 1, u32> is_right_connected;
BitField<5, 1, u32> is_right_wired;
};
};
static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
// This is nn::hid::NpadFullKeyState
// This is nn::hid::NpadHandheldState
// This is nn::hid::NpadJoyDualState
// This is nn::hid::NpadJoyLeftState
// This is nn::hid::NpadJoyRightState
// This is nn::hid::NpadPalmaState
// This is nn::hid::NpadSystemExtState
struct NPadGenericState {
s64_le sampling_number{};
Core::HID::NpadButtonState npad_buttons{};
Core::HID::AnalogStickState l_stick{};
Core::HID::AnalogStickState r_stick{};
NpadAttribute connection_status{};
INSERT_PADDING_BYTES(4); // Reserved
};
static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
// This is nn::hid::server::NpadGcTriggerState
struct NpadGcTriggerState {
s64 sampling_number{};
s32 l_analog{};
s32 r_analog{};
};
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
// This is nn::hid::NpadSystemProperties
struct NPadSystemProperties {
union {
s64 raw{};
BitField<0, 1, s64> is_charging_joy_dual;
BitField<1, 1, s64> is_charging_joy_left;
BitField<2, 1, s64> is_charging_joy_right;
BitField<3, 1, s64> is_powered_joy_dual;
BitField<4, 1, s64> is_powered_joy_left;
BitField<5, 1, s64> is_powered_joy_right;
BitField<9, 1, s64> is_system_unsupported_button;
BitField<10, 1, s64> is_system_ext_unsupported_button;
BitField<11, 1, s64> is_vertical;
BitField<12, 1, s64> is_horizontal;
BitField<13, 1, s64> use_plus;
BitField<14, 1, s64> use_minus;
BitField<15, 1, s64> use_directional_buttons;
};
};
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
// This is nn::hid::NpadSystemButtonProperties
struct NpadSystemButtonProperties {
union {
s32 raw{};
BitField<0, 1, s32> is_home_button_protection_enabled;
};
};
static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
"NPadButtonProperties is an invalid size");
// This is nn::hid::system::DeviceType
struct DeviceType {
union {
u32 raw{};
BitField<0, 1, s32> fullkey;
BitField<1, 1, s32> debug_pad;
BitField<2, 1, s32> handheld_left;
BitField<3, 1, s32> handheld_right;
BitField<4, 1, s32> joycon_left;
BitField<5, 1, s32> joycon_right;
BitField<6, 1, s32> palma;
BitField<7, 1, s32> lark_hvc_left;
BitField<8, 1, s32> lark_hvc_right;
BitField<9, 1, s32> lark_nes_left;
BitField<10, 1, s32> lark_nes_right;
BitField<11, 1, s32> handheld_lark_hvc_left;
BitField<12, 1, s32> handheld_lark_hvc_right;
BitField<13, 1, s32> handheld_lark_nes_left;
BitField<14, 1, s32> handheld_lark_nes_right;
BitField<15, 1, s32> lucia;
BitField<16, 1, s32> lagon;
BitField<17, 1, s32> lager;
BitField<31, 1, s32> system;
};
};
// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
struct NfcXcdDeviceHandleStateImpl {
u64 handle{};
bool is_available{};
bool is_activated{};
INSERT_PADDING_BYTES(0x6); // Reserved
u64 sampling_number{};
};
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
"NfcXcdDeviceHandleStateImpl is an invalid size");
// This is nn::hid::NpadLarkType
enum class NpadLarkType : u32 {
Invalid,
H1,
H2,
NL,
NR,
};
// This is nn::hid::NpadLuciaType
enum class NpadLuciaType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::NpadLagonType
enum class NpadLagonType : u32 {
Invalid,
};
// This is nn::hid::NpadLagerType
enum class NpadLagerType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::detail::NpadInternalState
struct NpadInternalState {
Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
NpadFullKeyColorState fullkey_color{};
NpadJoyColorState joycon_color{};
Lifo<NPadGenericState, hid_entry_count> fullkey_lifo{};
Lifo<NPadGenericState, hid_entry_count> handheld_lifo{};
Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{};
Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{};
Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{};
Lifo<NPadGenericState, hid_entry_count> palma_lifo{};
Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{};
Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{};
Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{};
Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{};
Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{};
Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{};
Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{};
DeviceType device_type{};
INSERT_PADDING_BYTES(0x4); // Reserved
NPadSystemProperties system_properties{};
NpadSystemButtonProperties button_properties{};
Core::HID::NpadBatteryLevel battery_level_dual{};
Core::HID::NpadBatteryLevel battery_level_left{};
Core::HID::NpadBatteryLevel battery_level_right{};
AppletFooterUiAttributes applet_footer_attributes{};
AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
INSERT_PADDING_BYTES(0x5B); // Reserved
INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
NpadLarkType lark_type_l_and_main{};
NpadLarkType lark_type_r{};
NpadLuciaType lucia_type{};
NpadLagonType lagon_type{};
NpadLagerType lager_type{};
Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
Core::HID::SixAxisSensorProperties sixaxis_left_properties;
Core::HID::SixAxisSensorProperties sixaxis_right_properties;
INSERT_PADDING_BYTES(0xc06); // Unknown
};
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
struct VibrationData { struct VibrationData {
bool device_mounted{}; bool device_mounted{};
Core::HID::VibrationValue latest_vibration_value{}; Core::HID::VibrationValue latest_vibration_value{};
@ -189,7 +479,7 @@ private:
std::atomic<u64> press_state{}; std::atomic<u64> press_state{};
std::array<NpadControllerData, NpadCount> controller_data{}; std::array<NpadControllerData, NPAD_COUNT> controller_data{};
KernelHelpers::ServiceContext& service_context; KernelHelpers::ServiceContext& service_context;
std::mutex mutex; std::mutex mutex;
std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; std::vector<Core::HID::NpadIdType> supported_npad_id_types{};

View File

@ -12,7 +12,8 @@
namespace Service::HID { namespace Service::HID {
Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} { : ControllerBase{hid_core_}, service_context{service_context_} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");

View File

@ -97,7 +97,8 @@ public:
static_assert(sizeof(PalmaConnectionHandle) == 0x8, static_assert(sizeof(PalmaConnectionHandle) == 0x8,
"PalmaConnectionHandle has incorrect size."); "PalmaConnectionHandle has incorrect size.");
explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_);
~Palma() override; ~Palma() override;
// Called when the controller is initialized // Called when the controller is initialized

View File

@ -1,240 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/vector_math.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid//controllers/types/debug_pad_types.h"
#include "core/hle/service/hid//controllers/types/keyboard_types.h"
#include "core/hle/service/hid//controllers/types/mouse_types.h"
#include "core/hle/service/hid//controllers/types/npad_types.h"
#include "core/hle/service/hid//controllers/types/touch_types.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID {
static const std::size_t HidEntryCount = 17;
struct CommonHeader {
s64 timestamp{};
s64 total_entry_count{};
s64 last_entry_index{};
s64 entry_count{};
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
// This is nn::hid::detail::DebugPadSharedMemoryFormat
struct DebugPadSharedMemoryFormat {
// This is nn::hid::detail::DebugPadLifo
Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{};
static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
INSERT_PADDING_WORDS(0x4E);
};
static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400,
"DebugPadSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::TouchScreenSharedMemoryFormat
struct TouchScreenSharedMemoryFormat {
// This is nn::hid::detail::TouchScreenLifo
Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{};
static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
INSERT_PADDING_WORDS(0xF2);
};
static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000,
"TouchScreenSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::MouseSharedMemoryFormat
struct MouseSharedMemoryFormat {
// This is nn::hid::detail::MouseLifo
Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{};
static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
INSERT_PADDING_WORDS(0x2C);
};
static_assert(sizeof(MouseSharedMemoryFormat) == 0x400,
"MouseSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::KeyboardSharedMemoryFormat
struct KeyboardSharedMemoryFormat {
// This is nn::hid::detail::KeyboardLifo
Lifo<KeyboardState, HidEntryCount> keyboard_lifo{};
static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
INSERT_PADDING_WORDS(0xA);
};
static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400,
"KeyboardSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::DigitizerSharedMemoryFormat
struct DigitizerSharedMemoryFormat {
CommonHeader header;
INSERT_PADDING_BYTES(0xFE0);
};
static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
"DigitizerSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::HomeButtonSharedMemoryFormat
struct HomeButtonSharedMemoryFormat {
CommonHeader header;
INSERT_PADDING_BYTES(0x1E0);
};
static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
"HomeButtonSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::SleepButtonSharedMemoryFormat
struct SleepButtonSharedMemoryFormat {
CommonHeader header;
INSERT_PADDING_BYTES(0x1E0);
};
static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
"SleepButtonSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
struct CaptureButtonSharedMemoryFormat {
CommonHeader header;
INSERT_PADDING_BYTES(0x1E0);
};
static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
"CaptureButtonSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::InputDetectorSharedMemoryFormat
struct InputDetectorSharedMemoryFormat {
CommonHeader header;
INSERT_PADDING_BYTES(0x7E0);
};
static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800,
"InputDetectorSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::UniquePadSharedMemoryFormat
struct UniquePadSharedMemoryFormat {
CommonHeader header;
INSERT_PADDING_BYTES(0x3FE0);
};
static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000,
"UniquePadSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::NpadSixAxisSensorLifo
struct NpadSixAxisSensorLifo {
Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo;
};
// This is nn::hid::detail::NpadInternalState
struct NpadInternalState {
Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
NpadFullKeyColorState fullkey_color{};
NpadJoyColorState joycon_color{};
Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{};
Lifo<NPadGenericState, HidEntryCount> handheld_lifo{};
Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{};
Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{};
Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{};
Lifo<NPadGenericState, HidEntryCount> palma_lifo{};
Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{};
NpadSixAxisSensorLifo sixaxis_fullkey_lifo{};
NpadSixAxisSensorLifo sixaxis_handheld_lifo{};
NpadSixAxisSensorLifo sixaxis_dual_left_lifo{};
NpadSixAxisSensorLifo sixaxis_dual_right_lifo{};
NpadSixAxisSensorLifo sixaxis_left_lifo{};
NpadSixAxisSensorLifo sixaxis_right_lifo{};
DeviceType device_type{};
INSERT_PADDING_BYTES(0x4); // Reserved
NPadSystemProperties system_properties{};
NpadSystemButtonProperties button_properties{};
Core::HID::NpadBatteryLevel battery_level_dual{};
Core::HID::NpadBatteryLevel battery_level_left{};
Core::HID::NpadBatteryLevel battery_level_right{};
AppletFooterUiAttributes applet_footer_attributes{};
AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
INSERT_PADDING_BYTES(0x5B); // Reserved
INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{};
NpadLarkType lark_type_l_and_main{};
NpadLarkType lark_type_r{};
NpadLuciaType lucia_type{};
NpadLagerType lager_type{};
Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
Core::HID::SixAxisSensorProperties sixaxis_left_properties;
Core::HID::SixAxisSensorProperties sixaxis_right_properties;
};
static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size");
// This is nn::hid::detail::NpadSharedMemoryEntry
struct NpadSharedMemoryEntry {
NpadInternalState internal_state;
INSERT_PADDING_BYTES(0xC08);
};
static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size");
// This is nn::hid::detail::NpadSharedMemoryFormat
struct NpadSharedMemoryFormat {
std::array<NpadSharedMemoryEntry, NpadCount> npad_entry;
};
static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000,
"NpadSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::GestureSharedMemoryFormat
struct GestureSharedMemoryFormat {
// This is nn::hid::detail::GestureLifo
Lifo<GestureState, HidEntryCount> gesture_lifo{};
static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
INSERT_PADDING_WORDS(0x3E);
};
static_assert(sizeof(GestureSharedMemoryFormat) == 0x800,
"GestureSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
struct ConsoleSixAxisSensorSharedMemoryFormat {
u64 sampling_number{};
bool is_seven_six_axis_sensor_at_rest{};
INSERT_PADDING_BYTES(3); // padding
f32 verticalization_error{};
Common::Vec3f gyro_bias{};
INSERT_PADDING_BYTES(4); // padding
};
static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
"ConsoleSixAxisSensorSharedMemoryFormat is an invalid size");
// This is nn::hid::detail::SharedMemoryFormat
struct SharedMemoryFormat {
void Initialize() {}
DebugPadSharedMemoryFormat debug_pad;
TouchScreenSharedMemoryFormat touch_screen;
MouseSharedMemoryFormat mouse;
KeyboardSharedMemoryFormat keyboard;
DigitizerSharedMemoryFormat digitizer;
HomeButtonSharedMemoryFormat home_button;
SleepButtonSharedMemoryFormat sleep_button;
CaptureButtonSharedMemoryFormat capture_button;
InputDetectorSharedMemoryFormat input_detector;
UniquePadSharedMemoryFormat unique_pad;
NpadSharedMemoryFormat npad;
GestureSharedMemoryFormat gesture;
ConsoleSixAxisSensorSharedMemoryFormat console;
INSERT_PADDING_BYTES(0x19E0);
MouseSharedMemoryFormat debug_mouse;
INSERT_PADDING_BYTES(0x2000);
};
static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset");
static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset");
static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset");
static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset");
static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00,
"sleep_button has wrong offset");
static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000,
"capture_button has wrong offset");
static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200,
"input_detector has wrong offset");
static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset");
static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
} // namespace Service::HID

View File

@ -1,53 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/shared_memory_holder.h"
#include "core/hle/service/hid/errors.h"
namespace Service::HID {
SharedMemoryHolder::SharedMemoryHolder() {}
SharedMemoryHolder::~SharedMemoryHolder() {
Finalize();
}
Result SharedMemoryHolder::Initialize(Core::System& system) {
shared_memory = Kernel::KSharedMemory::Create(system.Kernel());
const Result result = shared_memory->Initialize(
system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None,
Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat));
if (result.IsError()) {
return result;
}
Kernel::KSharedMemory::Register(system.Kernel(), shared_memory);
is_created = true;
is_mapped = true;
address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer()));
return ResultSuccess;
}
void SharedMemoryHolder::Finalize() {
if (address != nullptr) {
shared_memory->Close();
}
is_created = false;
is_mapped = false;
address = nullptr;
}
bool SharedMemoryHolder::IsMapped() {
return is_mapped;
}
SharedMemoryFormat* SharedMemoryHolder::GetAddress() {
return address;
}
Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() {
return shared_memory;
}
} // namespace Service::HID

View File

@ -1,44 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Core {
class System;
}
namespace Kernel {
class KSharedMemory;
}
namespace Service::HID {
struct SharedMemoryFormat;
// This is nn::hid::detail::SharedMemoryHolder
class SharedMemoryHolder {
public:
SharedMemoryHolder();
~SharedMemoryHolder();
Result Initialize(Core::System& system);
void Finalize();
bool IsMapped();
SharedMemoryFormat* GetAddress();
Kernel::KSharedMemory* GetHandle();
private:
bool is_owner{};
bool is_created{};
bool is_mapped{};
INSERT_PADDING_BYTES(0x5);
Kernel::KSharedMemory* shared_memory;
INSERT_PADDING_BYTES(0x38);
SharedMemoryFormat* address = nullptr;
};
// Correct size is 0x50 bytes
static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
} // namespace Service::HID

View File

@ -6,7 +6,6 @@
#include "core/hid/emulated_controller.h" #include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/hid/hid_util.h"
@ -133,30 +132,30 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
} }
sixaxis_fullkey_state.sampling_number = sixaxis_fullkey_state.sampling_number =
sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_handheld_state.sampling_number = sixaxis_handheld_state.sampling_number =
sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_dual_left_state.sampling_number = sixaxis_dual_left_state.sampling_number =
sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_dual_right_state.sampling_number = sixaxis_dual_right_state.sampling_number =
sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_left_lifo_state.sampling_number = sixaxis_left_lifo_state.sampling_number =
sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_right_lifo_state.sampling_number = sixaxis_right_lifo_state.sampling_number =
sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
// This buffer only is updated on handheld on HW // This buffer only is updated on handheld on HW
sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state); sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
} else { } else {
// Handheld doesn't update this buffer on HW // Handheld doesn't update this buffer on HW
sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state); sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
} }
sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state); sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state); sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state); sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state); sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
} }
} }

View File

@ -1,15 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/common_types.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/stubbed.h" #include "core/hle/service/hid/controllers/stubbed.h"
namespace Service::HID { namespace Service::HID {
Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
CommonHeader& ring_lifo_header) : ControllerBase{hid_core_} {
: ControllerBase{hid_core_}, header{ring_lifo_header} {} raw_shared_memory = raw_shared_memory_;
}
Controller_Stubbed::~Controller_Stubbed() = default; Controller_Stubbed::~Controller_Stubbed() = default;
@ -22,10 +25,18 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return; return;
} }
CommonHeader header{};
header.timestamp = core_timing.GetGlobalTimeNs().count(); header.timestamp = core_timing.GetGlobalTimeNs().count();
header.total_entry_count = 17; header.total_entry_count = 17;
header.entry_count = 0; header.entry_count = 0;
header.last_entry_index = 0; header.last_entry_index = 0;
std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
}
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
common_offset = off;
smart_update = true;
} }
} // namespace Service::HID } // namespace Service::HID

View File

@ -3,14 +3,13 @@
#pragma once #pragma once
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
namespace Service::HID { namespace Service::HID {
struct CommonHeader;
class Controller_Stubbed final : public ControllerBase { class Controller_Stubbed final : public ControllerBase {
public: public:
explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header); explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Controller_Stubbed() override; ~Controller_Stubbed() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -22,8 +21,19 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
void SetCommonHeaderOffset(std::size_t off);
private: private:
CommonHeader& header; struct CommonHeader {
s64 timestamp{};
s64 total_entry_count{};
s64 last_entry_index{};
s64 entry_count{};
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
u8* raw_shared_memory = nullptr;
bool smart_update{}; bool smart_update{};
std::size_t common_offset{};
}; };
} // namespace Service::HID } // namespace Service::HID

View File

@ -2,22 +2,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <algorithm>
#include <cstring>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/hid/emulated_console.h" #include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/touchscreen.h" #include "core/hle/service/hid/controllers/touchscreen.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
TouchScreenSharedMemoryFormat& touch_shared_memory) : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
: ControllerBase{hid_core_}, shared_memory{touch_shared_memory},
touchscreen_width(Layout::ScreenUndocked::Width),
touchscreen_height(Layout::ScreenUndocked::Height) { touchscreen_height(Layout::ScreenUndocked::Height) {
static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
"TouchSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
console = hid_core.GetEmulatedConsole(); console = hid_core.GetEmulatedConsole();
} }
@ -28,11 +32,11 @@ void TouchScreen::OnInit() {}
void TouchScreen::OnRelease() {} void TouchScreen::OnRelease() {}
void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.touch_screen_lifo.buffer_count = 0; shared_memory->touch_screen_lifo.buffer_count = 0;
shared_memory.touch_screen_lifo.buffer_tail = 0; shared_memory->touch_screen_lifo.buffer_tail = 0;
return; return;
} }
@ -82,7 +86,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count()); const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state; const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1; next_state.sampling_number = last_entry.sampling_number + 1;
next_state.entry_count = static_cast<s32>(active_fingers_count); next_state.entry_count = static_cast<s32>(active_fingers_count);
@ -114,7 +118,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
} }
} }
shared_memory.touch_screen_lifo.WriteNextEntry(next_state); shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
} }
void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) { void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {

View File

@ -3,23 +3,20 @@
#pragma once #pragma once
#include <array> #include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/touch_types.h" #include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID { namespace Core::HID {
class EmulatedConsole; class EmulatedConsole;
} // namespace Core::HID } // namespace Core::HID
namespace Service::HID { namespace Service::HID {
struct TouchScreenSharedMemoryFormat;
class TouchScreen final : public ControllerBase { class TouchScreen final : public ControllerBase {
public: public:
explicit TouchScreen(Core::HID::HIDCore& hid_core_, explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
TouchScreenSharedMemoryFormat& touch_shared_memory);
~TouchScreen() override; ~TouchScreen() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -34,8 +31,27 @@ public:
void SetTouchscreenDimensions(u32 width, u32 height); void SetTouchscreenDimensions(u32 width, u32 height);
private: private:
static constexpr std::size_t MAX_FINGERS = 16;
// This is nn::hid::TouchScreenState
struct TouchScreenState {
s64 sampling_number{};
s32 entry_count{};
INSERT_PADDING_BYTES(4); // Reserved
std::array<Core::HID::TouchState, MAX_FINGERS> states{};
};
static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
struct TouchSharedMemory {
// This is nn::hid::detail::TouchScreenLifo
Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
INSERT_PADDING_WORDS(0xF2);
};
static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
TouchScreenState next_state{}; TouchScreenState next_state{};
TouchScreenSharedMemoryFormat& shared_memory; TouchSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedConsole* console = nullptr; Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};

View File

@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hid/hid_types.h"
namespace Service::HID {
// This is nn::hid::DebugPadAttribute
struct DebugPadAttribute {
union {
u32 raw{};
BitField<0, 1, u32> connected;
};
};
static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
// This is nn::hid::DebugPadState
struct DebugPadState {
s64 sampling_number{};
DebugPadAttribute attribute{};
Core::HID::DebugPadButton pad_state{};
Core::HID::AnalogStickState r_stick{};
Core::HID::AnalogStickState l_stick{};
};
static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
} // namespace Service::HID

View File

@ -1,77 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/point.h"
namespace Service::HID {
static constexpr size_t MAX_FINGERS = 16;
static constexpr size_t MAX_POINTS = 4;
// This is nn::hid::GestureType
enum class GestureType : u32 {
Idle, // Nothing touching the screen
Complete, // Set at the end of a touch event
Cancel, // Set when the number of fingers change
Touch, // A finger just touched the screen
Press, // Set if last type is touch and the finger hasn't moved
Tap, // Fast press then release
Pan, // All points moving together across the screen
Swipe, // Fast press movement and release of a single point
Pinch, // All points moving away/closer to the midpoint
Rotate, // All points rotating from the midpoint
};
// This is nn::hid::GestureDirection
enum class GestureDirection : u32 {
None,
Left,
Up,
Right,
Down,
};
// This is nn::hid::GestureAttribute
struct GestureAttribute {
union {
u32 raw{};
BitField<4, 1, u32> is_new_touch;
BitField<8, 1, u32> is_double_tap;
};
};
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
// This is nn::hid::GestureState
struct GestureState {
s64 sampling_number{};
s64 detection_count{};
GestureType type{GestureType::Idle};
GestureDirection direction{GestureDirection::None};
Common::Point<s32> pos{};
Common::Point<s32> delta{};
f32 vel_x{};
f32 vel_y{};
GestureAttribute attributes{};
f32 scale{};
f32 rotation_angle{};
s32 point_count{};
std::array<Common::Point<s32>, 4> points{};
};
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
struct GestureProperties {
std::array<Common::Point<s32>, MAX_POINTS> points{};
std::size_t active_points{};
Common::Point<s32> mid_point{};
s64 detection_count{};
u64 delta_time{};
f32 average_distance{};
f32 angle{};
};
} // namespace Service::HID

View File

@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/hid/hid_types.h"
namespace Service::HID {
// This is nn::hid::detail::KeyboardState
struct KeyboardState {
s64 sampling_number{};
Core::HID::KeyboardModifier modifier{};
Core::HID::KeyboardAttribute attribute{};
Core::HID::KeyboardKey key{};
};
static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
} // namespace Service::HID

View File

@ -1,8 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/common_types.h"
namespace Service::HID {} // namespace Service::HID

View File

@ -1,254 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hid/hid_types.h"
namespace Service::HID {
static constexpr std::size_t NpadCount = 10;
// This is nn::hid::NpadJoyHoldType
enum class NpadJoyHoldType : u64 {
Vertical = 0,
Horizontal = 1,
};
// This is nn::hid::NpadJoyAssignmentMode
enum class NpadJoyAssignmentMode : u32 {
Dual = 0,
Single = 1,
};
// This is nn::hid::NpadJoyDeviceType
enum class NpadJoyDeviceType : s64 {
Left = 0,
Right = 1,
};
// This is nn::hid::NpadHandheldActivationMode
enum class NpadHandheldActivationMode : u64 {
Dual = 0,
Single = 1,
None = 2,
MaxActivationMode = 3,
};
// This is nn::hid::system::AppletFooterUiAttributesSet
struct AppletFooterUiAttributes {
INSERT_PADDING_BYTES(0x4);
};
// This is nn::hid::system::AppletFooterUiType
enum class AppletFooterUiType : u8 {
None = 0,
HandheldNone = 1,
HandheldJoyConLeftOnly = 2,
HandheldJoyConRightOnly = 3,
HandheldJoyConLeftJoyConRight = 4,
JoyDual = 5,
JoyDualLeftOnly = 6,
JoyDualRightOnly = 7,
JoyLeftHorizontal = 8,
JoyLeftVertical = 9,
JoyRightHorizontal = 10,
JoyRightVertical = 11,
SwitchProController = 12,
CompatibleProController = 13,
CompatibleJoyCon = 14,
LarkHvc1 = 15,
LarkHvc2 = 16,
LarkNesLeft = 17,
LarkNesRight = 18,
Lucia = 19,
Verification = 20,
Lagon = 21,
};
using AppletFooterUiVariant = u8;
// This is "nn::hid::system::AppletDetailedUiType".
struct AppletDetailedUiType {
AppletFooterUiVariant ui_variant;
INSERT_PADDING_BYTES(0x2);
AppletFooterUiType footer;
};
static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
// This is nn::hid::NpadCommunicationMode
enum class NpadCommunicationMode : u64 {
Mode_5ms = 0,
Mode_10ms = 1,
Mode_15ms = 2,
Default = 3,
};
enum class NpadRevision : u32 {
Revision0 = 0,
Revision1 = 1,
Revision2 = 2,
Revision3 = 3,
};
// This is nn::hid::detail::ColorAttribute
enum class ColorAttribute : u32 {
Ok = 0,
ReadError = 1,
NoController = 2,
};
static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
// This is nn::hid::detail::NpadFullKeyColorState
struct NpadFullKeyColorState {
ColorAttribute attribute{ColorAttribute::NoController};
Core::HID::NpadControllerColor fullkey{};
};
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
// This is nn::hid::detail::NpadJoyColorState
struct NpadJoyColorState {
ColorAttribute attribute{ColorAttribute::NoController};
Core::HID::NpadControllerColor left{};
Core::HID::NpadControllerColor right{};
};
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
// This is nn::hid::NpadAttribute
struct NpadAttribute {
union {
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected;
BitField<3, 1, u32> is_left_wired;
BitField<4, 1, u32> is_right_connected;
BitField<5, 1, u32> is_right_wired;
};
};
static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
// This is nn::hid::NpadFullKeyState
// This is nn::hid::NpadHandheldState
// This is nn::hid::NpadJoyDualState
// This is nn::hid::NpadJoyLeftState
// This is nn::hid::NpadJoyRightState
// This is nn::hid::NpadPalmaState
// This is nn::hid::NpadSystemExtState
struct NPadGenericState {
s64_le sampling_number{};
Core::HID::NpadButtonState npad_buttons{};
Core::HID::AnalogStickState l_stick{};
Core::HID::AnalogStickState r_stick{};
NpadAttribute connection_status{};
INSERT_PADDING_BYTES(4); // Reserved
};
static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
// This is nn::hid::server::NpadGcTriggerState
struct NpadGcTriggerState {
s64 sampling_number{};
s32 l_analog{};
s32 r_analog{};
};
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
// This is nn::hid::NpadSystemProperties
struct NPadSystemProperties {
union {
s64 raw{};
BitField<0, 1, s64> is_charging_joy_dual;
BitField<1, 1, s64> is_charging_joy_left;
BitField<2, 1, s64> is_charging_joy_right;
BitField<3, 1, s64> is_powered_joy_dual;
BitField<4, 1, s64> is_powered_joy_left;
BitField<5, 1, s64> is_powered_joy_right;
BitField<9, 1, s64> is_system_unsupported_button;
BitField<10, 1, s64> is_system_ext_unsupported_button;
BitField<11, 1, s64> is_vertical;
BitField<12, 1, s64> is_horizontal;
BitField<13, 1, s64> use_plus;
BitField<14, 1, s64> use_minus;
BitField<15, 1, s64> use_directional_buttons;
};
};
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
// This is nn::hid::NpadSystemButtonProperties
struct NpadSystemButtonProperties {
union {
s32 raw{};
BitField<0, 1, s32> is_home_button_protection_enabled;
};
};
static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
// This is nn::hid::system::DeviceType
struct DeviceType {
union {
u32 raw{};
BitField<0, 1, s32> fullkey;
BitField<1, 1, s32> debug_pad;
BitField<2, 1, s32> handheld_left;
BitField<3, 1, s32> handheld_right;
BitField<4, 1, s32> joycon_left;
BitField<5, 1, s32> joycon_right;
BitField<6, 1, s32> palma;
BitField<7, 1, s32> lark_hvc_left;
BitField<8, 1, s32> lark_hvc_right;
BitField<9, 1, s32> lark_nes_left;
BitField<10, 1, s32> lark_nes_right;
BitField<11, 1, s32> handheld_lark_hvc_left;
BitField<12, 1, s32> handheld_lark_hvc_right;
BitField<13, 1, s32> handheld_lark_nes_left;
BitField<14, 1, s32> handheld_lark_nes_right;
BitField<15, 1, s32> lucia;
BitField<16, 1, s32> lagon;
BitField<17, 1, s32> lager;
BitField<31, 1, s32> system;
};
};
// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
struct NfcXcdDeviceHandleStateImpl {
u64 handle{};
bool is_available{};
bool is_activated{};
INSERT_PADDING_BYTES(0x6); // Reserved
u64 sampling_number{};
};
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
"NfcXcdDeviceHandleStateImpl is an invalid size");
// This is nn::hid::NpadLarkType
enum class NpadLarkType : u32 {
Invalid,
H1,
H2,
NL,
NR,
};
// This is nn::hid::NpadLuciaType
enum class NpadLuciaType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::NpadLagonType
enum class NpadLagonType : u32 {
Invalid,
};
// This is nn::hid::NpadLagerType
enum class NpadLagerType : u32 {
Invalid,
J,
E,
U,
};
} // namespace Service::HID

View File

@ -1,90 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <array>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/point.h"
#include "core/hid/hid_types.h"
namespace Service::HID {
static constexpr std::size_t MAX_FINGERS = 16;
static constexpr size_t MAX_POINTS = 4;
// This is nn::hid::GestureType
enum class GestureType : u32 {
Idle, // Nothing touching the screen
Complete, // Set at the end of a touch event
Cancel, // Set when the number of fingers change
Touch, // A finger just touched the screen
Press, // Set if last type is touch and the finger hasn't moved
Tap, // Fast press then release
Pan, // All points moving together across the screen
Swipe, // Fast press movement and release of a single point
Pinch, // All points moving away/closer to the midpoint
Rotate, // All points rotating from the midpoint
};
// This is nn::hid::GestureDirection
enum class GestureDirection : u32 {
None,
Left,
Up,
Right,
Down,
};
// This is nn::hid::GestureAttribute
struct GestureAttribute {
union {
u32 raw{};
BitField<4, 1, u32> is_new_touch;
BitField<8, 1, u32> is_double_tap;
};
};
static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
// This is nn::hid::GestureState
struct GestureState {
s64 sampling_number{};
s64 detection_count{};
GestureType type{GestureType::Idle};
GestureDirection direction{GestureDirection::None};
Common::Point<s32> pos{};
Common::Point<s32> delta{};
f32 vel_x{};
f32 vel_y{};
GestureAttribute attributes{};
f32 scale{};
f32 rotation_angle{};
s32 point_count{};
std::array<Common::Point<s32>, 4> points{};
};
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
struct GestureProperties {
std::array<Common::Point<s32>, MAX_POINTS> points{};
std::size_t active_points{};
Common::Point<s32> mid_point{};
s64 detection_count{};
u64 delta_time{};
f32 average_distance{};
f32 angle{};
};
// This is nn::hid::TouchScreenState
struct TouchScreenState {
s64 sampling_number{};
s32 entry_count{};
INSERT_PADDING_BYTES(4); // Reserved
std::array<Core::HID::TouchState, MAX_FINGERS> states{};
};
static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
} // namespace Service::HID

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
"XpadSharedMemory is bigger than the shared memory");
shared_memory = std::construct_at(
reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
}
XPad::~XPad() = default;
void XPad::OnInit() {}
void XPad::OnRelease() {}
void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
shared_memory->basic_xpad_lifo.buffer_count = 0;
shared_memory->basic_xpad_lifo.buffer_tail = 0;
return;
}
const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
// TODO(ogniK): Update xpad states
shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID

View File

@ -0,0 +1,112 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID {
class XPad final : public ControllerBase {
public:
explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~XPad() override;
// Called when the controller is initialized
void OnInit() override;
// When the controller is released
void OnRelease() override;
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
// This is nn::hid::BasicXpadAttributeSet
struct BasicXpadAttributeSet {
union {
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected;
BitField<3, 1, u32> is_left_wired;
BitField<4, 1, u32> is_right_connected;
BitField<5, 1, u32> is_right_wired;
};
};
static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
// This is nn::hid::BasicXpadButtonSet
struct BasicXpadButtonSet {
union {
u32 raw{};
// Button states
BitField<0, 1, u32> a;
BitField<1, 1, u32> b;
BitField<2, 1, u32> x;
BitField<3, 1, u32> y;
BitField<4, 1, u32> l_stick;
BitField<5, 1, u32> r_stick;
BitField<6, 1, u32> l;
BitField<7, 1, u32> r;
BitField<8, 1, u32> zl;
BitField<9, 1, u32> zr;
BitField<10, 1, u32> plus;
BitField<11, 1, u32> minus;
// D-Pad
BitField<12, 1, u32> d_left;
BitField<13, 1, u32> d_up;
BitField<14, 1, u32> d_right;
BitField<15, 1, u32> d_down;
// Left JoyStick
BitField<16, 1, u32> l_stick_left;
BitField<17, 1, u32> l_stick_up;
BitField<18, 1, u32> l_stick_right;
BitField<19, 1, u32> l_stick_down;
// Right JoyStick
BitField<20, 1, u32> r_stick_left;
BitField<21, 1, u32> r_stick_up;
BitField<22, 1, u32> r_stick_right;
BitField<23, 1, u32> r_stick_down;
// Not always active?
BitField<24, 1, u32> left_sl;
BitField<25, 1, u32> left_sr;
BitField<26, 1, u32> right_sl;
BitField<27, 1, u32> right_sr;
BitField<28, 1, u32> palma;
BitField<30, 1, u32> handheld_left_b;
};
};
static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
// This is nn::hid::detail::BasicXpadState
struct BasicXpadState {
s64 sampling_number{};
BasicXpadAttributeSet attributes{};
BasicXpadButtonSet pad_states{};
Core::HID::AnalogStickState l_stick{};
Core::HID::AnalogStickState r_stick{};
};
static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
struct XpadSharedMemory {
// This is nn::hid::detail::BasicXpadLifo
Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
INSERT_PADDING_WORDS(0x4E);
};
static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
BasicXpadState next_state{};
XpadSharedMemory* shared_memory = nullptr;
};
} // namespace Service::HID

View File

@ -28,7 +28,6 @@
#include "core/hle/service/hid/controllers/seven_six_axis.h" #include "core/hle/service/hid/controllers/seven_six_axis.h"
#include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/controllers/touchscreen.h" #include "core/hle/service/hid/controllers/touchscreen.h"
#include "core/hle/service/hid/controllers/types/npad_types.h"
namespace Service::HID { namespace Service::HID {
@ -51,7 +50,7 @@ private:
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
if (resource_manager != nullptr && resource_manager->GetNpad()) { if (resource_manager != nullptr) {
resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle); resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle);
} }
@ -1100,7 +1099,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
NpadRevision revision; NPad::NpadRevision revision;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
@ -1123,7 +1122,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
const auto hold_type{rp.PopEnum<NpadJoyHoldType>()}; const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()};
GetResourceManager()->GetNpad()->SetHoldType(hold_type); GetResourceManager()->GetNpad()->SetHoldType(hold_type);
@ -1158,8 +1157,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx)
Core::HID::NpadIdType new_npad_id{}; Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad(); auto controller = GetResourceManager()->GetNpad();
controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left, controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left,
NpadJoyAssignmentMode::Single); NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id); parameters.applet_resource_user_id);
@ -1174,7 +1173,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
Core::HID::NpadIdType npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
NpadJoyDeviceType npad_joy_device_type; NPad::NpadJoyDeviceType npad_joy_device_type;
}; };
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@ -1183,7 +1182,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
Core::HID::NpadIdType new_npad_id{}; Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad(); auto controller = GetResourceManager()->GetNpad();
controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
NpadJoyAssignmentMode::Single); NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id, parameters.npad_id, parameters.applet_resource_user_id,
@ -1206,7 +1205,7 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
Core::HID::NpadIdType new_npad_id{}; Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad(); auto controller = GetResourceManager()->GetNpad();
controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual); controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual);
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id); // Spams a lot when controller applet is open parameters.applet_resource_user_id); // Spams a lot when controller applet is open
@ -1258,7 +1257,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()}; const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()};
GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode); GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode);
@ -1350,7 +1349,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
Core::HID::NpadIdType npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
NpadJoyDeviceType npad_joy_device_type; NPad::NpadJoyDeviceType npad_joy_device_type;
}; };
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@ -1360,7 +1359,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
auto controller = GetResourceManager()->GetNpad(); auto controller = GetResourceManager()->GetNpad();
const auto is_reassigned = const auto is_reassigned =
controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
NpadJoyAssignmentMode::Single); NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id, parameters.npad_id, parameters.applet_resource_user_id,
@ -2316,7 +2315,7 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()}; const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()};
GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode); GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode);

View File

@ -5,7 +5,6 @@
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/palma.h" #include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/touchscreen.h" #include "core/hle/service/hid/controllers/touchscreen.h"
#include "core/hle/service/hid/controllers/types/npad_types.h"
#include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_system_server.h" #include "core/hle/service/hid/hid_system_server.h"
#include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/hid/resource_manager.h"
@ -329,7 +328,7 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, npad_id_type={}", LOG_DEBUG(Service_HID, "called, npad_id_type={}",
npad_id_type); // Spams a lot when controller applet is running npad_id_type); // Spams a lot when controller applet is running
const AppletDetailedUiType detailed_ui_type = const NPad::AppletDetailedUiType detailed_ui_type =
GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type); GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type);
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};

View File

@ -18,10 +18,10 @@
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/palma.h" #include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/seven_six_axis.h" #include "core/hle/service/hid/controllers/seven_six_axis.h"
#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/controllers/stubbed.h" #include "core/hle/service/hid/controllers/stubbed.h"
#include "core/hle/service/hid/controllers/touchscreen.h" #include "core/hle/service/hid/controllers/touchscreen.h"
#include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID { namespace Service::HID {
@ -45,43 +45,40 @@ void ResourceManager::Initialize() {
return; return;
} }
system.HIDCore().ReloadInputDevices(); u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
is_initialized = true; debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory);
} mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory);
debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory);
keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory);
unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory);
npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context);
gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory);
touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory);
xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory);
void ResourceManager::InitializeController(u64 aruid) { palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context);
SharedMemoryFormat* shared_memory = nullptr;
const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid);
if (result.IsError()) {
return;
}
debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad); home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory);
mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse); sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory);
debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse); capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory);
keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard);
unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header);
npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context);
gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture);
touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen);
palma = std::make_shared<Palma>(system.HIDCore(), service_context);
home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header);
sleep_button =
std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header);
capture_button =
std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header);
digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header);
six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console); console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory);
seven_six_axis = std::make_shared<SevenSixAxis>(system); seven_six_axis = std::make_shared<SevenSixAxis>(system);
home_button->SetCommonHeaderOffset(0x4C00);
sleep_button->SetCommonHeaderOffset(0x4E00);
capture_button->SetCommonHeaderOffset(0x5000);
unique_pad->SetCommonHeaderOffset(0x5A00);
debug_mouse->SetCommonHeaderOffset(0x3DC00);
// Homebrew doesn't try to activate some controllers, so we activate them by default // Homebrew doesn't try to activate some controllers, so we activate them by default
npad->Activate(); npad->Activate();
six_axis->Activate(); six_axis->Activate();
touch_screen->Activate(); touch_screen->Activate();
system.HIDCore().ReloadInputDevices();
is_initialized = true;
} }
std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const { std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
@ -104,10 +101,6 @@ std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
return debug_pad; return debug_pad;
} }
std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const {
return digitizer;
}
std::shared_ptr<Gesture> ResourceManager::GetGesture() const { std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
return gesture; return gesture;
} }
@ -170,11 +163,7 @@ Result ResourceManager::CreateAppletResource(u64 aruid) {
Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
std::scoped_lock lock{shared_mutex}; std::scoped_lock lock{shared_mutex};
const auto result = applet_resource->CreateAppletResource(aruid); return applet_resource->CreateAppletResource(aruid);
if (result.IsSuccess()) {
InitializeController(aruid);
}
return result;
} }
Result ResourceManager::RegisterCoreAppletResource() { Result ResourceManager::RegisterCoreAppletResource() {
@ -231,7 +220,6 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) { std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();
debug_pad->OnUpdate(core_timing); debug_pad->OnUpdate(core_timing);
digitizer->OnUpdate(core_timing);
unique_pad->OnUpdate(core_timing); unique_pad->OnUpdate(core_timing);
gesture->OnUpdate(core_timing); gesture->OnUpdate(core_timing);
touch_screen->OnUpdate(core_timing); touch_screen->OnUpdate(core_timing);
@ -239,6 +227,7 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
home_button->OnUpdate(core_timing); home_button->OnUpdate(core_timing);
sleep_button->OnUpdate(core_timing); sleep_button->OnUpdate(core_timing);
capture_button->OnUpdate(core_timing); capture_button->OnUpdate(core_timing);
xpad->OnUpdate(core_timing);
} }
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {

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