Compare commits

..

7 Commits

Author SHA1 Message Date
d813f6291d Android #162 2023-12-16 00:57:45 +00:00
2ace6da47d Merge PR 12358 2023-12-16 00:57:45 +00:00
a497205c8d Merge PR 12349 2023-12-16 00:57:44 +00:00
c22f983b7c Merge PR 12345 2023-12-16 00:57:44 +00:00
de53d5a716 Merge PR 12344 2023-12-16 00:57:44 +00:00
f105e51b40 Merge PR 12335 2023-12-16 00:57:44 +00:00
8244f327ca Merge PR 12237 2023-12-16 00:57:44 +00:00
94 changed files with 1444 additions and 3262 deletions

View File

@ -142,9 +142,6 @@ if (YUZU_USE_BUNDLED_VCPKG)
if (ENABLE_WEB_SERVICE)
list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
endif()
if (ANDROID)
list(APPEND VCPKG_MANIFEST_FEATURES "android")
endif()
include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")

View File

@ -1,10 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12304](https://github.com/yuzu-emu/yuzu//pull/12304) | [`fcc85abe2`](https://github.com/yuzu-emu/yuzu//pull/12304/files) | nvnflinger: mark buffer as acquired when acquired | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12349](https://github.com/yuzu-emu/yuzu//pull/12349) | [`6851e9329`](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 |
| [12382](https://github.com/yuzu-emu/yuzu//pull/12382) | [`7fc06260d`](https://github.com/yuzu-emu/yuzu//pull/12382/files) | renderer_vulkan: allow up to 7 swapchain images | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12387](https://github.com/yuzu-emu/yuzu//pull/12387) | [`6ca530a72`](https://github.com/yuzu-emu/yuzu//pull/12387/files) | android: add oboe audio sink | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12391](https://github.com/yuzu-emu/yuzu//pull/12391) | [`65e646eeb`](https://github.com/yuzu-emu/yuzu//pull/12391/files) | Revert "video_core: use interval map for page count tracking" | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12237](https://github.com/yuzu-emu/yuzu//pull/12237) | [`a05c24242`](https://github.com/yuzu-emu/yuzu//pull/12237/files) | nce: implement instruction emulation for misaligned memory accesses | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12335](https://github.com/yuzu-emu/yuzu//pull/12335) | [`86d26914a`](https://github.com/yuzu-emu/yuzu//pull/12335/files) | android: Game Properties | [t895](https://github.com/t895/) | Yes |
| [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 |
| [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 |
| [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.

View File

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

View File

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

View File

@ -253,17 +253,6 @@ if (ENABLE_SDL2)
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
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)
target_precompile_headers(audio_core PRIVATE precompiled_headers.h)
endif()

View File

@ -1,207 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <span>
#include <vector>
#include <oboe/Oboe.h>
#include "audio_core/common/common.h"
#include "audio_core/sink/oboe_sink.h"
#include "audio_core/sink/sink_stream.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "core/core.h"
namespace AudioCore::Sink {
class OboeSinkStream final : public SinkStream,
public oboe::AudioStreamDataCallback,
public oboe::AudioStreamErrorCallback {
public:
explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
u32 system_channels_)
: SinkStream(system_, type_) {
name = name_;
system_channels = system_channels_;
this->OpenStream();
}
~OboeSinkStream() override {
LOG_DEBUG(Audio_Sink, "Destructing Oboe stream {}", name);
}
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 = builder.setDirection(direction)
->setSampleRate(TargetSampleRate)
->setFormat(oboe::AudioFormat::I16)
->setFormatConversionAllowed(true)
->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:
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 = builder.setDirection(direction)
->setSampleRate(TargetSampleRate)
->setChannelCount(expected_channels)
->setChannelMask(expected_mask)
->setFormat(oboe::AudioFormat::I16)
->setFormatConversionAllowed(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);
device_channels = m_stream->getChannelCount();
LOG_INFO(Audio_Sink, "Opened Oboe stream with {} channels", device_channels);
return true;
}
std::shared_ptr<oboe::AudioStream> m_stream{};
};
OboeSink::OboeSink() {
// TODO: This is not generally knowable
// The channel count is distinct based on direction and can change
device_channels = OboeSinkStream::QueryChannelCount(oboe::Direction::Output);
}
OboeSink::~OboeSink() = default;
SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) {
SinkStreamPtr& stream = sink_streams.emplace_back(
std::make_unique<OboeSinkStream>(system, type, name, system_channels));
return stream.get();
}
void OboeSink::CloseStream(SinkStream* to_remove) {
sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
}
void OboeSink::CloseStreams() {
sink_streams.clear();
}
f32 OboeSink::GetDeviceVolume() const {
if (sink_streams.empty()) {
return 1.0f;
}
return sink_streams.front()->GetDeviceVolume();
}
void OboeSink::SetDeviceVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetDeviceVolume(volume);
}
}
void OboeSink::SetSystemVolume(f32 volume) {
for (auto& stream : sink_streams) {
stream->SetSystemVolume(volume);
}
}
} // namespace AudioCore::Sink

View File

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

View File

