Compare commits
131 Commits
android-16
...
android-17
Author | SHA1 | Date | |
---|---|---|---|
bcd1f34ce9 | |||
1b18205166 | |||
83236d44ab | |||
6e215fbf25 | |||
0b0f4c0586 | |||
12178c694a | |||
de1e5584b3 | |||
1559984f77 | |||
467ac4fdfe | |||
69b7100dac | |||
14dc41d4b3 | |||
ad049f13aa | |||
4f569fd568 | |||
553dac2ae0 | |||
96abe0d7d3 | |||
47e44a6693 | |||
cf8c7d4ed3 | |||
5165ed9efd | |||
05e3db3ac9 | |||
e3491a9ee8 | |||
6a1ddc5028 | |||
b1d4804c07 | |||
c57ae803a6 | |||
db7b2bc8f1 | |||
31bf57a310 | |||
cae675343c | |||
35501ba41c | |||
419055e484 | |||
91290b9be4 | |||
820f113d9e | |||
373a1ff2ce | |||
4d6b6ba76c | |||
4aa713e861 | |||
9e9aed41be | |||
3d268b8480 | |||
ad7445d4cc | |||
3a30271219 | |||
bb5196aaae | |||
d3070cafa7 | |||
5cd3b6f58c | |||
bedc758fe7 | |||
76701185ad | |||
f1cb14eb54 | |||
f4f4a469a9 | |||
9e5b4052ed | |||
234867b84d | |||
61e8c5f798 | |||
4b60aec190 | |||
bbc0ed118d | |||
ecfba79d98 | |||
310834aea2 | |||
6a1fa9bb17 | |||
db8a601cf8 | |||
1bb76201e6 | |||
372bca5945 | |||
93c19a40bf | |||
d0a75580da | |||
345ec25532 | |||
a94721fde0 | |||
816c7a8d1f | |||
efe52db690 | |||
d61df0f400 | |||
b14547b8b6 | |||
97ad3e7530 | |||
0589a32f75 | |||
617dc0f822 | |||
fcfa8b680b | |||
94244437de | |||
53956a2990 | |||
a7731abb72 | |||
50fd029eaa | |||
a2b567dfd6 | |||
b770f6a985 | |||
797e8fdbc3 | |||
b8c5027686 | |||
65e646eeba | |||
fba3fa705d | |||
09e8fb75ce | |||
6ca530a721 | |||
e01c535178 | |||
7239547ead | |||
7fc06260d1 | |||
e357896674 | |||
225f4f40cb | |||
927be75616 | |||
00965e6c34 | |||
4bf1f217ae | |||
fcc85abe27 | |||
6851e93296 | |||
67660972c9 | |||
ffbba74c91 | |||
2b0cf73bf0 | |||
a093f3d47a | |||
4f600f746a | |||
360418f1a1 | |||
3bc7575c47 | |||
fde8dc1652 | |||
b8f83aa4bf | |||
85b1e17df6 | |||
4144c517a5 | |||
8ad5f2c506 | |||
2a3f84aaf2 | |||
030e6b3980 | |||
e8ad603cd9 | |||
b560ade663 | |||
d10464de30 | |||
64f68e9635 | |||
86d26914a2 | |||
6ae4177b25 | |||
f6bf8b3ed3 | |||
345fb6b226 | |||
87a9dc9489 | |||
6c6e8b8de0 | |||
5acffe75df | |||
ac222ceba2 | |||
f9d4827102 | |||
7ea7c72dde | |||
809230f634 | |||
698c854d5b | |||
ca5b135ddf | |||
dbddc627d4 | |||
62fc386bb4 | |||
f2eb3c579f | |||
2fce812026 | |||
e975f3cde9 | |||
6b5fb2063f | |||
70c3d36536 | |||
adc3079613 | |||
a05c242429 | |||
bd59934350 | |||
d5de9402ee |
@ -142,6 +142,9 @@ 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 "")
|
||||||
@ -302,7 +305,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.256 REQUIRED)
|
find_package(Vulkan 1.3.274 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_LIBUSB)
|
if (ENABLE_LIBUSB)
|
||||||
|
10
README.md
10
README.md
@ -1,11 +1,9 @@
|
|||||||
| 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 |
|
| [12454](https://github.com/yuzu-emu/yuzu//pull/12454) | [`3a4e7d45f`](https://github.com/yuzu-emu/yuzu//pull/12454/files) | core_timing: minor refactors | [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 |
|
| [12466](https://github.com/yuzu-emu/yuzu//pull/12466) | [`adb2af0a2`](https://github.com/yuzu-emu/yuzu//pull/12466/files) | core: track separate heap allocation for linux | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12344](https://github.com/yuzu-emu/yuzu//pull/12344) | [`2a3f84aaf`](https://github.com/yuzu-emu/yuzu//pull/12344/files) | video_core: use interval map for page count tracking | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12479](https://github.com/yuzu-emu/yuzu//pull/12479) | [`20e040723`](https://github.com/yuzu-emu/yuzu//pull/12479/files) | video_core: Fix buffer_row_length for linear compressed textures | [GPUCode](https://github.com/GPUCode/) | Yes |
|
||||||
| [12345](https://github.com/yuzu-emu/yuzu//pull/12345) | [`b560ade66`](https://github.com/yuzu-emu/yuzu//pull/12345/files) | renderer_vulkan: cap async presentation frame count | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12487](https://github.com/yuzu-emu/yuzu//pull/12487) | [`d0c60605a`](https://github.com/yuzu-emu/yuzu//pull/12487/files) | shader_recompiler: use default value for clip distances array | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12349](https://github.com/yuzu-emu/yuzu//pull/12349) | [`8abdfcf8d`](https://github.com/yuzu-emu/yuzu//pull/12349/files) | Have GetActiveChannelCount return the system channels instead of host device channels | [Kelebek1](https://github.com/Kelebek1/) | Yes |
|
|
||||||
| [12358](https://github.com/yuzu-emu/yuzu//pull/12358) | [`8ad5f2c50`](https://github.com/yuzu-emu/yuzu//pull/12358/files) | common: use memory holepunching when clearing memory | [liamwhite](https://github.com/liamwhite/) | 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.
|
||||||
|
2
externals/Vulkan-Headers
vendored
2
externals/Vulkan-Headers
vendored
Submodule externals/Vulkan-Headers updated: df60f03168...80207f9da8
@ -91,18 +91,20 @@ class GamesFragment : Fragment() {
|
|||||||
viewLifecycleOwner.lifecycleScope.apply {
|
viewLifecycleOwner.lifecycleScope.apply {
|
||||||
launch {
|
launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
gamesViewModel.isReloading.collect { binding.swipeRefresh.isRefreshing = it }
|
gamesViewModel.isReloading.collect {
|
||||||
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,11 +256,13 @@
|
|||||||
|
|
||||||
<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>
|
||||||
|
@ -503,6 +503,7 @@
|
|||||||
<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 -->
|
||||||
|
@ -253,6 +253,17 @@ 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()
|
||||||
|
@ -18,9 +18,7 @@ constexpr auto INCREMENT_TIME{5ms};
|
|||||||
DeviceSession::DeviceSession(Core::System& system_)
|
DeviceSession::DeviceSession(Core::System& system_)
|
||||||
: system{system_}, thread_event{Core::Timing::CreateEvent(
|
: system{system_}, thread_event{Core::Timing::CreateEvent(
|
||||||
"AudioOutSampleTick",
|
"AudioOutSampleTick",
|
||||||
[this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
|
[this](s64 time, std::chrono::nanoseconds) { return ThreadFunc(); })} {}
|
||||||
return ThreadFunc();
|
|
||||||
})} {}
|
|
||||||
|
|
||||||
DeviceSession::~DeviceSession() {
|
DeviceSession::~DeviceSession() {
|
||||||
Finalize();
|
Finalize();
|
||||||
|
223
src/audio_core/sink/oboe_sink.cpp
Normal file
223
src/audio_core/sink/oboe_sink.cpp
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
// 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
|
75
src/audio_core/sink/oboe_sink.h
Normal file
75
src/audio_core/sink/oboe_sink.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// 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
|
@ -7,6 +7,9 @@
|
|||||||
#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
|
||||||
@ -36,6 +39,16 @@ 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,
|
||||||
|
@ -42,11 +42,9 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
|||||||
// 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
|
// Front = 1.0
|
||||||
// Center = 0.596
|
// Center = 0.596
|
||||||
// Back = 0.707
|
|
||||||
// LFE = 0.354
|
// LFE = 0.354
|
||||||
// 1.0 + 0.596 + 0.707 + 0.354 = 2.657, 1/2.657 = 0.37636f downscale coefficient
|
// Back = 0.707
|
||||||
static constexpr std::array<f32, 4> down_mix_coeff{0.37636f, 0.22431056f, 0.13323144f,
|
static constexpr std::array<f32, 4> down_mix_coeff{1.0, 0.596f, 0.354f, 0.707f};
|
||||||
0.26608652f};
|
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -64,6 +64,8 @@ add_library(common STATIC
|
|||||||
fs/path_util.cpp
|
fs/path_util.cpp
|
||||||
fs/path_util.h
|
fs/path_util.h
|
||||||
hash.h
|
hash.h
|
||||||
|
heap_tracker.cpp
|
||||||
|
heap_tracker.h
|
||||||
hex_util.cpp
|
hex_util.cpp
|
||||||
hex_util.h
|
hex_util.h
|
||||||
host_memory.cpp
|
host_memory.cpp
|
||||||
|
@ -3,16 +3,19 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/logging/backend.h"
|
||||||
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
|
||||||
void assert_fail_impl() {
|
void assert_fail_impl() {
|
||||||
if (Settings::values.use_debug_asserts) {
|
if (Settings::values.use_debug_asserts) {
|
||||||
|
Common::Log::Stop();
|
||||||
Crash();
|
Crash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void unreachable_impl() {
|
[[noreturn]] void unreachable_impl() {
|
||||||
|
Common::Log::Stop();
|
||||||
Crash();
|
Crash();
|
||||||
throw std::runtime_error("Unreachable code");
|
throw std::runtime_error("Unreachable code");
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,12 @@ 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()) {
|
||||||
|
@ -354,18 +354,36 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> SplitPathComponents(std::string_view filename) {
|
template <typename F>
|
||||||
std::string copy(filename);
|
static void ForEachPathComponent(std::string_view filename, F&& cb) {
|
||||||
std::replace(copy.begin(), copy.end(), '\\', '/');
|
const char* component_begin = filename.data();
|
||||||
std::vector<std::string> out;
|
const char* const end = component_begin + filename.size();
|
||||||
|
for (const char* it = component_begin; it != end; ++it) {
|
||||||
std::stringstream stream(copy);
|
const char c = *it;
|
||||||
std::string item;
|
if (c == '\\' || c == '/') {
|
||||||
while (std::getline(stream, item, '/')) {
|
if (component_begin != it) {
|
||||||
out.push_back(std::move(item));
|
cb(std::string_view{component_begin, it});
|
||||||
}
|
}
|
||||||
|
component_begin = it + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (component_begin != end) {
|
||||||
|
cb(std::string_view{component_begin, end});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
std::vector<std::string_view> SplitPathComponents(std::string_view filename) {
|
||||||
|
std::vector<std::string_view> components;
|
||||||
|
ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); });
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
@ -400,9 +418,9 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
|
|||||||
return std::string(RemoveTrailingSlash(path));
|
return std::string(RemoveTrailingSlash(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view GetParentPath(std::string_view path) {
|
std::string GetParentPath(std::string_view path) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
return path;
|
return std::string(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
@ -421,7 +439,7 @@ std::string_view 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 path.substr(0, name_index);
|
return std::string(path.substr(0, name_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view GetPathWithoutTop(std::string_view path) {
|
std::string_view GetPathWithoutTop(std::string_view path) {
|
||||||
|
@ -289,7 +289,11 @@ 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> SplitPathComponents(std::string_view filename);
|
[[nodiscard]] std::vector<std::string_view> 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
|
||||||
@ -298,7 +302,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_view GetParentPath(std::string_view path);
|
[[nodiscard]] std::string 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);
|
||||||
|
281
src/common/heap_tracker.cpp
Normal file
281
src/common/heap_tracker.cpp
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/heap_tracker.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
s64 GetMaxPermissibleResidentMapCount() {
|
||||||
|
// Default value.
|
||||||
|
s64 value = 65530;
|
||||||
|
|
||||||
|
// Try to read how many mappings we can make.
|
||||||
|
std::ifstream s("/proc/sys/vm/max_map_count");
|
||||||
|
s >> value;
|
||||||
|
|
||||||
|
// Print, for debug.
|
||||||
|
LOG_INFO(HW_Memory, "Current maximum map count: {}", value);
|
||||||
|
|
||||||
|
// Allow 20000 maps for other code and to account for split inaccuracy.
|
||||||
|
return std::max<s64>(value - 20000, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
HeapTracker::HeapTracker(Common::HostMemory& buffer)
|
||||||
|
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
|
||||||
|
HeapTracker::~HeapTracker() = default;
|
||||||
|
|
||||||
|
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||||
|
MemoryPermission perm, bool is_separate_heap) {
|
||||||
|
// When mapping other memory, map pages immediately.
|
||||||
|
if (!is_separate_heap) {
|
||||||
|
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// We are mapping part of a separate heap.
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
|
auto* const map = new SeparateHeapMap{
|
||||||
|
.vaddr = virtual_offset,
|
||||||
|
.paddr = host_offset,
|
||||||
|
.size = length,
|
||||||
|
.tick = m_tick++,
|
||||||
|
.perm = perm,
|
||||||
|
.is_resident = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert into mappings.
|
||||||
|
m_map_count++;
|
||||||
|
m_mappings.insert(*map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, map.
|
||||||
|
this->DeferredMapSeparateHeap(virtual_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
|
||||||
|
// If this is a separate heap...
|
||||||
|
if (is_separate_heap) {
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
|
const SeparateHeapMap key{
|
||||||
|
.vaddr = virtual_offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Split at the boundaries of the region we are removing.
|
||||||
|
this->SplitHeapMapLocked(virtual_offset);
|
||||||
|
this->SplitHeapMapLocked(virtual_offset + size);
|
||||||
|
|
||||||
|
// Erase all mappings in range.
|
||||||
|
auto it = m_mappings.find(key);
|
||||||
|
while (it != m_mappings.end() && it->vaddr < virtual_offset + size) {
|
||||||
|
// Get underlying item.
|
||||||
|
auto* const item = std::addressof(*it);
|
||||||
|
|
||||||
|
// If resident, erase from resident map.
|
||||||
|
if (item->is_resident) {
|
||||||
|
ASSERT(--m_resident_map_count >= 0);
|
||||||
|
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase from map.
|
||||||
|
ASSERT(--m_map_count >= 0);
|
||||||
|
it = m_mappings.erase(it);
|
||||||
|
|
||||||
|
// Free the item.
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap pages.
|
||||||
|
m_buffer.Unmap(virtual_offset, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission perm) {
|
||||||
|
// Ensure no rebuild occurs while reprotecting.
|
||||||
|
std::shared_lock lk{m_rebuild_lock};
|
||||||
|
|
||||||
|
// Split at the boundaries of the region we are reprotecting.
|
||||||
|
this->SplitHeapMap(virtual_offset, size);
|
||||||
|
|
||||||
|
// Declare tracking variables.
|
||||||
|
const VAddr end = virtual_offset + size;
|
||||||
|
VAddr cur = virtual_offset;
|
||||||
|
|
||||||
|
while (cur < end) {
|
||||||
|
VAddr next = cur;
|
||||||
|
bool should_protect = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::scoped_lock lk2{m_lock};
|
||||||
|
|
||||||
|
const SeparateHeapMap key{
|
||||||
|
.vaddr = next,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to get the next mapping corresponding to this address.
|
||||||
|
const auto it = m_mappings.nfind(key);
|
||||||
|
|
||||||
|
if (it == m_mappings.end()) {
|
||||||
|
// There are no separate heap mappings remaining.
|
||||||
|
next = end;
|
||||||
|
should_protect = true;
|
||||||
|
} else if (it->vaddr == cur) {
|
||||||
|
// We are in range.
|
||||||
|
// Update permission bits.
|
||||||
|
it->perm = perm;
|
||||||
|
|
||||||
|
// Determine next address and whether we should protect.
|
||||||
|
next = cur + it->size;
|
||||||
|
should_protect = it->is_resident;
|
||||||
|
} else /* if (it->vaddr > cur) */ {
|
||||||
|
// We weren't in range, but there is a block coming up that will be.
|
||||||
|
next = it->vaddr;
|
||||||
|
should_protect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp to end.
|
||||||
|
next = std::min(next, end);
|
||||||
|
|
||||||
|
// Reprotect, if we need to.
|
||||||
|
if (should_protect) {
|
||||||
|
m_buffer.Protect(cur, next - cur, perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance.
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
|
||||||
|
if (m_buffer.IsInVirtualRange(fault_address)) {
|
||||||
|
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||||
|
bool rebuild_required = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
|
// Check to ensure this was a non-resident separate heap mapping.
|
||||||
|
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
||||||
|
if (it == m_mappings.end() || it->is_resident) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update tick before possible rebuild.
|
||||||
|
it->tick = m_tick++;
|
||||||
|
|
||||||
|
// Check if we need to rebuild.
|
||||||
|
if (m_resident_map_count > m_max_resident_map_count) {
|
||||||
|
rebuild_required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the area.
|
||||||
|
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||||
|
|
||||||
|
// This map is now resident.
|
||||||
|
it->is_resident = true;
|
||||||
|
m_resident_map_count++;
|
||||||
|
m_resident_mappings.insert(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rebuild_required) {
|
||||||
|
// A rebuild was required, so perform it now.
|
||||||
|
this->RebuildSeparateHeapAddressSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||||
|
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
||||||
|
|
||||||
|
ASSERT(!m_resident_mappings.empty());
|
||||||
|
|
||||||
|
// Dump half of the mappings.
|
||||||
|
//
|
||||||
|
// Despite being worse in theory, this has proven to be better in practice than more
|
||||||
|
// regularly dumping a smaller amount, because it significantly reduces average case
|
||||||
|
// lock contention.
|
||||||
|
const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||||
|
const size_t evict_count = m_resident_map_count - desired_count;
|
||||||
|
auto it = m_resident_mappings.begin();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||||
|
// Unmark and unmap.
|
||||||
|
it->is_resident = false;
|
||||||
|
m_buffer.Unmap(it->vaddr, it->size, false);
|
||||||
|
|
||||||
|
// Advance.
|
||||||
|
ASSERT(--m_resident_map_count >= 0);
|
||||||
|
it = m_resident_mappings.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapTracker::SplitHeapMap(VAddr offset, size_t size) {
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
|
this->SplitHeapMapLocked(offset);
|
||||||
|
this->SplitHeapMapLocked(offset + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||||
|
const auto it = this->GetNearestHeapMapLocked(offset);
|
||||||
|
if (it == m_mappings.end() || it->vaddr == offset) {
|
||||||
|
// Not contained or no split required.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the original values.
|
||||||
|
auto* const left = std::addressof(*it);
|
||||||
|
const size_t orig_size = left->size;
|
||||||
|
|
||||||
|
// Adjust the left map.
|
||||||
|
const size_t left_size = offset - left->vaddr;
|
||||||
|
left->size = left_size;
|
||||||
|
|
||||||
|
// Create the new right map.
|
||||||
|
auto* const right = new SeparateHeapMap{
|
||||||
|
.vaddr = left->vaddr + left_size,
|
||||||
|
.paddr = left->paddr + left_size,
|
||||||
|
.size = orig_size - left_size,
|
||||||
|
.tick = left->tick,
|
||||||
|
.perm = left->perm,
|
||||||
|
.is_resident = left->is_resident,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert the new right map.
|
||||||
|
m_map_count++;
|
||||||
|
m_mappings.insert(*right);
|
||||||
|
|
||||||
|
// If resident, also insert into resident map.
|
||||||
|
if (right->is_resident) {
|
||||||
|
m_resident_map_count++;
|
||||||
|
m_resident_mappings.insert(*right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
|
||||||
|
const SeparateHeapMap key{
|
||||||
|
.vaddr = offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
return m_mappings.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Common
|
98
src/common/heap_tracker.h
Normal file
98
src/common/heap_tracker.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <set>
|
||||||
|
#include <shared_mutex>
|
||||||
|
|
||||||
|
#include "common/host_memory.h"
|
||||||
|
#include "common/intrusive_red_black_tree.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
struct SeparateHeapMap {
|
||||||
|
Common::IntrusiveRedBlackTreeNode addr_node{};
|
||||||
|
Common::IntrusiveRedBlackTreeNode tick_node{};
|
||||||
|
VAddr vaddr{};
|
||||||
|
PAddr paddr{};
|
||||||
|
size_t size{};
|
||||||
|
size_t tick{};
|
||||||
|
MemoryPermission perm{};
|
||||||
|
bool is_resident{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SeparateHeapMapAddrComparator {
|
||||||
|
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
|
||||||
|
if (lhs.vaddr < rhs.vaddr) {
|
||||||
|
return -1;
|
||||||
|
} else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SeparateHeapMapTickComparator {
|
||||||
|
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
|
||||||
|
if (lhs.tick < rhs.tick) {
|
||||||
|
return -1;
|
||||||
|
} else if (lhs.tick > rhs.tick) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return SeparateHeapMapAddrComparator::Compare(lhs, rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class HeapTracker {
|
||||||
|
public:
|
||||||
|
explicit HeapTracker(Common::HostMemory& buffer);
|
||||||
|
~HeapTracker();
|
||||||
|
|
||||||
|
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm,
|
||||||
|
bool is_separate_heap);
|
||||||
|
void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap);
|
||||||
|
void Protect(size_t virtual_offset, size_t length, MemoryPermission perm);
|
||||||
|
u8* VirtualBasePointer() {
|
||||||
|
return m_buffer.VirtualBasePointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeferredMapSeparateHeap(u8* fault_address);
|
||||||
|
bool DeferredMapSeparateHeap(size_t virtual_offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using AddrTreeTraits =
|
||||||
|
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>;
|
||||||
|
using AddrTree = AddrTreeTraits::TreeType<SeparateHeapMapAddrComparator>;
|
||||||
|
|
||||||
|
using TickTreeTraits =
|
||||||
|
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>;
|
||||||
|
using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>;
|
||||||
|
|
||||||
|
AddrTree m_mappings{};
|
||||||
|
TickTree m_resident_mappings{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SplitHeapMap(VAddr offset, size_t size);
|
||||||
|
void SplitHeapMapLocked(VAddr offset);
|
||||||
|
|
||||||
|
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
|
||||||
|
|
||||||
|
void RebuildSeparateHeapAddressSpace();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::HostMemory& m_buffer;
|
||||||
|
const s64 m_max_resident_map_count;
|
||||||
|
|
||||||
|
std::shared_mutex m_rebuild_lock{};
|
||||||
|
std::mutex m_lock{};
|
||||||
|
s64 m_map_count{};
|
||||||
|
s64 m_resident_map_count{};
|
||||||
|
size_t m_tick{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Common
|
@ -679,7 +679,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
|
|||||||
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
||||||
|
|
||||||
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||||
MemoryPermission perms) {
|
MemoryPermission perms, bool separate_heap) {
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(host_offset % PageAlignment == 0);
|
ASSERT(host_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
@ -691,7 +691,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
|||||||
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Unmap(size_t virtual_offset, size_t length) {
|
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
@ -701,14 +701,16 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) {
|
|||||||
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write,
|
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
|
||||||
bool execute) {
|
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const bool read = True(perm & MemoryPermission::Read);
|
||||||
|
const bool write = True(perm & MemoryPermission::Write);
|
||||||
|
const bool execute = True(perm & MemoryPermission::Execute);
|
||||||
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
|
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +40,12 @@ public:
|
|||||||
HostMemory(HostMemory&& other) noexcept;
|
HostMemory(HostMemory&& other) noexcept;
|
||||||
HostMemory& operator=(HostMemory&& other) noexcept;
|
HostMemory& operator=(HostMemory&& other) noexcept;
|
||||||
|
|
||||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms);
|
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms,
|
||||||
|
bool separate_heap);
|
||||||
|
|
||||||
void Unmap(size_t virtual_offset, size_t length);
|
void Unmap(size_t virtual_offset, size_t length, bool separate_heap);
|
||||||
|
|
||||||
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false);
|
void Protect(size_t virtual_offset, size_t length, MemoryPermission perms);
|
||||||
|
|
||||||
void EnableDirectMappedAddress();
|
void EnableDirectMappedAddress();
|
||||||
|
|
||||||
@ -64,6 +65,10 @@ public:
|
|||||||
return virtual_base;
|
return virtual_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsInVirtualRange(void* address) const noexcept {
|
||||||
|
return address >= virtual_base && address < virtual_base + virtual_size;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t backing_size{};
|
size_t backing_size{};
|
||||||
size_t virtual_size{};
|
size_t virtual_size{};
|
||||||
|
@ -208,6 +208,10 @@ public:
|
|||||||
instance->StartBackendThread();
|
instance->StartBackendThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Stop() {
|
||||||
|
instance->StopBackendThread();
|
||||||
|
}
|
||||||
|
|
||||||
Impl(const Impl&) = delete;
|
Impl(const Impl&) = delete;
|
||||||
Impl& operator=(const Impl&) = delete;
|
Impl& operator=(const Impl&) = delete;
|
||||||
|
|
||||||
@ -259,6 +263,15 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StopBackendThread() {
|
||||||
|
backend_thread.request_stop();
|
||||||
|
if (backend_thread.joinable()) {
|
||||||
|
backend_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
ForEachBackend([](Backend& backend) { backend.Flush(); });
|
||||||
|
}
|
||||||
|
|
||||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||||
const char* function, std::string&& message) const {
|
const char* function, std::string&& message) const {
|
||||||
using std::chrono::duration_cast;
|
using std::chrono::duration_cast;
|
||||||
@ -313,6 +326,10 @@ void Start() {
|
|||||||
Impl::Start();
|
Impl::Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stop() {
|
||||||
|
Impl::Stop();
|
||||||
|
}
|
||||||
|
|
||||||
void DisableLoggingInTests() {
|
void DisableLoggingInTests() {
|
||||||
initialization_in_progress_suppress_logging = true;
|
initialization_in_progress_suppress_logging = true;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ void Initialize();
|
|||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
|
/// Explicitly stops the logger thread and flushes the buffers
|
||||||
|
void Stop();
|
||||||
|
|
||||||
void DisableLoggingInTests();
|
void DisableLoggingInTests();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,7 +103,7 @@ private:
|
|||||||
// Having them on the same cache-line would result in false-sharing between them.
|
// Having them on the same cache-line would result in false-sharing between them.
|
||||||
// TODO: Remove this ifdef whenever clang and GCC support
|
// TODO: Remove this ifdef whenever clang and GCC support
|
||||||
// std::hardware_destructive_interference_size.
|
// std::hardware_destructive_interference_size.
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1911
|
#ifdef __cpp_lib_hardware_interference_size
|
||||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
|
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
|
||||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
|
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
|
||||||
#else
|
#else
|
||||||
|
@ -82,16 +82,15 @@ 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},
|
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
|
||||||
{"cubeb", AudioEngine::Cubeb},
|
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||||
{"sdl2", AudioEngine::Sdl2},
|
|
||||||
{"null", AudioEngine::Null},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +549,11 @@ 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
|
||||||
@ -569,14 +574,15 @@ 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
|
||||||
@ -784,6 +790,12 @@ 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
|
||||||
@ -792,6 +804,8 @@ 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
|
||||||
@ -964,6 +978,7 @@ endif()
|
|||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
|
arm/dynarmic/arm_dynarmic.cpp
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
arm/dynarmic/arm_dynarmic_64.cpp
|
arm/dynarmic/arm_dynarmic_64.cpp
|
||||||
arm/dynarmic/arm_dynarmic_64.h
|
arm/dynarmic/arm_dynarmic_64.h
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const {
|
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
||||||
Kernel::Svc::ThreadContext ctx;
|
Kernel::Svc::ThreadContext ctx;
|
||||||
this->GetContext(ctx);
|
this->GetContext(ctx);
|
||||||
|
|
||||||
|
@ -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(const Kernel::KProcess* process) const;
|
void LogBacktrace(Kernel::KProcess* process) const;
|
||||||
|
|
||||||
// Debug functionality.
|
// Debug functionality.
|
||||||
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
|
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
|
||||||
|
@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
|
|||||||
0x7100000000ULL,
|
0x7100000000ULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
|
void SymbolicateBacktrace(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(const Kernel::KProcess* process, std::vector<Backtrace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetAArch64Backtrace(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(const Kernel::KProcess* process,
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetAArch32Backtrace(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(const Kernel::KProcess* process,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
|
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
|
||||||
const auto* process = thread->GetOwnerProcess();
|
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(const Kernel::KProcess* process) {
|
Loader::AppLoader::Modules FindModules(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(const Kernel::KProcess* process) {
|
|||||||
return modules;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) {
|
Kernel::KProcessAddress FindMainModuleEntrypoint(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(const Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetBacktraceFromContext(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);
|
||||||
|
@ -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(const Kernel::KProcess* process);
|
Loader::AppLoader::Modules FindModules(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(const Kernel::KProcess* process);
|
Kernel::KProcessAddress FindMainModuleEntrypoint(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(const Kernel::KProcess* process,
|
std::vector<BacktraceEntry> GetBacktraceFromContext(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);
|
||||||
|
|
||||||
|
49
src/core/arm/dynarmic/arm_dynarmic.cpp
Normal file
49
src/core/arm/dynarmic/arm_dynarmic.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include "common/signal_chain.h"
|
||||||
|
|
||||||
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
thread_local Core::Memory::Memory* g_current_memory{};
|
||||||
|
std::once_flag g_registered{};
|
||||||
|
struct sigaction g_old_segv {};
|
||||||
|
|
||||||
|
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
|
||||||
|
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_old_segv.sa_sigaction(sig, info, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
|
||||||
|
g_current_memory = std::addressof(process->GetMemory());
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedJitExecution::~ScopedJitExecution() {
|
||||||
|
g_current_memory = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScopedJitExecution::RegisterHandler() {
|
||||||
|
std::call_once(g_registered, [] {
|
||||||
|
struct sigaction sa {};
|
||||||
|
sa.sa_sigaction = &HandleSigSegv;
|
||||||
|
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||||
|
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
|
#endif
|
@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
|||||||
return static_cast<HaltReason>(hr);
|
return static_cast<HaltReason>(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
class ScopedJitExecution {
|
||||||
|
public:
|
||||||
|
explicit ScopedJitExecution(Kernel::KProcess* process);
|
||||||
|
~ScopedJitExecution();
|
||||||
|
static void RegisterHandler();
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
class ScopedJitExecution {
|
||||||
|
public:
|
||||||
|
explicit ScopedJitExecution(Kernel::KProcess* process) {}
|
||||||
|
~ScopedJitExecution() {}
|
||||||
|
static void RegisterHandler() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -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, const Kernel::KProcess* process)
|
explicit DynarmicCallbacks32(ArmDynarmic32& parent, 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;
|
||||||
const Kernel::KProcess* m_process{};
|
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;
|
||||||
@ -331,11 +331,15 @@ bool ArmDynarmic32::IsInThumbMode() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
||||||
|
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Run());
|
return TranslateHaltReason(m_jit->Run());
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
||||||
|
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Step());
|
return TranslateHaltReason(m_jit->Step());
|
||||||
}
|
}
|
||||||
@ -370,13 +374,14 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
|
|||||||
this->SetContext(m_breakpoint_context);
|
this->SetContext(m_breakpoint_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
|
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, 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)),
|
||||||
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
||||||
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
||||||
m_jit = MakeJit(&page_table_impl);
|
m_jit = MakeJit(&page_table_impl);
|
||||||
|
ScopedJitExecution::RegisterHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic32::~ArmDynarmic32() = default;
|
ArmDynarmic32::~ArmDynarmic32() = default;
|
||||||
|
@ -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, const Kernel::KProcess* process,
|
ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
|
||||||
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||||
~ArmDynarmic32() override;
|
~ArmDynarmic32() override;
|
||||||
|
|
||||||
|
@ -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, const Kernel::KProcess* process)
|
explicit DynarmicCallbacks64(ArmDynarmic64& parent, 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{};
|
||||||
const Kernel::KProcess* m_process{};
|
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;
|
||||||
@ -362,11 +362,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
||||||
|
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Run());
|
return TranslateHaltReason(m_jit->Run());
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
||||||
|
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||||
|
|
||||||
m_jit->ClearExclusiveState();
|
m_jit->ClearExclusiveState();
|
||||||
return TranslateHaltReason(m_jit->Step());
|
return TranslateHaltReason(m_jit->Step());
|
||||||
}
|
}
|
||||||
@ -399,13 +403,14 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
|
|||||||
this->SetContext(m_breakpoint_context);
|
this->SetContext(m_breakpoint_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
|
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, 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} {
|
||||||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||||
auto& page_table_impl = page_table.GetImpl();
|
auto& page_table_impl = page_table.GetImpl();
|
||||||
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
||||||
|
ScopedJitExecution::RegisterHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmDynarmic64::~ArmDynarmic64() = default;
|
ArmDynarmic64::~ArmDynarmic64() = default;
|
||||||
|
@ -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, const Kernel::KProcess* process,
|
ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
|
||||||
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||||
~ArmDynarmic64() override;
|
~ArmDynarmic64() override;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
constexpr u32 StackSize = 32_KiB;
|
constexpr u32 StackSize = 128_KiB;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#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>
|
||||||
@ -249,6 +247,7 @@ 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;
|
||||||
@ -530,7 +529,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);
|
m_memory.ReadBlock(address, &data, datasize / 8);
|
||||||
this->SetVec(Vt, data);
|
this->SetVec(Vt, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,15 @@
|
|||||||
|
|
||||||
#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 {
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#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"
|
||||||
@ -130,11 +129,8 @@ 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}, memory{system}, hid_core{}, room_network{},
|
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
|
||||||
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
|
reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
|
||||||
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>();
|
||||||
@ -241,17 +237,17 @@ struct System::Impl {
|
|||||||
debugger = std::make_unique<Debugger>(system, port);
|
debugger = std::make_unique<Debugger>(system, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
|
void InitializeKernel(System& system) {
|
||||||
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();
|
||||||
|
|
||||||
@ -300,17 +296,9 @@ struct System::Impl {
|
|||||||
return SystemResultStatus::ErrorGetLoader;
|
return SystemResultStatus::ErrorGetLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
|
InitializeKernel(system);
|
||||||
if (init_result != SystemResultStatus::Success) {
|
|
||||||
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
|
||||||
static_cast<int>(init_result));
|
|
||||||
ShutdownMainProcess();
|
|
||||||
return init_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
// Create the application process.
|
||||||
|
|
||||||
// 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);
|
||||||
@ -323,7 +311,18 @@ 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) {
|
||||||
@ -426,7 +425,6 @@ 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()) {
|
||||||
@ -507,7 +505,6 @@ 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;
|
||||||
|
|
||||||
@ -567,9 +564,6 @@ 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -652,29 +646,12 @@ 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) {
|
||||||
for (auto& manager : impl->gpu_dirty_memory_write_manager) {
|
return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
|
||||||
manager.Gather(callback);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PerfStatsResults System::GetAndResetPerfStats() {
|
PerfStatsResults System::GetAndResetPerfStats() {
|
||||||
@ -723,20 +700,12 @@ 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->memory;
|
return impl->kernel.ApplicationProcess()->GetMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Core::Memory::Memory& System::ApplicationMemory() const {
|
const Core::Memory::Memory& System::ApplicationMemory() const {
|
||||||
return impl->memory;
|
return impl->kernel.ApplicationProcess()->GetMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
Tegra::GPU& System::GPU() {
|
Tegra::GPU& System::GPU() {
|
||||||
|
@ -116,7 +116,6 @@ 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;
|
||||||
@ -225,12 +224,6 @@ 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;
|
||||||
@ -250,12 +243,6 @@ 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();
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
|
|||||||
struct CoreTiming::Event {
|
struct CoreTiming::Event {
|
||||||
s64 time;
|
s64 time;
|
||||||
u64 fifo_order;
|
u64 fifo_order;
|
||||||
std::uintptr_t user_data;
|
|
||||||
std::weak_ptr<EventType> type;
|
std::weak_ptr<EventType> type;
|
||||||
s64 reschedule_time;
|
s64 reschedule_time;
|
||||||
heap_t::handle_type handle{};
|
heap_t::handle_type handle{};
|
||||||
@ -67,17 +66,15 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
|||||||
event_fifo_id = 0;
|
event_fifo_id = 0;
|
||||||
shutting_down = false;
|
shutting_down = false;
|
||||||
cpu_ticks = 0;
|
cpu_ticks = 0;
|
||||||
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
|
||||||
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
|
||||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
|
||||||
if (is_multicore) {
|
if (is_multicore) {
|
||||||
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
|
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::ClearPendingEvents() {
|
void CoreTiming::ClearPendingEvents() {
|
||||||
std::scoped_lock lock{basic_lock};
|
std::scoped_lock lock{advance_lock, basic_lock};
|
||||||
event_queue.clear();
|
event_queue.clear();
|
||||||
|
event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::Pause(bool is_paused) {
|
void CoreTiming::Pause(bool is_paused) {
|
||||||
@ -119,14 +116,12 @@ bool CoreTiming::HasPendingEvents() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||||
const std::shared_ptr<EventType>& event_type,
|
const std::shared_ptr<EventType>& event_type, bool absolute_time) {
|
||||||
std::uintptr_t user_data, bool absolute_time) {
|
|
||||||
{
|
{
|
||||||
std::scoped_lock scope{basic_lock};
|
std::scoped_lock scope{basic_lock};
|
||||||
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
|
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
|
||||||
|
|
||||||
auto h{event_queue.emplace(
|
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, event_type, 0})};
|
||||||
Event{next_time.count(), event_fifo_id++, user_data, event_type, 0})};
|
|
||||||
(*h).handle = h;
|
(*h).handle = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,13 +131,13 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
|||||||
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||||
std::chrono::nanoseconds resched_time,
|
std::chrono::nanoseconds resched_time,
|
||||||
const std::shared_ptr<EventType>& event_type,
|
const std::shared_ptr<EventType>& event_type,
|
||||||
std::uintptr_t user_data, bool absolute_time) {
|
bool absolute_time) {
|
||||||
{
|
{
|
||||||
std::scoped_lock scope{basic_lock};
|
std::scoped_lock scope{basic_lock};
|
||||||
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
|
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
|
||||||
|
|
||||||
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, user_data, event_type,
|
auto h{event_queue.emplace(
|
||||||
resched_time.count()})};
|
Event{next_time.count(), event_fifo_id++, event_type, resched_time.count()})};
|
||||||
(*h).handle = h;
|
(*h).handle = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,14 +145,14 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||||
std::uintptr_t user_data, bool wait) {
|
UnscheduleEventType type) {
|
||||||
{
|
{
|
||||||
std::scoped_lock lk{basic_lock};
|
std::scoped_lock lk{basic_lock};
|
||||||
|
|
||||||
std::vector<heap_t::handle_type> to_remove;
|
std::vector<heap_t::handle_type> to_remove;
|
||||||
for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
|
for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
|
||||||
const Event& e = *itr;
|
const Event& e = *itr;
|
||||||
if (e.type.lock().get() == event_type.get() && e.user_data == user_data) {
|
if (e.type.lock().get() == event_type.get()) {
|
||||||
to_remove.push_back(itr->handle);
|
to_remove.push_back(itr->handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,10 +160,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
|||||||
for (auto h : to_remove) {
|
for (auto h : to_remove) {
|
||||||
event_queue.erase(h);
|
event_queue.erase(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event_type->sequence_number++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force any in-progress events to finish
|
// Force any in-progress events to finish
|
||||||
if (wait) {
|
if (type == UnscheduleEventType::Wait) {
|
||||||
std::scoped_lock lk{advance_lock};
|
std::scoped_lock lk{advance_lock};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,28 +205,31 @@ std::optional<s64> CoreTiming::Advance() {
|
|||||||
const Event& evt = event_queue.top();
|
const Event& evt = event_queue.top();
|
||||||
|
|
||||||
if (const auto event_type{evt.type.lock()}) {
|
if (const auto event_type{evt.type.lock()}) {
|
||||||
if (evt.reschedule_time == 0) {
|
|
||||||
const auto evt_user_data = evt.user_data;
|
|
||||||
const auto evt_time = evt.time;
|
const auto evt_time = evt.time;
|
||||||
|
const auto evt_sequence_num = event_type->sequence_number;
|
||||||
|
|
||||||
|
if (evt.reschedule_time == 0) {
|
||||||
event_queue.pop();
|
event_queue.pop();
|
||||||
|
|
||||||
basic_lock.unlock();
|
basic_lock.unlock();
|
||||||
|
|
||||||
event_type->callback(
|
event_type->callback(
|
||||||
evt_user_data, evt_time,
|
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
|
||||||
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
|
|
||||||
|
|
||||||
basic_lock.lock();
|
basic_lock.lock();
|
||||||
} else {
|
} else {
|
||||||
basic_lock.unlock();
|
basic_lock.unlock();
|
||||||
|
|
||||||
const auto new_schedule_time{event_type->callback(
|
const auto new_schedule_time{event_type->callback(
|
||||||
evt.user_data, evt.time,
|
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time})};
|
||||||
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
|
|
||||||
|
|
||||||
basic_lock.lock();
|
basic_lock.lock();
|
||||||
|
|
||||||
|
if (evt_sequence_num != event_type->sequence_number) {
|
||||||
|
// Heap handle is invalidated after external modification.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const auto next_schedule_time{new_schedule_time.has_value()
|
const auto next_schedule_time{new_schedule_time.has_value()
|
||||||
? new_schedule_time.value().count()
|
? new_schedule_time.value().count()
|
||||||
: evt.reschedule_time};
|
: evt.reschedule_time};
|
||||||
@ -241,8 +241,8 @@ std::optional<s64> CoreTiming::Advance() {
|
|||||||
next_time = pause_end_time + next_schedule_time;
|
next_time = pause_end_time + next_schedule_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.user_data,
|
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.type,
|
||||||
evt.type, next_schedule_time, evt.handle});
|
next_schedule_time, evt.handle});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,17 +22,25 @@ namespace Core::Timing {
|
|||||||
|
|
||||||
/// A callback that may be scheduled for a particular core timing event.
|
/// A callback that may be scheduled for a particular core timing event.
|
||||||
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
|
||||||
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
|
s64 time, std::chrono::nanoseconds ns_late)>;
|
||||||
|
|
||||||
/// Contains the characteristics of a particular event.
|
/// Contains the characteristics of a particular event.
|
||||||
struct EventType {
|
struct EventType {
|
||||||
explicit EventType(TimedCallback&& callback_, std::string&& name_)
|
explicit EventType(TimedCallback&& callback_, std::string&& name_)
|
||||||
: callback{std::move(callback_)}, name{std::move(name_)} {}
|
: callback{std::move(callback_)}, name{std::move(name_)}, sequence_number{0} {}
|
||||||
|
|
||||||
/// The event's callback function.
|
/// The event's callback function.
|
||||||
TimedCallback callback;
|
TimedCallback callback;
|
||||||
/// A pointer to the name of the event.
|
/// A pointer to the name of the event.
|
||||||
const std::string name;
|
const std::string name;
|
||||||
|
/// A monotonic sequence number, incremented when this event is
|
||||||
|
/// changed externally.
|
||||||
|
size_t sequence_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class UnscheduleEventType {
|
||||||
|
Wait,
|
||||||
|
NoWait,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,23 +97,17 @@ public:
|
|||||||
|
|
||||||
/// Schedules an event in core timing
|
/// Schedules an event in core timing
|
||||||
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||||
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
|
const std::shared_ptr<EventType>& event_type, bool absolute_time = false);
|
||||||
bool absolute_time = false);
|
|
||||||
|
|
||||||
/// Schedules an event which will automatically re-schedule itself with the given time, until
|
/// Schedules an event which will automatically re-schedule itself with the given time, until
|
||||||
/// unscheduled
|
/// unscheduled
|
||||||
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
|
||||||
std::chrono::nanoseconds resched_time,
|
std::chrono::nanoseconds resched_time,
|
||||||
const std::shared_ptr<EventType>& event_type,
|
const std::shared_ptr<EventType>& event_type,
|
||||||
std::uintptr_t user_data = 0, bool absolute_time = false);
|
bool absolute_time = false);
|
||||||
|
|
||||||
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
|
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||||
bool wait = true);
|
UnscheduleEventType type = UnscheduleEventType::Wait);
|
||||||
|
|
||||||
void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
|
|
||||||
std::uintptr_t user_data) {
|
|
||||||
UnscheduleEvent(event_type, user_data, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddTicks(u64 ticks_to_add);
|
void AddTicks(u64 ticks_to_add);
|
||||||
|
|
||||||
@ -158,7 +160,6 @@ private:
|
|||||||
heap_t event_queue;
|
heap_t event_queue;
|
||||||
u64 event_fifo_id = 0;
|
u64 event_fifo_id = 0;
|
||||||
|
|
||||||
std::shared_ptr<EventType> ev_lost;
|
|
||||||
Common::Event event{};
|
Common::Event event{};
|
||||||
Common::Event pause_event{};
|
Common::Event pause_event{};
|
||||||
mutable std::mutex basic_lock;
|
mutable std::mutex basic_lock;
|
||||||
|
@ -166,6 +166,10 @@ 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;
|
||||||
}
|
}
|
||||||
@ -201,7 +205,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.is_retail ? "YES" : "NO");
|
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "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);
|
||||||
|
@ -34,6 +34,13 @@ 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.
|
||||||
@ -72,6 +79,7 @@ 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;
|
||||||
@ -116,8 +124,9 @@ private:
|
|||||||
union {
|
union {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
|
||||||
BitField<0, 1, u32> is_retail;
|
BitField<0, 1, u32> production_flag;
|
||||||
BitField<1, 31, u32> flags_unk;
|
BitField<1, 1, u32> unqualified_approval;
|
||||||
|
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;
|
||||||
|
@ -201,8 +201,6 @@ 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;
|
||||||
}
|
}
|
||||||
@ -237,8 +235,6 @@ 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
|
||||||
@ -303,8 +299,6 @@ 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;
|
||||||
}
|
}
|
||||||
@ -334,8 +328,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -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::SplitPathComponents(path_)),
|
parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(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.back();
|
return path_components.empty() ? "" : std::string(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::SplitPathComponents(path)), perms(perms_) {
|
path_components(FS::SplitPathComponentsCopy(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.back();
|
return path_components.empty() ? "" : std::string(path_components.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualDir RealVfsDirectory::GetParentDirectory() const {
|
VirtualDir RealVfsDirectory::GetParentDirectory() const {
|
||||||
|
@ -20,6 +20,9 @@ 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;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#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"
|
||||||
@ -26,9 +27,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) {
|
bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) {
|
||||||
auto& monitor = system.Monitor();
|
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
|
||||||
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
const auto current_core = 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;
|
||||||
@ -66,10 +67,10 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value,
|
bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value,
|
||||||
s32 new_value) {
|
s32 new_value) {
|
||||||
auto& monitor = system.Monitor();
|
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
|
||||||
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
const auto current_core = 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;
|
||||||
@ -159,7 +160,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_system, std::addressof(user_value), addr, value, value + 1),
|
R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1),
|
||||||
ResultInvalidCurrentMemory);
|
ResultInvalidCurrentMemory);
|
||||||
R_UNLESS(user_value == value, ResultInvalidState);
|
R_UNLESS(user_value == value, ResultInvalidState);
|
||||||
|
|
||||||
@ -219,7 +220,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_system, std::addressof(user_value), addr, value, new_value);
|
succeeded = UpdateIfEqual(m_kernel, 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);
|
||||||
}
|
}
|
||||||
@ -262,7 +263,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_system, std::addressof(user_value), addr, value);
|
succeeded = DecrementIfLessThan(m_kernel, 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);
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,22 @@
|
|||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
||||||
KScopedLightLock lk(m_lock);
|
// KScopedInterruptDisable di;
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
m_object_list.insert_unique(*obj);
|
m_object_list.insert_unique(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
||||||
KScopedLightLock lk(m_lock);
|
// KScopedInterruptDisable di;
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
m_object_list.erase(*obj);
|
m_object_list.erase(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
||||||
KScopedLightLock lk(m_lock);
|
// KScopedInterruptDisable di;
|
||||||
|
KScopedSpinLock lk(m_lock);
|
||||||
|
|
||||||
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
||||||
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
#include "core/hle/kernel/k_light_lock.h"
|
#include "core/hle/kernel/k_spin_lock.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
@ -21,32 +21,7 @@ public:
|
|||||||
|
|
||||||
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
||||||
|
|
||||||
class ListAccessor : public KScopedLightLock {
|
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
|
||||||
public:
|
|
||||||
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
|
||||||
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
|
|
||||||
explicit ListAccessor(KAutoObjectWithListContainer& container)
|
|
||||||
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
|
|
||||||
|
|
||||||
typename ListType::iterator begin() const {
|
|
||||||
return m_list.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
typename ListType::iterator end() const {
|
|
||||||
return m_list.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
typename ListType::iterator find(typename ListType::const_reference ref) const {
|
|
||||||
return m_list.find(ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ListType& m_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
friend class ListAccessor;
|
|
||||||
|
|
||||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
|
||||||
|
|
||||||
void Initialize() {}
|
void Initialize() {}
|
||||||
void Finalize() {}
|
void Finalize() {}
|
||||||
@ -56,7 +31,7 @@ public:
|
|||||||
size_t GetOwnedCount(KProcess* owner);
|
size_t GetOwnedCount(KProcess* owner);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KLightLock m_lock;
|
KSpinLock m_lock;
|
||||||
ListType m_object_list;
|
ListType m_object_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,9 +58,8 @@ 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.
|
||||||
//! FIXME: we are reserving this from the wrong resource limit!
|
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
|
||||||
KScopedResourceReservation session_reservation(
|
LimitableResource::SessionCountMax);
|
||||||
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.
|
||||||
|
@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero,
|
bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero,
|
||||||
u32 new_orr_mask) {
|
u32 new_orr_mask) {
|
||||||
auto& monitor = system.Monitor();
|
auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
|
||||||
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
const auto current_core = 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_system, std::addressof(prev_tag), address, own_tag,
|
UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
|
||||||
Svc::HandleWaitMask);
|
Svc::HandleWaitMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,7 @@ 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) {
|
||||||
//! FIXME: this is the wrong process!
|
auto* const cur_process = GetCurrentProcessPointer(m_kernel);
|
||||||
auto* const cur_process = m_kernel.ApplicationProcess();
|
|
||||||
ASSERT(cur_process != nullptr);
|
ASSERT(cur_process != nullptr);
|
||||||
return cur_process;
|
return cur_process;
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,15 @@ namespace Kernel {
|
|||||||
|
|
||||||
void KHardwareTimer::Initialize() {
|
void KHardwareTimer::Initialize() {
|
||||||
// Create the timing callback to register with CoreTiming.
|
// Create the timing callback to register with CoreTiming.
|
||||||
m_event_type = Core::Timing::CreateEvent(
|
m_event_type = Core::Timing::CreateEvent("KHardwareTimer::Callback",
|
||||||
"KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) {
|
[this](s64, std::chrono::nanoseconds) {
|
||||||
reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask();
|
this->DoTask();
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void KHardwareTimer::Finalize() {
|
void KHardwareTimer::Finalize() {
|
||||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
|
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type);
|
||||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||||
m_event_type.reset();
|
m_event_type.reset();
|
||||||
}
|
}
|
||||||
@ -57,13 +57,12 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
|
|||||||
|
|
||||||
m_wakeup_time = wakeup_time;
|
m_wakeup_time = wakeup_time;
|
||||||
m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
|
m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
|
||||||
m_event_type, reinterpret_cast<uintptr_t>(this),
|
m_event_type, true);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KHardwareTimer::DisableInterrupt() {
|
void KHardwareTimer::DisableInterrupt() {
|
||||||
m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
|
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type,
|
||||||
reinterpret_cast<uintptr_t>(this));
|
Core::Timing::UnscheduleEventType::NoWait);
|
||||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +434,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||||||
void KPageTableBase::Finalize() {
|
void KPageTableBase::Finalize() {
|
||||||
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
||||||
if (Settings::IsFastmemEnabled()) {
|
if (Settings::IsFastmemEnabled()) {
|
||||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size);
|
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5243,7 +5243,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
|||||||
// Unmap.
|
// Unmap.
|
||||||
R_ASSERT(this->Operate(updater.GetPageList(), cur_address,
|
R_ASSERT(this->Operate(updater.GetPageList(), cur_address,
|
||||||
cur_pages, 0, false, unmap_properties,
|
cur_pages, 0, false, unmap_properties,
|
||||||
OperationType::Unmap, true));
|
OperationType::UnmapPhysical, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're done.
|
// Check if we're done.
|
||||||
@ -5326,7 +5326,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
|||||||
// Map the papges.
|
// Map the papges.
|
||||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages,
|
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages,
|
||||||
cur_pg, map_properties,
|
cur_pg, map_properties,
|
||||||
OperationType::MapFirstGroup, false));
|
OperationType::MapFirstGroupPhysical, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5480,7 +5480,7 @@ Result KPageTableBase::UnmapPhysicalMemory(KProcessAddress address, size_t size)
|
|||||||
|
|
||||||
// Unmap.
|
// Unmap.
|
||||||
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false,
|
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false,
|
||||||
unmap_properties, OperationType::Unmap, false));
|
unmap_properties, OperationType::UnmapPhysical, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're done.
|
// Check if we're done.
|
||||||
@ -5655,7 +5655,10 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
// or free them to the page list, and so it goes unused (along with page properties).
|
// or free them to the page list, and so it goes unused (along with page properties).
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType::Unmap: {
|
case OperationType::Unmap:
|
||||||
|
case OperationType::UnmapPhysical: {
|
||||||
|
const bool separate_heap = operation == OperationType::UnmapPhysical;
|
||||||
|
|
||||||
// Ensure that any pages we track are closed on exit.
|
// Ensure that any pages we track are closed on exit.
|
||||||
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
|
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
|
||||||
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
|
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
|
||||||
@ -5664,7 +5667,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||||
|
|
||||||
// Unmap.
|
// Unmap.
|
||||||
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize);
|
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@ -5672,7 +5675,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
ASSERT(virt_addr != 0);
|
ASSERT(virt_addr != 0);
|
||||||
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||||
ConvertToMemoryPermission(properties.perm));
|
ConvertToMemoryPermission(properties.perm), false);
|
||||||
|
|
||||||
// Open references to pages, if we should.
|
// Open references to pages, if we should.
|
||||||
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
if (this->IsHeapPhysicalAddress(phys_addr)) {
|
||||||
@ -5711,16 +5714,19 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType::MapGroup:
|
case OperationType::MapGroup:
|
||||||
case OperationType::MapFirstGroup: {
|
case OperationType::MapFirstGroup:
|
||||||
|
case OperationType::MapFirstGroupPhysical: {
|
||||||
|
const bool separate_heap = operation == OperationType::MapFirstGroupPhysical;
|
||||||
|
|
||||||
// We want to maintain a new reference to every page in the group.
|
// We want to maintain a new reference to every page in the group.
|
||||||
KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
|
KScopedPageGroup spg(page_group, operation == OperationType::MapGroup);
|
||||||
|
|
||||||
for (const auto& node : page_group) {
|
for (const auto& node : page_group) {
|
||||||
const size_t size{node.GetNumPages() * PageSize};
|
const size_t size{node.GetNumPages() * PageSize};
|
||||||
|
|
||||||
// Map the pages.
|
// Map the pages.
|
||||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
||||||
ConvertToMemoryPermission(properties.perm));
|
ConvertToMemoryPermission(properties.perm), separate_heap);
|
||||||
|
|
||||||
virt_addr += size;
|
virt_addr += size;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,9 @@ protected:
|
|||||||
ChangePermissionsAndRefresh = 5,
|
ChangePermissionsAndRefresh = 5,
|
||||||
ChangePermissionsAndRefreshAndFlush = 6,
|
ChangePermissionsAndRefreshAndFlush = 6,
|
||||||
Separate = 7,
|
Separate = 7,
|
||||||
|
|
||||||
|
MapFirstGroupPhysical = 65000,
|
||||||
|
UnmapPhysical = 65001,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr size_t MaxPhysicalMapAlignment = 1_GiB;
|
static constexpr size_t MaxPhysicalMapAlignment = 1_GiB;
|
||||||
|
@ -306,12 +306,16 @@ 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, this->GetMemory(), 0));
|
m_system_resource, res_limit, m_memory, 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),
|
||||||
@ -399,12 +403,16 @@ 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,
|
||||||
this->GetMemory(), aslr_space_start));
|
m_memory, 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);
|
||||||
@ -1094,8 +1102,7 @@ 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) {
|
||||||
// TODO: use current memory reference
|
auto& memory = this->GetMemory();
|
||||||
auto& memory = m_kernel.System().ApplicationMemory();
|
|
||||||
|
|
||||||
// Lock the list.
|
// Lock the list.
|
||||||
KScopedLightLock lk(m_list_lock);
|
KScopedLightLock lk(m_list_lock);
|
||||||
@ -1128,14 +1135,15 @@ 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_handle_table{kernel}, m_dirty_memory_managers{},
|
||||||
|
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 physical_memory_size =
|
const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
|
||||||
m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application);
|
const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
|
||||||
auto* res_limit =
|
auto* res_limit =
|
||||||
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
|
||||||
|
|
||||||
@ -1146,8 +1154,10 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
|||||||
Svc::CreateProcessFlag flag{};
|
Svc::CreateProcessFlag flag{};
|
||||||
u64 code_address{};
|
u64 code_address{};
|
||||||
|
|
||||||
// We are an application.
|
// Determine if 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()) {
|
||||||
@ -1196,8 +1206,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,
|
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool,
|
||||||
KMemoryManager::Pool::Application, aslr_space_start));
|
aslr_space_start));
|
||||||
|
|
||||||
// Assign remaining properties.
|
// Assign remaining properties.
|
||||||
m_is_hbl = is_hbl;
|
m_is_hbl = is_hbl;
|
||||||
@ -1223,22 +1233,25 @@ 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 (Settings::IsNceEnabled()) {
|
if (this->IsApplication() && 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();
|
||||||
buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true);
|
buffer.Protect(GetInteger(base_addr + code.addr), code.size,
|
||||||
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true);
|
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
|
||||||
|
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size,
|
||||||
|
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
|
||||||
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
|
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::InitializeInterfaces() {
|
void KProcess::InitializeInterfaces() {
|
||||||
this->GetMemory().SetCurrentPageTable(*this);
|
m_exclusive_monitor =
|
||||||
|
Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
|
||||||
|
|
||||||
#ifdef HAS_NCE
|
#ifdef HAS_NCE
|
||||||
if (this->Is64Bit() && Settings::IsNceEnabled()) {
|
if (this->IsApplication() && 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);
|
||||||
}
|
}
|
||||||
@ -1248,13 +1261,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_kernel.GetExclusiveMonitor()), i);
|
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), 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_kernel.GetExclusiveMonitor()), i);
|
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1305,9 +1318,10 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Memory::Memory& KProcess::GetMemory() const {
|
void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
|
||||||
// TODO: per-process memory
|
for (auto& manager : m_dirty_memory_managers) {
|
||||||
return m_kernel.System().ApplicationMemory();
|
manager.Gather(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#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"
|
||||||
@ -17,6 +18,7 @@
|
|||||||
#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 {
|
||||||
|
|
||||||
@ -126,6 +128,9 @@ 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();
|
||||||
@ -502,7 +507,15 @@ public:
|
|||||||
|
|
||||||
void InitializeInterfaces();
|
void InitializeInterfaces();
|
||||||
|
|
||||||
Core::Memory::Memory& GetMemory() const;
|
Core::Memory::Memory& GetMemory() {
|
||||||
|
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.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -49,14 +49,21 @@ 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(bool is_hle = false);
|
Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size,
|
||||||
Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
|
KPhysicalAddress server_message_paddr, bool is_hle = false);
|
||||||
|
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() {
|
||||||
return SendReply(true);
|
R_RETURN(this->SendReply(0, 0, 0, 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:
|
||||||
|
@ -33,8 +33,7 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
|
|||||||
m_name = name;
|
m_name = name;
|
||||||
|
|
||||||
// Set our owner process.
|
// Set our owner process.
|
||||||
//! FIXME: this is the wrong process!
|
m_process = GetCurrentProcessPointer(m_kernel);
|
||||||
m_process = m_kernel.ApplicationProcess();
|
|
||||||
m_process->Open();
|
m_process->Open();
|
||||||
|
|
||||||
// Set our port.
|
// Set our port.
|
||||||
|
@ -1422,8 +1422,7 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
|
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
|
||||||
// TODO: per-process memory
|
return GetCurrentProcess(kernel).GetMemory();
|
||||||
return kernel.System().ApplicationMemory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KScopedDisableDispatch::~KScopedDisableDispatch() {
|
KScopedDisableDispatch::~KScopedDisableDispatch() {
|
||||||
|
@ -314,11 +314,7 @@ public:
|
|||||||
m_current_core_id = core;
|
m_current_core_id = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcess* GetOwnerProcess() {
|
KProcess* GetOwnerProcess() const {
|
||||||
return m_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
const KProcess* GetOwnerProcess() const {
|
|
||||||
return m_parent;
|
return m_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_light_lock.h"
|
||||||
#include "core/hle/kernel/k_page_group.h"
|
#include "core/hle/kernel/k_page_group.h"
|
||||||
#include "core/hle/kernel/slab_helpers.h"
|
#include "core/hle/kernel/slab_helpers.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
#include "core/hle/kernel/svc_types.h"
|
||||||
|
@ -68,8 +68,6 @@ 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;
|
||||||
|
|
||||||
@ -121,13 +119,8 @@ 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) {
|
||||||
@ -135,7 +128,6 @@ 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);
|
||||||
@ -192,8 +184,6 @@ 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)};
|
||||||
|
|
||||||
@ -248,7 +238,7 @@ struct KernelCore::Impl {
|
|||||||
void InitializePreemption(KernelCore& kernel) {
|
void InitializePreemption(KernelCore& kernel) {
|
||||||
preemption_event = Core::Timing::CreateEvent(
|
preemption_event = Core::Timing::CreateEvent(
|
||||||
"PreemptionCallback",
|
"PreemptionCallback",
|
||||||
[this, &kernel](std::uintptr_t, s64 time,
|
[this, &kernel](s64 time,
|
||||||
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
@ -744,22 +734,16 @@ 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);
|
||||||
@ -798,10 +782,6 @@ 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;
|
||||||
@ -812,7 +792,6 @@ 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
|
||||||
@ -889,10 +868,6 @@ 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);
|
||||||
}
|
}
|
||||||
@ -966,14 +941,6 @@ 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;
|
||||||
}
|
}
|
||||||
@ -1037,14 +1004,6 @@ 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);
|
||||||
}
|
}
|
||||||
@ -1190,14 +1149,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -116,9 +116,6 @@ 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);
|
||||||
|
|
||||||
@ -170,10 +167,6 @@ 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;
|
||||||
@ -239,12 +232,6 @@ 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();
|
||||||
|
|
||||||
|
@ -18,13 +18,13 @@ public:
|
|||||||
static constexpr inline u64 NullTag = 0;
|
static constexpr inline u64 NullTag = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class ReceiveListCountType : u32 {
|
enum ReceiveListCountType : u32 {
|
||||||
None = 0,
|
ReceiveListCountType_None = 0,
|
||||||
ToMessageBuffer = 1,
|
ReceiveListCountType_ToMessageBuffer = 1,
|
||||||
ToSingleBuffer = 2,
|
ReceiveListCountType_ToSingleBuffer = 2,
|
||||||
|
|
||||||
CountOffset = 2,
|
ReceiveListCountType_CountOffset = 2,
|
||||||
CountMax = 13,
|
ReceiveListCountType_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;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,6 @@ 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();
|
||||||
|
|
||||||
|
@ -48,8 +48,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send the reply.
|
// Send the reply.
|
||||||
R_TRY(session->SendReply());
|
R_TRY(session->SendReply(message, buffer_size, message_paddr));
|
||||||
// R_TRY(session->SendReply(message, buffer_size, message_paddr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a message.
|
// Receive a message.
|
||||||
@ -85,8 +84,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,9 @@ 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
|
||||||
|
@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto transfer_mem =
|
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
|
||||||
|
|
||||||
if (transfer_mem.IsNull()) {
|
if (transfer_mem.IsNull()) {
|
||||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||||
@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> memory(transfer_mem->GetSize());
|
std::vector<u8> memory(transfer_mem->GetSize());
|
||||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||||
memory.size());
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto transfer_mem =
|
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
|
||||||
|
|
||||||
if (transfer_mem.IsNull()) {
|
if (transfer_mem.IsNull()) {
|
||||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||||
@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> memory(transfer_mem->GetSize());
|
std::vector<u8> memory(transfer_mem->GetSize());
|
||||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||||
memory.size());
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||||
auto transfer_memory{
|
|
||||||
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
|
|
||||||
|
|
||||||
const auto session_id{impl->GetSessionId()};
|
const auto session_id{impl->GetSessionId()};
|
||||||
if (session_id == -1) {
|
if (session_id == -1) {
|
||||||
|
@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
|
|||||||
auto params = rp.PopRaw<OpusParameters>();
|
auto params = rp.PopRaw<OpusParameters>();
|
||||||
auto transfer_memory_size{rp.Pop<u32>()};
|
auto transfer_memory_size{rp.Pop<u32>()};
|
||||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||||
auto transfer_memory{
|
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
transfer_memory_handle)};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||||
@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
auto transfer_memory_size{rp.Pop<u32>()};
|
auto transfer_memory_size{rp.Pop<u32>()};
|
||||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||||
auto transfer_memory{
|
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
transfer_memory_handle)};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio,
|
LOG_DEBUG(Service_Audio,
|
||||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||||
@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
|
|||||||
auto params = rp.PopRaw<OpusParametersEx>();
|
auto params = rp.PopRaw<OpusParametersEx>();
|
||||||
auto transfer_memory_size{rp.Pop<u32>()};
|
auto transfer_memory_size{rp.Pop<u32>()};
|
||||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||||
auto transfer_memory{
|
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
transfer_memory_handle)};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||||
@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
auto transfer_memory_size{rp.Pop<u32>()};
|
auto transfer_memory_size{rp.Pop<u32>()};
|
||||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||||
auto transfer_memory{
|
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
|
||||||
transfer_memory_handle)};
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_Audio,
|
LOG_DEBUG(Service_Audio,
|
||||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||||
|
@ -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 (size_t i = 0; i < info.backtrace_size; i++) {
|
for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); 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]);
|
||||||
}
|
}
|
||||||
|
@ -104,11 +104,7 @@ 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) {
|
||||||
// Skip empty path components
|
relative_path = Common::FS::SanitizePath(fmt::format("{}/{}", relative_path, component));
|
||||||
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
|
||||||
|
@ -54,6 +54,13 @@ 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_);
|
||||||
|
@ -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_)
|
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode)
|
||||||
: 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,9 +269,13 @@ 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.
|
||||||
BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
|
if (True(mode & OpenDirectoryMode::Directory)) {
|
||||||
BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
|
BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
|
||||||
}
|
}
|
||||||
|
if (True(mode & OpenDirectoryMode::File)) {
|
||||||
|
BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileSys::VirtualDir backend;
|
FileSys::VirtualDir backend;
|
||||||
@ -446,11 +450,9 @@ 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>();
|
||||||
|
|
||||||
// TODO(Subv): Implement this filter.
|
LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
|
||||||
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);
|
||||||
@ -460,7 +462,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto directory = std::make_shared<IDirectory>(system, vfs_dir);
|
auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#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 {
|
||||||
@ -23,11 +24,24 @@ Result AppletResource::CreateAppletResource(u64 aruid) {
|
|||||||
return ResultAruidAlreadyRegistered;
|
return ResultAruidAlreadyRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Here shared memory is created for the process we don't quite emulate this part so
|
auto& shared_memory = shared_memory_holder[index];
|
||||||
// obtain this pointer from system
|
if (!shared_memory.IsMapped()) {
|
||||||
auto& shared_memory = system.Kernel().GetHidSharedMem();
|
const Result result = shared_memory.Initialize(system);
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (shared_memory.GetAddress() == nullptr) {
|
||||||
|
shared_memory.Finalize();
|
||||||
|
return ResultSharedMemoryNotInitialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data[index].shared_memory_handle = &shared_memory;
|
auto* shared_memory_format = shared_memory.GetAddress();
|
||||||
|
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;
|
||||||
@ -94,7 +108,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_handle = nullptr;
|
data[index].shared_memory_format = nullptr;
|
||||||
data[index].flag.is_assigned.Assign(false);
|
data[index].flag.is_assigned.Assign(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +134,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_handle = nullptr;
|
aruid_data.shared_memory_format = nullptr;
|
||||||
aruid_data.flag.is_assigned.Assign(false);
|
aruid_data.flag.is_assigned.Assign(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +149,18 @@ Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle,
|
|||||||
return ResultAruidNotRegistered;
|
return ResultAruidNotRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_handle = data[index].shared_memory_handle;
|
*out_handle = shared_memory_holder[index].GetHandle();
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#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;
|
||||||
@ -18,6 +19,8 @@ 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_);
|
||||||
@ -32,6 +35,7 @@ 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);
|
||||||
|
|
||||||
@ -80,12 +84,13 @@ private:
|
|||||||
struct AruidData {
|
struct AruidData {
|
||||||
DataStatusFlag flag{};
|
DataStatusFlag flag{};
|
||||||
u64 aruid{};
|
u64 aruid{};
|
||||||
Kernel::KSharedMemory* shared_memory_handle{nullptr};
|
SharedMemoryFormat* shared_memory_format{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;
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
// 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/memory.h"
|
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
|
|
||||||
|
|
||||||
ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
|
||||||
: ControllerBase{hid_core_} {
|
ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory)
|
||||||
|
: 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;
|
||||||
@ -33,10 +28,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
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#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 {
|
||||||
@ -11,9 +10,12 @@ 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_, u8* raw_shared_memory_);
|
explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
|
||||||
|
ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory);
|
||||||
~ConsoleSixAxis() override;
|
~ConsoleSixAxis() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
@ -26,18 +28,7 @@ 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::ConsoleSixAxisSensorSharedMemoryFormat
|
ConsoleSixAxisSensorSharedMemoryFormat& shared_memory;
|
||||||
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
|
||||||
|
@ -39,9 +39,6 @@ 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};
|
||||||
|
|
||||||
|
@ -1,24 +1,19 @@
|
|||||||
// 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_, u8* raw_shared_memory_)
|
DebugPad::DebugPad(Core::HID::HIDCore& hid_core_,
|
||||||
: ControllerBase{hid_core_} {
|
DebugPadSharedMemoryFormat& debug_pad_shared_memory)
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
|
: ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} {
|
||||||
"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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,12 +25,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) {
|
||||||
@ -49,7 +44,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
|
||||||
|
@ -3,21 +3,24 @@
|
|||||||
|
|
||||||
#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/ring_lifo.h"
|
#include "core/hle/service/hid/controllers/types/debug_pad_types.h"
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
class EmulatedController;
|
class HIDCore;
|
||||||
struct DebugPadButton;
|
}
|
||||||
struct AnalogStickState;
|
|
||||||
} // namespace Core::HID
|
namespace Core::Timing {
|
||||||
|
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_, u8* raw_shared_memory_);
|
explicit DebugPad(Core::HID::HIDCore& hid_core_,
|
||||||
|
DebugPadSharedMemoryFormat& debug_pad_shared_memory);
|
||||||
~DebugPad() override;
|
~DebugPad() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
@ -30,35 +33,8 @@ 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{};
|
||||||
DebugPadSharedMemory* shared_memory = nullptr;
|
DebugPadSharedMemoryFormat& shared_memory;
|
||||||
Core::HID::EmulatedController* controller = nullptr;
|
Core::HID::EmulatedController* controller = nullptr;
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
// 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
|
||||||
@ -23,19 +21,15 @@ constexpr f32 Square(s32 num) {
|
|||||||
return static_cast<f32>(num * num);
|
return static_cast<f32>(num * num);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
|
Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory)
|
||||||
: ControllerBase(hid_core_) {
|
: ControllerBase(hid_core_), shared_memory{gesture_shared_memory} {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,8 +37,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +46,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
|
||||||
@ -60,7 +54,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +97,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;
|
||||||
@ -133,7 +127,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,
|
||||||
@ -305,11 +299,11 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_
|
|||||||
next_state.direction = GestureDirection::Up;
|
next_state.direction = GestureDirection::Up;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Gesture::GestureState& Gesture::GetLastGestureEntry() const {
|
const GestureState& Gesture::GetLastGestureEntry() const {
|
||||||
return shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
return shared_memory.gesture_lifo.ReadCurrentEntry().state;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gesture::GestureProperties Gesture::GetGestureProperties() {
|
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(),
|
||||||
|
@ -4,17 +4,22 @@
|
|||||||
#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/ring_lifo.h"
|
#include "core/hle/service/hid/controllers/types/touch_types.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_, u8* raw_shared_memory_);
|
explicit Gesture(Core::HID::HIDCore& hid_core_,
|
||||||
|
GestureSharedMemoryFormat& gesture_shared_memory);
|
||||||
~Gesture() override;
|
~Gesture() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
@ -27,79 +32,6 @@ 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();
|
||||||
|
|
||||||
@ -142,7 +74,7 @@ private:
|
|||||||
GestureProperties GetGestureProperties();
|
GestureProperties GetGestureProperties();
|
||||||
|
|
||||||
GestureState next_state{};
|
GestureState next_state{};
|
||||||
GestureSharedMemory* shared_memory = nullptr;
|
GestureSharedMemoryFormat& shared_memory;
|
||||||
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{};
|
||||||
|
@ -1,23 +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 "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_, u8* raw_shared_memory_)
|
Keyboard::Keyboard(Core::HID::HIDCore& hid_core_,
|
||||||
: ControllerBase{hid_core_} {
|
KeyboardSharedMemoryFormat& keyboard_shared_memory)
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
|
: ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} {
|
||||||
"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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,12 +24,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) {
|
||||||
@ -46,7 +41,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
|
||||||
|
@ -3,20 +3,16 @@
|
|||||||
|
|
||||||
#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"
|
#include "core/hle/service/hid/controllers/types/keyboard_types.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_, u8* raw_shared_memory_);
|
explicit Keyboard(Core::HID::HIDCore& hid_core_,
|
||||||
|
KeyboardSharedMemoryFormat& keyboard_shared_memory);
|
||||||
~Keyboard() override;
|
~Keyboard() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
@ -29,25 +25,8 @@ 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{};
|
||||||
KeyboardSharedMemory* shared_memory = nullptr;
|
KeyboardSharedMemoryFormat& shared_memory;
|
||||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -1,22 +1,17 @@
|
|||||||
// 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_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
|
Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory)
|
||||||
static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
|
: ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} {
|
||||||
"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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,14 +22,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) {
|
||||||
@ -53,7 +48,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
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
#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;
|
||||||
@ -14,9 +12,11 @@ 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_, u8* raw_shared_memory_);
|
explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory);
|
||||||
~Mouse() override;
|
~Mouse() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
@ -29,17 +29,9 @@ 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{};
|
||||||
MouseSharedMemory* shared_memory = nullptr;
|
MouseSharedMemoryFormat& shared_memory;
|
||||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||||
};
|
};
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
@ -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,14 +30,12 @@ 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_, u8* raw_shared_memory_,
|
NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
|
||||||
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 = std::construct_at(reinterpret_cast<NpadInternalState*>(
|
controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state;
|
||||||
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;
|
||||||
@ -617,7 +615,7 @@ void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
|
|||||||
hold_type = joy_hold_type;
|
hold_type = joy_hold_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::NpadJoyHoldType NPad::GetHoldType() const {
|
NpadJoyHoldType NPad::GetHoldType() const {
|
||||||
return hold_type;
|
return hold_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,7 +628,7 @@ void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_m
|
|||||||
handheld_activation_mode = activation_mode;
|
handheld_activation_mode = activation_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
|
NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
|
||||||
return handheld_activation_mode;
|
return handheld_activation_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,7 +636,7 @@ void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
|
|||||||
communication_mode = communication_mode_;
|
communication_mode = communication_mode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
|
NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
|
||||||
return communication_mode;
|
return communication_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -978,27 +976,27 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
|
|||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
|
NpadSixAxisSensorLifo& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
|
NpadSixAxisSensorLifo& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
|
NpadSixAxisSensorLifo& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
|
NpadSixAxisSensorLifo& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
|
NpadSixAxisSensorLifo& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
|
NpadSixAxisSensorLifo& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1343,7 +1341,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
|
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 {
|
||||||
|
@ -8,12 +8,10 @@
|
|||||||
#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/ring_lifo.h"
|
#include "core/hle/service/hid/controllers/types/npad_types.h"
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
class EmulatedController;
|
class EmulatedController;
|
||||||
@ -32,10 +30,13 @@ 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_, u8* raw_shared_memory_,
|
explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
|
||||||
KernelHelpers::ServiceContext& service_context_);
|
KernelHelpers::ServiceContext& service_context_);
|
||||||
~NPad() override;
|
~NPad() override;
|
||||||
|
|
||||||
@ -48,89 +49,6 @@ 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;
|
||||||
|
|
||||||
@ -188,12 +106,12 @@ public:
|
|||||||
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
|
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
|
||||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
|
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
|
||||||
|
|
||||||
SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
|
NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
|
||||||
SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
|
NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
|
||||||
SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
|
NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
|
||||||
SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
|
NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
|
||||||
SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
|
NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
|
||||||
SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
|
NpadSixAxisSensorLifo& 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,
|
||||||
@ -221,214 +139,6 @@ 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{};
|
||||||
@ -479,7 +189,7 @@ private:
|
|||||||
|
|
||||||
std::atomic<u64> press_state{};
|
std::atomic<u64> press_state{};
|
||||||
|
|
||||||
std::array<NpadControllerData, NPAD_COUNT> controller_data{};
|
std::array<NpadControllerData, NpadCount> 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{};
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
|
|
||||||
Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
|
Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
|
||||||
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");
|
||||||
|
@ -97,8 +97,7 @@ 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_, u8* raw_shared_memory_,
|
explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
|
||||||
KernelHelpers::ServiceContext& service_context_);
|
|
||||||
~Palma() override;
|
~Palma() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
|
240
src/core/hle/service/hid/controllers/shared_memory_format.h
Normal file
240
src/core/hle/service/hid/controllers/shared_memory_format.h
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
// 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
|
@ -0,0 +1,53 @@
|
|||||||
|
// 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
|
44
src/core/hle/service/hid/controllers/shared_memory_holder.h
Normal file
44
src/core/hle/service/hid/controllers/shared_memory_holder.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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
|
@ -6,6 +6,7 @@
|
|||||||
#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"
|
||||||
@ -132,30 +133,30 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sixaxis_fullkey_state.sampling_number =
|
sixaxis_fullkey_state.sampling_number =
|
||||||
sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||||
sixaxis_handheld_state.sampling_number =
|
sixaxis_handheld_state.sampling_number =
|
||||||
sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||||
sixaxis_dual_left_state.sampling_number =
|
sixaxis_dual_left_state.sampling_number =
|
||||||
sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||||
sixaxis_dual_right_state.sampling_number =
|
sixaxis_dual_right_state.sampling_number =
|
||||||
sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||||
sixaxis_left_lifo_state.sampling_number =
|
sixaxis_left_lifo_state.sampling_number =
|
||||||
sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||||
sixaxis_right_lifo_state.sampling_number =
|
sixaxis_right_lifo_state.sampling_number =
|
||||||
sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
sixaxis_right_lifo.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.WriteNextEntry(sixaxis_handheld_state);
|
sixaxis_handheld_lifo.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.WriteNextEntry(sixaxis_fullkey_state);
|
sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
|
sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
|
||||||
sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
|
sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
|
||||||
sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
|
sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
|
||||||
sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
|
sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
// 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/hid/hid_core.h"
|
#include "core/hle/service/hid/controllers/shared_memory_format.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_, u8* raw_shared_memory_)
|
Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_,
|
||||||
: ControllerBase{hid_core_} {
|
CommonHeader& ring_lifo_header)
|
||||||
raw_shared_memory = raw_shared_memory_;
|
: ControllerBase{hid_core_}, header{ring_lifo_header} {}
|
||||||
}
|
|
||||||
|
|
||||||
Controller_Stubbed::~Controller_Stubbed() = default;
|
Controller_Stubbed::~Controller_Stubbed() = default;
|
||||||
|
|
||||||
@ -25,18 +22,10 @@ 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
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user