@ -7,9 +7,6 @@
#include <vector>
#include "audio_core/sink/sink_details.h"
#ifdef HAVE_OBOE
#include "audio_core/sink/oboe_sink.h"
#endif
#ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h"
#endif
@ -39,16 +36,6 @@ struct SinkDetails {
// sink_details is ordered in terms of desirability, with the best choice at the top.
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
SinkDetails{
Settings::AudioEngine::Cubeb,

View File

@ -42,9 +42,11 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
// We're given 6 channels, but our device only outputs 2, so downmix.
// Front = 1.0
// Center = 0.596
// LFE = 0.354
// Back = 0.707
static constexpr std::array<f32, 4> down_mix_coeff{1.0, 0.596f, 0.354f, 0.707f};
// LFE = 0.354
// 1.0 + 0.596 + 0.707 + 0.354 = 2.657, 1/2.657 = 0.37636f downscale coefficient
static constexpr std::array<f32, 4> down_mix_coeff{0.37636f, 0.22431056f, 0.13323144f,
0.26608652f};
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
read_index += system_channels, write_index += device_channels) {

View File

@ -123,12 +123,6 @@ namespace Common {
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.
template <class C>
constexpr auto Size(const C& c) -> decltype(c.size()) {

View File

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

View File

@ -289,11 +289,7 @@ enum class DirectorySeparator {
// 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_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);
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
@ -302,7 +298,7 @@ enum class DirectorySeparator {
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
// Gets all of the text up to the last '/' or '\' in the path.
[[nodiscard]] std::string GetParentPath(std::string_view path);
[[nodiscard]] std::string_view GetParentPath(std::string_view path);
// Gets all of the text after the first '/' or '\' in the path.
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);

View File

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

View File

@ -549,11 +549,6 @@ add_library(core STATIC
hle/service/hid/xcd.cpp
hle/service/hid/xcd.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.h
hle/service/hid/controllers/console_six_axis.cpp
@ -574,15 +569,14 @@ add_library(core STATIC
hle/service/hid/controllers/palma.h
hle/service/hid/controllers/seven_six_axis.cpp
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.h
hle/service/hid/controllers/stubbed.cpp
hle/service/hid/controllers/stubbed.h
hle/service/hid/controllers/touchscreen.cpp
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.h
hle/service/hid/hidbus/ringcon.cpp
@ -790,12 +784,6 @@ add_library(core STATIC
hle/service/service.h
hle/service/set/set.cpp
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.h
hle/service/set/set_fd.cpp
@ -804,8 +792,6 @@ add_library(core STATIC
hle/service/set/set_sys.h
hle/service/set/settings.cpp
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.h
hle/service/sm/sm_controller.cpp

View File

@ -201,6 +201,8 @@ std::string VfsFile::GetFullPath() const {
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
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()) {
return nullptr;
}
@ -235,6 +237,8 @@ VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
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()) {
// TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
// because of const-ness
@ -299,6 +303,8 @@ std::size_t VfsDirectory::GetSize() const {
VirtualFile VfsDirectory::CreateFileRelative(std::string_view 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()) {
return nullptr;
}
@ -328,6 +334,8 @@ VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view 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()) {
return nullptr;
}

View File

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

View File

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

View File

@ -135,6 +135,7 @@ struct KernelCore::Impl {
obj = nullptr;
}
};
CleanupObject(hid_shared_mem);
CleanupObject(font_shared_mem);
CleanupObject(irs_shared_mem);
CleanupObject(time_shared_mem);
@ -743,16 +744,22 @@ struct KernelCore::Impl {
void InitializeHackSharedMemory(KernelCore& kernel) {
// Setup memory regions for emulated processes
// 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 irs_size{0x8000};
constexpr std::size_t time_size{0x1000};
constexpr std::size_t hidbus_size{0x1000};
hid_shared_mem = KSharedMemory::Create(system.Kernel());
font_shared_mem = KSharedMemory::Create(system.Kernel());
irs_shared_mem = KSharedMemory::Create(system.Kernel());
time_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,
Svc::MemoryPermission::Read, font_size);
KSharedMemory::Register(kernel, font_shared_mem);
@ -1183,6 +1190,14 @@ const KSystemResource& KernelCore::GetSystemSystemResource() const {
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() {
return *impl->font_shared_mem;
}

View File

@ -239,6 +239,12 @@ public:
/// Gets the system resource manager.
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.
Kernel::KSharedMemory& GetFontSharedMem();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,24 +3,21 @@
#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/types/debug_pad_types.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class HIDCore;
}
namespace Core::Timing {
class CoreTiming;
}
class EmulatedController;
struct DebugPadButton;
struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID {
struct DebugPadSharedMemoryFormat;
class DebugPad final : public ControllerBase {
public:
explicit DebugPad(Core::HID::HIDCore& hid_core_,
DebugPadSharedMemoryFormat& debug_pad_shared_memory);
explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~DebugPad() override;
// Called when the controller is initialized
@ -33,8 +30,35 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
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{};
DebugPadSharedMemoryFormat& shared_memory;
DebugPadSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedController* controller = nullptr;
};
} // namespace Service::HID

View File

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

View File

@ -4,22 +4,17 @@
#pragma once
#include <array>
#include "common/bit_field.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/types/touch_types.h"
namespace Core::HID {
class EmulatedConsole;
}
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID {
struct GestureSharedMemoryFormat;
class Gesture final : public ControllerBase {
public:
explicit Gesture(Core::HID::HIDCore& hid_core_,
GestureSharedMemoryFormat& gesture_shared_memory);
explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Gesture() override;
// Called when the controller is initialized
@ -32,6 +27,79 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
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
void ReadTouchInput();
@ -74,7 +142,7 @@ private:
GestureProperties GetGestureProperties();
GestureState next_state{};
GestureSharedMemoryFormat& shared_memory;
GestureSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};

View File

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

View File

@ -3,16 +3,20 @@
#pragma once
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/keyboard_types.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
struct KeyboardModifier;
struct KeyboardKey;
} // namespace Core::HID
namespace Service::HID {
struct KeyboardSharedMemoryFormat;
class Keyboard final : public ControllerBase {
public:
explicit Keyboard(Core::HID::HIDCore& hid_core_,
KeyboardSharedMemoryFormat& keyboard_shared_memory);
explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Keyboard() override;
// Called when the controller is initialized
@ -25,8 +29,25 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
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{};
KeyboardSharedMemoryFormat& shared_memory;
KeyboardSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedDevices* emulated_devices = nullptr;
};
} // namespace Service::HID

View File

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

View File

@ -3,7 +3,9 @@
#pragma once
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
@ -12,11 +14,9 @@ struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID {
struct MouseSharedMemoryFormat;
class Mouse final : public ControllerBase {
public:
explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory);
explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
~Mouse() override;
// Called when the controller is initialized
@ -29,9 +29,17 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
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::AnalogStickState last_mouse_wheel_state{};
MouseSharedMemoryFormat& shared_memory;
MouseSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedDevices* emulated_devices = nullptr;
};
} // namespace Service::HID

View File

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

View File

@ -8,10 +8,12 @@
#include <mutex>
#include <span>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/npad_types.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedController;
@ -30,13 +32,10 @@ class ServiceContext;
union Result;
namespace Service::HID {
struct NpadInternalState;
struct NpadSixAxisSensorLifo;
struct NpadSharedMemoryFormat;
class NPad final : public ControllerBase {
public:
explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_);
~NPad() override;
@ -49,6 +48,89 @@ public:
// When the controller is requesting an update for the shared memory
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);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
@ -106,12 +188,12 @@ public:
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
@ -139,6 +221,214 @@ public:
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
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 {
bool device_mounted{};
Core::HID::VibrationValue latest_vibration_value{};
@ -189,7 +479,7 @@ private:
std::atomic<u64> press_state{};
std::array<NpadControllerData, NpadCount> controller_data{};
std::array<NpadControllerData, NPAD_COUNT> controller_data{};
KernelHelpers::ServiceContext& service_context;
std::mutex mutex;
std::vector<Core::HID::NpadIdType> supported_npad_id_types{};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,10 +31,10 @@ class Palma;
class SevenSixAxis;
class SixAxis;
class TouchScreen;
class XPad;
using CaptureButton = Controller_Stubbed;
using DebugMouse = Mouse;
using Digitizer = Controller_Stubbed;
using DebugMouse = Controller_Stubbed;
using HomeButton = Controller_Stubbed;
using SleepButton = Controller_Stubbed;
using UniquePad = Controller_Stubbed;
@ -46,14 +46,12 @@ public:
~ResourceManager();
void Initialize();
void InitializeController(u64 aruid);
std::shared_ptr<AppletResource> GetAppletResource() const;
std::shared_ptr<CaptureButton> GetCaptureButton() const;
std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
std::shared_ptr<DebugMouse> GetDebugMouse() const;
std::shared_ptr<DebugPad> GetDebugPad() const;
std::shared_ptr<Digitizer> GetDigitizer() const;
std::shared_ptr<Gesture> GetGesture() const;
std::shared_ptr<HomeButton> GetHomeButton() const;
std::shared_ptr<Keyboard> GetKeyboard() const;
@ -98,7 +96,6 @@ private:
std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
std::shared_ptr<DebugMouse> debug_mouse = nullptr;
std::shared_ptr<DebugPad> debug_pad = nullptr;
std::shared_ptr<Digitizer> digitizer = nullptr;
std::shared_ptr<Gesture> gesture = nullptr;
std::shared_ptr<HomeButton> home_button = nullptr;
std::shared_ptr<Keyboard> keyboard = nullptr;
@ -110,6 +107,7 @@ private:
std::shared_ptr<SleepButton> sleep_button = nullptr;
std::shared_ptr<TouchScreen> touch_screen = nullptr;
std::shared_ptr<UniquePad> unique_pad = nullptr;
std::shared_ptr<XPad> xpad = nullptr;
// TODO: Create these resources
// std::shared_ptr<AudioControl> audio_control = nullptr;

View File

@ -90,18 +90,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
LOG_DEBUG(Service_Nvnflinger, "acquiring slot={}", slot);
// If the front buffer is still being tracked, update its slot state
if (core->StillTracking(*front)) {
slots[slot].acquire_called = true;
slots[slot].needs_cleanup_on_release = false;
slots[slot].buffer_state = BufferState::Acquired;
// TODO: for now, avoid resetting the fence, so that when we next return this
// slot to the producer, it will wait for the fence to pass. We should fix this
// by properly waiting for the fence in the BufferItemConsumer.
// slots[slot].fence = Fence::NoFence();
}
// If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
// avoid unnecessarily remapping this buffer on the consumer side.
if (out_buffer->acquire_called) {
@ -144,28 +132,11 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
++current;
}
if (slots[slot].buffer_state == BufferState::Acquired) {
// TODO: for now, avoid resetting the fence, so that when we next return this
// slot to the producer, it can wait for its own fence to pass. We should fix this
// by properly waiting for the fence in the BufferItemConsumer.
// slots[slot].fence = release_fence;
slots[slot].buffer_state = BufferState::Free;
slots[slot].buffer_state = BufferState::Free;
listener = core->connected_producer_listener;
listener = core->connected_producer_listener;
LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
} else if (slots[slot].needs_cleanup_on_release) {
LOG_DEBUG(Service_Nvnflinger, "releasing a stale buffer slot {} (state = {})", slot,
slots[slot].buffer_state);
slots[slot].needs_cleanup_on_release = false;
return Status::StaleBufferSlot;
} else {
LOG_ERROR(Service_Nvnflinger,
"attempted to release buffer slot {} but its state was {}", slot,
slots[slot].buffer_state);
return Status::BadValue;
}
LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
core->SignalDequeueCondition();
}

View File

@ -74,10 +74,6 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) {
slots[slot].graphic_buffer.reset();
if (slots[slot].buffer_state == BufferState::Acquired) {
slots[slot].needs_cleanup_on_release = true;
}
slots[slot].buffer_state = BufferState::Free;
slots[slot].frame_number = UINT32_MAX;
slots[slot].acquire_called = false;

View File

@ -31,7 +31,6 @@ struct BufferSlot final {
u64 frame_number{};
Fence fence;
bool acquire_called{};
bool needs_cleanup_on_release{};
bool attached_by_consumer{};
bool is_preallocated{};
};

View File

@ -204,9 +204,8 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u
// Record the display id.
m_display_id = display_id;
// Create and open a layer for the display.
// Create a layer for the display.
m_layer_id = m_flinger.CreateLayer(m_display_id).value();
m_flinger.OpenLayer(m_layer_id);
// Set up the buffer.
m_buffer_id = m_next_buffer_id++;

View File

@ -176,37 +176,17 @@ void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
}
void Nvnflinger::OpenLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
if (auto* layer = display.FindLayer(layer_id); layer) {
layer->Open();
}
}
}
void Nvnflinger::CloseLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
if (auto* layer = display.FindLayer(layer_id); layer) {
layer->Close();
}
}
}
void Nvnflinger::DestroyLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
display.DestroyLayer(layer_id);
display.CloseLayer(layer_id);
}
}
std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
const auto lock_guard = Lock();
const auto* const layer = FindLayer(display_id, layer_id);
const auto* const layer = FindOrCreateLayer(display_id, layer_id);
if (layer == nullptr) {
return std::nullopt;
@ -260,6 +240,24 @@ VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) {
return display->FindLayer(layer_id);
}
VI::Layer* Nvnflinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
return nullptr;
}
auto* layer = display->FindLayer(layer_id);
if (layer == nullptr) {
LOG_DEBUG(Service_Nvnflinger, "Layer at id {} not found. Trying to create it.", layer_id);
CreateLayerAtId(*display, layer_id);
return display->FindLayer(layer_id);
}
return layer;
}
void Nvnflinger::Compose() {
for (auto& display : displays) {
// Trigger vsync for this display at the end of drawing

View File

@ -73,15 +73,9 @@ public:
/// If an invalid display ID is specified, then an empty optional is returned.
[[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
/// Opens a layer on all displays for the given layer ID.
void OpenLayer(u64 layer_id);
/// Closes a layer on all displays for the given layer ID.
void CloseLayer(u64 layer_id);
/// Destroys the given layer ID.
void DestroyLayer(u64 layer_id);
/// Finds the buffer queue ID of the specified layer in the specified display.
///
/// If an invalid display ID or layer ID is provided, then an empty optional is returned.
@ -123,6 +117,11 @@ private:
/// Finds the layer identified by the specified ID in the desired display.
[[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
/// Finds the layer identified by the specified ID in the desired display,
/// or creates the layer if it is not found.
/// To be used when the system expects the specified ID to already exist.
[[nodiscard]] VI::Layer* FindOrCreateLayer(u64 display_id, u64 layer_id);
/// Creates a layer with the specified layer ID in the desired display.
void CreateLayerAtId(VI::Display& display, u64 layer_id);

View File

@ -1,12 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/appln_settings.h"
namespace Service::Set {
ApplnSettings DefaultApplnSettings() {
return {};
}
} // namespace Service::Set

View File

@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <cstddef>
#include "common/common_types.h"
namespace Service::Set {
struct ApplnSettings {
std::array<u8, 0x10> reserved_000;
// nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0
std::array<u8, 0x10> mii_author_id;
std::array<u8, 0x30> reserved_020;
// nn::settings::system::ServiceDiscoveryControlSettings
std::array<u8, 0x4> service_discovery_control_settings;
std::array<u8, 0x20> reserved_054;
bool in_repair_process_enable_flag;
std::array<u8, 0x3> pad_075;
};
static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10);
static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50);
static_assert(offsetof(ApplnSettings, in_repair_process_enable_flag) == 0x74);
static_assert(sizeof(ApplnSettings) == 0x78, "ApplnSettings has the wrong size!");
ApplnSettings DefaultApplnSettings();
} // namespace Service::Set

View File

@ -1,12 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/device_settings.h"
namespace Service::Set {
DeviceSettings DefaultDeviceSettings() {
return {};
}
} // namespace Service::Set

View File

@ -1,54 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <cstddef>
#include "common/common_types.h"
namespace Service::Set {
struct DeviceSettings {
std::array<u8, 0x10> reserved_000;
// nn::settings::BatteryLot
std::array<u8, 0x18> ptm_battery_lot;
// nn::settings::system::PtmFuelGaugeParameter
std::array<u8, 0x18> ptm_fuel_gauge_parameter;
u8 ptm_battery_version;
// nn::settings::system::PtmCycleCountReliability
u32 ptm_cycle_count_reliability;
std::array<u8, 0x48> reserved_048;
// nn::settings::system::AnalogStickUserCalibration L
std::array<u8, 0x10> analog_user_stick_calibration_l;
// nn::settings::system::AnalogStickUserCalibration R
std::array<u8, 0x10> analog_user_stick_calibration_r;
std::array<u8, 0x20> reserved_0B0;
// nn::settings::system::ConsoleSixAxisSensorAccelerationBias
std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias;
// nn::settings::system::ConsoleSixAxisSensorAccelerationGain
std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration;
};
static_assert(offsetof(DeviceSettings, ptm_battery_lot) == 0x10);
static_assert(offsetof(DeviceSettings, ptm_cycle_count_reliability) == 0x44);
static_assert(offsetof(DeviceSettings, analog_user_stick_calibration_l) == 0x90);
static_assert(offsetof(DeviceSettings, console_six_axis_sensor_acceleration_bias) == 0xD0);
static_assert(offsetof(DeviceSettings, console_six_axis_sensor_angular_acceleration) == 0x13C);
static_assert(sizeof(DeviceSettings) == 0x160, "DeviceSettings has the wrong size!");
DeviceSettings DefaultDeviceSettings();
} // namespace Service::Set

View File

@ -1,12 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/private_settings.h"
namespace Service::Set {
PrivateSettings DefaultPrivateSettings() {
return {};
}
} // namespace Service::Set

View File

@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Set {
/// This is nn::settings::system::InitialLaunchFlag
struct InitialLaunchFlag {
union {
u32 raw{};
BitField<0, 1, u32> InitialLaunchCompletionFlag;
BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
BitField<16, 1, u32> InitialLaunchTimestampFlag;
};
};
static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
/// This is nn::settings::system::InitialLaunchSettings
struct InitialLaunchSettings {
InitialLaunchFlag flags;
INSERT_PADDING_BYTES(0x4);
Service::Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
#pragma pack(push, 4)
struct InitialLaunchSettingsPacked {
InitialLaunchFlag flags;
Service::Time::Clock::SteadyClockTimePoint timestamp;
};
#pragma pack(pop)
static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
"InitialLaunchSettingsPacked is incorrect size");
struct PrivateSettings {
std::array<u8, 0x10> reserved_00;
// nn::settings::system::InitialLaunchSettings
InitialLaunchSettings initial_launch_settings;
std::array<u8, 0x20> reserved_30;
Common::UUID external_clock_source_id;
s64 shutdown_rtc_value;
s64 external_steady_clock_internal_offset;
std::array<u8, 0x60> reserved_70;
// nn::settings::system::PlatformRegion
std::array<u8, 0x4> platform_region;
std::array<u8, 0x4> reserved_D4;
};
static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10);
static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50);
static_assert(offsetof(PrivateSettings, reserved_70) == 0x70);
static_assert(offsetof(PrivateSettings, platform_region) == 0xD0);
static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!");
PrivateSettings DefaultPrivateSettings();
} // namespace Service::Set

View File

@ -4,13 +4,35 @@
#pragma once
#include "core/hle/service/service.h"
#include "core/hle/service/set/system_settings.h"
namespace Core {
class System;
}
namespace Service::Set {
/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
enum class LanguageCode : u64 {
JA = 0x000000000000616A,
EN_US = 0x00000053552D6E65,
FR = 0x0000000000007266,
DE = 0x0000000000006564,
IT = 0x0000000000007469,
ES = 0x0000000000007365,
ZH_CN = 0x0000004E432D687A,
KO = 0x0000000000006F6B,
NL = 0x0000000000006C6E,
PT = 0x0000000000007470,
RU = 0x0000000000007572,
ZH_TW = 0x00000057542D687A,
EN_GB = 0x00000042472D6E65,
FR_CA = 0x00000041432D7266,
ES_419 = 0x00003931342D7365,
ZH_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A,
PT_BR = 0x00000052422D7470,
};
enum class KeyboardLayout : u64 {
Japanese = 0,
EnglishUs = 1,

View File

@ -1,12 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include "common/assert.h"
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
@ -24,16 +19,6 @@
namespace Service::Set {
namespace {
constexpr u32 SETTINGS_VERSION{1u};
constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't');
struct SettingsHeader {
u64 magic;
u32 version;
u32 reserved;
};
} // Anonymous namespace
Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system,
GetFirmwareVersionType type) {
constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809;
@ -87,120 +72,11 @@ Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System&
return ResultSuccess;
}
bool SET_SYS::LoadSettingsFile(std::filesystem::path& path, auto&& default_func) {
using settings_type = decltype(default_func());
if (!Common::FS::CreateDirs(path)) {
return false;
}
auto settings_file = path / "settings.dat";
auto exists = std::filesystem::exists(settings_file);
auto file_size_ok = exists && std::filesystem::file_size(settings_file) ==
sizeof(SettingsHeader) + sizeof(settings_type);
auto ResetToDefault = [&]() {
auto default_settings{default_func()};
SettingsHeader hdr{
.magic = SETTINGS_MAGIC,
.version = SETTINGS_VERSION,
.reserved = 0u,
};
std::ofstream out_settings_file(settings_file, std::ios::out | std::ios::binary);
out_settings_file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr));
out_settings_file.write(reinterpret_cast<const char*>(&default_settings),
sizeof(settings_type));
out_settings_file.flush();
out_settings_file.close();
};
constexpr auto IsHeaderValid = [](std::ifstream& file) -> bool {
if (!file.is_open()) {
return false;
}
SettingsHeader hdr{};
file.read(reinterpret_cast<char*>(&hdr), sizeof(hdr));
return hdr.magic == SETTINGS_MAGIC && hdr.version == SETTINGS_VERSION;
};
if (!exists || !file_size_ok) {
ResetToDefault();
}
std::ifstream file(settings_file, std::ios::binary | std::ios::in);
if (!IsHeaderValid(file)) {
file.close();
ResetToDefault();
file = std::ifstream(settings_file, std::ios::binary | std::ios::in);
if (!IsHeaderValid(file)) {
return false;
}
}
if constexpr (std::is_same_v<settings_type, PrivateSettings>) {
file.read(reinterpret_cast<char*>(&m_private_settings), sizeof(settings_type));
} else if constexpr (std::is_same_v<settings_type, DeviceSettings>) {
file.read(reinterpret_cast<char*>(&m_device_settings), sizeof(settings_type));
} else if constexpr (std::is_same_v<settings_type, ApplnSettings>) {
file.read(reinterpret_cast<char*>(&m_appln_settings), sizeof(settings_type));
} else if constexpr (std::is_same_v<settings_type, SystemSettings>) {
file.read(reinterpret_cast<char*>(&m_system_settings), sizeof(settings_type));
} else {
UNREACHABLE();
}
file.close();
return true;
}
bool SET_SYS::StoreSettingsFile(std::filesystem::path& path, auto& settings) {
using settings_type = std::decay_t<decltype(settings)>;
if (!Common::FS::IsDir(path)) {
return false;
}
auto settings_base = path / "settings";
auto settings_tmp_file = settings_base;
settings_tmp_file = settings_tmp_file.replace_extension("tmp");
std::ofstream file(settings_tmp_file, std::ios::binary | std::ios::out);
if (!file.is_open()) {
return false;
}
SettingsHeader hdr{
.magic = SETTINGS_MAGIC,
.version = SETTINGS_VERSION,
.reserved = 0u,
};
file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr));
if constexpr (std::is_same_v<settings_type, PrivateSettings>) {
file.write(reinterpret_cast<const char*>(&m_private_settings), sizeof(settings_type));
} else if constexpr (std::is_same_v<settings_type, DeviceSettings>) {
file.write(reinterpret_cast<const char*>(&m_device_settings), sizeof(settings_type));
} else if constexpr (std::is_same_v<settings_type, ApplnSettings>) {
file.write(reinterpret_cast<const char*>(&m_appln_settings), sizeof(settings_type));
} else if constexpr (std::is_same_v<settings_type, SystemSettings>) {
file.write(reinterpret_cast<const char*>(&m_system_settings), sizeof(settings_type));
} else {
UNREACHABLE();
}
file.close();
std::filesystem::rename(settings_tmp_file, settings_base.replace_extension("dat"));
return true;
}
void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.language_code = rp.PopEnum<LanguageCode>();
SetSaveNeeded();
language_code_setting = rp.PopEnum<LanguageCode>();
LOG_INFO(Service_SET, "called, language_code={}", m_system_settings.language_code);
LOG_INFO(Service_SET, "called, language_code={}", language_code_setting);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -236,68 +112,19 @@ void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
rb.Push(result);
}
void SET_SYS::GetExternalSteadyClockSourceId(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
Common::UUID id{};
auto res = GetExternalSteadyClockSourceId(id);
IPC::ResponseBuilder rb{ctx, 2 + sizeof(Common::UUID) / sizeof(u32)};
rb.Push(res);
rb.PushRaw(id);
}
void SET_SYS::SetExternalSteadyClockSourceId(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto id{rp.PopRaw<Common::UUID>()};
auto res = SetExternalSteadyClockSourceId(id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::GetUserSystemClockContext(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
Service::Time::Clock::SystemClockContext context{};
auto res = GetUserSystemClockContext(context);
IPC::ResponseBuilder rb{ctx,
2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)};
rb.Push(res);
rb.PushRaw(context);
}
void SET_SYS::SetUserSystemClockContext(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()};
auto res = SetUserSystemClockContext(context);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(m_system_settings.account_settings);
rb.PushRaw(account_settings);
}
void SET_SYS::SetAccountSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.account_settings = rp.PopRaw<AccountSettings>();
SetSaveNeeded();
account_settings = rp.PopRaw<AccountSettings>();
LOG_INFO(Service_SET, "called, account_settings_flags={}",
m_system_settings.account_settings.flags);
LOG_INFO(Service_SET, "called, account_settings_flags={}", account_settings.flags);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -306,11 +133,11 @@ void SET_SYS::SetAccountSettings(HLERequestContext& ctx) {
void SET_SYS::GetEulaVersions(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
ctx.WriteBuffer(m_system_settings.eula_versions);
ctx.WriteBuffer(eula_versions);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(m_system_settings.eula_version_count);
rb.Push(static_cast<u32>(eula_versions.size()));
}
void SET_SYS::SetEulaVersions(HLERequestContext& ctx) {
@ -318,12 +145,13 @@ void SET_SYS::SetEulaVersions(HLERequestContext& ctx) {
const auto buffer_data = ctx.ReadBuffer();
LOG_INFO(Service_SET, "called, elements={}", elements);
ASSERT(elements <= m_system_settings.eula_versions.size());
m_system_settings.eula_version_count = static_cast<u32>(elements);
std::memcpy(&m_system_settings.eula_versions, buffer_data.data(),
sizeof(EulaVersion) * elements);
SetSaveNeeded();
eula_versions.resize(elements);
for (std::size_t index = 0; index < elements; index++) {
const std::size_t start_index = index * sizeof(EulaVersion);
memcpy(eula_versions.data() + start_index, buffer_data.data() + start_index,
sizeof(EulaVersion));
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -334,15 +162,14 @@ void SET_SYS::GetColorSetId(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(m_system_settings.color_set_id);
rb.PushEnum(color_set);
}
void SET_SYS::SetColorSetId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.color_set_id = rp.PopEnum<ColorSet>();
SetSaveNeeded();
color_set = rp.PopEnum<ColorSet>();
LOG_DEBUG(Service_SET, "called, color_set={}", m_system_settings.color_set_id);
LOG_DEBUG(Service_SET, "called, color_set={}", color_set);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -353,21 +180,17 @@ void SET_SYS::GetNotificationSettings(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 8};
rb.Push(ResultSuccess);
rb.PushRaw(m_system_settings.notification_settings);
rb.PushRaw(notification_settings);
}
void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.notification_settings = rp.PopRaw<NotificationSettings>();
SetSaveNeeded();
notification_settings = rp.PopRaw<NotificationSettings>();
LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}",
m_system_settings.notification_settings.flags.raw,
m_system_settings.notification_settings.volume,
m_system_settings.notification_settings.start_time.hour,
m_system_settings.notification_settings.start_time.minute,
m_system_settings.notification_settings.stop_time.hour,
m_system_settings.notification_settings.stop_time.minute);
notification_settings.flags.raw, notification_settings.volume,
notification_settings.start_time.hour, notification_settings.start_time.minute,
notification_settings.stop_time.hour, notification_settings.stop_time.minute);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -376,11 +199,11 @@ void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) {
void SET_SYS::GetAccountNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
ctx.WriteBuffer(m_system_settings.account_notification_settings);
ctx.WriteBuffer(account_notifications);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(m_system_settings.account_notification_settings_count);
rb.Push(static_cast<u32>(account_notifications.size()));
}
void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) {
@ -389,12 +212,12 @@ void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, elements={}", elements);
ASSERT(elements <= m_system_settings.account_notification_settings.size());
m_system_settings.account_notification_settings_count = static_cast<u32>(elements);
std::memcpy(&m_system_settings.account_notification_settings, buffer_data.data(),
elements * sizeof(AccountNotificationSettings));
SetSaveNeeded();
account_notifications.resize(elements);
for (std::size_t index = 0; index < elements; index++) {
const std::size_t start_index = index * sizeof(AccountNotificationSettings);
memcpy(account_notifications.data() + start_index, buffer_data.data() + start_index,
sizeof(AccountNotificationSettings));
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -421,14 +244,6 @@ static Settings GetSettings() {
ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0});
ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000});
// Time
ret["time"]["notify_time_to_fs_interval_seconds"] = ToBytes(s32{600});
ret["time"]["standard_network_clock_sufficient_accuracy_minutes"] =
ToBytes(s32{43200}); // 30 days
ret["time"]["standard_steady_clock_rtc_update_interval_minutes"] = ToBytes(s32{5});
ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0});
ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023});
return ret;
}
@ -458,6 +273,8 @@ void SET_SYS::GetSettingsItemValueSize(HLERequestContext& ctx) {
}
void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
// The category of the setting. This corresponds to the top-level keys of
// system_settings.ini.
const auto setting_category_buf{ctx.ReadBuffer(0)};
@ -468,13 +285,14 @@ void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
const auto setting_name_buf{ctx.ReadBuffer(1)};
const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()};
std::vector<u8> value;
auto response = GetSettingsItemValue(value, setting_category, setting_name);
auto settings{GetSettings()};
Result response{ResultUnknown};
LOG_INFO(Service_SET, "called. category={}, name={} -- res=0x{:X}", setting_category,
setting_name, response.raw);
ctx.WriteBuffer(value.data(), value.size());
if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) {
auto setting_value = settings[setting_category][setting_name];
ctx.WriteBuffer(setting_value.data(), setting_value.size());
response = ResultSuccess;
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(response);
@ -485,23 +303,19 @@ void SET_SYS::GetTvSettings(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(m_system_settings.tv_settings);
rb.PushRaw(tv_settings);
}
void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.tv_settings = rp.PopRaw<TvSettings>();
SetSaveNeeded();
tv_settings = rp.PopRaw<TvSettings>();
LOG_INFO(Service_SET,
"called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, "
"rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}",
m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode,
m_system_settings.tv_settings.constrast_ratio,
m_system_settings.tv_settings.hdmi_content_type,
m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama,
m_system_settings.tv_settings.tv_resolution,
m_system_settings.tv_settings.tv_underscan);
tv_settings.flags.raw, tv_settings.cmu_mode, tv_settings.constrast_ratio,
tv_settings.hdmi_content_type, tv_settings.rgb_range, tv_settings.tv_gama,
tv_settings.tv_resolution, tv_settings.tv_underscan);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -515,87 +329,16 @@ void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
rb.PushEnum(QuestFlag::Retail);
}
void SET_SYS::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called");
Service::Time::TimeZone::LocationName name{};
auto res = GetDeviceTimeZoneLocationName(name);
IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::Time::TimeZone::LocationName) / sizeof(u32)};
rb.Push(res);
rb.PushRaw<Service::Time::TimeZone::LocationName>(name);
}
void SET_SYS::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()};
auto res = SetDeviceTimeZoneLocationName(name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::SetRegionCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.region_code = rp.PopEnum<RegionCode>();
SetSaveNeeded();
region_code = rp.PopEnum<RegionCode>();
LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code);
LOG_INFO(Service_SET, "called, region_code={}", region_code);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SET_SYS::GetNetworkSystemClockContext(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
Service::Time::Clock::SystemClockContext context{};
auto res = GetNetworkSystemClockContext(context);
IPC::ResponseBuilder rb{ctx,
2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)};
rb.Push(res);
rb.PushRaw(context);
}
void SET_SYS::SetNetworkSystemClockContext(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()};
auto res = SetNetworkSystemClockContext(context);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
bool enabled{};
auto res = IsUserSystemClockAutomaticCorrectionEnabled(enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.PushRaw(enabled);
}
void SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto enabled{rp.Pop<bool>()};
auto res = SetUserSystemClockAutomaticCorrectionEnabled(enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::GetPrimaryAlbumStorage(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@ -609,18 +352,16 @@ void SET_SYS::GetSleepSettings(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
rb.PushRaw(m_system_settings.sleep_settings);
rb.PushRaw(sleep_settings);
}
void SET_SYS::SetSleepSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.sleep_settings = rp.PopRaw<SleepSettings>();
SetSaveNeeded();
sleep_settings = rp.PopRaw<SleepSettings>();
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
m_system_settings.sleep_settings.flags.raw,
m_system_settings.sleep_settings.handheld_sleep_plan,
m_system_settings.sleep_settings.console_sleep_plan);
sleep_settings.flags.raw, sleep_settings.handheld_sleep_plan,
sleep_settings.console_sleep_plan);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -630,20 +371,15 @@ void SET_SYS::GetInitialLaunchSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(m_system_settings.initial_launch_settings_packed);
rb.PushRaw(launch_settings);
}
void SET_SYS::SetInitialLaunchSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>();
launch_settings = rp.PopRaw<InitialLaunchSettings>();
m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags;
m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp;
SetSaveNeeded();
LOG_INFO(Service_SET, "called, flags={}, timestamp={}",
m_system_settings.initial_launch_settings_packed.flags.raw,
m_system_settings.initial_launch_settings_packed.timestamp.time_point);
LOG_INFO(Service_SET, "called, flags={}, timestamp={}", launch_settings.flags.raw,
launch_settings.timestamp.time_point);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -701,37 +437,13 @@ void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) {
u8 battery_percentage_flag{1};
LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
battery_percentage_flag);
LOG_DEBUG(Service_SET, "(STUBBED) called, battery_percentage_flag={}", battery_percentage_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(battery_percentage_flag);
}
void SET_SYS::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called.");
IPC::RequestParser rp{ctx};
auto offset{rp.Pop<s64>()};
auto res = SetExternalSteadyClockInternalOffset(offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::GetExternalSteadyClockInternalOffset(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called.");
s64 offset{};
auto res = GetExternalSteadyClockInternalOffset(offset);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.Push(offset);
}
void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@ -741,19 +453,18 @@ void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) {
}
void SET_SYS::GetAppletLaunchFlags(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag);
LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(m_system_settings.applet_launch_flag);
rb.Push(applet_launch_flag);
}
void SET_SYS::SetAppletLaunchFlags(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.applet_launch_flag = rp.Pop<u32>();
SetSaveNeeded();
applet_launch_flag = rp.Pop<u32>();
LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag);
LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -778,52 +489,6 @@ void SET_SYS::GetKeyboardLayout(HLERequestContext& ctx) {
rb.Push(static_cast<u32>(selected_keyboard_layout));
}
void SET_SYS::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
Service::Time::Clock::SteadyClockTimePoint time_point{};
auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point);
}
void SET_SYS::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
IPC::RequestParser rp{ctx};
auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()};
auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
Service::Time::Clock::SteadyClockTimePoint time_point{};
auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point);
}
void SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
IPC::RequestParser rp{ctx};
auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()};
auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@ -843,7 +508,7 @@ void SET_SYS::GetHomeMenuScheme(HLERequestContext& ctx) {
.extra = 0xFF000000,
};
IPC::ResponseBuilder rb{ctx, 2 + sizeof(HomeMenuScheme) / sizeof(u32)};
IPC::ResponseBuilder rb{ctx, 7};
rb.Push(ResultSuccess);
rb.PushRaw(default_color);
}
@ -855,7 +520,6 @@ void SET_SYS::GetHomeMenuSchemeModel(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
rb.Push(0);
}
void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@ -864,7 +528,7 @@ void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
rb.Push<u8>(false);
}
SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"}, m_system{system} {
SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &SET_SYS::SetLanguageCode, "SetLanguageCode"},
@ -879,10 +543,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
{10, nullptr, "SetBacklightSettings"},
{11, nullptr, "SetBluetoothDevicesSettings"},
{12, nullptr, "GetBluetoothDevicesSettings"},
{13, &SET_SYS::GetExternalSteadyClockSourceId, "GetExternalSteadyClockSourceId"},
{14, &SET_SYS::SetExternalSteadyClockSourceId, "SetExternalSteadyClockSourceId"},
{15, &SET_SYS::GetUserSystemClockContext, "GetUserSystemClockContext"},
{16, &SET_SYS::SetUserSystemClockContext, "SetUserSystemClockContext"},
{13, nullptr, "GetExternalSteadyClockSourceId"},
{14, nullptr, "SetExternalSteadyClockSourceId"},
{15, nullptr, "GetUserSystemClockContext"},
{16, nullptr, "SetUserSystemClockContext"},
{17, &SET_SYS::GetAccountSettings, "GetAccountSettings"},
{18, &SET_SYS::SetAccountSettings, "SetAccountSettings"},
{19, nullptr, "GetAudioVolume"},
@ -917,15 +581,15 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
{50, nullptr, "SetDataDeletionSettings"},
{51, nullptr, "GetInitialSystemAppletProgramId"},
{52, nullptr, "GetOverlayDispProgramId"},
{53, &SET_SYS::GetDeviceTimeZoneLocationName, "GetDeviceTimeZoneLocationName"},
{54, &SET_SYS::SetDeviceTimeZoneLocationName, "SetDeviceTimeZoneLocationName"},
{53, nullptr, "GetDeviceTimeZoneLocationName"},
{54, nullptr, "SetDeviceTimeZoneLocationName"},
{55, nullptr, "GetWirelessCertificationFileSize"},
{56, nullptr, "GetWirelessCertificationFile"},
{57, &SET_SYS::SetRegionCode, "SetRegionCode"},
{58, &SET_SYS::GetNetworkSystemClockContext, "GetNetworkSystemClockContext"},
{59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"},
{60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"},
{61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"},
{58, nullptr, "GetNetworkSystemClockContext"},
{59, nullptr, "SetNetworkSystemClockContext"},
{60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"},
{61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"},
{62, nullptr, "GetDebugModeFlag"},
{63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
{64, nullptr, "SetPrimaryAlbumStorage"},
@ -969,8 +633,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
{102, nullptr, "SetExternalRtcResetFlag"},
{103, nullptr, "GetUsbFullKeyEnableFlag"},
{104, nullptr, "SetUsbFullKeyEnableFlag"},
{105, &SET_SYS::SetExternalSteadyClockInternalOffset, "SetExternalSteadyClockInternalOffset"},
{106, &SET_SYS::GetExternalSteadyClockInternalOffset, "GetExternalSteadyClockInternalOffset"},
{105, nullptr, "SetExternalSteadyClockInternalOffset"},
{106, nullptr, "GetExternalSteadyClockInternalOffset"},
{107, nullptr, "GetBacklightSettingsEx"},
{108, nullptr, "SetBacklightSettingsEx"},
{109, nullptr, "GetHeadphoneVolumeWarningCount"},
@ -1014,10 +678,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
{147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"},
{148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"},
{149, nullptr, "GetRebootlessSystemUpdateVersion"},
{150, &SET_SYS::GetDeviceTimeZoneLocationUpdatedTime, "GetDeviceTimeZoneLocationUpdatedTime"},
{151, &SET_SYS::SetDeviceTimeZoneLocationUpdatedTime, "SetDeviceTimeZoneLocationUpdatedTime"},
{152, &SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime, "GetUserSystemClockAutomaticCorrectionUpdatedTime"},
{153, &SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime, "SetUserSystemClockAutomaticCorrectionUpdatedTime"},
{150, nullptr, "GetDeviceTimeZoneLocationUpdatedTime"},
{151, nullptr, "SetDeviceTimeZoneLocationUpdatedTime"},
{152, nullptr, "GetUserSystemClockAutomaticCorrectionUpdatedTime"},
{153, nullptr, "SetUserSystemClockAutomaticCorrectionUpdatedTime"},
{154, nullptr, "GetAccountOnlineStorageSettings"},
{155, nullptr, "SetAccountOnlineStorageSettings"},
{156, nullptr, "GetPctlReadyFlag"},
@ -1079,184 +743,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
// clang-format on
RegisterHandlers(functions);
SetupSettings();
m_save_thread =
std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); });
}
SET_SYS::~SET_SYS() {
SetSaveNeeded();
m_save_thread.request_stop();
}
void SET_SYS::SetupSettings() {
auto system_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) {
ASSERT(false);
}
auto private_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
if (!LoadSettingsFile(private_dir, []() { return DefaultPrivateSettings(); })) {
ASSERT(false);
}
auto device_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
if (!LoadSettingsFile(device_dir, []() { return DefaultDeviceSettings(); })) {
ASSERT(false);
}
auto appln_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
if (!LoadSettingsFile(appln_dir, []() { return DefaultApplnSettings(); })) {
ASSERT(false);
}
}
void SET_SYS::StoreSettings() {
auto system_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
if (!StoreSettingsFile(system_dir, m_system_settings)) {
LOG_ERROR(HW_GPU, "Failed to store System settings");
}
auto private_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
if (!StoreSettingsFile(private_dir, m_private_settings)) {
LOG_ERROR(HW_GPU, "Failed to store Private settings");
}
auto device_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
if (!StoreSettingsFile(device_dir, m_device_settings)) {
LOG_ERROR(HW_GPU, "Failed to store Device settings");
}
auto appln_dir =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
if (!StoreSettingsFile(appln_dir, m_appln_settings)) {
LOG_ERROR(HW_GPU, "Failed to store ApplLn settings");
}
}
void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) {
while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) {
std::scoped_lock l{m_save_needed_mutex};
if (!std::exchange(m_save_needed, false)) {
continue;
}
StoreSettings();
}
}
void SET_SYS::SetSaveNeeded() {
std::scoped_lock l{m_save_needed_mutex};
m_save_needed = true;
}
Result SET_SYS::GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category,
const std::string& name) {
auto settings{GetSettings()};
R_UNLESS(settings.contains(category) && settings[category].contains(name), ResultUnknown);
out_value = settings[category][name];
R_SUCCEED();
}
Result SET_SYS::GetExternalSteadyClockSourceId(Common::UUID& out_id) {
out_id = m_private_settings.external_clock_source_id;
R_SUCCEED();
}
Result SET_SYS::SetExternalSteadyClockSourceId(Common::UUID id) {
m_private_settings.external_clock_source_id = id;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context) {
out_context = m_system_settings.user_system_clock_context;
R_SUCCEED();
}
Result SET_SYS::SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context) {
m_system_settings.user_system_clock_context = context;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name) {
out_name = m_system_settings.device_time_zone_location_name;
R_SUCCEED();
}
Result SET_SYS::SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name) {
m_system_settings.device_time_zone_location_name = name;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::GetNetworkSystemClockContext(
Service::Time::Clock::SystemClockContext& out_context) {
out_context = m_system_settings.network_system_clock_context;
R_SUCCEED();
}
Result SET_SYS::SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context) {
m_system_settings.network_system_clock_context = context;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled) {
out_enabled = m_system_settings.user_system_clock_automatic_correction_enabled;
R_SUCCEED();
}
Result SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(bool enabled) {
m_system_settings.user_system_clock_automatic_correction_enabled = enabled;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::SetExternalSteadyClockInternalOffset(s64 offset) {
m_private_settings.external_steady_clock_internal_offset = offset;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::GetExternalSteadyClockInternalOffset(s64& out_offset) {
out_offset = m_private_settings.external_steady_clock_internal_offset;
R_SUCCEED();
}
Result SET_SYS::GetDeviceTimeZoneLocationUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint& out_time_point) {
out_time_point = m_system_settings.device_time_zone_location_updated_time;
R_SUCCEED();
}
Result SET_SYS::SetDeviceTimeZoneLocationUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint& time_point) {
m_system_settings.device_time_zone_location_updated_time = time_point;
SetSaveNeeded();
R_SUCCEED();
}
Result SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint& out_time_point) {
out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point;
R_SUCCEED();
}
Result SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint out_time_point) {
m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point;
SetSaveNeeded();
R_SUCCEED();
}
SET_SYS::~SET_SYS() = default;
} // namespace Service::Set

View File

@ -3,27 +3,17 @@
#pragma once
#include <filesystem>
#include <mutex>
#include <string>
#include <thread>
#include "common/polyfill_thread.h"
#include "common/uuid.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/appln_settings.h"
#include "core/hle/service/set/device_settings.h"
#include "core/hle/service/set/private_settings.h"
#include "core/hle/service/set/system_settings.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_zone_types.h"
namespace Core {
class System;
}
namespace Service::Set {
enum class LanguageCode : u64;
enum class GetFirmwareVersionType {
Version1,
Version2,
@ -52,38 +42,270 @@ public:
explicit SET_SYS(Core::System& system_);
~SET_SYS() override;
Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category,
const std::string& name);
Result GetExternalSteadyClockSourceId(Common::UUID& out_id);
Result SetExternalSteadyClockSourceId(Common::UUID id);
Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context);
Result SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context);
Result GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name);
Result SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name);
Result GetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& out_context);
Result SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context);
Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled);
Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled);
Result SetExternalSteadyClockInternalOffset(s64 offset);
Result GetExternalSteadyClockInternalOffset(s64& out_offset);
Result GetDeviceTimeZoneLocationUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint& out_time_point);
Result SetDeviceTimeZoneLocationUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint& time_point);
Result GetUserSystemClockAutomaticCorrectionUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint& out_time_point);
Result SetUserSystemClockAutomaticCorrectionUpdatedTime(
Service::Time::Clock::SteadyClockTimePoint time_point);
private:
/// Indicates the current theme set by the system settings
enum class ColorSet : u32 {
BasicWhite = 0,
BasicBlack = 1,
};
/// Indicates the current console is a retail or kiosk unit
enum class QuestFlag : u8 {
Retail = 0,
Kiosk = 1,
};
/// This is nn::settings::system::TvResolution
enum class TvResolution : u32 {
Auto,
Resolution1080p,
Resolution720p,
Resolution480p,
};
/// This is nn::settings::system::HdmiContentType
enum class HdmiContentType : u32 {
None,
Graphics,
Cinema,
Photo,
Game,
};
/// This is nn::settings::system::RgbRange
enum class RgbRange : u32 {
Auto,
Full,
Limited,
};
/// This is nn::settings::system::CmuMode
enum class CmuMode : u32 {
None,
ColorInvert,
HighContrast,
GrayScale,
};
/// This is nn::settings::system::PrimaryAlbumStorage
enum class PrimaryAlbumStorage : u32 {
Nand,
SdCard,
};
/// This is nn::settings::system::NotificationVolume
enum class NotificationVolume : u32 {
Mute,
Low,
High,
};
/// This is nn::settings::system::ChineseTraditionalInputMethod
enum class ChineseTraditionalInputMethod : u32 {
Unknown0 = 0,
Unknown1 = 1,
Unknown2 = 2,
};
/// This is nn::settings::system::ErrorReportSharePermission
enum class ErrorReportSharePermission : u32 {
NotConfirmed,
Granted,
Denied,
};
/// This is nn::settings::system::FriendPresenceOverlayPermission
enum class FriendPresenceOverlayPermission : u8 {
NotConfirmed,
NoDisplay,
FavoriteFriends,
Friends,
};
/// This is nn::settings::system::HandheldSleepPlan
enum class HandheldSleepPlan : u32 {
Sleep1Min,
Sleep3Min,
Sleep5Min,
Sleep10Min,
Sleep30Min,
Never,
};
/// This is nn::settings::system::ConsoleSleepPlan
enum class ConsoleSleepPlan : u32 {
Sleep1Hour,
Sleep2Hour,
Sleep3Hour,
Sleep6Hour,
Sleep12Hour,
Never,
};
/// This is nn::settings::system::RegionCode
enum class RegionCode : u32 {
Japan,
Usa,
Europe,
Australia,
HongKongTaiwanKorea,
China,
};
/// This is nn::settings::system::EulaVersionClockType
enum class EulaVersionClockType : u32 {
NetworkSystemClock,
SteadyClock,
};
/// This is nn::settings::system::SleepFlag
struct SleepFlag {
union {
u32 raw{};
BitField<0, 1, u32> SleepsWhilePlayingMedia;
BitField<1, 1, u32> WakesAtPowerStateChange;
};
};
static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::TvFlag
struct TvFlag {
union {
u32 raw{};
BitField<0, 1, u32> Allows4k;
BitField<1, 1, u32> Allows3d;
BitField<2, 1, u32> AllowsCec;
BitField<3, 1, u32> PreventsScreenBurnIn;
};
};
static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::InitialLaunchFlag
struct InitialLaunchFlag {
union {
u32 raw{};
BitField<0, 1, u32> InitialLaunchCompletionFlag;
BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
BitField<16, 1, u32> InitialLaunchTimestampFlag;
};
};
static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
/// This is nn::settings::system::NotificationFlag
struct NotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> RingtoneFlag;
BitField<1, 1, u32> DownloadCompletionFlag;
BitField<8, 1, u32> EnablesNews;
BitField<9, 1, u32> IncomingLampFlag;
};
};
static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
/// This is nn::settings::system::AccountNotificationFlag
struct AccountNotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> FriendOnlineFlag;
BitField<1, 1, u32> FriendRequestFlag;
BitField<8, 1, u32> CoralInvitationFlag;
};
};
static_assert(sizeof(AccountNotificationFlag) == 4,
"AccountNotificationFlag is an invalid size");
/// This is nn::settings::system::TvSettings
struct TvSettings {
TvFlag flags;
TvResolution tv_resolution;
HdmiContentType hdmi_content_type;
RgbRange rgb_range;
CmuMode cmu_mode;
u32 tv_underscan;
f32 tv_gama;
f32 constrast_ratio;
};
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
/// This is nn::settings::system::NotificationTime
struct NotificationTime {
u32 hour;
u32 minute;
};
static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
/// This is nn::settings::system::NotificationSettings
struct NotificationSettings {
NotificationFlag flags;
NotificationVolume volume;
NotificationTime start_time;
NotificationTime stop_time;
};
static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
/// This is nn::settings::system::AccountSettings
struct AccountSettings {
u32 flags;
};
static_assert(sizeof(AccountSettings) == 0x4, "AccountSettings is an invalid size");
/// This is nn::settings::system::AccountNotificationSettings
struct AccountNotificationSettings {
Common::UUID uid;
AccountNotificationFlag flags;
FriendPresenceOverlayPermission friend_presence_permission;
FriendPresenceOverlayPermission friend_invitation_permission;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(AccountNotificationSettings) == 0x18,
"AccountNotificationSettings is an invalid size");
/// This is nn::settings::system::InitialLaunchSettings
struct SleepSettings {
SleepFlag flags;
HandheldSleepPlan handheld_sleep_plan;
ConsoleSleepPlan console_sleep_plan;
};
static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
/// This is nn::settings::system::InitialLaunchSettings
struct InitialLaunchSettings {
InitialLaunchFlag flags;
INSERT_PADDING_BYTES(0x4);
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
/// This is nn::settings::system::InitialLaunchSettings
struct EulaVersion {
u32 version;
RegionCode region_code;
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
s64 posix_time;
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
/// This is nn::settings::system::HomeMenuScheme
struct HomeMenuScheme {
u32 main;
u32 back;
u32 sub;
u32 bezel;
u32 extra;
};
static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
void SetLanguageCode(HLERequestContext& ctx);
void GetFirmwareVersion(HLERequestContext& ctx);
void GetFirmwareVersion2(HLERequestContext& ctx);
void GetExternalSteadyClockSourceId(HLERequestContext& ctx);
void SetExternalSteadyClockSourceId(HLERequestContext& ctx);
void GetUserSystemClockContext(HLERequestContext& ctx);
void SetUserSystemClockContext(HLERequestContext& ctx);
void GetAccountSettings(HLERequestContext& ctx);
void SetAccountSettings(HLERequestContext& ctx);
void GetEulaVersions(HLERequestContext& ctx);
@ -99,13 +321,7 @@ private:
void GetTvSettings(HLERequestContext& ctx);
void SetTvSettings(HLERequestContext& ctx);
void GetQuestFlag(HLERequestContext& ctx);
void GetDeviceTimeZoneLocationName(HLERequestContext& ctx);
void SetDeviceTimeZoneLocationName(HLERequestContext& ctx);
void SetRegionCode(HLERequestContext& ctx);
void GetNetworkSystemClockContext(HLERequestContext& ctx);
void SetNetworkSystemClockContext(HLERequestContext& ctx);
void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void GetPrimaryAlbumStorage(HLERequestContext& ctx);
void GetSleepSettings(HLERequestContext& ctx);
void SetSleepSettings(HLERequestContext& ctx);
@ -117,36 +333,59 @@ private:
void GetMiiAuthorId(HLERequestContext& ctx);
void GetAutoUpdateEnableFlag(HLERequestContext& ctx);
void GetBatteryPercentageFlag(HLERequestContext& ctx);
void SetExternalSteadyClockInternalOffset(HLERequestContext& ctx);
void GetExternalSteadyClockInternalOffset(HLERequestContext& ctx);
void GetErrorReportSharePermission(HLERequestContext& ctx);
void GetAppletLaunchFlags(HLERequestContext& ctx);
void SetAppletLaunchFlags(HLERequestContext& ctx);
void GetKeyboardLayout(HLERequestContext& ctx);
void GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx);
void SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx);
void GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
void SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
void GetFieldTestingFlag(HLERequestContext& ctx);
void GetHomeMenuScheme(HLERequestContext& ctx);
void GetHomeMenuSchemeModel(HLERequestContext& ctx);
void GetFieldTestingFlag(HLERequestContext& ctx);
bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func);
bool StoreSettingsFile(std::filesystem::path& path, auto& settings);
void SetupSettings();
void StoreSettings();
void StoreSettingsThreadFunc(std::stop_token stop_token);
void SetSaveNeeded();
AccountSettings account_settings{
.flags = {},
};
Core::System& m_system;
SystemSettings m_system_settings{};
PrivateSettings m_private_settings{};
DeviceSettings m_device_settings{};
ApplnSettings m_appln_settings{};
std::jthread m_save_thread;
std::mutex m_save_needed_mutex;
bool m_save_needed{false};
ColorSet color_set = ColorSet::BasicWhite;
NotificationSettings notification_settings{
.flags = {0x300},
.volume = NotificationVolume::High,
.start_time = {.hour = 9, .minute = 0},
.stop_time = {.hour = 21, .minute = 0},
};
std::vector<AccountNotificationSettings> account_notifications{};
TvSettings tv_settings{
.flags = {0xc},
.tv_resolution = TvResolution::Auto,
.hdmi_content_type = HdmiContentType::Game,
.rgb_range = RgbRange::Auto,
.cmu_mode = CmuMode::None,
.tv_underscan = {},
.tv_gama = 1.0f,
.constrast_ratio = 0.5f,
};
InitialLaunchSettings launch_settings{
.flags = {0x10001},
.timestamp = {},
};
SleepSettings sleep_settings{
.flags = {0x3},
.handheld_sleep_plan = HandheldSleepPlan::Sleep10Min,
.console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
};
u32 applet_launch_flag{};
std::vector<EulaVersion> eula_versions{};
RegionCode region_code;
LanguageCode language_code_setting;
};
} // namespace Service::Set

View File

@ -1,51 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/system_settings.h"
namespace Service::Set {
SystemSettings DefaultSystemSettings() {
SystemSettings settings{};
settings.version = 0x140000;
settings.flags = 7;
settings.color_set_id = ColorSet::BasicWhite;
settings.notification_settings = {
.flags{0x300},
.volume = NotificationVolume::High,
.start_time = {.hour = 9, .minute = 0},
.stop_time = {.hour = 21, .minute = 0},
};
settings.tv_settings = {
.flags = {0xC},
.tv_resolution = TvResolution::Auto,
.hdmi_content_type = HdmiContentType::Game,
.rgb_range = RgbRange::Auto,
.cmu_mode = CmuMode::None,
.tv_underscan = {},
.tv_gama = 1.0f,
.constrast_ratio = 0.5f,
};
settings.initial_launch_settings_packed = {
.flags = {0x10001},
.timestamp = {},
};
settings.sleep_settings = {
.flags = {0x3},
.handheld_sleep_plan = HandheldSleepPlan::Sleep10Min,
.console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
};
settings.device_time_zone_location_name = {"UTC"};
settings.user_system_clock_automatic_correction_enabled = false;
return settings;
}
} // namespace Service::Set

View File

@ -1,699 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/service/set/private_settings.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Set {
/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
enum class LanguageCode : u64 {
JA = 0x000000000000616A,
EN_US = 0x00000053552D6E65,
FR = 0x0000000000007266,
DE = 0x0000000000006564,
IT = 0x0000000000007469,
ES = 0x0000000000007365,
ZH_CN = 0x0000004E432D687A,
KO = 0x0000000000006F6B,
NL = 0x0000000000006C6E,
PT = 0x0000000000007470,
RU = 0x0000000000007572,
ZH_TW = 0x00000057542D687A,
EN_GB = 0x00000042472D6E65,
FR_CA = 0x00000041432D7266,
ES_419 = 0x00003931342D7365,
ZH_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A,
PT_BR = 0x00000052422D7470,
};
/// This is nn::settings::system::ErrorReportSharePermission
enum class ErrorReportSharePermission : u32 {
NotConfirmed,
Granted,
Denied,
};
/// This is nn::settings::system::ChineseTraditionalInputMethod
enum class ChineseTraditionalInputMethod : u32 {
Unknown0 = 0,
Unknown1 = 1,
Unknown2 = 2,
};
/// This is nn::settings::system::HomeMenuScheme
struct HomeMenuScheme {
u32 main;
u32 back;
u32 sub;
u32 bezel;
u32 extra;
};
static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
/// Indicates the current theme set by the system settings
enum class ColorSet : u32 {
BasicWhite = 0,
BasicBlack = 1,
};
/// Indicates the current console is a retail or kiosk unit
enum class QuestFlag : u8 {
Retail = 0,
Kiosk = 1,
};
/// This is nn::settings::system::RegionCode
enum class RegionCode : u32 {
Japan,
Usa,
Europe,
Australia,
HongKongTaiwanKorea,
China,
};
/// This is nn::settings::system::AccountSettings
struct AccountSettings {
u32 flags;
};
static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size");
/// This is nn::settings::system::NotificationVolume
enum class NotificationVolume : u32 {
Mute,
Low,
High,
};
/// This is nn::settings::system::NotificationFlag
struct NotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> RingtoneFlag;
BitField<1, 1, u32> DownloadCompletionFlag;
BitField<8, 1, u32> EnablesNews;
BitField<9, 1, u32> IncomingLampFlag;
};
};
static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
/// This is nn::settings::system::NotificationTime
struct NotificationTime {
u32 hour;
u32 minute;
};
static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
/// This is nn::settings::system::NotificationSettings
struct NotificationSettings {
NotificationFlag flags;
NotificationVolume volume;
NotificationTime start_time;
NotificationTime stop_time;
};
static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
/// This is nn::settings::system::AccountNotificationFlag
struct AccountNotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> FriendOnlineFlag;
BitField<1, 1, u32> FriendRequestFlag;
BitField<8, 1, u32> CoralInvitationFlag;
};
};
static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size");
/// This is nn::settings::system::FriendPresenceOverlayPermission
enum class FriendPresenceOverlayPermission : u8 {
NotConfirmed,
NoDisplay,
FavoriteFriends,
Friends,
};
/// This is nn::settings::system::AccountNotificationSettings
struct AccountNotificationSettings {
Common::UUID uid;
AccountNotificationFlag flags;
FriendPresenceOverlayPermission friend_presence_permission;
FriendPresenceOverlayPermission friend_invitation_permission;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(AccountNotificationSettings) == 0x18,
"AccountNotificationSettings is an invalid size");
/// This is nn::settings::system::TvFlag
struct TvFlag {
union {
u32 raw{};
BitField<0, 1, u32> Allows4k;
BitField<1, 1, u32> Allows3d;
BitField<2, 1, u32> AllowsCec;
BitField<3, 1, u32> PreventsScreenBurnIn;
};
};
static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::TvResolution
enum class TvResolution : u32 {
Auto,
Resolution1080p,
Resolution720p,
Resolution480p,
};
/// This is nn::settings::system::HdmiContentType
enum class HdmiContentType : u32 {
None,
Graphics,
Cinema,
Photo,
Game,
};
/// This is nn::settings::system::RgbRange
enum class RgbRange : u32 {
Auto,
Full,
Limited,
};
/// This is nn::settings::system::CmuMode
enum class CmuMode : u32 {
None,
ColorInvert,
HighContrast,
GrayScale,
};
/// This is nn::settings::system::TvSettings
struct TvSettings {
TvFlag flags;
TvResolution tv_resolution;
HdmiContentType hdmi_content_type;
RgbRange rgb_range;
CmuMode cmu_mode;
u32 tv_underscan;
f32 tv_gama;
f32 constrast_ratio;
};
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
/// This is nn::settings::system::PrimaryAlbumStorage
enum class PrimaryAlbumStorage : u32 {
Nand,
SdCard,
};
/// This is nn::settings::system::HandheldSleepPlan
enum class HandheldSleepPlan : u32 {
Sleep1Min,
Sleep3Min,
Sleep5Min,
Sleep10Min,
Sleep30Min,
Never,
};
/// This is nn::settings::system::ConsoleSleepPlan
enum class ConsoleSleepPlan : u32 {
Sleep1Hour,
Sleep2Hour,
Sleep3Hour,
Sleep6Hour,
Sleep12Hour,
Never,
};
/// This is nn::settings::system::SleepFlag
struct SleepFlag {
union {
u32 raw{};
BitField<0, 1, u32> SleepsWhilePlayingMedia;
BitField<1, 1, u32> WakesAtPowerStateChange;
};
};
static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::SleepSettings
struct SleepSettings {
SleepFlag flags;
HandheldSleepPlan handheld_sleep_plan;
ConsoleSleepPlan console_sleep_plan;
};
static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
/// This is nn::settings::system::EulaVersionClockType
enum class EulaVersionClockType : u32 {
NetworkSystemClock,
SteadyClock,
};
/// This is nn::settings::system::EulaVersion
struct EulaVersion {
u32 version;
RegionCode region_code;
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
s64 posix_time;
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
struct SystemSettings {
// 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000
// (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000
// (9.0.0-10.0.4), 0x100100 (10.1.0+), 0x120000 (12.0.0-12.1.0), 0x130000 (13.0.0-13.2.1),
// 0x140000 (14.0.0+)
u32 version;
// 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+).
// if (flags & 2), defaults are written for AnalogStickUserCalibration
u32 flags;
std::array<u8, 0x8> reserved_00008;
// nn::settings::LanguageCode
LanguageCode language_code;
std::array<u8, 0x38> reserved_00018;
// nn::settings::system::NetworkSettings
u32 network_setting_count;
bool wireless_lan_enable_flag;
std::array<u8, 0x3> pad_00055;
std::array<u8, 0x8> reserved_00058;
// nn::settings::system::NetworkSettings
std::array<std::array<u8, 0x400>, 32> network_settings_1B0;
// nn::settings::system::BluetoothDevicesSettings
std::array<u8, 0x4> bluetooth_device_settings_count;
bool bluetooth_enable_flag;
std::array<u8, 0x3> pad_08065;
bool bluetooth_afh_enable_flag;
std::array<u8, 0x3> pad_08069;
bool bluetooth_boost_enable_flag;
std::array<u8, 0x3> pad_0806D;
std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10;
s32 ldn_channel;
std::array<u8, 0x3C> reserved_09474;
// nn::util::Uuid MiiAuthorId
std::array<u8, 0x10> mii_author_id;
std::array<u8, 0x30> reserved_094C0;
// nn::settings::system::NxControllerSettings
u32 nx_controller_settings_count;
std::array<u8, 0xC> reserved_094F4;
// nn::settings::system::NxControllerSettings,
// nn::settings::system::NxControllerLegacySettings on 13.0.0+
std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings;
std::array<u8, 0x170> reserved_09780;
bool external_rtc_reset_flag;
std::array<u8, 0x3> pad_098F1;
std::array<u8, 0x3C> reserved_098F4;
s32 push_notification_activity_mode_on_sleep;
std::array<u8, 0x3C> reserved_09934;
// nn::settings::system::ErrorReportSharePermission
ErrorReportSharePermission error_report_share_permssion;
std::array<u8, 0x3C> reserved_09974;
// nn::settings::KeyboardLayout
std::array<u8, 0x4> keyboard_layout;
std::array<u8, 0x3C> reserved_099B4;
bool web_inspector_flag;
std::array<u8, 0x3> pad_099F1;
// nn::settings::system::AllowedSslHost
u32 allowed_ssl_host_count;
bool memory_usage_rate_flag;
std::array<u8, 0x3> pad_099F9;
std::array<u8, 0x34> reserved_099FC;
// nn::settings::system::HostFsMountPoint
std::array<u8, 0x100> host_fs_mount_point;
// nn::settings::system::AllowedSslHost
std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts;
std::array<u8, 0x6C0> reserved_0A330;
// nn::settings::system::BlePairingSettings
u32 ble_pairing_settings_count;
std::array<u8, 0xC> reserved_0A9F4;
std::array<std::array<u8, 0x80>, 10> ble_pairing_settings;
// nn::settings::system::AccountOnlineStorageSettings
u32 account_online_storage_settings_count;
std::array<u8, 0xC> reserved_0AF04;
std::array<std::array<u8, 0x40>, 8> account_online_storage_settings;
bool pctl_ready_flag;
std::array<u8, 0x3> pad_0B111;
std::array<u8, 0x3C> reserved_0B114;
// nn::settings::system::ThemeId
std::array<u8, 0x80> theme_id_type0;
std::array<u8, 0x80> theme_id_type1;
std::array<u8, 0x100> reserved_0B250;
// nn::settings::ChineseTraditionalInputMethod
ChineseTraditionalInputMethod chinese_traditional_input_method;
std::array<u8, 0x3C> reserved_0B354;
bool zoom_flag;
std::array<u8, 0x3> pad_0B391;
std::array<u8, 0x3C> reserved_0B394;
// nn::settings::system::ButtonConfigRegisteredSettings
u32 button_config_registered_settings_count;
std::array<u8, 0xC> reserved_0B3D4;
// nn::settings::system::ButtonConfigSettings
u32 button_config_settings_count;
std::array<u8, 0x4> reserved_0B3E4;
std::array<std::array<u8, 0x5A8>, 5> button_config_settings;
std::array<u8, 0x13B0> reserved_0D030;
u32 button_config_settings_embedded_count;
std::array<u8, 0x4> reserved_0E3E4;
std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded;
std::array<u8, 0x13B0> reserved_10030;
u32 button_config_settings_left_count;
std::array<u8, 0x4> reserved_113E4;
std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left;
std::array<u8, 0x13B0> reserved_13030;
u32 button_config_settings_right_count;
std::array<u8, 0x4> reserved_143E4;
std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right;
std::array<u8, 0x73B0> reserved_16030;
// nn::settings::system::ButtonConfigRegisteredSettings
std::array<u8, 0x5C8> button_config_registered_settings_embedded;
std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings;
std::array<u8, 0x7FF8> reserved_21378;
// nn::settings::system::ConsoleSixAxisSensorAccelerationBias
std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias;
// nn::settings::system::ConsoleSixAxisSensorAccelerationGain
std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration;
std::array<u8, 0x70> reserved_29400;
bool lock_screen_flag;
std::array<u8, 0x3> pad_29471;
std::array<u8, 0x4> reserved_249274;
ColorSet color_set_id;
QuestFlag quest_flag;
// nn::settings::system::RegionCode
RegionCode region_code;
// Different to nn::settings::system::InitialLaunchSettings?
InitialLaunchSettingsPacked initial_launch_settings_packed;
bool battery_percentage_flag;
std::array<u8, 0x3> pad_294A1;
// BitFlagSet<32, nn::settings::system::AppletLaunchFlag>
u32 applet_launch_flag;
// nn::settings::system::ThemeSettings
std::array<u8, 0x8> theme_settings;
// nn::fssystem::ArchiveMacKey
std::array<u8, 0x10> theme_key;
bool field_testing_flag;
std::array<u8, 0x3> pad_294C1;
s32 panel_crc_mode;
std::array<u8, 0x28> reserved_294C8;
// nn::settings::system::BacklightSettings
std::array<u8, 0x2C> backlight_settings_mixed_up;
std::array<u8, 0x64> reserved_2951C;
// nn::time::SystemClockContext
Service::Time::Clock::SystemClockContext user_system_clock_context;
Service::Time::Clock::SystemClockContext network_system_clock_context;
bool user_system_clock_automatic_correction_enabled;
std::array<u8, 0x3> pad_295C1;
std::array<u8, 0x4> reserved_295C4;
// nn::time::SteadyClockTimePoint
Service::Time::Clock::SteadyClockTimePoint
user_system_clock_automatic_correction_updated_time_point;
std::array<u8, 0x10> reserved_295E0;
// nn::settings::system::AccountSettings
AccountSettings account_settings;
std::array<u8, 0xFC> reserved_295F4;
// nn::settings::system::AudioVolume
std::array<u8, 0x8> audio_volume_type0;
std::array<u8, 0x8> audio_volume_type1;
// nn::settings::system::AudioOutputMode
s32 audio_output_mode_type0;
s32 audio_output_mode_type1;
s32 audio_output_mode_type2;
bool force_mute_on_headphone_removed;
std::array<u8, 0x3> pad_2970D;
s32 headphone_volume_warning_count;
bool heaphone_volume_update_flag;
std::array<u8, 0x3> pad_29715;
// nn::settings::system::AudioVolume
std::array<u8, 0x8> audio_volume_type2;
// nn::settings::system::AudioOutputMode
s32 audio_output_mode_type3;
s32 audio_output_mode_type4;
bool hearing_protection_safeguard_flag;
std::array<u8, 0x3> pad_29729;
std::array<u8, 0x4> reserved_2972C;
s64 hearing_protection_safeguard_remaining_time;
std::array<u8, 0x38> reserved_29738;
bool console_information_upload_flag;
std::array<u8, 0x3> pad_29771;
std::array<u8, 0x3C> reserved_29774;
bool automatic_application_download_flag;
std::array<u8, 0x3> pad_297B1;
std::array<u8, 0x4> reserved_297B4;
// nn::settings::system::NotificationSettings
NotificationSettings notification_settings;
std::array<u8, 0x60> reserved_297D0;
// nn::settings::system::AccountNotificationSettings
u32 account_notification_settings_count;
std::array<u8, 0xC> reserved_29834;
std::array<AccountNotificationSettings, 8> account_notification_settings;
std::array<u8, 0x140> reserved_29900;
f32 vibration_master_volume;
bool usb_full_key_enable_flag;
std::array<u8, 0x3> pad_29A45;
// nn::settings::system::AnalogStickUserCalibration
std::array<u8, 0x10> analog_stick_user_calibration_left;
std::array<u8, 0x10> analog_stick_user_calibration_right;
// nn::settings::system::TouchScreenMode
s32 touch_screen_mode;
std::array<u8, 0x14> reserved_29A6C;
// nn::settings::system::TvSettings
TvSettings tv_settings;
// nn::settings::system::Edid
std::array<u8, 0x100> edid;
std::array<u8, 0x2E0> reserved_29BA0;
// nn::settings::system::DataDeletionSettings
std::array<u8, 0x8> data_deletion_settings;
std::array<u8, 0x38> reserved_29E88;
// nn::ncm::ProgramId
std::array<u8, 0x8> initial_system_applet_program_id;
std::array<u8, 0x8> overlay_disp_program_id;
std::array<u8, 0x4> reserved_29ED0;
bool requires_run_repair_time_reviser;
std::array<u8, 0x6B> reserved_29ED5;
// nn::time::LocationName
Service::Time::TimeZone::LocationName device_time_zone_location_name;
std::array<u8, 0x4> reserved_29F64;
// nn::time::SteadyClockTimePoint
Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time;
std::array<u8, 0xC0> reserved_29F80;
// nn::settings::system::PrimaryAlbumStorage
PrimaryAlbumStorage primary_album_storage;
std::array<u8, 0x3C> reserved_2A044;
bool usb_30_enable_flag;
std::array<u8, 0x3> pad_2A081;
bool usb_30_host_enable_flag;
std::array<u8, 0x3> pad_2A085;
bool usb_30_device_enable_flag;
std::array<u8, 0x3> pad_2A089;
std::array<u8, 0x34> reserved_2A08C;
bool nfc_enable_flag;
std::array<u8, 0x3> pad_2A0C1;
std::array<u8, 0x3C> reserved_2A0C4;
// nn::settings::system::SleepSettings
SleepSettings sleep_settings;
std::array<u8, 0x34> reserved_2A10C;
// nn::settings::system::EulaVersion
u32 eula_version_count;
std::array<u8, 0xC> reserved_2A144;
std::array<EulaVersion, 32> eula_versions;
std::array<u8, 0x200> reserved_2A750;
// nn::settings::system::DeviceNickName
std::array<u8, 0x80> device_nick_name;
std::array<u8, 0x80> reserved_2A9D0;
bool auto_update_enable_flag;
std::array<u8, 0x3> pad_2AA51;
std::array<u8, 0x4C> reserved_2AA54;
// nn::settings::system::BluetoothDevicesSettings
std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14;
std::array<u8, 0x2000> reserved_2C6A0;
// nn::settings::system::NxControllerSettings
std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30;
};
static_assert(offsetof(SystemSettings, language_code) == 0x10);
static_assert(offsetof(SystemSettings, network_setting_count) == 0x50);
static_assert(offsetof(SystemSettings, network_settings_1B0) == 0x60);
static_assert(offsetof(SystemSettings, bluetooth_device_settings_count) == 0x8060);
static_assert(offsetof(SystemSettings, bluetooth_enable_flag) == 0x8064);
static_assert(offsetof(SystemSettings, bluetooth_device_settings_first_10) == 0x8070);
static_assert(offsetof(SystemSettings, ldn_channel) == 0x9470);
static_assert(offsetof(SystemSettings, mii_author_id) == 0x94B0);
static_assert(offsetof(SystemSettings, nx_controller_settings_count) == 0x94F0);
static_assert(offsetof(SystemSettings, nx_controller_legacy_settings) == 0x9500);
static_assert(offsetof(SystemSettings, external_rtc_reset_flag) == 0x98F0);
static_assert(offsetof(SystemSettings, push_notification_activity_mode_on_sleep) == 0x9930);
static_assert(offsetof(SystemSettings, allowed_ssl_host_count) == 0x99F4);
static_assert(offsetof(SystemSettings, host_fs_mount_point) == 0x9A30);
static_assert(offsetof(SystemSettings, allowed_ssl_hosts) == 0x9B30);
static_assert(offsetof(SystemSettings, ble_pairing_settings_count) == 0xA9F0);
static_assert(offsetof(SystemSettings, ble_pairing_settings) == 0xAA00);
static_assert(offsetof(SystemSettings, account_online_storage_settings_count) == 0xAF00);
static_assert(offsetof(SystemSettings, account_online_storage_settings) == 0xAF10);
static_assert(offsetof(SystemSettings, pctl_ready_flag) == 0xB110);
static_assert(offsetof(SystemSettings, theme_id_type0) == 0xB150);
static_assert(offsetof(SystemSettings, chinese_traditional_input_method) == 0xB350);
static_assert(offsetof(SystemSettings, button_config_registered_settings_count) == 0xB3D0);
static_assert(offsetof(SystemSettings, button_config_settings_count) == 0xB3E0);
static_assert(offsetof(SystemSettings, button_config_settings) == 0xB3E8);
static_assert(offsetof(SystemSettings, button_config_registered_settings_embedded) == 0x1D3E0);
static_assert(offsetof(SystemSettings, console_six_axis_sensor_acceleration_bias) == 0x29370);
static_assert(offsetof(SystemSettings, lock_screen_flag) == 0x29470);
static_assert(offsetof(SystemSettings, battery_percentage_flag) == 0x294A0);
static_assert(offsetof(SystemSettings, field_testing_flag) == 0x294C0);
static_assert(offsetof(SystemSettings, backlight_settings_mixed_up) == 0x294F0);
static_assert(offsetof(SystemSettings, user_system_clock_context) == 0x29580);
static_assert(offsetof(SystemSettings, network_system_clock_context) == 0x295A0);
static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_enabled) == 0x295C0);
static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_updated_time_point) ==
0x295C8);
static_assert(offsetof(SystemSettings, account_settings) == 0x295F0);
static_assert(offsetof(SystemSettings, audio_volume_type0) == 0x296F0);
static_assert(offsetof(SystemSettings, hearing_protection_safeguard_remaining_time) == 0x29730);
static_assert(offsetof(SystemSettings, automatic_application_download_flag) == 0x297B0);
static_assert(offsetof(SystemSettings, notification_settings) == 0x297B8);
static_assert(offsetof(SystemSettings, account_notification_settings) == 0x29840);
static_assert(offsetof(SystemSettings, vibration_master_volume) == 0x29A40);
static_assert(offsetof(SystemSettings, analog_stick_user_calibration_left) == 0x29A48);
static_assert(offsetof(SystemSettings, touch_screen_mode) == 0x29A68);
static_assert(offsetof(SystemSettings, edid) == 0x29AA0);
static_assert(offsetof(SystemSettings, data_deletion_settings) == 0x29E80);
static_assert(offsetof(SystemSettings, requires_run_repair_time_reviser) == 0x29ED4);
static_assert(offsetof(SystemSettings, device_time_zone_location_name) == 0x29F40);
static_assert(offsetof(SystemSettings, nfc_enable_flag) == 0x2A0C0);
static_assert(offsetof(SystemSettings, eula_version_count) == 0x2A140);
static_assert(offsetof(SystemSettings, device_nick_name) == 0x2A950);
static_assert(offsetof(SystemSettings, bluetooth_device_settings_last_14) == 0x2AAA0);
static_assert(offsetof(SystemSettings, nx_controller_settings_data_from_offset_30) == 0x2E6A0);
static_assert(sizeof(SystemSettings) == 0x336A0, "SystemSettings has the wrong size!");
SystemSettings DefaultSystemSettings();
} // namespace Service::Set

View File

@ -240,7 +240,7 @@ private:
return ret;
}
Result ReadImpl(std::vector<u8>* out_data) {
Result ReadImpl(std::vector<u8>* out_data, size_t size) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
size_t actual_size{};
Result res = backend->Read(&actual_size, *out_data);
@ -326,8 +326,8 @@ private:
}
void Read(HLERequestContext& ctx) {
std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
const Result res = ReadImpl(&output_bytes);
std::vector<u8> output_bytes;
const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
if (res == ResultSuccess) {

View File

@ -51,24 +51,11 @@ Display::~Display() {
}
Layer& Display::GetLayer(std::size_t index) {
size_t i = 0;
for (auto& layer : layers) {
if (!layer->IsOpen()) {
continue;
}
if (i == index) {
return *layer;
}
i++;
}
UNREACHABLE();
return *layers.at(index);
}
size_t Display::GetNumLayers() const {
return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); });
const Layer& Display::GetLayer(std::size_t index) const {
return *layers.at(index);
}
Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) {
@ -105,11 +92,7 @@ void Display::CreateLayer(u64 layer_id, u32 binder_id,
hos_binder_driver_server.RegisterProducer(std::move(producer));
}
void Display::DestroyLayer(u64 layer_id) {
if (auto* layer = this->FindLayer(layer_id); layer != nullptr) {
layer->GetConsumer().Abandon();
}
void Display::CloseLayer(u64 layer_id) {
std::erase_if(layers,
[layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
}

View File

@ -66,13 +66,18 @@ public:
/// Whether or not this display has any layers added to it.
bool HasLayers() const {
return GetNumLayers() > 0;
return !layers.empty();
}
/// Gets a layer for this display based off an index.
Layer& GetLayer(std::size_t index);
std::size_t GetNumLayers() const;
/// Gets a layer for this display based off an index.
const Layer& GetLayer(std::size_t index) const;
std::size_t GetNumLayers() const {
return layers.size();
}
/**
* Gets the internal vsync event.
@ -95,11 +100,11 @@ public:
///
void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core);
/// Removes a layer from this display with the given ID.
/// Closes and removes a layer from this display with the given ID.
///
/// @param layer_id The ID assigned to the layer to destroy.
/// @param layer_id The ID assigned to the layer to close.
///
void DestroyLayer(u64 layer_id);
void CloseLayer(u64 layer_id);
/// Resets the display for a new connection.
void Reset() {

View File

@ -8,8 +8,8 @@ namespace Service::VI {
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_)
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
consumer{std::move(consumer_)}, open{false} {}
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
consumer_)} {}
Layer::~Layer() = default;

View File

@ -71,25 +71,12 @@ public:
return core;
}
bool IsOpen() const {
return open;
}
void Close() {
open = false;
}
void Open() {
open = true;
}
private:
const u64 layer_id;
const u32 binder_id;
android::BufferQueueCore& core;
android::BufferQueueProducer& binder;
std::shared_ptr<android::BufferItemConsumer> consumer;
bool open;
};
} // namespace Service::VI

View File

@ -719,8 +719,6 @@ private:
return;
}
nv_flinger.OpenLayer(layer_id);
android::OutputParcel parcel;
parcel.WriteInterface(NativeWindow{*buffer_queue_id});
@ -785,7 +783,6 @@ private:
const u64 layer_id = rp.Pop<u64>();
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
nv_flinger.DestroyLayer(layer_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -62,7 +62,7 @@ u64 StandardVmCallbacks::HidKeysDown() {
}
const auto applet_resource = hid->GetResourceManager();
if (applet_resource == nullptr || applet_resource->GetNpad() == nullptr) {
if (applet_resource == nullptr) {
LOG_WARNING(CheatEngine,
"Attempted to read input state, but applet resource is not initialized!");
return 0;

View File

@ -23,13 +23,13 @@ constexpr VAddr c = 16 * HIGH_PAGE_SIZE;
class RasterizerInterface {
public:
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {
const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS};
const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >>
Core::Memory::YUZU_PAGEBITS};
for (u64 page = page_start; page < page_end; ++page) {
int& value = page_table[page];
value += delta;
value += (cache ? 1 : -1);
if (value < 0) {
throw std::logic_error{"negative page"};
}
@ -546,4 +546,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") {
REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
memory_track->MarkRegionAsCpuModified(c, WORD);
REQUIRE(rasterizer.Count() == 0);
}
}

View File

@ -473,7 +473,7 @@ private:
VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
IteratePages(changed_bits, [&](size_t offset, size_t size) {
rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE,
size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1);
size * BYTES_PER_PAGE, add_to_rasterizer);
});
}

View File

@ -270,7 +270,7 @@ private:
std::jthread fence_thread;
DelayedDestructionRing<TFence, 8> delayed_destruction_ring;
DelayedDestructionRing<TFence, 6> delayed_destruction_ring;
};
} // namespace VideoCommon

View File

@ -3,6 +3,7 @@
#include <atomic>
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
@ -11,61 +12,65 @@
namespace VideoCore {
static constexpr u16 IdentityValue = 1;
using namespace Core::Memory;
RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_)
: cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {}
RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : map{}, cpu_memory{cpu_memory_} {
// We are tracking CPU memory, which cannot map more than 39 bits.
const VAddr start_address = 0;
const VAddr end_address = (1ULL << 39);
const IntervalType address_space_interval(start_address, end_address);
const auto value = std::make_pair(address_space_interval, IdentityValue);
map.add(value);
}
RasterizerAccelerated::~RasterizerAccelerated() = default;
void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
u64 uncache_begin = 0;
u64 cache_begin = 0;
u64 uncache_bytes = 0;
u64 cache_bytes = 0;
void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {
std::scoped_lock lk{map_lock};
std::atomic_thread_fence(std::memory_order_acquire);
const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE);
for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) {
std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page);
// Align sizes.
addr = Common::AlignDown(addr, YUZU_PAGESIZE);
size = Common::AlignUp(size, YUZU_PAGESIZE);
if (delta > 0) {
ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!");
} else if (delta < 0) {
ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
} else {
ASSERT_MSG(false, "Delta must be non-zero!");
}
// Declare the overall interval we are going to operate on.
const VAddr start_address = addr;
const VAddr end_address = addr + size;
const IntervalType modification_range(start_address, end_address);
// Adds or subtracts 1, as count is a unsigned 8-bit value
count.fetch_add(static_cast<u16>(delta), std::memory_order_release);
// Find the boundaries of where to iterate.
const auto lower = map.lower_bound(modification_range);
const auto upper = map.upper_bound(modification_range);
// Assume delta is either -1 or 1
if (count.load(std::memory_order::relaxed) == 0) {
if (uncache_bytes == 0) {
uncache_begin = page;
}
uncache_bytes += YUZU_PAGESIZE;
} else if (uncache_bytes > 0) {
cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes,
false);
uncache_bytes = 0;
}
if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
if (cache_bytes == 0) {
cache_begin = page;
}
cache_bytes += YUZU_PAGESIZE;
} else if (cache_bytes > 0) {
cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
cache_bytes = 0;
// Iterate over the contained intervals.
for (auto it = lower; it != upper; it++) {
// Intersect interval range with modification range.
const auto current_range = modification_range & it->first;
// Calculate the address and size to operate over.
const auto current_addr = current_range.lower();
const auto current_size = current_range.upper() - current_addr;
// Get the current value of the range.
const auto value = it->second;
if (cache && value == IdentityValue) {
// If we are going to cache, and the value is not yet referenced, then cache this range.
cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, true);
} else if (!cache && value == IdentityValue + 1) {
// If we are going to uncache, and this is the last reference, then uncache this range.
cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, false);
}
}
if (uncache_bytes > 0) {
cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false);
}
if (cache_bytes > 0) {
cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
// Update the set.
const auto value = std::make_pair(modification_range, IdentityValue);
if (cache) {
map.add(value);
} else {
map.subtract(value);
}
}

View File

@ -3,8 +3,8 @@
#pragma once
#include <array>
#include <atomic>
#include <mutex>
#include <boost/icl/interval_map.hpp>
#include "common/common_types.h"
#include "video_core/rasterizer_interface.h"
@ -21,28 +21,17 @@ public:
explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_);
~RasterizerAccelerated() override;
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) override;
private:
class CacheEntry final {
public:
CacheEntry() = default;
using PageIndex = VAddr;
using PageReferenceCount = u16;
std::atomic_uint16_t& Count(std::size_t page) {
return values[page & 3];
}
using IntervalMap = boost::icl::interval_map<PageIndex, PageReferenceCount>;
using IntervalType = IntervalMap::interval_type;
const std::atomic_uint16_t& Count(std::size_t page) const {
return values[page & 3];
}
private:
std::array<std::atomic_uint16_t, 4> values{};
};
static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
using CachedPages = std::array<CacheEntry, 0x2000000>;
std::unique_ptr<CachedPages> cached_pages;
IntervalMap map;
std::mutex map_lock;
Core::Memory::Memory& cpu_memory;
};

View File

@ -162,7 +162,7 @@ public:
}
/// Increase/decrease the number of object in pages touching the specified region
virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
virtual void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {}
/// Initialize disk cached resources for the game being emulated
virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,

View File

@ -333,7 +333,7 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
glBindBuffersRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
static_cast<GLsizei>(bindings.buffers.size()), buffer_handles.data(),
reinterpret_cast<const GLintptr*>(bindings.offsets.data()),
reinterpret_cast<const GLsizeiptr*>(bindings.sizes.data()));
reinterpret_cast<const GLsizeiptr*>(bindings.strides.data()));
}
void BufferCacheRuntime::BindTextureBuffer(Buffer& buffer, u32 offset, u32 size,

View File

@ -293,10 +293,10 @@ void PresentManager::RecreateSwapchain(Frame* frame) {
}
void PresentManager::SetImageCount() {
// We cannot have more than 7 images in flight at any given time.
// FRAMES_IN_FLIGHT is 8, and the cache TICKS_TO_DESTROY is 8.
// We cannot have more than 5 images in flight at any given time.
// FRAMES_IN_FLIGHT is 7, and the cache TICKS_TO_DESTROY is 6.
// Mali drivers will give us 6.
image_count = std::min<size_t>(swapchain.GetImageCount(), 7);
image_count = std::min<size_t>(swapchain.GetImageCount(), 5);
}
void PresentManager::CopyToSwapchain(Frame* frame) {

View File

@ -31,7 +31,7 @@ struct DescriptorUpdateEntry {
class UpdateDescriptorQueue final {
// This should be plenty for the vast majority of cases. Most desktop platforms only
// provide up to 3 swapchain images.
static constexpr size_t FRAMES_IN_FLIGHT = 8;
static constexpr size_t FRAMES_IN_FLIGHT = 7;
static constexpr size_t FRAME_PAYLOAD_SIZE = 0x20000;
static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;

View File

@ -132,7 +132,7 @@ void ShaderCache::Register(std::unique_ptr<ShaderInfo> data, VAddr addr, size_t
storage.push_back(std::move(data));
rasterizer.UpdatePagesCachedCount(addr, size, 1);
rasterizer.UpdatePagesCachedCount(addr, size, true);
}
void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) {
@ -209,7 +209,7 @@ void ShaderCache::UnmarkMemory(Entry* entry) {
const VAddr addr = entry->addr_start;
const size_t size = entry->addr_end - addr;
rasterizer.UpdatePagesCachedCount(addr, size, -1);
rasterizer.UpdatePagesCachedCount(addr, size, false);
}
void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) {

View File

@ -2080,7 +2080,7 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
ASSERT(False(image.flags & ImageFlagBits::Tracked));
image.flags |= ImageFlagBits::Tracked;
if (False(image.flags & ImageFlagBits::Sparse)) {
rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1);
rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, true);
return;
}
if (True(image.flags & ImageFlagBits::Registered)) {
@ -2091,13 +2091,13 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
const auto& map = slot_map_views[map_view_id];
const VAddr cpu_addr = map.cpu_addr;
const std::size_t size = map.size;
rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
rasterizer.UpdatePagesCachedCount(cpu_addr, size, true);
}
return;
}
ForEachSparseSegment(image,
[this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) {
rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
rasterizer.UpdatePagesCachedCount(cpu_addr, size, true);
});
}
@ -2106,7 +2106,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
ASSERT(True(image.flags & ImageFlagBits::Tracked));
image.flags &= ~ImageFlagBits::Tracked;
if (False(image.flags & ImageFlagBits::Sparse)) {
rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1);
rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, false);
return;
}
ASSERT(True(image.flags & ImageFlagBits::Registered));
@ -2117,7 +2117,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
const auto& map = slot_map_views[map_view_id];
const VAddr cpu_addr = map.cpu_addr;
const std::size_t size = map.size;
rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
rasterizer.UpdatePagesCachedCount(cpu_addr, size, false);
}
}

View File

@ -474,7 +474,7 @@ private:
};
Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
static constexpr size_t TICKS_TO_DESTROY = 8;
static constexpr size_t TICKS_TO_DESTROY = 6;
DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;

View File

@ -41,15 +41,6 @@
"platform": "windows"
}
]
},
"android": {
"description": "Enable Android dependencies",
"dependencies": [
{
"name": "oboe",
"platform": "android"
}
]
}
},
"overrides": [