mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-29 09:58:05 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9985c74cea | |||
| eec3a4168f | |||
| d39f9126f7 | |||
| 4563af7527 | |||
| 64059d5d64 | |||
| d5f064380d | |||
| 06a2420ae7 | |||
| 71d43234a1 | |||
| 0c389249a0 | |||
| 5bcbf2cf91 | |||
| ed351fbd41 | |||
| a57c284ee9 | |||
| 3cd8aea0ae | |||
| 45074ba1ae | |||
| 764cbf747c | |||
| 5ec2d443c0 | |||
| c1eece6218 | |||
| 5201e6bea5 | |||
| 81162d376f | |||
| e80ec69795 | |||
| 07f8605957 | |||
| e3fc6fc6ea | |||
| 1d377180e7 | |||
| ecb1ac96e0 | |||
| daded9e507 | |||
| 80a6576c7a | |||
| 6d03182e33 | |||
| bc47304607 | |||
| f5e488db05 | |||
| c9df8409df | |||
| 7cf84f0936 | |||
| 6e5af6a3c1 | |||
| c2fbcd816a | |||
| 54cd5fb8eb | |||
| 119291dc77 | |||
| f7dbff2157 | |||
| b859d7fdf4 | |||
| f635827fa6 | |||
| 243453c172 | |||
| 39158b67a7 | |||
| 50cb8fd1c9 |
@@ -69,6 +69,26 @@ if (YUZU_STATIC_ROOM)
|
|||||||
set(fmt_FORCE_BUNDLED ON)
|
set(fmt_FORCE_BUNDLED ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# my unity/jumbo build
|
||||||
|
option(ENABLE_UNITY_BUILD "Enable Unity/Jumbo build" OFF)
|
||||||
|
|
||||||
|
# 0 compiles all files in
|
||||||
|
# not ideal, but if you're going gung-ho with a unity build, expect failure
|
||||||
|
# MSVC physically can't compile that many files into one TU, so we limit it to 100.
|
||||||
|
if (MSVC)
|
||||||
|
set(_unity_default 100)
|
||||||
|
else()
|
||||||
|
set(_unity_default 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(UNITY_BATCH_SIZE ${_unity_default} CACHE STRING "Unity build batch size")
|
||||||
|
|
||||||
|
if(MSVC AND ENABLE_UNITY_BUILD)
|
||||||
|
message(STATUS "Unity build")
|
||||||
|
# Unity builds need big objects for MSVC...
|
||||||
|
add_compile_options(/bigobj)
|
||||||
|
endif()
|
||||||
|
|
||||||
# qt stuff
|
# qt stuff
|
||||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ These options control dependencies.
|
|||||||
- This option is subject for removal.
|
- This option is subject for removal.
|
||||||
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
|
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
|
||||||
- `ENABLE_LTO` (OFF) Enable link-time optimization
|
- `ENABLE_LTO` (OFF) Enable link-time optimization
|
||||||
|
- `ENABLE_UNITY_BUILD` (OFF) Enables "Unity/Jumbo" builds
|
||||||
- Not recommended on Windows
|
- Not recommended on Windows
|
||||||
- UNIX may be better off appending `-flto=thin` to compiler args
|
- UNIX may be better off appending `-flto=thin` to compiler args
|
||||||
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
|
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
# Enable modules to include each other's files
|
# Enable modules to include each other's files
|
||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
||||||
|
if (ENABLE_UNITY_BUILD)
|
||||||
|
set(CMAKE_UNITY_BUILD ON)
|
||||||
|
set(CMAKE_UNITY_BUILD_BATCH_SIZE ${UNITY_BATCH_SIZE})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ extern "C" {
|
|||||||
#include "core/frontend/applets/software_keyboard.h"
|
#include "core/frontend/applets/software_keyboard.h"
|
||||||
#include "core/frontend/applets/web_browser.h"
|
#include "core/frontend/applets/web_browser.h"
|
||||||
#include "common/android/applets/web_browser.h"
|
#include "common/android/applets/web_browser.h"
|
||||||
|
#include "core/file_sys/common_funcs.h"
|
||||||
#include "core/hle/service/am/applet_manager.h"
|
#include "core/hle/service/am/applet_manager.h"
|
||||||
#include "core/hle/service/am/frontend/applets.h"
|
#include "core/hle/service/am/frontend/applets.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
@@ -311,11 +312,23 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
|||||||
ConfigureFilesystemProvider(filepath);
|
ConfigureFilesystemProvider(filepath);
|
||||||
|
|
||||||
// Load the ROM.
|
// Load the ROM.
|
||||||
|
const u64 previous_program_id =
|
||||||
|
program_index != 0 && m_next_program_id.load() >
|
||||||
|
static_cast<u64>(Service::AM::AppletProgramId::MaxProgramId)
|
||||||
|
? m_next_program_id.load()
|
||||||
|
: 0;
|
||||||
|
|
||||||
Service::AM::FrontendAppletParameters params{
|
Service::AM::FrontendAppletParameters params{
|
||||||
|
.program_id = previous_program_id,
|
||||||
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
|
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
|
||||||
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
|
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
|
||||||
: Service::AM::LaunchType::ApplicationInitiated,
|
: Service::AM::LaunchType::ApplicationInitiated,
|
||||||
.program_index = static_cast<s32>(program_index),
|
.program_index = static_cast<s32>(program_index),
|
||||||
|
.previous_program_index =
|
||||||
|
previous_program_id != 0
|
||||||
|
? static_cast<s32>(previous_program_id -
|
||||||
|
FileSys::GetBaseTitleID(previous_program_id))
|
||||||
|
: -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
|
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
|
||||||
@@ -328,8 +341,12 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
|||||||
m_system.GetCpuManager().OnGpuReady();
|
m_system.GetCpuManager().OnGpuReady();
|
||||||
m_system.RegisterExitCallback([&] { HaltEmulation(); });
|
m_system.RegisterExitCallback([&] { HaltEmulation(); });
|
||||||
|
|
||||||
|
m_system.RegisterApplicationChangedCallback(
|
||||||
|
[&](u64 changed_program_id) { RequestDiskShaderCacheReload(changed_program_id); });
|
||||||
|
|
||||||
// Register an ExecuteProgram callback such that Core can execute a sub-program
|
// Register an ExecuteProgram callback such that Core can execute a sub-program
|
||||||
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
|
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
|
||||||
|
m_next_program_id = m_system.GetApplicationProcessProgramID();
|
||||||
m_next_program_index = program_index_;
|
m_next_program_index = program_index_;
|
||||||
EmulationSession::GetInstance().HaltEmulation();
|
EmulationSession::GetInstance().HaltEmulation();
|
||||||
});
|
});
|
||||||
@@ -407,20 +424,58 @@ void EmulationSession::RunEmulation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
std::optional<u64> reload_title;
|
||||||
{
|
{
|
||||||
[[maybe_unused]] std::unique_lock lock(m_mutex);
|
[[maybe_unused]] std::unique_lock lock(m_mutex);
|
||||||
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
|
if (m_cv.wait_for(lock, std::chrono::milliseconds(800), [&]() {
|
||||||
[&]() { return !m_is_running; })) {
|
return !m_is_running || m_pending_shader_cache_title.has_value();
|
||||||
// Emulation halted.
|
})) {
|
||||||
break;
|
if (!m_is_running) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reload_title = std::exchange(m_pending_shader_cache_title, std::nullopt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reload_title.has_value())
|
||||||
|
ReloadDiskShaderCache(*reload_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset current applet ID.
|
// Reset current applet ID.
|
||||||
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
|
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulationSession::RequestDiskShaderCacheReload(u64 program_id) {
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(m_mutex);
|
||||||
|
m_pending_shader_cache_title = program_id;
|
||||||
|
}
|
||||||
|
m_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulationSession::ReloadDiskShaderCache(u64 program_id) {
|
||||||
|
if (!Settings::values.use_disk_shader_cache.GetValue())
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_INFO(Frontend, "Reloading disk shader cache for {:016X}", program_id);
|
||||||
|
|
||||||
|
const bool was_paused = m_is_paused;
|
||||||
|
|
||||||
|
m_system.Pause();
|
||||||
|
m_system.GPU().WaitForIdle();
|
||||||
|
m_system.GPU().ObtainContext();
|
||||||
|
|
||||||
|
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||||
|
m_system.Renderer().ReadRasterizer()->LoadDiskResources(program_id, std::stop_token{},
|
||||||
|
LoadDiskCacheProgress);
|
||||||
|
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||||
|
|
||||||
|
m_system.GPU().ReleaseContext();
|
||||||
|
|
||||||
|
if (!was_paused)
|
||||||
|
m_system.Run();
|
||||||
|
}
|
||||||
|
|
||||||
Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
|
Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
|
||||||
return m_software_keyboard;
|
return m_software_keyboard;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
#include "common/android/applets/software_keyboard.h"
|
#include "common/android/applets/software_keyboard.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
@@ -44,6 +46,7 @@ public:
|
|||||||
void HaltEmulation();
|
void HaltEmulation();
|
||||||
void RunEmulation();
|
void RunEmulation();
|
||||||
void ShutdownEmulation();
|
void ShutdownEmulation();
|
||||||
|
void RequestDiskShaderCacheReload(u64 program_id);
|
||||||
|
|
||||||
const Core::PerfStatsResults& PerfStats();
|
const Core::PerfStatsResults& PerfStats();
|
||||||
int ShadersBuilding();
|
int ShadersBuilding();
|
||||||
@@ -65,6 +68,7 @@ private:
|
|||||||
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
|
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
|
||||||
static void OnEmulationStopped(Core::SystemResultStatus result);
|
static void OnEmulationStopped(Core::SystemResultStatus result);
|
||||||
static void ChangeProgram(std::size_t program_index);
|
static void ChangeProgram(std::size_t program_index);
|
||||||
|
void ReloadDiskShaderCache(u64 program_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Window management
|
// Window management
|
||||||
@@ -83,6 +87,7 @@ private:
|
|||||||
Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
|
Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
|
||||||
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
|
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
|
||||||
int m_applet_id{1};
|
int m_applet_id{1};
|
||||||
|
std::optional<u64> m_pending_shader_cache_title;
|
||||||
|
|
||||||
// GPU driver parameters
|
// GPU driver parameters
|
||||||
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
||||||
@@ -93,4 +98,5 @@ private:
|
|||||||
|
|
||||||
// Program index for next boot
|
// Program index for next boot
|
||||||
std::atomic<s32> m_next_program_index = -1;
|
std::atomic<s32> m_next_program_index = -1;
|
||||||
|
std::atomic<u64> m_next_program_id = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -5,17 +8,11 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
|
||||||
namespace AudioCore::ADSP::OpusDecoder {
|
namespace AudioCore::ADSP::OpusDecoder {
|
||||||
namespace {
|
|
||||||
bool IsValidChannelCount(u32 channel_count) {
|
|
||||||
return channel_count == 1 || channel_count == 2;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
|
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
|
||||||
if (!IsValidChannelCount(channel_count)) {
|
if (channel_count == 1 || channel_count == 2)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
return u32(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
|
||||||
return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ namespace AudioCore::ADSP::OpusDecoder {
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr size_t OpusStreamCountMax = 255;
|
constexpr size_t OpusStreamCountMax = 255;
|
||||||
|
|
||||||
bool IsValidChannelCount(u32 channel_count) {
|
|
||||||
return channel_count == 1 || channel_count == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValidMultiStreamChannelCount(u32 channel_count) {
|
bool IsValidMultiStreamChannelCount(u32 channel_count) {
|
||||||
return channel_count <= OpusStreamCountMax;
|
return channel_count <= OpusStreamCountMax;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,13 +10,12 @@
|
|||||||
namespace AudioCore::ADSP::OpusDecoder {
|
namespace AudioCore::ADSP::OpusDecoder {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool IsValidChannelCount(u32 channel_count) {
|
constexpr u32 OpusStreamCountMax = 255;
|
||||||
return channel_count == 1 || channel_count == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
return total_stream_count > 0 && total_stream_count <= OpusStreamCountMax &&
|
||||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
static_cast<s32>(stereo_stream_count) >= 0 &&
|
||||||
|
stereo_stream_count <= total_stream_count;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,16 @@
|
|||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
|
||||||
|
namespace AudioCore::AudioIn {
|
||||||
|
|
||||||
// See texture_cache/util.h
|
// See texture_cache/util.h
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
||||||
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
std::vector<T> u;
|
std::vector<T> u;
|
||||||
for (auto const& e : v)
|
for (auto const& e : v)
|
||||||
u.push_back(e);
|
u.push_back(e);
|
||||||
@@ -29,8 +31,6 @@ template<typename T, size_t N>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace AudioCore::AudioIn {
|
|
||||||
|
|
||||||
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
|
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
|
||||||
: system{system_}, buffer_event{event_},
|
: system{system_}, buffer_event{event_},
|
||||||
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -105,7 +108,7 @@ Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 chan
|
|||||||
shared_memory.host_send_data[4] = total_stream_count;
|
shared_memory.host_send_data[4] = total_stream_count;
|
||||||
shared_memory.host_send_data[5] = stereo_stream_count;
|
shared_memory.host_send_data[5] = stereo_stream_count;
|
||||||
|
|
||||||
ASSERT(channel_count <= MaxChannels);
|
ASSERT(channel_count <= shared_memory.channel_mapping.size());
|
||||||
std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
|
std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
|
||||||
|
|
||||||
opus_decoder.Send(ADSP::Direction::DSP,
|
opus_decoder.Send(ADSP::Direction::DSP,
|
||||||
|
|||||||
@@ -14,14 +14,15 @@
|
|||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
|
||||||
|
namespace AudioCore::AudioOut {
|
||||||
// See texture_cache/util.h
|
// See texture_cache/util.h
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
||||||
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
std::vector<T> u;
|
std::vector<T> u;
|
||||||
for (auto const& e : v)
|
for (auto const& e : v)
|
||||||
u.push_back(e);
|
u.push_back(e);
|
||||||
@@ -29,8 +30,6 @@ template<typename T, size_t N>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace AudioCore::AudioOut {
|
|
||||||
|
|
||||||
System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
|
System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
|
||||||
: system{system_}, buffer_event{event_},
|
: system{system_}, buffer_event{event_},
|
||||||
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
@@ -16,7 +16,7 @@ namespace AudioCore::Renderer {
|
|||||||
* @param memory - Core memory for writing.
|
* @param memory - Core memory for writing.
|
||||||
* @param aux_info - Memory address pointing to the AuxInfo to reset.
|
* @param aux_info - Memory address pointing to the AuxInfo to reset.
|
||||||
*/
|
*/
|
||||||
static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_info) {
|
static void CaptureResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_info) {
|
||||||
if (aux_info == 0) {
|
if (aux_info == 0) {
|
||||||
LOG_ERROR(Service_Audio, "Aux info is 0!");
|
LOG_ERROR(Service_Audio, "Aux info is 0!");
|
||||||
return;
|
return;
|
||||||
@@ -134,7 +134,7 @@ void CaptureCommand::Process(const AudioRenderer::CommandListProcessor& processo
|
|||||||
WriteAuxBufferDsp(*processor.memory, send_buffer_info, send_buffer, count_max, input_buffer,
|
WriteAuxBufferDsp(*processor.memory, send_buffer_info, send_buffer, count_max, input_buffer,
|
||||||
processor.sample_count, write_offset, update_count);
|
processor.sample_count, write_offset, update_count);
|
||||||
} else {
|
} else {
|
||||||
ResetAuxBufferDsp(*processor.memory, send_buffer_info);
|
CaptureResetAuxBufferDsp(*processor.memory, send_buffer_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,23 @@
|
|||||||
namespace AudioCore::Sink {
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] bool InitializeAudio() {
|
||||||
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
|
// See https://github.com/PCSX2/pcsx2/pull/12312
|
||||||
|
// "SDL and cubeb backends previously resulted in different names for the output which
|
||||||
|
// caused them be identified as different applications by the OS."
|
||||||
|
//
|
||||||
|
// Keep in sync with cubeb_sink.cpp name.
|
||||||
|
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
|
||||||
|
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
|
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
|
||||||
int device_count = 0;
|
int device_count = 0;
|
||||||
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
|
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||||
@@ -204,20 +221,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (InitializeAudio()) {
|
||||||
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
output_device = target_device_name;
|
||||||
return;
|
} else {
|
||||||
|
output_device.clear();
|
||||||
}
|
}
|
||||||
|
device_channels = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
|
||||||
output_device = target_device_name;
|
|
||||||
} else {
|
|
||||||
output_device.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
device_channels = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLSink::~SDLSink() = default;
|
SDLSink::~SDLSink() = default;
|
||||||
@@ -265,15 +276,10 @@ void SDLSink::SetSystemVolume(f32 volume) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||||
|
if (!InitializeAudio())
|
||||||
|
return {}; //no devices
|
||||||
|
|
||||||
std::vector<std::string> device_list;
|
std::vector<std::string> device_list;
|
||||||
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
|
||||||
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int device_count = 0;
|
int device_count = 0;
|
||||||
SDL_AudioDeviceID* devices =
|
SDL_AudioDeviceID* devices =
|
||||||
capture ? SDL_GetAudioRecordingDevices(&device_count)
|
capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||||
@@ -304,13 +310,8 @@ bool IsSDLSuitable() {
|
|||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
// Check SDL can init
|
// Check SDL can init
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!InitializeAudio()!
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
return false;
|
||||||
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can set any latency frequency we want with SDL, so no need to check that.
|
// We can set any latency frequency we want with SDL, so no need to check that.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2011 Google, Inc.
|
// SPDX-FileCopyrightText: 2011 Google, Inc.
|
||||||
// SPDX-FileContributor: Geoff Pike
|
// SPDX-FileContributor: Geoff Pike
|
||||||
// SPDX-FileContributor: Jyrki Alakuijala
|
// SPDX-FileContributor: Jyrki Alakuijala
|
||||||
@@ -27,8 +30,6 @@
|
|||||||
#define WORDS_BIGENDIAN 1
|
#define WORDS_BIGENDIAN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
static u64 unaligned_load64(const char* p) {
|
static u64 unaligned_load64(const char* p) {
|
||||||
@@ -135,18 +136,18 @@ static u64 HashLen17to32(const char* s, size_t len) {
|
|||||||
|
|
||||||
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||||
// Callers do best to use "random-looking" values for a and b.
|
// Callers do best to use "random-looking" values for a and b.
|
||||||
static pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
|
static std::pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
|
||||||
a += w;
|
a += w;
|
||||||
b = Rotate(b + a + z, 21);
|
b = Rotate(b + a + z, 21);
|
||||||
u64 c = a;
|
u64 c = a;
|
||||||
a += x;
|
a += x;
|
||||||
a += y;
|
a += y;
|
||||||
b += Rotate(a, 44);
|
b += Rotate(a, 44);
|
||||||
return make_pair(a + z, b + c);
|
return std::make_pair(a + z, b + c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||||
static pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
|
static std::pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
|
||||||
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
||||||
b);
|
b);
|
||||||
}
|
}
|
||||||
@@ -189,8 +190,8 @@ u64 CityHash64(const char* s, size_t len) {
|
|||||||
u64 x = Fetch64(s + len - 40);
|
u64 x = Fetch64(s + len - 40);
|
||||||
u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
||||||
u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
||||||
pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
std::pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||||
pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
std::pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
||||||
x = x * k1 + Fetch64(s);
|
x = x * k1 + Fetch64(s);
|
||||||
|
|
||||||
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
||||||
@@ -258,7 +259,7 @@ u128 CityHash128WithSeed(const char* s, size_t len, u128 seed) {
|
|||||||
|
|
||||||
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
||||||
// v, w, x, y, and z.
|
// v, w, x, y, and z.
|
||||||
pair<u64, u64> v, w;
|
std::pair<u64, u64> v, w;
|
||||||
u64 x = seed[0];
|
u64 x = seed[0];
|
||||||
u64 y = seed[1];
|
u64 y = seed[1];
|
||||||
u64 z = len * k1;
|
u64 z = len * k1;
|
||||||
|
|||||||
@@ -16,3 +16,5 @@
|
|||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#undef INVALID_SOCKET
|
||||||
|
|||||||
@@ -7,6 +7,4 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION 1
|
#define STB_IMAGE_IMPLEMENTATION 1
|
||||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
|
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
|
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
|
||||||
#define STBI_ONLY_JPEG 1
|
|
||||||
|
|
||||||
#include "common/stb.h"
|
#include "common/stb.h"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define STBI_ONLY_JPEG 1
|
#define STBI_ONLY_JPEG 1
|
||||||
|
#define STBI_WRITE_NO_STDIO 1
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <stb_image_resize.h>
|
#include <stb_image_resize.h>
|
||||||
#include <stb_image_write.h>
|
#include <stb_image_write.h>
|
||||||
|
|||||||
@@ -7,19 +7,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <dynarmic/interface/halt_reason.h>
|
#include <dynarmic/interface/halt_reason.h>
|
||||||
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
|
inline constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
|
||||||
constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
|
inline constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
|
||||||
constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
|
inline constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
|
||||||
constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
|
inline constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
|
||||||
constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
|
inline constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
|
||||||
constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
|
inline constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
|
||||||
|
|
||||||
constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
[[nodiscard]] inline constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||||
static_assert(u64(HaltReason::StepThread) == u64(StepThread));
|
static_assert(u64(HaltReason::StepThread) == u64(StepThread));
|
||||||
static_assert(u64(HaltReason::DataAbort) == u64(DataAbort));
|
static_assert(u64(HaltReason::DataAbort) == u64(DataAbort));
|
||||||
static_assert(u64(HaltReason::BreakLoop) == u64(BreakLoop));
|
static_assert(u64(HaltReason::BreakLoop) == u64(BreakLoop));
|
||||||
|
|||||||
+43
-2
@@ -295,6 +295,10 @@ struct System::Impl {
|
|||||||
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, Service::AM::FrontendAppletParameters& params) {
|
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, Service::AM::FrontendAppletParameters& params) {
|
||||||
InitializeKernel(system);
|
InitializeKernel(system);
|
||||||
|
|
||||||
|
if (params.applet_type == Service::AM::AppletType::Application) {
|
||||||
|
current_application_filepath = filepath;
|
||||||
|
}
|
||||||
|
|
||||||
const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
|
const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
|
||||||
|
|
||||||
// Create the application process
|
// Create the application process
|
||||||
@@ -330,7 +334,7 @@ struct System::Impl {
|
|||||||
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);
|
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);
|
||||||
|
|
||||||
// Make the process created be the application
|
// Make the process created be the application
|
||||||
kernel.MakeApplicationProcess(process->GetHandle());
|
kernel.SetApplicationProcess(process->GetHandle());
|
||||||
|
|
||||||
// Set up the rest of the system.
|
// Set up the rest of the system.
|
||||||
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
|
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
|
||||||
@@ -467,6 +471,7 @@ struct System::Impl {
|
|||||||
Core::SpeedLimiter speed_limiter;
|
Core::SpeedLimiter speed_limiter;
|
||||||
ExecuteProgramCallback execute_program_callback;
|
ExecuteProgramCallback execute_program_callback;
|
||||||
ExitCallback exit_callback;
|
ExitCallback exit_callback;
|
||||||
|
ApplicationChangedCallback application_changed_callback;
|
||||||
|
|
||||||
std::optional<Service::Services> services;
|
std::optional<Service::Services> services;
|
||||||
std::optional<Core::Debugger> debugger;
|
std::optional<Core::Debugger> debugger;
|
||||||
@@ -488,6 +493,8 @@ struct System::Impl {
|
|||||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
||||||
std::array<u8, 0x20> build_id{};
|
std::array<u8, 0x20> build_id{};
|
||||||
|
|
||||||
|
std::string current_application_filepath;
|
||||||
|
|
||||||
/// Service manager
|
/// Service manager
|
||||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||||
/// ContentProviderUnion instance
|
/// ContentProviderUnion instance
|
||||||
@@ -727,7 +734,25 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 System::GetApplicationProcessProgramID() const {
|
u64 System::GetApplicationProcessProgramID() const {
|
||||||
return impl->kernel.ApplicationProcess()->GetProgramId();
|
const auto* const process = impl->kernel.ApplicationProcess();
|
||||||
|
return process != nullptr ? process->GetProgramId() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 System::GetProgramIdForProcessId(u64 process_id) const {
|
||||||
|
auto process = impl->kernel.GetProcessByProcessId(process_id);
|
||||||
|
return process.IsNull() ? 0 : process->GetProgramId();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 System::ResolveCallerProgramId(u64 process_id) const {
|
||||||
|
if (const auto program_id = this->GetProgramIdForProcessId(process_id); program_id != 0) {
|
||||||
|
return program_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fallback = this->GetApplicationProcessProgramID();
|
||||||
|
LOG_WARNING(Core,
|
||||||
|
"Could not resolve caller process_id={}, falling back to application {:016X}",
|
||||||
|
process_id, fallback);
|
||||||
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus System::GetGameName(std::string& out) const {
|
Loader::ResultStatus System::GetGameName(std::string& out) const {
|
||||||
@@ -910,6 +935,10 @@ void System::ExecuteProgram(std::size_t program_index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& System::GetCurrentApplicationFilePath() const {
|
||||||
|
return impl->current_application_filepath;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Gets a reference to the user channel stack.
|
/// @brief Gets a reference to the user channel stack.
|
||||||
/// It is used to transfer data between programs.
|
/// It is used to transfer data between programs.
|
||||||
std::vector<std::vector<u8>>& System::GetUserChannel() {
|
std::vector<std::vector<u8>>& System::GetUserChannel() {
|
||||||
@@ -961,6 +990,18 @@ void System::Exit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::RegisterApplicationChangedCallback(ApplicationChangedCallback&& callback) {
|
||||||
|
impl->application_changed_callback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::NotifyApplicationChanged(u64 program_id) {
|
||||||
|
//LOG_DEBUG(Core, "Running application changed to {:016X}", program_id);
|
||||||
|
|
||||||
|
if (impl->application_changed_callback) {
|
||||||
|
impl->application_changed_callback(program_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void System::ApplySettings() {
|
void System::ApplySettings() {
|
||||||
impl->RefreshTime(*this);
|
impl->RefreshTime(*this);
|
||||||
|
|
||||||
|
|||||||
@@ -322,6 +322,10 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] u64 GetApplicationProcessProgramID() const;
|
[[nodiscard]] u64 GetApplicationProcessProgramID() const;
|
||||||
|
|
||||||
|
[[nodiscard]] u64 GetProgramIdForProcessId(u64 process_id) const;
|
||||||
|
|
||||||
|
[[nodiscard]] u64 ResolveCallerProgramId(u64 process_id) const;
|
||||||
|
|
||||||
/// Gets the name of the current game
|
/// Gets the name of the current game
|
||||||
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
|
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
|
||||||
|
|
||||||
@@ -422,6 +426,7 @@ public:
|
|||||||
void PushGeneralChannelData(std::vector<u8>&& data);
|
void PushGeneralChannelData(std::vector<u8>&& data);
|
||||||
bool TryPopGeneralChannel(std::vector<u8>& out_data);
|
bool TryPopGeneralChannel(std::vector<u8>& out_data);
|
||||||
[[nodiscard]] Service::Event& GetGeneralChannelEvent();
|
[[nodiscard]] Service::Event& GetGeneralChannelEvent();
|
||||||
|
[[nodiscard]] const std::string& GetCurrentApplicationFilePath() const;
|
||||||
|
|
||||||
/// Type used for the frontend to designate a callback for System to exit the application.
|
/// Type used for the frontend to designate a callback for System to exit the application.
|
||||||
using ExitCallback = std::function<void()>;
|
using ExitCallback = std::function<void()>;
|
||||||
@@ -435,6 +440,10 @@ public:
|
|||||||
/// Instructs the frontend to exit the application.
|
/// Instructs the frontend to exit the application.
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
|
using ApplicationChangedCallback = std::function<void(u64 program_id)>;
|
||||||
|
void RegisterApplicationChangedCallback(ApplicationChangedCallback&& callback);
|
||||||
|
void NotifyApplicationChanged(u64 program_id);
|
||||||
|
|
||||||
/// Applies any changes to settings to this core instance.
|
/// Applies any changes to settings to this core instance.
|
||||||
void ApplySettings();
|
void ApplySettings();
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ constexpr u32 CpuClockTargetMhz(Settings::CpuClock clock) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CreateEvent
|
||||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ static u8 MasterKeyIdForKeyGeneration(u8 key_generation) {
|
|||||||
return std::max<u8>(key_generation, 1) - 1;
|
return std::max<u8>(key_generation, 1) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NCA::NCA(VirtualFile file_, const NCA* base_nca)
|
NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
|
||||||
: file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
|
: file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
status = Loader::ResultStatus::ErrorNullFile;
|
status = Loader::ResultStatus::ErrorNullFile;
|
||||||
@@ -110,7 +110,7 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_update && base_nca == nullptr) {
|
if (is_update && base_nca == nullptr && !allow_missing_base) {
|
||||||
status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS;
|
status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS;
|
||||||
} else {
|
} else {
|
||||||
status = Loader::ResultStatus::Success;
|
status = Loader::ResultStatus::Success;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) {
|
|||||||
// After construction, use GetStatus to determine if the file is valid and ready to be used.
|
// After construction, use GetStatus to determine if the file is valid and ready to be used.
|
||||||
class NCA : public ReadOnlyVfsDirectory {
|
class NCA : public ReadOnlyVfsDirectory {
|
||||||
public:
|
public:
|
||||||
explicit NCA(VirtualFile file, const NCA* base_nca = nullptr);
|
explicit NCA(VirtualFile file, const NCA* base_nca = nullptr, bool allow_missing_base = false);
|
||||||
~NCA() override;
|
~NCA() override;
|
||||||
|
|
||||||
Loader::ResultStatus GetStatus() const;
|
Loader::ResultStatus GetStatus() const;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -185,13 +185,13 @@ static_assert(sizeof(SaveDataFilter) == 0x48, "SaveDataFilter has invalid size."
|
|||||||
static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
|
static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
|
||||||
"Data type must be trivially copyable.");
|
"Data type must be trivially copyable.");
|
||||||
|
|
||||||
struct HashSalt {
|
struct SaveDataHashSalt {
|
||||||
static constexpr size_t Size = 32;
|
static constexpr size_t Size = 32;
|
||||||
|
|
||||||
std::array<u8, Size> value;
|
std::array<u8, Size> value;
|
||||||
};
|
};
|
||||||
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
|
static_assert(std::is_trivially_copyable_v<SaveDataHashSalt>, "Data type must be trivially copyable.");
|
||||||
static_assert(sizeof(HashSalt) == HashSalt::Size);
|
static_assert(sizeof(SaveDataHashSalt) == SaveDataHashSalt::Size);
|
||||||
|
|
||||||
struct SaveDataCreationInfo2 {
|
struct SaveDataCreationInfo2 {
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ struct SaveDataCreationInfo2 {
|
|||||||
u8 reserved1;
|
u8 reserved1;
|
||||||
bool is_hash_salt_enabled;
|
bool is_hash_salt_enabled;
|
||||||
u8 reserved2;
|
u8 reserved2;
|
||||||
HashSalt hash_salt;
|
SaveDataHashSalt hash_salt;
|
||||||
SaveDataMetaType meta_type;
|
SaveDataMetaType meta_type;
|
||||||
u8 reserved3;
|
u8 reserved3;
|
||||||
s32 meta_size;
|
s32 meta_size;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -11,7 +14,7 @@
|
|||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
#include "core/file_sys/vfs/vfs_vector.h"
|
#include "core/file_sys/vfs/vfs_vector.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys::RomFSBuilder {
|
||||||
|
|
||||||
constexpr u64 FS_MAX_PATH = 0x301;
|
constexpr u64 FS_MAX_PATH = 0x301;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys::RomFSBuilder {
|
||||||
|
|
||||||
struct RomFSBuildDirectoryContext;
|
struct RomFSBuildDirectoryContext;
|
||||||
struct RomFSBuildFileContext;
|
struct RomFSBuildFileContext;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/logging.h"
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_indirect_storage.h"
|
#include "core/file_sys/fssystem/fssystem_indirect_storage.h"
|
||||||
|
|
||||||
@@ -99,6 +100,18 @@ Result IndirectStorage::GetEntryList(Entry* out_entries, s32* out_entry_count, s
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IndirectStorage::ReportMissingOriginal(s64 offset, s64 size) {
|
||||||
|
if (m_reported_missing_original) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_reported_missing_original = true;
|
||||||
|
|
||||||
|
LOG_ERROR(Common_Filesystem,
|
||||||
|
"Patch storage requests {:#x} bytes at {:#x} from a base storage that is not "
|
||||||
|
"present; this data will read as garbage",
|
||||||
|
size, offset);
|
||||||
|
}
|
||||||
|
|
||||||
size_t IndirectStorage::Read(u8* buffer, size_t size, size_t offset) const {
|
size_t IndirectStorage::Read(u8* buffer, size_t size, size_t offset) const {
|
||||||
// Validate pre-conditions.
|
// Validate pre-conditions.
|
||||||
ASSERT(this->IsInitialized());
|
ASSERT(this->IsInitialized());
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ public:
|
|||||||
void SetStorage(s32 idx, VirtualFile storage) {
|
void SetStorage(s32 idx, VirtualFile storage) {
|
||||||
ASSERT(0 <= idx && idx < StorageCount);
|
ASSERT(0 <= idx && idx < StorageCount);
|
||||||
m_data_storage[idx] = storage;
|
m_data_storage[idx] = storage;
|
||||||
|
if (idx == 0) {
|
||||||
|
m_original_missing = storage == nullptr || storage->GetSize() == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -130,6 +133,9 @@ protected:
|
|||||||
|
|
||||||
template <bool ContinuousCheck, bool RangeCheck, typename F>
|
template <bool ContinuousCheck, bool RangeCheck, typename F>
|
||||||
Result OperatePerEntry(s64 offset, s64 size, F func);
|
Result OperatePerEntry(s64 offset, s64 size, F func);
|
||||||
|
// Launching another game makes the original storage inaccessable.
|
||||||
|
// This is a helper for multi-nca games.
|
||||||
|
void ReportMissingOriginal(s64 offset, s64 size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ContinuousReadingEntry {
|
struct ContinuousReadingEntry {
|
||||||
@@ -154,6 +160,8 @@ private:
|
|||||||
private:
|
private:
|
||||||
mutable BucketTree m_table;
|
mutable BucketTree m_table;
|
||||||
std::array<VirtualFile, StorageCount> m_data_storage;
|
std::array<VirtualFile, StorageCount> m_data_storage;
|
||||||
|
bool m_original_missing{false};
|
||||||
|
bool m_reported_missing_original{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool ContinuousCheck, bool RangeCheck, typename F>
|
template <bool ContinuousCheck, bool RangeCheck, typename F>
|
||||||
@@ -272,6 +280,10 @@ Result IndirectStorage::OperatePerEntry(s64 offset, s64 size, F func) {
|
|||||||
if (needs_operate) {
|
if (needs_operate) {
|
||||||
const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset();
|
const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset();
|
||||||
|
|
||||||
|
if (cur_entry.storage_index == 0 && m_original_missing) {
|
||||||
|
this->ReportMissingOriginal(cur_offset, cur_size);
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr (RangeCheck) {
|
if constexpr (RangeCheck) {
|
||||||
// Get the current data storage's size.
|
// Get the current data storage's size.
|
||||||
s64 cur_data_storage_size = m_data_storage[cur_entry.storage_index]->GetSize();
|
s64 cur_data_storage_size = m_data_storage[cur_entry.storage_index]->GetSize();
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ struct ContentRecord {
|
|||||||
std::array<u8, 0x10> nca_id;
|
std::array<u8, 0x10> nca_id;
|
||||||
std::array<u8, 0x6> size;
|
std::array<u8, 0x6> size;
|
||||||
ContentRecordType type;
|
ContentRecordType type;
|
||||||
INSERT_PADDING_BYTES(1);
|
u8 id_offset;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size.");
|
static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size.");
|
||||||
|
|
||||||
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, {}};
|
constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, 0};
|
||||||
|
|
||||||
struct MetaRecord {
|
struct MetaRecord {
|
||||||
u64_le title_id;
|
u64_le title_id;
|
||||||
|
|||||||
@@ -567,20 +567,45 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
|
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
|
||||||
const auto cmnt_iter = map.find(title_id);
|
auto cmnt_iter = map.find(title_id);
|
||||||
|
u8 id_offset = 0;
|
||||||
|
|
||||||
if (cmnt_iter == map.cend()) {
|
if (cmnt_iter == map.cend()) {
|
||||||
return std::nullopt;
|
const auto program_index = title_id & AOC_TITLE_ID_MASK;
|
||||||
|
if (program_index == 0) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmnt_iter = map.find(title_id & ~AOC_TITLE_ID_MASK);
|
||||||
|
if (cmnt_iter == map.cend()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
id_offset = static_cast<u8>(program_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& cnmt = cmnt_iter->second;
|
const auto& cnmt = cmnt_iter->second;
|
||||||
const auto& content_records = cnmt.GetContentRecords();
|
const auto& content_records = cnmt.GetContentRecords();
|
||||||
const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
|
const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
|
||||||
[type](const ContentRecord& rec) { return rec.type == type; });
|
[type, id_offset](const ContentRecord& rec) {
|
||||||
if (iter == content_records.cend()) {
|
return rec.type == type && rec.id_offset == id_offset;
|
||||||
|
});
|
||||||
|
if (iter != content_records.cend()) {
|
||||||
|
return std::make_optional(iter->nca_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id_offset != 0) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_optional(iter->nca_id);
|
const auto fallback_iter =
|
||||||
|
std::find_if(content_records.cbegin(), content_records.cend(),
|
||||||
|
[type](const ContentRecord& rec) { return rec.type == type; });
|
||||||
|
if (fallback_iter == content_records.cend()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_optional(fallback_iter->nca_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
|
std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
|
||||||
|
|||||||
+10
-10
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -38,7 +38,7 @@ struct RomFSHeader {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
|
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
|
||||||
|
|
||||||
struct DirectoryEntry {
|
struct RomFSDirectoryEntry {
|
||||||
u32_le parent;
|
u32_le parent;
|
||||||
u32_le sibling;
|
u32_le sibling;
|
||||||
u32_le child_dir;
|
u32_le child_dir;
|
||||||
@@ -46,9 +46,9 @@ struct DirectoryEntry {
|
|||||||
u32_le hash;
|
u32_le hash;
|
||||||
u32_le name_length;
|
u32_le name_length;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DirectoryEntry) == 0x18, "DirectoryEntry has incorrect size.");
|
static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size.");
|
||||||
|
|
||||||
struct FileEntry {
|
struct RomFSFileEntry {
|
||||||
u32_le parent;
|
u32_le parent;
|
||||||
u32_le sibling;
|
u32_le sibling;
|
||||||
u64_le offset;
|
u64_le offset;
|
||||||
@@ -56,7 +56,7 @@ struct FileEntry {
|
|||||||
u32_le hash;
|
u32_le hash;
|
||||||
u32_le name_length;
|
u32_le name_length;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
|
static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size.");
|
||||||
|
|
||||||
struct RomFSTraversalContext {
|
struct RomFSTraversalContext {
|
||||||
RomFSHeader header;
|
RomFSHeader header;
|
||||||
@@ -84,14 +84,14 @@ std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, siz
|
|||||||
return {entry, std::move(name)};
|
return {entry, std::move(name)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
|
std::pair<RomFSDirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
|
||||||
size_t directory_offset) {
|
size_t directory_offset) {
|
||||||
return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
|
return GetEntry<RomFSDirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
|
std::pair<RomFSFileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
|
||||||
size_t file_offset) {
|
size_t file_offset) {
|
||||||
return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
|
return GetEntry<RomFSFileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
|
void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
|
||||||
@@ -163,7 +163,7 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
|
|||||||
if (dir == nullptr)
|
if (dir == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
RomFSBuildContext ctx{dir, ext};
|
RomFSBuilder::RomFSBuildContext ctx{dir, ext};
|
||||||
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
|
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "common/hex_util.h"
|
#include "common/hex_util.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "core/crypto/key_manager.h"
|
#include "core/crypto/key_manager.h"
|
||||||
|
#include "core/file_sys/common_funcs.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/nca_metadata.h"
|
#include "core/file_sys/nca_metadata.h"
|
||||||
#include "core/file_sys/partition_filesystem.h"
|
#include "core/file_sys/partition_filesystem.h"
|
||||||
@@ -65,10 +66,12 @@ u64 NSP::GetProgramTitleID() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto program_id = expected_program_id;
|
auto program_id = expected_program_id;
|
||||||
if (program_id == 0) {
|
if (program_id == 0 && !program_status.empty()) {
|
||||||
if (!program_status.empty()) {
|
program_id = std::min_element(program_status.cbegin(), program_status.cend(),
|
||||||
program_id = program_status.begin()->first;
|
[](const auto& lhs, const auto& rhs) {
|
||||||
}
|
return lhs.first < rhs.first;
|
||||||
|
})
|
||||||
|
->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
program_id = program_id + program_index;
|
program_id = program_id + program_index;
|
||||||
@@ -273,8 +276,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
|||||||
// If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
|
// If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
|
||||||
// 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
|
// 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
|
||||||
// update NCA.
|
// update NCA.
|
||||||
if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
|
if ((next_nca->GetTitleId() & AOC_TITLE_ID_MASK) != 0) {
|
||||||
(next_nca->GetTitleId() & 0x800) == 0) {
|
|
||||||
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
|
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
|
||||||
std::move(next_nca);
|
std::move(next_nca);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -10,6 +10,12 @@
|
|||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
#undef CopyFile
|
||||||
|
#undef MoveFile
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
|
VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -99,6 +99,10 @@ private:
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
|
||||||
// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
|
// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
|
||||||
// Vector data is supplied upon construction.
|
// Vector data is supplied upon construction.
|
||||||
class VectorVfsDirectory : public VfsDirectory {
|
class VectorVfsDirectory : public VfsDirectory {
|
||||||
|
|||||||
@@ -349,9 +349,18 @@ struct KernelCore::Impl {
|
|||||||
object_name_global_data.emplace(kernel);
|
object_name_global_data.emplace(kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MakeApplicationProcess(KernelCore& kernel, KProcess* process) {
|
void SetApplicationProcess(KernelCore& kernel, KProcess* process) {
|
||||||
|
if (application_process == process)
|
||||||
|
return;
|
||||||
|
|
||||||
|
KProcess* const previous = application_process;
|
||||||
application_process = process;
|
application_process = process;
|
||||||
application_process->Open(kernel);
|
|
||||||
|
if (application_process != nullptr)
|
||||||
|
application_process->Open(kernel);
|
||||||
|
|
||||||
|
if (previous != nullptr)
|
||||||
|
previous->Close(kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the host thread ID for the caller.
|
/// Sets the host thread ID for the caller.
|
||||||
@@ -879,8 +888,8 @@ void KernelCore::RemoveProcess(KProcess* process) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::MakeApplicationProcess(KProcess* process) {
|
void KernelCore::SetApplicationProcess(KProcess* process) {
|
||||||
impl->MakeApplicationProcess(*this, process);
|
impl->SetApplicationProcess(*this, process);
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcess* KernelCore::ApplicationProcess() {
|
KProcess* KernelCore::ApplicationProcess() {
|
||||||
@@ -891,6 +900,14 @@ const KProcess* KernelCore::ApplicationProcess() const {
|
|||||||
return impl->application_process;
|
return impl->application_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KScopedAutoObject<KProcess> KernelCore::GetProcessByProcessId(u64 process_id) {
|
||||||
|
std::scoped_lock lk{impl->process_list_lock};
|
||||||
|
for (auto* const process : impl->process_list)
|
||||||
|
if (process != nullptr && process->GetProcessId() == process_id)
|
||||||
|
return {*this, process};
|
||||||
|
return {*this, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() {
|
std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() {
|
||||||
std::list<KScopedAutoObject<KProcess>> processes;
|
std::list<KScopedAutoObject<KProcess>> processes;
|
||||||
std::scoped_lock lk{impl->process_list_lock};
|
std::scoped_lock lk{impl->process_list_lock};
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ public:
|
|||||||
void AppendNewProcess(KProcess* process);
|
void AppendNewProcess(KProcess* process);
|
||||||
void RemoveProcess(KProcess* process);
|
void RemoveProcess(KProcess* process);
|
||||||
|
|
||||||
/// Makes the given process the new application process.
|
/// Makes the given process the current application process.
|
||||||
void MakeApplicationProcess(KProcess* process);
|
void SetApplicationProcess(KProcess* process);
|
||||||
|
|
||||||
/// Retrieves a pointer to the application process.
|
/// Retrieves a pointer to the application process.
|
||||||
KProcess* ApplicationProcess();
|
KProcess* ApplicationProcess();
|
||||||
@@ -133,6 +133,9 @@ public:
|
|||||||
/// Retrieves a const pointer to the application process.
|
/// Retrieves a const pointer to the application process.
|
||||||
const KProcess* ApplicationProcess() const;
|
const KProcess* ApplicationProcess() const;
|
||||||
|
|
||||||
|
/// Retrieves the process with the given process ID, or a null object.
|
||||||
|
KScopedAutoObject<KProcess> GetProcessByProcessId(u64 process_id);
|
||||||
|
|
||||||
/// Retrieves the list of processes.
|
/// Retrieves the list of processes.
|
||||||
std::list<KScopedAutoObject<KProcess>> GetProcessList();
|
std::list<KScopedAutoObject<KProcess>> GetProcessList();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-late
|
// SPDX-License-Identifier: GPL-2.0-or-late
|
||||||
@@ -13,6 +13,10 @@
|
|||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
|
|
||||||
|
#undef OutputDebugString
|
||||||
|
#undef GetObject
|
||||||
|
#undef CreateProcess
|
||||||
|
|
||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
|
|
||||||
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
|
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
[[nodiscard]] inline constexpr bool IsValidSetAddressRange(u64 address, u64 size) {
|
||||||
|
return address + size > address;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
||||||
switch (perm) {
|
switch (perm) {
|
||||||
case MemoryPermission::None:
|
case MemoryPermission::None:
|
||||||
case MemoryPermission::Read:
|
case MemoryPermission::Read:
|
||||||
@@ -22,13 +26,6 @@ constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if address + size is greater than the given address
|
|
||||||
// This can return false if the size causes an overflow of a 64-bit type
|
|
||||||
// or if the given size is zero.
|
|
||||||
constexpr bool IsValidAddressRange(u64 address, u64 size) {
|
|
||||||
return address + size > address;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function that performs the common sanity checks for svcMapMemory
|
// Helper function that performs the common sanity checks for svcMapMemory
|
||||||
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
|
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
|
||||||
// in the same order.
|
// in the same order.
|
||||||
@@ -53,14 +50,17 @@ Result MapUnmapMemorySanityChecks(const KProcessPageTable& manager, u64 dst_addr
|
|||||||
R_THROW(ResultInvalidSize);
|
R_THROW(ResultInvalidSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidAddressRange(dst_addr, size)) {
|
// Checks if address + size is greater than the given address
|
||||||
|
// This can return false if the size causes an overflow of a 64-bit type
|
||||||
|
// or if the given size is zero.
|
||||||
|
if (!IsValidSetAddressRange(dst_addr, size)) {
|
||||||
LOG_ERROR(Kernel_SVC,
|
LOG_ERROR(Kernel_SVC,
|
||||||
"Destination is not a valid address range, addr={:#016x}, size={:#016x}",
|
"Destination is not a valid address range, addr={:#016x}, size={:#016x}",
|
||||||
dst_addr, size);
|
dst_addr, size);
|
||||||
R_THROW(ResultInvalidCurrentMemory);
|
R_THROW(ResultInvalidCurrentMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidAddressRange(src_addr, size)) {
|
if (!IsValidSetAddressRange(src_addr, size)) {
|
||||||
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr={:#016x}, size={:#016x}",
|
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr={:#016x}, size={:#016x}",
|
||||||
src_addr, size);
|
src_addr, size);
|
||||||
R_THROW(ResultInvalidCurrentMemory);
|
R_THROW(ResultInvalidCurrentMemory);
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsValidAddressRange(u64 address, u64 size) {
|
[[nodiscard]] inline constexpr bool IsValidAddressRange(u64 address, u64 size) {
|
||||||
return address + size > address;
|
return address + size > address;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
|
[[nodiscard]] inline constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
switch (perm) {
|
switch (perm) {
|
||||||
case Svc::MemoryPermission::None:
|
case Svc::MemoryPermission::None:
|
||||||
case Svc::MemoryPermission::Read:
|
case Svc::MemoryPermission::Read:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -10,6 +13,7 @@ namespace Service::AM {
|
|||||||
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
|
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
|
||||||
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
|
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
|
||||||
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
|
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
|
||||||
|
constexpr Result ResultApplicationRecordNotFound{ErrorModule::AM, 37};
|
||||||
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
|
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
|
||||||
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
|
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
|
||||||
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
|
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -201,6 +201,14 @@ enum class ProgramSpecifyKind : u32 {
|
|||||||
RestartProgram = 2,
|
RestartProgram = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Maufeat: Use enums for zindex instead of using random zindex numbers
|
||||||
|
enum AppletZIndex : s32 {
|
||||||
|
Background = 0,
|
||||||
|
Foreground = 1,
|
||||||
|
ForegroundVisible = 2,
|
||||||
|
Overlay = 3,
|
||||||
|
};
|
||||||
|
|
||||||
struct CommonArguments {
|
struct CommonArguments {
|
||||||
CommonArgumentVersion arguments_version;
|
CommonArgumentVersion arguments_version;
|
||||||
CommonArgumentSize size;
|
CommonArgumentSize size;
|
||||||
|
|||||||
@@ -56,22 +56,22 @@ void Applet::UpdateSuspensionStateLocked(bool force_message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Applet::SetInteractibleLocked(bool interactible) {
|
void Applet::SetInteractibleLocked(bool pad_interactible, bool touch_interactible) {
|
||||||
if (is_interactible == interactible) {
|
if (is_pad_interactible == pad_interactible && is_touch_interactible == touch_interactible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_interactible = interactible;
|
is_pad_interactible = pad_interactible;
|
||||||
|
is_touch_interactible = touch_interactible;
|
||||||
|
|
||||||
const bool exit_requested = lifecycle_manager.GetExitRequested();
|
const bool exit_requested = lifecycle_manager.GetExitRequested();
|
||||||
const bool input_enabled = interactible && !exit_requested;
|
const bool pad_enabled = pad_interactible && !exit_requested;
|
||||||
|
const bool touch_enabled = touch_interactible && !exit_requested;
|
||||||
|
|
||||||
if (applet_id == AppletId::OverlayDisplay || applet_id == AppletId::Application) {
|
LOG_DEBUG(Service_AM, "applet={} pad={} touch={} exit_requested={}",
|
||||||
LOG_DEBUG(Service_AM, "called, applet={} interactible={} exit_requested={} input_enabled={} overlay_in_foreground={}",
|
static_cast<u32>(applet_id), pad_enabled, touch_enabled, exit_requested);
|
||||||
static_cast<u32>(applet_id), interactible, exit_requested, input_enabled, overlay_in_foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
hid_registration.EnableAppletToGetInput(input_enabled);
|
hid_registration.EnableAppletToGetInput(pad_enabled, touch_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Applet::OnProcessTerminatedLocked() {
|
void Applet::OnProcessTerminatedLocked() {
|
||||||
|
|||||||
@@ -125,9 +125,11 @@ struct Applet {
|
|||||||
bool album_image_taken_notification_enabled{};
|
bool album_image_taken_notification_enabled{};
|
||||||
bool record_volume_muted{};
|
bool record_volume_muted{};
|
||||||
bool is_activity_runnable{};
|
bool is_activity_runnable{};
|
||||||
bool is_interactible{true};
|
bool is_pad_interactible{true};
|
||||||
|
bool is_touch_interactible{true};
|
||||||
bool window_visible{true};
|
bool window_visible{true};
|
||||||
bool overlay_in_foreground{false};
|
bool overlay_watching_short_home_button{false};
|
||||||
|
bool overlay_handling_touch_input{false};
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
Event overlay_event;
|
Event overlay_event;
|
||||||
@@ -148,7 +150,7 @@ struct Applet {
|
|||||||
|
|
||||||
// Process state management
|
// Process state management
|
||||||
void UpdateSuspensionStateLocked(bool force_message);
|
void UpdateSuspensionStateLocked(bool force_message);
|
||||||
void SetInteractibleLocked(bool interactible);
|
void SetInteractibleLocked(bool pad_interactible, bool touch_interactible);
|
||||||
void OnProcessTerminatedLocked();
|
void OnProcessTerminatedLocked();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/service/am/display_layer_manager.h"
|
#include "core/hle/service/am/display_layer_manager.h"
|
||||||
|
#include "core/hle/service/nvnflinger/hwc_layer.h"
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
#include "core/hle/service/vi/application_display_service.h"
|
#include "core/hle/service/vi/application_display_service.h"
|
||||||
#include "core/hle/service/vi/container.h"
|
#include "core/hle/service/vi/container.h"
|
||||||
@@ -33,6 +34,7 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro
|
|||||||
m_system_shared_buffer_id = 0;
|
m_system_shared_buffer_id = 0;
|
||||||
m_system_shared_layer_id = 0;
|
m_system_shared_layer_id = 0;
|
||||||
m_applet_id = applet_id;
|
m_applet_id = applet_id;
|
||||||
|
m_library_applet_mode = mode;
|
||||||
m_buffer_sharing_enabled = false;
|
m_buffer_sharing_enabled = false;
|
||||||
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
|
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
|
||||||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
|
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
|
||||||
@@ -72,14 +74,16 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
|
|||||||
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
|
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
|
||||||
|
|
||||||
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
|
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
|
||||||
|
(void)m_display_service->GetContainer()->SetLayerStackMask(*out_layer_id,
|
||||||
|
this->GetLayerStackMask());
|
||||||
|
|
||||||
if (m_applet_id != AppletId::Application) {
|
if (m_applet_id != AppletId::Application) {
|
||||||
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
|
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
|
||||||
if (m_applet_id == AppletId::OverlayDisplay) {
|
if (m_applet_id == AppletId::OverlayDisplay) {
|
||||||
(void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id);
|
(void)m_manager_display_service->SetLayerZIndex(Overlay, *out_layer_id);
|
||||||
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
|
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
|
||||||
} else {
|
} else {
|
||||||
(void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id);
|
(void)m_manager_display_service->SetLayerZIndex(Foreground, *out_layer_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +126,12 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
|
|||||||
|
|
||||||
// Ensure the overlay layer is visible
|
// Ensure the overlay layer is visible
|
||||||
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
|
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
|
||||||
|
(void)m_display_service->GetContainer()->SetLayerStackMask(m_system_shared_layer_id,
|
||||||
|
this->GetLayerStackMask());
|
||||||
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
|
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
|
||||||
s32 initial_z = 1;
|
s32 initial_z = Foreground;
|
||||||
if (m_applet_id == AppletId::OverlayDisplay) {
|
if (m_applet_id == AppletId::OverlayDisplay) {
|
||||||
initial_z = -1;
|
initial_z = Overlay;
|
||||||
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
|
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
|
||||||
}
|
}
|
||||||
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
|
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
|
||||||
@@ -142,6 +148,36 @@ Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_bu
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 DisplayLayerManager::GetLayerStackMask() const {
|
||||||
|
using Nvnflinger::LayerStackBit;
|
||||||
|
using Nvnflinger::LayerStackId;
|
||||||
|
|
||||||
|
constexpr u32 Displayed = LayerStackBit(LayerStackId::Default);
|
||||||
|
constexpr u32 Screenshot = LayerStackBit(LayerStackId::Screenshot);
|
||||||
|
constexpr u32 Recording = LayerStackBit(LayerStackId::Recording);
|
||||||
|
constexpr u32 LastFrame = LayerStackBit(LayerStackId::LastFrame);
|
||||||
|
constexpr u32 Debug = LayerStackBit(LayerStackId::ApplicationForDebug);
|
||||||
|
|
||||||
|
switch (m_applet_id) {
|
||||||
|
case AppletId::Application:
|
||||||
|
return Displayed | Screenshot | Recording | LastFrame | Debug;
|
||||||
|
case AppletId::OverlayDisplay:
|
||||||
|
return Displayed;
|
||||||
|
case AppletId::QLaunch:
|
||||||
|
return Displayed;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_library_applet_mode) {
|
||||||
|
case LibraryAppletMode::AllForeground:
|
||||||
|
case LibraryAppletMode::AllForegroundInitiallyHidden:
|
||||||
|
return Displayed | Screenshot | LastFrame;
|
||||||
|
default:
|
||||||
|
return Displayed | Screenshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayLayerManager::SetWindowVisibility(bool visible) {
|
void DisplayLayerManager::SetWindowVisibility(bool visible) {
|
||||||
if (m_visible == visible) {
|
if (m_visible == visible) {
|
||||||
return;
|
return;
|
||||||
@@ -185,10 +221,17 @@ void DisplayLayerManager::SetOverlayZIndex(s32 z_index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
|
Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
|
||||||
s32* out_fbshare_layer_index) {
|
s32* out_fbshare_layer_index,
|
||||||
|
VI::CaptureKind kind) {
|
||||||
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
|
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
|
||||||
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
|
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
|
||||||
out_was_written, out_fbshare_layer_index));
|
out_was_written, out_fbshare_layer_index, kind));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DisplayLayerManager::ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color) {
|
||||||
|
R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
|
||||||
|
R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->ClearAppletCaptureBuffer(
|
||||||
|
fbshare_layer_index, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::AM
|
} // namespace Service::AM
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -23,6 +23,7 @@ class KProcess;
|
|||||||
namespace Service::VI {
|
namespace Service::VI {
|
||||||
class IApplicationDisplayService;
|
class IApplicationDisplayService;
|
||||||
class IManagerDisplayService;
|
class IManagerDisplayService;
|
||||||
|
enum class CaptureKind : u32;
|
||||||
} // namespace Service::VI
|
} // namespace Service::VI
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
@@ -48,9 +49,13 @@ public:
|
|||||||
|
|
||||||
void SetOverlayZIndex(s32 z_index);
|
void SetOverlayZIndex(s32 z_index);
|
||||||
|
|
||||||
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
|
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index,
|
||||||
|
VI::CaptureKind kind);
|
||||||
|
Result ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
u32 GetLayerStackMask() const;
|
||||||
|
|
||||||
Kernel::KProcess* m_process{};
|
Kernel::KProcess* m_process{};
|
||||||
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
|
std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
|
||||||
std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
|
std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
|
||||||
@@ -59,6 +64,7 @@ private:
|
|||||||
u64 m_system_shared_buffer_id{};
|
u64 m_system_shared_buffer_id{};
|
||||||
u64 m_system_shared_layer_id{};
|
u64 m_system_shared_layer_id{};
|
||||||
AppletId m_applet_id{};
|
AppletId m_applet_id{};
|
||||||
|
LibraryAppletMode m_library_applet_mode{};
|
||||||
bool m_buffer_sharing_enabled{};
|
bool m_buffer_sharing_enabled{};
|
||||||
bool m_blending_enabled{};
|
bool m_blending_enabled{};
|
||||||
bool m_visible{true};
|
bool m_visible{true};
|
||||||
|
|||||||
@@ -36,12 +36,17 @@ HidRegistration::~HidRegistration() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HidRegistration::EnableAppletToGetInput(bool enable) {
|
void HidRegistration::EnableAppletToGetInput(bool enable_pad, bool enable_touch) {
|
||||||
if (m_process.IsInitialized()) {
|
if (!m_process.IsInitialized())
|
||||||
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
|
return;
|
||||||
enable);
|
|
||||||
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
|
const auto resource_manager = m_hid_server->GetResourceManager();
|
||||||
}
|
const u64 aruid = m_process.GetProcessId();
|
||||||
|
|
||||||
|
resource_manager->EnablePadInput(aruid, enable_pad);
|
||||||
|
resource_manager->EnableTouchScreen(aruid, enable_touch);
|
||||||
|
|
||||||
|
resource_manager->SetAruidValidForVibration(aruid, enable_pad);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::AM
|
} // namespace Service::AM
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
~HidRegistration();
|
~HidRegistration();
|
||||||
|
|
||||||
void RegisterCurrentProcess();
|
void RegisterCurrentProcess();
|
||||||
void EnableAppletToGetInput(bool enable);
|
void EnableAppletToGetInput(bool enable_pad, bool enable_touch);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Process& m_process;
|
Process& m_process;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/common_funcs.h"
|
||||||
#include "core/hle/service/am/applet.h"
|
#include "core/hle/service/am/applet.h"
|
||||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
@@ -78,7 +80,7 @@ Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
|
|||||||
|
|
||||||
Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
|
Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
*out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL;
|
*out_application_id = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#include "common/hex_util.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/uuid.h"
|
#include "common/uuid.h"
|
||||||
|
#include "core/file_sys/common_funcs.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/file_sys/registered_cache.h"
|
#include "core/file_sys/registered_cache.h"
|
||||||
@@ -28,6 +30,27 @@
|
|||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
FileSys::PatchManager::Metadata GetApplicationMetadata(Core::System& system, u64 program_id) {
|
||||||
|
auto metadata = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, program_id);
|
||||||
|
if (metadata.first != nullptr) {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto application_id = FileSys::GetBaseTitleID(program_id);
|
||||||
|
if (application_id == program_id) {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AM,
|
||||||
|
"no metadata for program_id={:016X}, falling back to application_id={:016X}",
|
||||||
|
program_id, application_id);
|
||||||
|
return FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, application_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
|
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
|
||||||
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
|
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -156,7 +179,7 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
|
|||||||
// Default to 0 (all languages supported)
|
// Default to 0 (all languages supported)
|
||||||
u32 supported_languages = 0;
|
u32 supported_languages = 0;
|
||||||
|
|
||||||
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
|
const auto res = GetApplicationMetadata(system, m_applet->program_id);
|
||||||
if (res.first != nullptr) {
|
if (res.first != nullptr) {
|
||||||
supported_languages = res.first->GetSupportedLanguages();
|
supported_languages = res.first->GetSupportedLanguages();
|
||||||
}
|
}
|
||||||
@@ -194,7 +217,7 @@ Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
|
|||||||
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
|
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
|
const auto res = GetApplicationMetadata(system, m_applet->program_id);
|
||||||
if (res.first != nullptr) {
|
if (res.first != nullptr) {
|
||||||
const auto& version = res.first->GetVersionString();
|
const auto& version = res.first->GetVersionString();
|
||||||
std::memcpy(out_display_version->string.data(), version.data(),
|
std::memcpy(out_display_version->string.data(), version.data(),
|
||||||
@@ -324,6 +347,7 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
|
|||||||
|
|
||||||
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
|
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
|
||||||
LOG_WARNING(Service_AM, "(stubbed)");
|
LOG_WARNING(Service_AM, "(stubbed)");
|
||||||
|
R_UNLESS(out_pseudo_device_id, ResultUnknown);
|
||||||
|
|
||||||
// This should be hashed with the device specific hash
|
// This should be hashed with the device specific hash
|
||||||
// for now this will do
|
// for now this will do
|
||||||
@@ -430,15 +454,21 @@ Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value)
|
|||||||
|
|
||||||
// https://switchbrew.org/wiki/Applet_Manager_services#CreateApplicationAndRequestToStart
|
// https://switchbrew.org/wiki/Applet_Manager_services#CreateApplicationAndRequestToStart
|
||||||
Result IApplicationFunctions::CreateApplicationAndRequestToStart(u64 application_id) {
|
Result IApplicationFunctions::CreateApplicationAndRequestToStart(u64 application_id) {
|
||||||
LOG_INFO(Service_AM, "called, application_id={:016X}", application_id);
|
LOG_INFO(Service_AM, "called, application_id={:016X} current_program_id={:016X}", application_id, m_applet->program_id);
|
||||||
|
|
||||||
// If application_id is 0, relaunch the current application
|
if (application_id == 0 ||
|
||||||
const u64 target_application_id =
|
FileSys::GetBaseTitleID(application_id) == FileSys::GetBaseTitleID(m_applet->program_id)) {
|
||||||
(application_id == 0) ? m_applet->program_id : application_id;
|
const auto program_index = application_id == 0
|
||||||
|
? 0
|
||||||
|
: application_id - FileSys::GetBaseTitleID(application_id);
|
||||||
|
|
||||||
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
|
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
|
||||||
system.ExecuteProgram(target_application_id);
|
system.ExecuteProgram(program_index);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR(Service_AM, "Launching a different application ({:016X}) is not implemented!", application_id);
|
||||||
|
R_THROW(ResultUnknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationFunctions::ClearUserChannel() {
|
Result IApplicationFunctions::ClearUserChannel() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "core/hle/service/am/applet.h"
|
#include "core/hle/service/am/applet.h"
|
||||||
#include "core/hle/service/am/service/display_controller.h"
|
#include "core/hle/service/am/service/display_controller.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/vi/shared_buffer_manager.h"
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
|
||||||
@@ -71,16 +72,16 @@ Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_l
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
|
Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}",
|
LOG_DEBUG(Service_AM, "called, unknown0={} fbshare_layer_index={} color={:#x}", unknown0,
|
||||||
unknown0, fbshare_layer_index, color);
|
fbshare_layer_index, color);
|
||||||
R_SUCCEED();
|
R_RETURN(applet->display_layer_manager.ClearAppletCaptureBuffer(fbshare_layer_index, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
|
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
|
||||||
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
|
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
|
||||||
out_fbshare_layer_index));
|
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastForeground));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
|
Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
|
||||||
@@ -90,9 +91,9 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
|
|||||||
|
|
||||||
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
|
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
|
||||||
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
|
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
|
||||||
out_fbshare_layer_index));
|
out_was_written, out_fbshare_layer_index, VI::CaptureKind::CallerApplet));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
|
Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
|
||||||
@@ -102,9 +103,9 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
|
|||||||
|
|
||||||
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
|
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
|
||||||
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
|
R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(
|
||||||
out_fbshare_layer_index));
|
out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastApplication));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() {
|
Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "core/hle/service/am/applet.h"
|
#include "core/hle/service/am/applet.h"
|
||||||
@@ -22,7 +22,7 @@ namespace Service::AM {
|
|||||||
{10, nullptr, "StartShutdownSequenceForOverlay"},
|
{10, nullptr, "StartShutdownSequenceForOverlay"},
|
||||||
{11, nullptr, "StartRebootSequenceForOverlay"},
|
{11, nullptr, "StartRebootSequenceForOverlay"},
|
||||||
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
|
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
|
||||||
{21, nullptr, "SetHandlingTouchScreenInputEnabled"},
|
{21, D<&IOverlayFunctions::SetHandlingTouchScreenInputEnabled>, "SetHandlingTouchScreenInputEnabled"},
|
||||||
{30, nullptr, "SetHealthWarningShowingState"},
|
{30, nullptr, "SetHealthWarningShowingState"},
|
||||||
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
|
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
|
||||||
{40, nullptr, "GetApplicationNintendoLogo"},
|
{40, nullptr, "GetApplicationNintendoLogo"},
|
||||||
@@ -43,10 +43,12 @@ namespace Service::AM {
|
|||||||
Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() {
|
Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
m_applet->overlay_in_foreground = true;
|
{
|
||||||
m_applet->home_button_short_pressed_blocked = false;
|
std::scoped_lock lk{m_applet->lock};
|
||||||
|
m_applet->overlay_watching_short_home_button = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
|
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) {
|
||||||
window_system->RequestUpdate();
|
window_system->RequestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +58,26 @@ namespace Service::AM {
|
|||||||
Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() {
|
Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
m_applet->overlay_in_foreground = false;
|
{
|
||||||
m_applet->home_button_short_pressed_blocked = false;
|
std::scoped_lock lk{m_applet->lock};
|
||||||
|
m_applet->overlay_watching_short_home_button = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto *window_system = system.GetAppletManager().GetWindowSystem()) {
|
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) {
|
||||||
window_system->RequestUpdate();
|
window_system->RequestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IOverlayFunctions::SetHandlingTouchScreenInputEnabled(bool enabled) {
|
||||||
|
LOG_DEBUG(Service_AM, "called, enabled={}", enabled);
|
||||||
|
|
||||||
|
std::scoped_lock lk{m_applet->lock};
|
||||||
|
m_applet->overlay_handling_touch_input = enabled;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
|
Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -20,6 +20,7 @@ namespace Service::AM {
|
|||||||
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
|
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
|
||||||
Result IsHealthWarningRequired(Out<bool> is_required);
|
Result IsHealthWarningRequired(Out<bool> is_required);
|
||||||
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
|
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
|
||||||
|
Result SetHandlingTouchScreenInputEnabled(bool enabled);
|
||||||
Result Unknown70();
|
Result Unknown70();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -4,7 +4,11 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/service/am/am_results.h"
|
#include "core/hle/service/am/am_results.h"
|
||||||
#include "core/hle/service/am/applet.h"
|
#include "core/hle/service/am/applet.h"
|
||||||
#include "core/hle/service/am/applet_manager.h"
|
#include "core/hle/service/am/applet_manager.h"
|
||||||
@@ -32,46 +36,82 @@ void WindowSystem::RequestUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WindowSystem::Update() {
|
void WindowSystem::Update() {
|
||||||
std::scoped_lock lk{m_lock};
|
{
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
|
LOG_DEBUG(Service_AM, "called, home_menu={} application={} overlay={}",
|
||||||
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
|
m_home_menu != nullptr, m_application != nullptr, m_overlay_display != nullptr);
|
||||||
|
|
||||||
// Loop through all applets and remove terminated applets.
|
// Loop through all applets and remove terminated applets.
|
||||||
this->PruneTerminatedAppletsLocked();
|
this->PruneTerminatedAppletsLocked();
|
||||||
|
|
||||||
// If the home menu is being locked into the foreground, handle that.
|
// If the home menu is being locked into the foreground, handle that.
|
||||||
if (this->LockHomeMenuIntoForegroundLocked()) {
|
if (!this->LockHomeMenuIntoForegroundLocked()) {
|
||||||
return;
|
const bool overlay_takes_input = this->DoesOverlayTakeInputLocked();
|
||||||
|
|
||||||
|
this->UpdateAppletStateLocked(m_overlay_display, true, overlay_takes_input);
|
||||||
|
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu, overlay_takes_input);
|
||||||
|
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application, overlay_takes_input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overlay_blocks_input = false;
|
this->NotifyApplicationChangedIfNeeded();
|
||||||
if (m_overlay_display) {
|
|
||||||
std::scoped_lock lk_overlay{m_overlay_display->lock};
|
|
||||||
overlay_blocks_input = m_overlay_display->overlay_in_foreground;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively update each applet root.
|
|
||||||
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu, overlay_blocks_input);
|
|
||||||
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application, overlay_blocks_input);
|
|
||||||
this->UpdateAppletStateLocked(m_overlay_display, true, false); // overlay is always updated, never blocked
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
|
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
|
||||||
std::scoped_lock lk{m_lock};
|
{
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
if (applet->applet_id == AppletId::QLaunch) {
|
if (applet->applet_id == AppletId::QLaunch) {
|
||||||
ASSERT(m_home_menu == nullptr);
|
ASSERT(m_home_menu == nullptr);
|
||||||
m_home_menu = applet.get();
|
m_home_menu = applet.get();
|
||||||
} else if (applet->applet_id == AppletId::OverlayDisplay) {
|
} else if (applet->applet_id == AppletId::OverlayDisplay) {
|
||||||
m_overlay_display = applet.get();
|
m_overlay_display = applet.get();
|
||||||
} else if (is_application) {
|
} else if (is_application) {
|
||||||
ASSERT(m_application == nullptr);
|
ASSERT(m_application == nullptr);
|
||||||
m_application = applet.get();
|
m_application = applet.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->UpdateCurrentApplicationLocked();
|
||||||
|
|
||||||
|
m_event_observer->TrackAppletProcess(*applet);
|
||||||
|
m_applets.emplace(applet->aruid.pid, std::move(applet));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_event_observer->TrackAppletProcess(*applet);
|
this->NotifyApplicationChangedIfNeeded();
|
||||||
m_applets.emplace(applet->aruid.pid, std::move(applet));
|
}
|
||||||
|
|
||||||
|
void WindowSystem::UpdateCurrentApplicationLocked() {
|
||||||
|
const Applet* const candidate = m_application != nullptr ? m_application : m_home_menu;
|
||||||
|
if (candidate == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* const process = candidate->process->GetHandle();
|
||||||
|
if (process == nullptr || process == m_system.Kernel().ApplicationProcess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_AM, "Current application is now {:016X}", candidate->program_id);
|
||||||
|
|
||||||
|
m_system.Kernel().SetApplicationProcess(process);
|
||||||
|
Settings::SetCurrentProgramID(candidate->program_id);
|
||||||
|
|
||||||
|
m_pending_application_notification = candidate->program_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSystem::NotifyApplicationChangedIfNeeded() {
|
||||||
|
std::optional<u64> program_id;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
program_id = std::exchange(m_pending_application_notification, std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!program_id.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_system.NotifyApplicationChanged(*program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
|
std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
|
||||||
@@ -169,18 +209,40 @@ void WindowSystem::OnExitRequested() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WindowSystem::SendButtonAppletMessageLocked(AppletMessage message) {
|
void WindowSystem::SendButtonAppletMessageLocked(AppletMessage message) {
|
||||||
if (m_home_menu) {
|
const auto is_blocked = [message](const Applet& applet) {
|
||||||
std::scoped_lock lk_home{m_home_menu->lock};
|
if (message == AppletMessage::DetectShortPressingHomeButton &&
|
||||||
m_home_menu->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
|
applet.applet_id == AppletId::OverlayDisplay &&
|
||||||
}
|
!applet.overlay_watching_short_home_button) {
|
||||||
if (m_overlay_display) {
|
return true;
|
||||||
std::scoped_lock lk_overlay{m_overlay_display->lock};
|
}
|
||||||
m_overlay_display->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
|
|
||||||
}
|
switch (message) {
|
||||||
if (m_application) {
|
case AppletMessage::DetectShortPressingHomeButton:
|
||||||
std::scoped_lock lk_application{m_application->lock};
|
return applet.home_button_short_pressed_blocked;
|
||||||
m_application->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
|
case AppletMessage::DetectLongPressingHomeButton:
|
||||||
}
|
return applet.home_button_long_pressed_blocked;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto send_to = [&](Applet* applet) {
|
||||||
|
if (!applet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::scoped_lock lk{applet->lock};
|
||||||
|
if (is_blocked(*applet)) {
|
||||||
|
LOG_DEBUG(Service_AM, "Applet {} is blocking message {}",
|
||||||
|
static_cast<u32>(applet->applet_id), static_cast<u32>(message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applet->lifecycle_manager.PushUnorderedMessage(m_system.Kernel(), message);
|
||||||
|
};
|
||||||
|
|
||||||
|
send_to(m_home_menu);
|
||||||
|
send_to(m_overlay_display);
|
||||||
|
send_to(m_application);
|
||||||
|
|
||||||
if (m_event_observer) {
|
if (m_event_observer) {
|
||||||
m_event_observer->RequestUpdate();
|
m_event_observer->RequestUpdate();
|
||||||
}
|
}
|
||||||
@@ -192,19 +254,9 @@ void WindowSystem::OnSystemButtonPress(SystemButtonType type) {
|
|||||||
case SystemButtonType::HomeButtonShortPressing:
|
case SystemButtonType::HomeButtonShortPressing:
|
||||||
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingHomeButton);
|
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingHomeButton);
|
||||||
break;
|
break;
|
||||||
case SystemButtonType::HomeButtonLongPressing: {
|
case SystemButtonType::HomeButtonLongPressing:
|
||||||
// Toggle overlay foreground visibility on long home press
|
|
||||||
if (m_overlay_display) {
|
|
||||||
std::scoped_lock lk_overlay{m_overlay_display->lock};
|
|
||||||
m_overlay_display->overlay_in_foreground = !m_overlay_display->overlay_in_foreground;
|
|
||||||
LOG_INFO(Service_AM, "Overlay long-press toggle: overlay_in_foreground={} window_visible={}", m_overlay_display->overlay_in_foreground, m_overlay_display->window_visible);
|
|
||||||
}
|
|
||||||
SendButtonAppletMessageLocked(AppletMessage::DetectLongPressingHomeButton);
|
SendButtonAppletMessageLocked(AppletMessage::DetectLongPressingHomeButton);
|
||||||
// Force a state update after toggling overlay
|
break;
|
||||||
if (m_event_observer) {
|
|
||||||
m_event_observer->RequestUpdate();
|
|
||||||
}
|
|
||||||
break; }
|
|
||||||
case SystemButtonType::CaptureButtonShortPressing:
|
case SystemButtonType::CaptureButtonShortPressing:
|
||||||
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingCaptureButton);
|
SendButtonAppletMessageLocked(AppletMessage::DetectShortPressingCaptureButton);
|
||||||
break;
|
break;
|
||||||
@@ -317,6 +369,8 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
|
|||||||
m_overlay_display = nullptr;
|
m_overlay_display = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->UpdateCurrentApplicationLocked();
|
||||||
|
|
||||||
// Finalize applet.
|
// Finalize applet.
|
||||||
applet->OnProcessTerminatedLocked();
|
applet->OnProcessTerminatedLocked();
|
||||||
|
|
||||||
@@ -389,7 +443,20 @@ void WindowSystem::TerminateChildAppletsLocked(Applet* applet) {
|
|||||||
applet->lock.lock();
|
applet->lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking) {
|
bool WindowSystem::IsOverlayOpenLocked(const Applet& overlay) const {
|
||||||
|
return overlay.window_visible && overlay.overlay_watching_short_home_button;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowSystem::DoesOverlayTakeInputLocked() const {
|
||||||
|
if (m_overlay_display == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::scoped_lock lk{m_overlay_display->lock};
|
||||||
|
return this->IsOverlayOpenLocked(*m_overlay_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input) {
|
||||||
// With no applet, we don't have anything to do.
|
// With no applet, we don't have anything to do.
|
||||||
if (!applet) {
|
if (!applet) {
|
||||||
return;
|
return;
|
||||||
@@ -420,24 +487,18 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
|
|||||||
return false;
|
return false;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
const bool is_overlay = applet->applet_id == AppletId::OverlayDisplay;
|
||||||
|
|
||||||
// Update visibility state.
|
// Update visibility state.
|
||||||
// Overlay applets should always be visible when window_visible is true, regardless of foreground state
|
const bool should_be_visible =
|
||||||
const bool should_be_visible = (applet->applet_id == AppletId::OverlayDisplay)
|
is_overlay ? applet->window_visible : (is_foreground && applet->window_visible);
|
||||||
? applet->window_visible
|
|
||||||
: (is_foreground && applet->window_visible);
|
|
||||||
applet->display_layer_manager.SetWindowVisibility(should_be_visible);
|
applet->display_layer_manager.SetWindowVisibility(should_be_visible);
|
||||||
|
|
||||||
|
const bool needs_hid_input =
|
||||||
|
is_overlay ? this->IsOverlayOpenLocked(*applet)
|
||||||
|
: (is_foreground && applet->window_visible && !overlay_takes_input);
|
||||||
|
|
||||||
const bool should_be_interactible = (applet->applet_id == AppletId::OverlayDisplay)
|
applet->SetInteractibleLocked(needs_hid_input, needs_hid_input);
|
||||||
? applet->overlay_in_foreground
|
|
||||||
: (is_foreground && applet->window_visible && !overlay_blocking);
|
|
||||||
|
|
||||||
if (applet->applet_id == AppletId::OverlayDisplay || applet->applet_id == AppletId::Application) {
|
|
||||||
LOG_DEBUG(Service_AM, "UpdateAppletStateLocked: applet={} overlay_in_foreground={} is_foreground={} window_visible={} overlay_blocking={} should_be_interactible={}",
|
|
||||||
static_cast<u32>(applet->applet_id), applet->overlay_in_foreground, is_foreground, applet->window_visible, overlay_blocking, should_be_interactible);
|
|
||||||
}
|
|
||||||
|
|
||||||
applet->SetInteractibleLocked(should_be_interactible);
|
|
||||||
|
|
||||||
// Update focus state and suspension.
|
// Update focus state and suspension.
|
||||||
const bool is_obscured = has_obscuring_child_applets || !applet->window_visible;
|
const bool is_obscured = has_obscuring_child_applets || !applet->window_visible;
|
||||||
@@ -453,23 +514,18 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
|
|||||||
applet->UpdateSuspensionStateLocked(true);
|
applet->UpdateSuspensionStateLocked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Z-index logic like in reference C# implementation (tuned for overlay extremes)
|
// Layer ordering. Composition sorts back-to-front. Now with enums for calrity.
|
||||||
s32 z_index = 0;
|
s32 z_index = Background;
|
||||||
const bool now_foreground = inherited_foreground;
|
if (is_overlay) {
|
||||||
if (applet->applet_id == AppletId::OverlayDisplay) {
|
z_index = Overlay;
|
||||||
z_index = applet->overlay_in_foreground ? 100000 : -1;
|
} else if (inherited_foreground) {
|
||||||
} else if (now_foreground && !is_obscured) {
|
z_index = is_obscured ? Foreground : ForegroundVisible;
|
||||||
z_index = 2;
|
|
||||||
} else if (now_foreground) {
|
|
||||||
z_index = 1;
|
|
||||||
} else {
|
|
||||||
z_index = 0;
|
|
||||||
}
|
}
|
||||||
applet->display_layer_manager.SetOverlayZIndex(z_index);
|
applet->display_layer_manager.SetOverlayZIndex(z_index);
|
||||||
|
|
||||||
// Recurse into child applets.
|
// Recurse into child applets.
|
||||||
for (const auto& child_applet : applet->child_applets) {
|
for (const auto& child_applet : applet->child_applets) {
|
||||||
this->UpdateAppletStateLocked(child_applet.get(), is_foreground, overlay_blocking);
|
this->UpdateAppletStateLocked(child_applet.get(), is_foreground, overlay_takes_input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/am/am_types.h"
|
#include "core/hle/service/am/am_types.h"
|
||||||
@@ -60,11 +61,16 @@ public:
|
|||||||
void OnPowerButtonPressed(ButtonPressDuration type) {}
|
void OnPowerButtonPressed(ButtonPressDuration type) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void UpdateCurrentApplicationLocked();
|
||||||
|
void NotifyApplicationChangedIfNeeded();
|
||||||
void PruneTerminatedAppletsLocked();
|
void PruneTerminatedAppletsLocked();
|
||||||
bool RestartAppletProcessLocked(Applet* applet);
|
bool RestartAppletProcessLocked(Applet* applet);
|
||||||
bool LockHomeMenuIntoForegroundLocked();
|
bool LockHomeMenuIntoForegroundLocked();
|
||||||
void TerminateChildAppletsLocked(Applet* applet);
|
void TerminateChildAppletsLocked(Applet* applet);
|
||||||
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking = false);
|
bool IsOverlayOpenLocked(const Applet& overlay) const;
|
||||||
|
bool DoesOverlayTakeInputLocked() const;
|
||||||
|
|
||||||
|
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_takes_input);
|
||||||
void SendButtonAppletMessageLocked(AppletMessage message);
|
void SendButtonAppletMessageLocked(AppletMessage message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -88,6 +94,7 @@ private:
|
|||||||
|
|
||||||
// Applet map by aruid.
|
// Applet map by aruid.
|
||||||
std::map<u64, std::shared_ptr<Applet>> m_applets{};
|
std::map<u64, std::shared_ptr<Applet>> m_applets{};
|
||||||
|
std::optional<u64> m_pending_application_notification{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::AM
|
} // namespace Service::AM
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
|
#include "core/hle/service/am/am_results.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
namespace Service::AOC {
|
namespace Service::AOC {
|
||||||
@@ -31,6 +32,10 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
|
|||||||
return FileSys::GetBaseTitleID(title_id) == base;
|
return FileSys::GetBaseTitleID(title_id) == base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 GetCallerBaseTitleID(Core::System& system, const ClientProcessId& process_id) {
|
||||||
|
return FileSys::GetBaseTitleID(system.ResolveCallerProgramId(*process_id));
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
|
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
|
||||||
std::vector<u64> add_on_content;
|
std::vector<u64> add_on_content;
|
||||||
const auto& rcu = system.GetContentProvider();
|
const auto& rcu = system.GetContentProvider();
|
||||||
@@ -91,7 +96,7 @@ IAddOnContentManager::~IAddOnContentManager() {
|
|||||||
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
|
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
|
||||||
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
|
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
|
||||||
|
|
||||||
const auto current = system.GetApplicationProcessProgramID();
|
const auto current = GetCallerBaseTitleID(system, process_id);
|
||||||
|
|
||||||
const auto& disabled = Settings::values.disabled_addons[current];
|
const auto& disabled = Settings::values.disabled_addons[current];
|
||||||
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
|
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
|
||||||
@@ -112,7 +117,7 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
|
|||||||
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
|
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
|
||||||
process_id.pid);
|
process_id.pid);
|
||||||
|
|
||||||
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
|
const auto current = GetCallerBaseTitleID(system, process_id);
|
||||||
|
|
||||||
std::vector<u32> out;
|
std::vector<u32> out;
|
||||||
const auto& disabled = Settings::values.disabled_addons[current];
|
const auto& disabled = Settings::values.disabled_addons[current];
|
||||||
@@ -126,8 +131,7 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(DarkLordZach): Find the correct error code.
|
R_UNLESS(out.size() >= offset, AM::ResultApplicationRecordNotFound);
|
||||||
R_UNLESS(out.size() >= offset, ResultUnknown);
|
|
||||||
|
|
||||||
*out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
|
*out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
|
||||||
std::rotate(out.begin(), out.begin() + offset, out.end());
|
std::rotate(out.begin(), out.begin() + offset, out.end());
|
||||||
@@ -141,7 +145,7 @@ Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
|
|||||||
ClientProcessId process_id) {
|
ClientProcessId process_id) {
|
||||||
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
|
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
|
||||||
|
|
||||||
const auto title_id = system.GetApplicationProcessProgramID();
|
const auto title_id = system.ResolveCallerProgramId(*process_id);
|
||||||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
|
||||||
system.GetContentProvider()};
|
system.GetContentProvider()};
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,12 @@
|
|||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioIn;
|
|
||||||
|
|
||||||
IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
|
IAudioIn::IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager, size_t session_id,
|
||||||
const std::string& device_name, const AudioInParameter& in_params,
|
const std::string& device_name, const AudioCore::AudioIn::AudioInParameter& in_params,
|
||||||
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
||||||
: ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
|
: ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
|
||||||
event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
|
event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<AudioCore::AudioIn::In>(system_,
|
||||||
manager, event,
|
manager, event,
|
||||||
session_id)} {
|
session_id)} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -71,12 +70,12 @@ Result IAudioIn::Stop() {
|
|||||||
R_RETURN(impl->StopSystem());
|
R_RETURN(impl->StopSystem());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
|
Result IAudioIn::AppendAudioInBuffer(InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
|
||||||
u64 buffer_client_ptr) {
|
u64 buffer_client_ptr) {
|
||||||
R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
|
R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
|
Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
|
||||||
u64 buffer_client_ptr) {
|
u64 buffer_client_ptr) {
|
||||||
if (buffer.empty()) {
|
if (buffer.empty()) {
|
||||||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
|
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,6 @@
|
|||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioIn;
|
|
||||||
|
|
||||||
IAudioInManager::IAudioInManager(Core::System& system_)
|
IAudioInManager::IAudioInManager(Core::System& system_)
|
||||||
: ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
|
: ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
|
||||||
@@ -34,11 +36,11 @@ Result IAudioInManager::ListAudioIns(
|
|||||||
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
|
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
|
Result IAudioInManager::OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
|
||||||
Out<SharedPointer<IAudioIn>> out_audio_in,
|
Out<SharedPointer<IAudioIn>> out_audio_in,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
||||||
AudioInParameter parameter,
|
AudioCore::AudioIn::AudioInParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle,
|
InCopyHandle<Kernel::KProcess> process_handle,
|
||||||
ClientAppletResourceUserId aruid) {
|
ClientAppletResourceUserId aruid) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
@@ -53,9 +55,9 @@ Result IAudioInManager::ListAudioInsAuto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioInManager::OpenAudioInAuto(
|
Result IAudioInManager::OpenAudioInAuto(
|
||||||
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
|
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioCore::AudioIn::AudioInParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
|
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
|
||||||
@@ -70,10 +72,10 @@ Result IAudioInManager::ListAudioInsAutoFiltered(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioInManager::OpenAudioInProtocolSpecified(
|
Result IAudioInManager::OpenAudioInProtocolSpecified(
|
||||||
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
|
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
|
||||||
AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
|
AudioCore::AudioIn::AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
|
||||||
ClientAppletResourceUserId aruid) {
|
ClientAppletResourceUserId aruid) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
|
|||||||
|
|
||||||
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
||||||
*out_parameter_internal =
|
*out_parameter_internal =
|
||||||
AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
AudioCore::AudioIn::AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
||||||
.channel_count = out_system.GetChannelCount(),
|
.channel_count = out_system.GetChannelCount(),
|
||||||
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
||||||
.state = static_cast<u32>(out_system.GetState())};
|
.state = static_cast<u32>(out_system.GetState())};
|
||||||
|
|||||||
@@ -13,10 +13,9 @@
|
|||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioOut;
|
|
||||||
|
|
||||||
IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
|
IAudioOut::IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, size_t session_id,
|
||||||
const std::string& device_name, const AudioOutParameter& in_params,
|
const std::string& device_name, const AudioCore::AudioOut::AudioOutParameter& in_params,
|
||||||
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
||||||
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
|
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
|
||||||
event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
|
event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
|
||||||
@@ -68,12 +67,12 @@ Result IAudioOut::Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOut::AppendAudioOutBuffer(
|
Result IAudioOut::AppendAudioOutBuffer(
|
||||||
InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
|
InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
|
||||||
R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
|
R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOut::AppendAudioOutBufferAuto(
|
Result IAudioOut::AppendAudioOutBufferAuto(
|
||||||
InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
|
InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
|
||||||
if (audio_out_buffer.empty()) {
|
if (audio_out_buffer.empty()) {
|
||||||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
|
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
|
||||||
R_THROW(Audio::ResultInsufficientBuffer);
|
R_THROW(Audio::ResultInsufficientBuffer);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioOut;
|
|
||||||
|
|
||||||
IAudioOutManager::IAudioOutManager(Core::System& system_)
|
IAudioOutManager::IAudioOutManager(Core::System& system_)
|
||||||
: ServiceFramework{system_, "audout:u"}
|
: ServiceFramework{system_, "audout:u"}
|
||||||
@@ -36,11 +35,11 @@ Result IAudioOutManager::ListAudioOuts(
|
|||||||
R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
|
R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
|
Result IAudioOutManager::OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
|
||||||
Out<SharedPointer<IAudioOut>> out_audio_out,
|
Out<SharedPointer<IAudioOut>> out_audio_out,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
||||||
AudioOutParameter parameter,
|
AudioCore::AudioOut::AudioOutParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle,
|
InCopyHandle<Kernel::KProcess> process_handle,
|
||||||
ClientAppletResourceUserId aruid) {
|
ClientAppletResourceUserId aruid) {
|
||||||
R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
|
R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
|
||||||
@@ -62,10 +61,10 @@ Result IAudioOutManager::ListAudioOutsAuto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOutManager::OpenAudioOutAuto(
|
Result IAudioOutManager::OpenAudioOutAuto(
|
||||||
Out<AudioOutParameterInternal> out_parameter_internal,
|
Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
|
||||||
Out<SharedPointer<IAudioOut>> out_audio_out,
|
Out<SharedPointer<IAudioOut>> out_audio_out,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
|
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioCore::AudioOut::AudioOutParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
||||||
if (!process_handle) {
|
if (!process_handle) {
|
||||||
LOG_ERROR(Service_Audio, "Failed to get process handle");
|
LOG_ERROR(Service_Audio, "Failed to get process handle");
|
||||||
@@ -95,7 +94,7 @@ Result IAudioOutManager::OpenAudioOutAuto(
|
|||||||
|
|
||||||
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
||||||
*out_parameter_internal =
|
*out_parameter_internal =
|
||||||
AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
AudioCore::AudioOut::AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
||||||
.channel_count = out_system.GetChannelCount(),
|
.channel_count = out_system.GetChannelCount(),
|
||||||
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
||||||
.state = static_cast<u32>(out_system.GetState())};
|
.state = static_cast<u32>(out_system.GetState())};
|
||||||
|
|||||||
@@ -4,21 +4,20 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "audio_core/renderer/audio_renderer.h"
|
||||||
#include "core/hle/service/audio/audio_renderer.h"
|
#include "core/hle/service/audio/audio_renderer.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::Renderer;
|
|
||||||
|
|
||||||
IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
|
IAudioRenderer::IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
|
||||||
AudioCore::AudioRendererParameterInternal& params,
|
AudioCore::AudioRendererParameterInternal& params,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
||||||
Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
|
Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
|
||||||
s32 session_id)
|
s32 session_id)
|
||||||
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
|
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
|
||||||
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
|
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
|
||||||
impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
|
impl{std::make_unique<AudioCore::Renderer::Renderer>(system_, manager, rendered_event)}, process_handle{process_handle_} {
|
||||||
process_handle_} {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
|
{0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ static u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
|
IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_)
|
||||||
: ServiceFramework{system_, "IBcatService"}, backend{backend_},
|
: ServiceFramework{system_, "IBcatService"}, backend{backend_}, program_id{program_id_},
|
||||||
progress{{
|
progress{{
|
||||||
ProgressServiceBackend{system_, "Normal"},
|
ProgressServiceBackend{system_, "Normal"},
|
||||||
ProgressServiceBackend{system_, "Directory"},
|
ProgressServiceBackend{system_, "Directory"},
|
||||||
@@ -70,8 +70,7 @@ Result IBcatService::RequestSyncDeliveryCache(
|
|||||||
LOG_DEBUG(Service_BCAT, "called");
|
LOG_DEBUG(Service_BCAT, "called");
|
||||||
|
|
||||||
auto& progress_backend{GetProgressBackend(SyncType::Normal)};
|
auto& progress_backend{GetProgressBackend(SyncType::Normal)};
|
||||||
backend.Synchronize(system.Kernel(), {system.GetApplicationProcessProgramID(),
|
backend.Synchronize(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())},
|
||||||
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
|
|
||||||
GetProgressBackend(SyncType::Normal));
|
GetProgressBackend(SyncType::Normal));
|
||||||
|
|
||||||
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
|
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
|
||||||
@@ -86,9 +85,8 @@ Result IBcatService::RequestSyncDeliveryCacheWithDirectoryName(
|
|||||||
LOG_DEBUG(Service_BCAT, "called, name={}", name);
|
LOG_DEBUG(Service_BCAT, "called, name={}", name);
|
||||||
|
|
||||||
auto& progress_backend{GetProgressBackend(SyncType::Directory)};
|
auto& progress_backend{GetProgressBackend(SyncType::Directory)};
|
||||||
backend.SynchronizeDirectory(system.Kernel(), {system.GetApplicationProcessProgramID(),
|
backend.SynchronizeDirectory(system.Kernel(), {program_id, GetCurrentBuildID(system.GetApplicationProcessBuildID())},
|
||||||
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
|
name, progress_backend);
|
||||||
name, progress_backend);
|
|
||||||
|
|
||||||
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
|
*out_interface = std::make_shared<IDeliveryCacheProgressService>(
|
||||||
system, progress_backend.GetEvent(), progress_backend.GetImpl());
|
system, progress_backend.GetEvent(), progress_backend.GetImpl());
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -19,7 +22,7 @@ class IDeliveryCacheProgressService;
|
|||||||
|
|
||||||
class IBcatService final : public ServiceFramework<IBcatService> {
|
class IBcatService final : public ServiceFramework<IBcatService> {
|
||||||
public:
|
public:
|
||||||
explicit IBcatService(Core::System& system_, BcatBackend& backend_);
|
explicit IBcatService(Core::System& system_, BcatBackend& backend_, u64 program_id_);
|
||||||
~IBcatService() override;
|
~IBcatService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -39,6 +42,7 @@ private:
|
|||||||
const ProgressServiceBackend& GetProgressBackend(SyncType type) const;
|
const ProgressServiceBackend& GetProgressBackend(SyncType type) const;
|
||||||
|
|
||||||
BcatBackend& backend;
|
BcatBackend& backend;
|
||||||
|
u64 program_id;
|
||||||
std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
|
std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,13 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::string_view ToStringView(std::span<const char> buf) {
|
[[nodiscard]] inline std::string_view ToStringViewNDS(std::span<const char> buf) {
|
||||||
const std::string_view sv{buf.data(), buf.size()};
|
const std::string_view sv{buf.data(), buf.size()};
|
||||||
const auto nul = sv.find('\0');
|
const auto nul = sv.find('\0');
|
||||||
return nul == std::string_view::npos ? sv : sv.substr(0, nul);
|
return nul == std::string_view::npos ? sv : sv.substr(0, nul);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
INewsDataService::INewsDataService(Core::System& system_)
|
INewsDataService::INewsDataService(Core::System& system_)
|
||||||
: ServiceFramework{system_, "INewsDataService"} {
|
: ServiceFramework{system_, "INewsDataService"} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
@@ -55,7 +52,7 @@ bool INewsDataService::TryOpen(std::string_view key, std::string_view user) {
|
|||||||
|
|
||||||
const auto list = NewsStorage::Instance().ListAll();
|
const auto list = NewsStorage::Instance().ListAll();
|
||||||
if (!list.empty()) {
|
if (!list.empty()) {
|
||||||
if (auto found = NewsStorage::Instance().FindByNewsId(ToStringView(list.front().news_id))) {
|
if (auto found = NewsStorage::Instance().FindByNewsId(ToStringViewNDS(list.front().news_id))) {
|
||||||
opened_payload = std::move(found->payload);
|
opened_payload = std::move(found->payload);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -67,7 +64,7 @@ bool INewsDataService::TryOpen(std::string_view key, std::string_view user) {
|
|||||||
Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
|
Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
|
||||||
EnsureBuiltinNewsLoaded();
|
EnsureBuiltinNewsLoaded();
|
||||||
|
|
||||||
const auto key = ToStringView({reinterpret_cast<const char*>(name.data()), name.size()});
|
const auto key = ToStringViewNDS({reinterpret_cast<const char*>(name.data()), name.size()});
|
||||||
|
|
||||||
if (TryOpen(key, {})) {
|
if (TryOpen(key, {})) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -79,8 +76,8 @@ Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
|
|||||||
Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
|
Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
|
||||||
EnsureBuiltinNewsLoaded();
|
EnsureBuiltinNewsLoaded();
|
||||||
|
|
||||||
const auto key = ToStringView(record.news_id);
|
const auto key = ToStringViewNDS(record.news_id);
|
||||||
const auto user = ToStringView(record.user_id);
|
const auto user = ToStringViewNDS(record.user_id);
|
||||||
|
|
||||||
if (TryOpen(key, user)) {
|
if (TryOpen(key, user)) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -92,8 +89,8 @@ Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
|
|||||||
Result INewsDataService::OpenWithNewsRecord(NewsRecord record) {
|
Result INewsDataService::OpenWithNewsRecord(NewsRecord record) {
|
||||||
EnsureBuiltinNewsLoaded();
|
EnsureBuiltinNewsLoaded();
|
||||||
|
|
||||||
const auto key = ToStringView(record.news_id);
|
const auto key = ToStringViewNDS(record.news_id);
|
||||||
const auto user = ToStringView(record.user_id);
|
const auto user = ToStringViewNDS(record.user_id);
|
||||||
|
|
||||||
if (TryOpen(key, user)) {
|
if (TryOpen(key, user)) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -15,13 +15,13 @@
|
|||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string_view ToStringView(std::span<const u8> buf) {
|
[[nodiscard]] inline std::string_view ToStringView(std::span<const u8> buf) {
|
||||||
if (buf.empty()) return {};
|
if (buf.empty()) return {};
|
||||||
auto data = reinterpret_cast<const char*>(buf.data());
|
auto data = reinterpret_cast<const char*>(buf.data());
|
||||||
return {data, strnlen(data, buf.size())};
|
return {data, strnlen(data, buf.size())};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view ToStringView(std::span<const char> buf) {
|
[[nodiscard]] inline std::string_view ToStringView(std::span<const char> buf) {
|
||||||
if (buf.empty()) return {};
|
if (buf.empty()) return {};
|
||||||
return {buf.data(), strnlen(buf.data(), buf.size())};
|
return {buf.data(), strnlen(buf.data(), buf.size())};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -6,6 +9,8 @@
|
|||||||
|
|
||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
|
|
||||||
|
#undef CreateEvent
|
||||||
|
|
||||||
IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
|
IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
|
||||||
: ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_,
|
: ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_,
|
||||||
"IOverwriteEventHolder"} {
|
"IOverwriteEventHolder"} {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/service/bcat/bcat_service.h"
|
#include "core/hle/service/bcat/bcat_service.h"
|
||||||
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
|
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
|
||||||
#include "core/hle/service/bcat/service_creator.h"
|
#include "core/hle/service/bcat/service_creator.h"
|
||||||
@@ -37,7 +41,8 @@ IServiceCreator::~IServiceCreator() = default;
|
|||||||
Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
|
Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
|
||||||
OutInterface<IBcatService> out_interface) {
|
OutInterface<IBcatService> out_interface) {
|
||||||
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
|
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
|
||||||
*out_interface = std::make_shared<IBcatService>(system, *backend);
|
*out_interface =
|
||||||
|
std::make_shared<IBcatService>(system, *backend, system.ResolveCallerProgramId(*process_id));
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +50,7 @@ Result IServiceCreator::CreateDeliveryCacheStorageService(
|
|||||||
ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
|
ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
|
||||||
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
|
LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
|
||||||
|
|
||||||
const auto title_id = system.GetApplicationProcessProgramID();
|
const auto title_id = system.ResolveCallerProgramId(*process_id);
|
||||||
*out_interface =
|
*out_interface =
|
||||||
std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
|
std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
|
|
||||||
|
#undef GetCurrentTime
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
|
||||||
AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
|
AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
|
||||||
@@ -243,10 +245,15 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
|||||||
return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid);
|
return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, AlbumReportOption report_option, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) {
|
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
|
const ScreenShotAttribute& attribute,
|
||||||
|
AlbumReportOption report_option,
|
||||||
|
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||||
|
u64 aruid) {
|
||||||
R_UNLESS(!image_data.empty(), ResultUnknown); //TODO: ???
|
R_UNLESS(!image_data.empty(), ResultUnknown); //TODO: ???
|
||||||
|
|
||||||
const u64 title_id = system.GetApplicationProcessProgramID();
|
const u64 title_id = system.ResolveCallerProgramId(aruid);
|
||||||
|
|
||||||
auto static_service =
|
auto static_service =
|
||||||
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
|
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
|
|||||||
manager->FlipVerticallyOnWrite(invert_y);
|
manager->FlipVerticallyOnWrite(invert_y);
|
||||||
manager->SaveScreenShot(entry, attribute, report_option, image_data, {});
|
manager->SaveScreenShot(entry, attribute, report_option, image_data, {});
|
||||||
},
|
},
|
||||||
layout);
|
layout,
|
||||||
|
Nvnflinger::LayerStackId::Screenshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/reporter.h"
|
#include "core/reporter.h"
|
||||||
|
|
||||||
|
#undef far
|
||||||
|
|
||||||
namespace Service::Fatal {
|
namespace Service::Fatal {
|
||||||
|
|
||||||
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
|
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
|
||||||
|
|||||||
@@ -32,6 +32,10 @@
|
|||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
namespace Service::FileSystem {
|
||||||
|
|
||||||
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
||||||
|
|||||||
@@ -1164,7 +1164,7 @@ Result IHidServer::InitializeSevenSixAxisSensor(ClientAppletResourceUserId aruid
|
|||||||
GetResourceManager()->GetConsoleSixAxis()->Activate();
|
GetResourceManager()->GetConsoleSixAxis()->Activate();
|
||||||
GetResourceManager()->GetSevenSixAxis()->Activate();
|
GetResourceManager()->GetSevenSixAxis()->Activate();
|
||||||
|
|
||||||
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
|
GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress(), t_mem_1->GetOwner());
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ Result Hidbus::EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode pollin
|
|||||||
|
|
||||||
auto& device = devices[device_index.value()].device;
|
auto& device = devices[device_index.value()].device;
|
||||||
device->SetPollingMode(polling_mode);
|
device->SetPollingMode(polling_mode);
|
||||||
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
device->SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner());
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -147,7 +150,7 @@ Result IRS::RunImageTransferProcessor(
|
|||||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
||||||
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
||||||
image_transfer_processor.SetConfig(processor_config);
|
image_transfer_processor.SetConfig(processor_config);
|
||||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(), t_mem->GetOwner());
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||||
Common::Input::PollingMode::IR);
|
Common::Input::PollingMode::IR);
|
||||||
|
|
||||||
@@ -295,7 +298,8 @@ Result IRS::RunImageTransferExProcessor(
|
|||||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
||||||
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
||||||
image_transfer_processor.SetConfig(processor_config);
|
image_transfer_processor.SetConfig(processor_config);
|
||||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress(),
|
||||||
|
t_mem->GetOwner());
|
||||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||||
Common::Input::PollingMode::IR);
|
Common::Input::PollingMode::IR);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
#undef SendMessage
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
|
||||||
SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
|
SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
, process{kernel, process_}
|
, process{kernel, process_}
|
||||||
, user_rx{std::move(user_rx_)}
|
, user_rx{std::move(user_rx_)}
|
||||||
, user_ro{std::move(user_ro_)}
|
, user_ro{std::move(user_ro_)}
|
||||||
, context{system_.ApplicationMemory()}
|
, context{process_->GetMemory()}
|
||||||
{
|
{
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|||||||
@@ -212,8 +212,9 @@ struct NifmNetworkProfileData {
|
|||||||
NifmWirelessSettingData wireless_setting_data{};
|
NifmWirelessSettingData wireless_setting_data{};
|
||||||
IpSettingData ip_setting_data{};
|
IpSettingData ip_setting_data{};
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
|
||||||
|
"NifmNetworkProfileData has incorrect size.");
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size.");
|
|
||||||
|
|
||||||
struct PendingProfile {
|
struct PendingProfile {
|
||||||
std::array<char, 0x21> ssid{};
|
std::array<char, 0x21> ssid{};
|
||||||
|
|||||||
@@ -9,15 +9,12 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define STBI_ONLY_JPEG 1
|
#include "common/stb.h"
|
||||||
#include <stb_image.h>
|
|
||||||
#include <stb_image_resize.h>
|
|
||||||
#include <stb_image_write.h>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_transfer_memory.h"
|
#include "core/hle/kernel/k_transfer_memory.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ns/language.h"
|
#include "core/hle/service/ns/language.h"
|
||||||
@@ -336,8 +333,8 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
|
|||||||
|
|
||||||
constexpr s32 data_offset = 0;
|
constexpr s32 data_offset = 0;
|
||||||
|
|
||||||
if (t_mem != nullptr && app_count > 0) {
|
if (t_mem != nullptr && t_mem->GetOwner() != nullptr && app_count > 0) {
|
||||||
auto& memory = system.ApplicationMemory();
|
auto& memory = t_mem->GetOwner()->GetMemory();
|
||||||
const auto t_mem_address = t_mem->GetSourceAddress();
|
const auto t_mem_address = t_mem->GetSourceAddress();
|
||||||
|
|
||||||
for (size_t i = 0; i < app_count; ++i) {
|
for (size_t i = 0; i < app_count; ++i) {
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
|
|||||||
.transform_flags = layer.transform,
|
.transform_flags = layer.transform,
|
||||||
.crop_rect = layer.crop_rect,
|
.crop_rect = layer.crop_rect,
|
||||||
.blending = ConvertBlending(layer.blending),
|
.blending = ConvertBlending(layer.blending),
|
||||||
|
.layer_stack_mask = layer.layer_stack_mask,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
|
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||||||
case 0x3:
|
case 0x3:
|
||||||
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
|
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
|
||||||
case 0x8:
|
case 0x8:
|
||||||
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
|
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, false);
|
||||||
case 0x9:
|
case 0x9:
|
||||||
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
|
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
|
||||||
case 0xb:
|
case 0xb:
|
||||||
@@ -83,7 +83,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||||||
case 0x1a:
|
case 0x1a:
|
||||||
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output, fd);
|
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output, fd);
|
||||||
case 0x1b:
|
case 0x1b:
|
||||||
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
|
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, fd, true);
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
|
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
|
||||||
default:
|
default:
|
||||||
@@ -387,8 +387,19 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
|
|||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core::Memory::Memory& nvhost_gpu::GetSessionMemory(DeviceFD fd) {
|
||||||
|
if (const auto it = sessions.find(fd); it != sessions.end())
|
||||||
|
if (auto* const session = core.GetSession(it->second);
|
||||||
|
session != nullptr && session->process != nullptr)
|
||||||
|
return session->process->GetMemory();
|
||||||
|
|
||||||
|
LOG_ERROR(Service_NVDRV, "No session for fd={}, falling back to application memory", fd);
|
||||||
|
return system.ApplicationMemory();
|
||||||
|
}
|
||||||
|
|
||||||
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||||
std::span<Tegra::CommandListHeader> commands, bool kickoff) {
|
std::span<Tegra::CommandListHeader> commands, DeviceFD fd,
|
||||||
|
bool kickoff) {
|
||||||
if (params.num_entries > commands.size()) {
|
if (params.num_entries > commands.size()) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return NvResult::InvalidSize;
|
return NvResult::InvalidSize;
|
||||||
@@ -396,7 +407,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
|||||||
|
|
||||||
Tegra::CommandList entries(params.num_entries);
|
Tegra::CommandList entries(params.num_entries);
|
||||||
if (kickoff) {
|
if (kickoff) {
|
||||||
system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
|
this->GetSessionMemory(fd).ReadBlock(params.address, entries.command_lists.data(),
|
||||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||||
} else {
|
} else {
|
||||||
std::memcpy(entries.command_lists.data(), commands.data(),
|
std::memcpy(entries.command_lists.data(), commands.data(),
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
#include "video_core/dma_pusher.h"
|
#include "video_core/dma_pusher.h"
|
||||||
|
|
||||||
|
namespace Core::Memory {
|
||||||
|
class Memory;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Tegra {
|
namespace Tegra {
|
||||||
namespace Control {
|
namespace Control {
|
||||||
struct ChannelState;
|
struct ChannelState;
|
||||||
@@ -196,8 +200,11 @@ private:
|
|||||||
|
|
||||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
|
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
|
||||||
|
|
||||||
|
Core::Memory::Memory& GetSessionMemory(DeviceFD fd);
|
||||||
|
|
||||||
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||||
std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
|
std::span<Tegra::CommandListHeader> commands, DeviceFD fd,
|
||||||
|
bool kickoff = false);
|
||||||
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||||
std::span<const Tegra::CommandListHeader> commands);
|
std::span<const Tegra::CommandListHeader> commands);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -15,7 +15,8 @@ struct Layer {
|
|||||||
explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
|
explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
|
||||||
s32 consumer_id_)
|
s32 consumer_id_)
|
||||||
: buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
|
: buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
|
||||||
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false) {}
|
blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false),
|
||||||
|
layer_stack_mask(DefaultLayerStackMask) {}
|
||||||
~Layer() {
|
~Layer() {
|
||||||
buffer_item_consumer->Abandon();
|
buffer_item_consumer->Abandon();
|
||||||
}
|
}
|
||||||
@@ -26,6 +27,7 @@ struct Layer {
|
|||||||
bool visible;
|
bool visible;
|
||||||
s32 z_index;
|
s32 z_index;
|
||||||
bool is_overlay;
|
bool is_overlay;
|
||||||
|
u32 layer_stack_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LayerStack {
|
struct LayerStack {
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
|
|||||||
.transform = static_cast<android::BufferTransformFlags>(item.transform),
|
.transform = static_cast<android::BufferTransformFlags>(item.transform),
|
||||||
.crop_rect = item.crop,
|
.crop_rect = item.crop,
|
||||||
.acquire_fence = item.fence,
|
.acquire_fence = item.fence,
|
||||||
|
.layer_stack_mask = layer->layer_stack_mask,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -23,6 +26,25 @@ enum class LayerBlending : u32 {
|
|||||||
Coverage = 0x405,
|
Coverage = 0x405,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class LayerStackId : u32 {
|
||||||
|
Default = 0,
|
||||||
|
Lcd = 1,
|
||||||
|
Screenshot = 2,
|
||||||
|
Recording = 3,
|
||||||
|
LastFrame = 4,
|
||||||
|
Arbitrary = 5,
|
||||||
|
ApplicationForDebug = 6,
|
||||||
|
Null = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr u32 LayerStackBit(LayerStackId id) {
|
||||||
|
return 1U << static_cast<u32>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr u32 DefaultLayerStackMask =
|
||||||
|
LayerStackBit(LayerStackId::Default) | LayerStackBit(LayerStackId::Screenshot) |
|
||||||
|
LayerStackBit(LayerStackId::Recording) | LayerStackBit(LayerStackId::LastFrame);
|
||||||
|
|
||||||
struct HwcLayer {
|
struct HwcLayer {
|
||||||
u32 buffer_handle;
|
u32 buffer_handle;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
@@ -35,6 +57,7 @@ struct HwcLayer {
|
|||||||
android::BufferTransformFlags transform;
|
android::BufferTransformFlags transform;
|
||||||
Common::Rectangle<int> crop_rect;
|
Common::Rectangle<int> crop_rect;
|
||||||
android::Fence acquire_fence;
|
android::Fence acquire_fence;
|
||||||
|
u32 layer_stack_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvnflinger
|
} // namespace Service::Nvnflinger
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -104,6 +104,14 @@ void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SurfaceFlinger::SetLayerStackMask(s32 consumer_binder_id, u32 layer_stack_mask) {
|
||||||
|
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
|
||||||
|
layer->layer_stack_mask = layer_stack_mask;
|
||||||
|
LOG_DEBUG(Service_VI, "Layer {} stack mask set to {:#x}", consumer_binder_id,
|
||||||
|
layer_stack_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SurfaceFlinger::SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay) {
|
void SurfaceFlinger::SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay) {
|
||||||
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
|
if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
|
||||||
layer->is_overlay = is_overlay;
|
layer->is_overlay = is_overlay;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -48,6 +48,7 @@ public:
|
|||||||
void SetLayerVisibility(s32 consumer_binder_id, bool visible);
|
void SetLayerVisibility(s32 consumer_binder_id, bool visible);
|
||||||
void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
|
void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
|
||||||
void SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay);
|
void SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay);
|
||||||
|
void SetLayerStackMask(s32 consumer_binder_id, u32 layer_stack_mask);
|
||||||
|
|
||||||
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
|
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -13,8 +13,10 @@
|
|||||||
|
|
||||||
namespace Service::PCTL {
|
namespace Service::PCTL {
|
||||||
|
|
||||||
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
|
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_,
|
||||||
|
u64 program_id_)
|
||||||
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
|
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
|
||||||
|
program_id{program_id_},
|
||||||
service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
|
service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
|
||||||
unlinked_event{service_context}, request_suspension_event{service_context} {
|
unlinked_event{service_context}, request_suspension_event{service_context} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -202,7 +204,6 @@ Result IParentalControlService::Initialize() {
|
|||||||
|
|
||||||
// TODO(ogniK): Recovery flag initialization for pctl:r
|
// TODO(ogniK): Recovery flag initialization for pctl:r
|
||||||
|
|
||||||
const auto program_id = system.GetApplicationProcessProgramID();
|
|
||||||
if (program_id != 0) {
|
if (program_id != 0) {
|
||||||
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
|
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
|
||||||
system.GetContentProvider()};
|
system.GetContentProvider()};
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ namespace Service::PCTL {
|
|||||||
|
|
||||||
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
|
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
|
||||||
public:
|
public:
|
||||||
explicit IParentalControlService(Core::System& system_, Capability capability_);
|
explicit IParentalControlService(Core::System& system_, Capability capability_,
|
||||||
|
u64 program_id_);
|
||||||
~IParentalControlService() override;
|
~IParentalControlService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -84,6 +85,7 @@ private:
|
|||||||
RestrictionSettings restriction_settings{};
|
RestrictionSettings restriction_settings{};
|
||||||
std::array<char, 8> pin_code{};
|
std::array<char, 8> pin_code{};
|
||||||
Capability capability{};
|
Capability capability{};
|
||||||
|
u64 program_id{};
|
||||||
// TODO: this is raw
|
// TODO: this is raw
|
||||||
PlayTimerSettings raw_play_timer_settings{};
|
PlayTimerSettings raw_play_timer_settings{};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/pctl/parental_control_service.h"
|
#include "core/hle/service/pctl/parental_control_service.h"
|
||||||
#include "core/hle/service/pctl/parental_control_service_factory.h"
|
#include "core/hle/service/pctl/parental_control_service_factory.h"
|
||||||
@@ -23,17 +27,17 @@ IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
|
|||||||
|
|
||||||
Result IParentalControlServiceFactory::CreateService(
|
Result IParentalControlServiceFactory::CreateService(
|
||||||
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
|
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
|
||||||
LOG_DEBUG(Service_PCTL, "called");
|
LOG_DEBUG(Service_PCTL, "called, process_id={}", process_id.pid);
|
||||||
// TODO(ogniK): Get application id from process
|
*out_service = std::make_shared<IParentalControlService>(
|
||||||
*out_service = std::make_shared<IParentalControlService>(system, capability);
|
system, capability, system.ResolveCallerProgramId(*process_id));
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
|
Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
|
||||||
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
|
Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
|
||||||
LOG_DEBUG(Service_PCTL, "called");
|
LOG_DEBUG(Service_PCTL, "called, process_id={}", process_id.pid);
|
||||||
// TODO(ogniK): Get application id from process
|
*out_service = std::make_shared<IParentalControlService>(
|
||||||
*out_service = std::make_shared<IParentalControlService>(system, capability);
|
system, capability, system.ResolveCallerProgramId(*process_id));
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,8 +132,7 @@ private:
|
|||||||
|
|
||||||
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
|
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
|
||||||
|
|
||||||
auto list = kernel.GetProcessList();
|
auto process = kernel.GetProcessByProcessId(pid);
|
||||||
auto process = SearchProcessList(system.Kernel(), list, [pid](auto& p) { return p->GetProcessId() == pid; });
|
|
||||||
|
|
||||||
if (process.IsNull()) {
|
if (process.IsNull()) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@@ -186,9 +185,7 @@ private:
|
|||||||
|
|
||||||
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
|
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
|
||||||
|
|
||||||
auto list = kernel.GetProcessList();
|
auto process = kernel.GetProcessByProcessId(process_id);
|
||||||
auto process = SearchProcessList(system.Kernel(),
|
|
||||||
list, [process_id](auto& p) { return p->GetProcessId() == process_id; });
|
|
||||||
|
|
||||||
if (process.IsNull()) {
|
if (process.IsNull()) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ private:
|
|||||||
Type, process_id, data1.size(), data2.size());
|
Type, process_id, data1.size(), data2.size());
|
||||||
|
|
||||||
const auto& reporter{system.GetReporter()};
|
const auto& reporter{system.GetReporter()};
|
||||||
reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
|
reporter.SavePlayReport(Type, system.ResolveCallerProgramId(process_id), {data1, data2},
|
||||||
process_id);
|
process_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@@ -98,7 +98,7 @@ private:
|
|||||||
Type, user_id[1], user_id[0], process_id, data1.size(), data2.size());
|
Type, user_id[1], user_id[0], process_id, data1.size(), data2.size());
|
||||||
|
|
||||||
const auto& reporter{system.GetReporter()};
|
const auto& reporter{system.GetReporter()};
|
||||||
reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
|
reporter.SavePlayReport(Type, system.ResolveCallerProgramId(process_id), {data1, data2},
|
||||||
process_id, user_id);
|
process_id, user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -10,6 +13,8 @@
|
|||||||
namespace Service::PSC::Time {
|
namespace Service::PSC::Time {
|
||||||
class ContextWriter;
|
class ContextWriter;
|
||||||
|
|
||||||
|
#undef GetCurrentTime
|
||||||
|
|
||||||
class SystemClockCore {
|
class SystemClockCore {
|
||||||
public:
|
public:
|
||||||
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
|
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ class System;
|
|||||||
|
|
||||||
namespace Service::PSC::Time {
|
namespace Service::PSC::Time {
|
||||||
|
|
||||||
|
#undef GetCurrentTime
|
||||||
|
|
||||||
class SystemClock final : public ServiceFramework<SystemClock> {
|
class SystemClock final : public ServiceFramework<SystemClock> {
|
||||||
public:
|
public:
|
||||||
explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, bool can_write_clock, bool can_write_uninitialized_clock);
|
explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, bool can_write_clock, bool can_write_uninitialized_clock);
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ void PutValue(std::span<u8> buffer, const T& t) {
|
|||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void BSD::PollWork::Execute(BSD* bsd) {
|
void NetworkBSD::PollWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
|
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::PollWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::PollWork::Response(HLERequestContext& ctx) {
|
||||||
if (write_buffer.size() > 0) {
|
if (write_buffer.size() > 0) {
|
||||||
ctx.WriteBuffer(write_buffer);
|
ctx.WriteBuffer(write_buffer);
|
||||||
}
|
}
|
||||||
@@ -69,11 +69,11 @@ void BSD::PollWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::AcceptWork::Execute(BSD* bsd) {
|
void NetworkBSD::AcceptWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
|
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::AcceptWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::AcceptWork::Response(HLERequestContext& ctx) {
|
||||||
if (write_buffer.size() > 0) {
|
if (write_buffer.size() > 0) {
|
||||||
ctx.WriteBuffer(write_buffer);
|
ctx.WriteBuffer(write_buffer);
|
||||||
}
|
}
|
||||||
@@ -85,22 +85,22 @@ void BSD::AcceptWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::ConnectWork::Execute(BSD* bsd) {
|
void NetworkBSD::ConnectWork::Execute(NetworkBSD* bsd) {
|
||||||
bsd_errno = bsd->ConnectImpl(fd, addr);
|
bsd_errno = bsd->ConnectImpl(fd, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::ConnectWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::ConnectWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvWork::Execute(BSD* bsd) {
|
void NetworkBSD::RecvWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
|
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::RecvWork::Response(HLERequestContext& ctx) {
|
||||||
ctx.WriteBuffer(message);
|
ctx.WriteBuffer(message);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
@@ -109,11 +109,11 @@ void BSD::RecvWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvFromWork::Execute(BSD* bsd) {
|
void NetworkBSD::RecvFromWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
|
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::RecvFromWork::Response(HLERequestContext& ctx) {
|
||||||
ctx.WriteBuffer(message, 0);
|
ctx.WriteBuffer(message, 0);
|
||||||
if (!addr.empty()) {
|
if (!addr.empty()) {
|
||||||
ctx.WriteBuffer(addr, 1);
|
ctx.WriteBuffer(addr, 1);
|
||||||
@@ -126,29 +126,29 @@ void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(addr.size()));
|
rb.Push<u32>(static_cast<u32>(addr.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendWork::Execute(BSD* bsd) {
|
void NetworkBSD::SendWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
|
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::SendWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(ret);
|
rb.Push<s32>(ret);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendToWork::Execute(BSD* bsd) {
|
void NetworkBSD::SendToWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
|
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendToWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::SendToWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(ret);
|
rb.Push<s32>(ret);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RegisterClient(HLERequestContext& ctx) {
|
void NetworkBSD::RegisterClient(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service, "(STUBBED) called");
|
LOG_WARNING(Service, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
@@ -157,7 +157,7 @@ void BSD::RegisterClient(HLERequestContext& ctx) {
|
|||||||
rb.Push<s32>(0); // bsd errno
|
rb.Push<s32>(0); // bsd errno
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::StartMonitoring(HLERequestContext& ctx) {
|
void NetworkBSD::StartMonitoring(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service, "(STUBBED) called");
|
LOG_WARNING(Service, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@@ -165,7 +165,7 @@ void BSD::StartMonitoring(HLERequestContext& ctx) {
|
|||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Socket(HLERequestContext& ctx) {
|
void NetworkBSD::Socket(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u32 domain = rp.Pop<u32>();
|
const u32 domain = rp.Pop<u32>();
|
||||||
const u32 type = rp.Pop<u32>();
|
const u32 type = rp.Pop<u32>();
|
||||||
@@ -200,7 +200,7 @@ void BSD::SocketExempt(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Select(HLERequestContext& ctx) {
|
void NetworkBSD::Select(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service, "(STUBBED) called");
|
LOG_DEBUG(Service, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
@@ -210,7 +210,7 @@ void BSD::Select(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); // bsd errno
|
rb.Push<u32>(0); // bsd errno
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Poll(HLERequestContext& ctx) {
|
void NetworkBSD::Poll(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 nfds = rp.Pop<s32>();
|
const s32 nfds = rp.Pop<s32>();
|
||||||
const s32 timeout = rp.Pop<s32>();
|
const s32 timeout = rp.Pop<s32>();
|
||||||
@@ -225,7 +225,7 @@ void BSD::Poll(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Accept(HLERequestContext& ctx) {
|
void NetworkBSD::Accept(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ void BSD::Accept(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Bind(HLERequestContext& ctx) {
|
void NetworkBSD::Bind(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ void BSD::Bind(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
|
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Connect(HLERequestContext& ctx) {
|
void NetworkBSD::Connect(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ void BSD::Connect(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::GetPeerName(HLERequestContext& ctx) {
|
void NetworkBSD::GetPeerName(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ void BSD::GetPeerName(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::GetSockName(HLERequestContext& ctx) {
|
void NetworkBSD::GetSockName(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ void BSD::GetSockName(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::GetSockOpt(HLERequestContext& ctx) {
|
void NetworkBSD::GetSockOpt(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const u32 level = rp.Pop<u32>();
|
const u32 level = rp.Pop<u32>();
|
||||||
@@ -315,7 +315,7 @@ void BSD::GetSockOpt(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(optval.size()));
|
rb.Push<u32>(static_cast<u32>(optval.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Listen(HLERequestContext& ctx) {
|
void NetworkBSD::Listen(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const s32 backlog = rp.Pop<s32>();
|
const s32 backlog = rp.Pop<s32>();
|
||||||
@@ -325,7 +325,7 @@ void BSD::Listen(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
|
BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Fcntl(HLERequestContext& ctx) {
|
void NetworkBSD::Fcntl(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const s32 cmd = rp.Pop<s32>();
|
const s32 cmd = rp.Pop<s32>();
|
||||||
@@ -341,7 +341,7 @@ void BSD::Fcntl(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SetSockOpt(HLERequestContext& ctx) {
|
void NetworkBSD::SetSockOpt(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -355,7 +355,7 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Shutdown(HLERequestContext& ctx) {
|
void NetworkBSD::Shutdown(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -366,7 +366,7 @@ void BSD::Shutdown(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
|
BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Recv(HLERequestContext& ctx) {
|
void NetworkBSD::Recv(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -381,7 +381,7 @@ void BSD::Recv(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvFrom(HLERequestContext& ctx) {
|
void NetworkBSD::RecvFrom(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -398,7 +398,7 @@ void BSD::RecvFrom(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Send(HLERequestContext& ctx) {
|
void NetworkBSD::Send(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -413,7 +413,7 @@ void BSD::Send(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendTo(HLERequestContext& ctx) {
|
void NetworkBSD::SendTo(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const u32 flags = rp.Pop<u32>();
|
const u32 flags = rp.Pop<u32>();
|
||||||
@@ -429,7 +429,7 @@ void BSD::SendTo(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Write(HLERequestContext& ctx) {
|
void NetworkBSD::Write(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -442,7 +442,7 @@ void BSD::Write(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Read(HLERequestContext& ctx) {
|
void NetworkBSD::Read(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -454,7 +454,7 @@ void BSD::Read(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); // bsd errno
|
rb.Push<u32>(0); // bsd errno
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Close(HLERequestContext& ctx) {
|
void NetworkBSD::Close(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -464,7 +464,7 @@ void BSD::Close(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Only bsd:s is able to dup()
|
/// @brief Only bsd:s is able to dup()
|
||||||
void BSD::DuplicateSocket(HLERequestContext& ctx) {
|
void NetworkBSD::DuplicateSocket(HLERequestContext& ctx) {
|
||||||
struct InputParameters {
|
struct InputParameters {
|
||||||
s32 fd;
|
s32 fd;
|
||||||
u64 reserved;
|
u64 reserved;
|
||||||
@@ -505,7 +505,7 @@ void BSD::DuplicateSocket(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::EventFd(HLERequestContext& ctx) {
|
void NetworkBSD::EventFd(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 initval = rp.Pop<u64>();
|
const u64 initval = rp.Pop<u64>();
|
||||||
const u32 flags = rp.Pop<u32>();
|
const u32 flags = rp.Pop<u32>();
|
||||||
@@ -516,12 +516,12 @@ void BSD::EventFd(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Work>
|
template <typename Work>
|
||||||
void BSD::ExecuteWork(HLERequestContext& ctx, Work work) {
|
void NetworkBSD::ExecuteWork(HLERequestContext& ctx, Work work) {
|
||||||
work.Execute(this);
|
work.Execute(this);
|
||||||
work.Response(ctx);
|
work.Response(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
std::pair<s32, Errno> NetworkBSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
||||||
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
|
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
|
||||||
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
|
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
|
||||||
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
|
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
|
||||||
@@ -565,7 +565,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
|
|||||||
return {fd, Errno::SUCCESS};
|
return {fd, Errno::SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
std::pair<s32, Errno> NetworkBSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||||
s32 nfds, s32 timeout) {
|
s32 nfds, s32 timeout) {
|
||||||
if (nfds <= 0) {
|
if (nfds <= 0) {
|
||||||
// When no entries are provided, -1 is returned with errno zero
|
// When no entries are provided, -1 is returned with errno zero
|
||||||
@@ -632,7 +632,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
|
|||||||
return Translate(result);
|
return Translate(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
std::pair<s32, Errno> NetworkBSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -660,7 +660,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
return {new_fd, Errno::SUCCESS};
|
return {new_fd, Errno::SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
Errno NetworkBSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -675,7 +675,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
|||||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
Errno NetworkBSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -698,7 +698,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
Errno NetworkBSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -720,7 +720,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
Errno NetworkBSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -742,7 +742,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::ListenImpl(s32 fd, s32 backlog) {
|
Errno NetworkBSD::ListenImpl(s32 fd, s32 backlog) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -753,7 +753,7 @@ Errno BSD::ListenImpl(s32 fd, s32 backlog) {
|
|||||||
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
std::pair<s32, Errno> NetworkBSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -783,7 +783,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
Errno NetworkBSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -818,7 +818,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
Errno NetworkBSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -872,7 +872,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::ShutdownImpl(s32 fd, s32 how) {
|
Errno NetworkBSD::ShutdownImpl(s32 fd, s32 how) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -884,7 +884,7 @@ Errno BSD::ShutdownImpl(s32 fd, s32 how) {
|
|||||||
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
std::pair<s32, Errno> NetworkBSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -911,7 +911,7 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
|
|||||||
return {ret, bsd_errno};
|
return {ret, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
std::pair<s32, Errno> NetworkBSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||||
std::vector<u8>& addr) {
|
std::vector<u8>& addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
@@ -958,7 +958,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
|
|||||||
return {ret, bsd_errno};
|
return {ret, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
std::pair<s32, Errno> NetworkBSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -969,7 +969,7 @@ std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> messa
|
|||||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
std::pair<s32, Errno> NetworkBSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||||
std::span<const u8> addr) {
|
std::span<const u8> addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
@@ -991,7 +991,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
|
|||||||
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::CloseImpl(s32 fd) {
|
Errno NetworkBSD::CloseImpl(s32 fd) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -1011,7 +1011,7 @@ Errno BSD::CloseImpl(s32 fd) {
|
|||||||
return bsd_errno;
|
return bsd_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
std::variant<s32, Errno> NetworkBSD::DuplicateSocketImpl(s32 fd) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1030,7 @@ std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
|||||||
return new_fd;
|
return new_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
|
std::optional<std::shared_ptr<Network::SocketBase>> NetworkBSD::GetSocket(s32 fd) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1041,7 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
|
|||||||
return file_descriptors[fd]->socket;
|
return file_descriptors[fd]->socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 BSD::FindFreeFileDescriptorHandle() noexcept {
|
s32 NetworkBSD::FindFreeFileDescriptorHandle() noexcept {
|
||||||
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
||||||
if (!file_descriptors[fd]) {
|
if (!file_descriptors[fd]) {
|
||||||
return fd;
|
return fd;
|
||||||
@@ -1050,7 +1050,7 @@ s32 BSD::FindFreeFileDescriptorHandle() noexcept {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
bool NetworkBSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
||||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
||||||
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
||||||
return false;
|
return false;
|
||||||
@@ -1062,7 +1062,7 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
void NetworkBSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@@ -1070,7 +1070,7 @@ void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noex
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
void NetworkBSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
||||||
for (auto& optional_descriptor : file_descriptors) {
|
for (auto& optional_descriptor : file_descriptors) {
|
||||||
if (!optional_descriptor.has_value()) {
|
if (!optional_descriptor.has_value()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1080,43 +1080,43 @@ void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BSD::BSD(Core::System& system_, const char* name, bool is_user_)
|
NetworkBSD::NetworkBSD(Core::System& system_, const char* name, bool is_user_)
|
||||||
: ServiceFramework{system_, name}
|
: ServiceFramework{system_, name}
|
||||||
, is_user{is_user_} {
|
, is_user{is_user_} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
{0, &NetworkBSD::RegisterClient, "RegisterClient"},
|
||||||
{1, &BSD::StartMonitoring, "StartMonitoring"},
|
{1, &NetworkBSD::StartMonitoring, "StartMonitoring"},
|
||||||
{2, &BSD::Socket, "Socket"},
|
{2, &NetworkBSD::Socket, "Socket"},
|
||||||
{3, &BSD::SocketExempt, "SocketExempt"},
|
{3, &NetworkBSD::SocketExempt, "SocketExempt"},
|
||||||
{4, nullptr, "Open"},
|
{4, nullptr, "Open"},
|
||||||
{5, &BSD::Select, "Select"},
|
{5, &NetworkBSD::Select, "Select"},
|
||||||
{6, &BSD::Poll, "Poll"},
|
{6, &NetworkBSD::Poll, "Poll"},
|
||||||
{7, nullptr, "Sysctl"},
|
{7, nullptr, "Sysctl"},
|
||||||
{8, &BSD::Recv, "Recv"},
|
{8, &NetworkBSD::Recv, "Recv"},
|
||||||
{9, &BSD::RecvFrom, "RecvFrom"},
|
{9, &NetworkBSD::RecvFrom, "RecvFrom"},
|
||||||
{10, &BSD::Send, "Send"},
|
{10, &NetworkBSD::Send, "Send"},
|
||||||
{11, &BSD::SendTo, "SendTo"},
|
{11, &NetworkBSD::SendTo, "SendTo"},
|
||||||
{12, &BSD::Accept, "Accept"},
|
{12, &NetworkBSD::Accept, "Accept"},
|
||||||
{13, &BSD::Bind, "Bind"},
|
{13, &NetworkBSD::Bind, "Bind"},
|
||||||
{14, &BSD::Connect, "Connect"},
|
{14, &NetworkBSD::Connect, "Connect"},
|
||||||
{15, &BSD::GetPeerName, "GetPeerName"},
|
{15, &NetworkBSD::GetPeerName, "GetPeerName"},
|
||||||
{16, &BSD::GetSockName, "GetSockName"},
|
{16, &NetworkBSD::GetSockName, "GetSockName"},
|
||||||
{17, &BSD::GetSockOpt, "GetSockOpt"},
|
{17, &NetworkBSD::GetSockOpt, "GetSockOpt"},
|
||||||
{18, &BSD::Listen, "Listen"},
|
{18, &NetworkBSD::Listen, "Listen"},
|
||||||
{19, nullptr, "Ioctl"},
|
{19, nullptr, "Ioctl"},
|
||||||
{20, &BSD::Fcntl, "Fcntl"},
|
{20, &NetworkBSD::Fcntl, "Fcntl"},
|
||||||
{21, &BSD::SetSockOpt, "SetSockOpt"},
|
{21, &NetworkBSD::SetSockOpt, "SetSockOpt"},
|
||||||
{22, &BSD::Shutdown, "Shutdown"},
|
{22, &NetworkBSD::Shutdown, "Shutdown"},
|
||||||
{23, nullptr, "ShutdownAllSockets"},
|
{23, nullptr, "ShutdownAllSockets"},
|
||||||
{24, &BSD::Write, "Write"},
|
{24, &NetworkBSD::Write, "Write"},
|
||||||
{25, &BSD::Read, "Read"},
|
{25, &NetworkBSD::Read, "Read"},
|
||||||
{26, &BSD::Close, "Close"},
|
{26, &NetworkBSD::Close, "Close"},
|
||||||
{27, &BSD::DuplicateSocket, "DuplicateSocket"},
|
{27, &NetworkBSD::DuplicateSocket, "DuplicateSocket"},
|
||||||
{28, nullptr, "GetResourceStatistics"},
|
{28, nullptr, "GetResourceStatistics"},
|
||||||
{29, nullptr, "RecvMMsg"}, //3.0.0+
|
{29, nullptr, "RecvMMsg"}, //3.0.0+
|
||||||
{30, nullptr, "SendMMsg"}, //3.0.0+
|
{30, nullptr, "SendMMsg"}, //3.0.0+
|
||||||
{31, &BSD::EventFd, "EventFd"}, //7.0.0+
|
{31, &NetworkBSD::EventFd, "EventFd"}, //7.0.0+
|
||||||
{32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+
|
{32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+
|
||||||
{33, nullptr, "RegisterClientShared"}, //10.0.0+
|
{33, nullptr, "RegisterClientShared"}, //10.0.0+
|
||||||
{34, nullptr, "GetSocketStatistics"}, //15.0.0+
|
{34, nullptr, "GetSocketStatistics"}, //15.0.0+
|
||||||
@@ -1144,13 +1144,13 @@ BSD::BSD(Core::System& system_, const char* name, bool is_user_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BSD::~BSD() {
|
NetworkBSD::~NetworkBSD() {
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
room_member->Unbind(proxy_packet_received);
|
room_member->Unbind(proxy_packet_received);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> BSD::LockService() noexcept {
|
std::unique_lock<std::mutex> NetworkBSD::LockService() noexcept {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ class Socket;
|
|||||||
|
|
||||||
namespace Service::Sockets {
|
namespace Service::Sockets {
|
||||||
|
|
||||||
class BSD final : public ServiceFramework<BSD> {
|
class NetworkBSD final : public ServiceFramework<NetworkBSD> {
|
||||||
public:
|
public:
|
||||||
explicit BSD(Core::System& system_, const char* name, bool is_user);
|
explicit NetworkBSD(Core::System& system_, const char* name, bool is_user);
|
||||||
~BSD() override;
|
~NetworkBSD() override;
|
||||||
|
|
||||||
// These methods are called from SSL; the first two are also called from
|
// These methods are called from SSL; the first two are also called from
|
||||||
// this class for the corresponding IPC methods.
|
// this class for the corresponding IPC methods.
|
||||||
@@ -50,7 +50,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PollWork {
|
struct PollWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 nfds;
|
s32 nfds;
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AcceptWork {
|
struct AcceptWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -72,7 +72,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectWork {
|
struct ConnectWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -81,7 +81,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RecvWork {
|
struct RecvWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -92,7 +92,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RecvFromWork {
|
struct RecvFromWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -104,7 +104,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SendWork {
|
struct SendWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -115,7 +115,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SendToWork {
|
struct SendToWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ void LoopProcess(Core::System& system) {
|
|||||||
|
|
||||||
server_manager->RegisterNamedService("ethc:c", std::make_shared<ETHC_C>(system));
|
server_manager->RegisterNamedService("ethc:c", std::make_shared<ETHC_C>(system));
|
||||||
server_manager->RegisterNamedService("ethc:i", std::make_shared<ETHC_I>(system));
|
server_manager->RegisterNamedService("ethc:i", std::make_shared<ETHC_I>(system));
|
||||||
server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD>(system, "bsd:s", false));
|
server_manager->RegisterNamedService("bsd:s", std::make_shared<NetworkBSD>(system, "bsd:s", false));
|
||||||
server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD>(system, "bsd:u", true));
|
server_manager->RegisterNamedService("bsd:u", std::make_shared<NetworkBSD>(system, "bsd:u", true));
|
||||||
server_manager->RegisterNamedService("bsd:a", std::make_shared<BSD>(system, "bsd:a", true));
|
server_manager->RegisterNamedService("bsd:a", std::make_shared<NetworkBSD>(system, "bsd:a", true));
|
||||||
server_manager->RegisterNamedService("bsd:nu", std::make_shared<BSD_NU>(system));
|
server_manager->RegisterNamedService("bsd:nu", std::make_shared<BSD_NU>(system));
|
||||||
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system, "bsdcfg"));
|
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system, "bsdcfg"));
|
||||||
server_manager->RegisterNamedService("ifcfg", std::make_shared<BSDCFG>(system, "ifcfg"));
|
server_manager->RegisterNamedService("ifcfg", std::make_shared<BSDCFG>(system, "ifcfg"));
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public:
|
|||||||
LOG_ERROR(Service_SSL,
|
LOG_ERROR(Service_SSL,
|
||||||
"do_not_close_socket was changed after setting socket; is this right?");
|
"do_not_close_socket was changed after setting socket; is this right?");
|
||||||
} else {
|
} else {
|
||||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
|
auto bsd = system.ServiceManager().GetService<Service::Sockets::NetworkBSD>("bsd:u");
|
||||||
if (bsd) {
|
if (bsd) {
|
||||||
auto err = bsd->CloseImpl(fd);
|
auto err = bsd->CloseImpl(fd);
|
||||||
if (err != Service::Sockets::Errno::SUCCESS) {
|
if (err != Service::Sockets::Errno::SUCCESS) {
|
||||||
@@ -157,7 +157,7 @@ private:
|
|||||||
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
|
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
|
||||||
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
|
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
|
||||||
ASSERT(!did_handshake);
|
ASSERT(!did_handshake);
|
||||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
|
auto bsd = system.ServiceManager().GetService<Service::Sockets::NetworkBSD>("bsd:u");
|
||||||
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
||||||
|
|
||||||
auto const res_v = bsd->DuplicateSocketImpl(fd);
|
auto const res_v = bsd->DuplicateSocketImpl(fd);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -166,6 +166,16 @@ Result Container::GetLayerZIndex(u64 layer_id, s32* out_z_index) {
|
|||||||
R_RETURN(VI::ResultNotFound);
|
R_RETURN(VI::ResultNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result Container::SetLayerStackMask(u64 layer_id, u32 layer_stack_mask) {
|
||||||
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
|
auto* const layer = m_layers.GetLayerById(layer_id);
|
||||||
|
R_UNLESS(layer != nullptr, VI::ResultNotFound);
|
||||||
|
|
||||||
|
m_surface_flinger->SetLayerStackMask(layer->GetConsumerBinderId(), layer_stack_mask);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result Container::SetLayerIsOverlay(u64 layer_id, bool is_overlay) {
|
Result Container::SetLayerIsOverlay(u64 layer_id, bool is_overlay) {
|
||||||
std::scoped_lock lk{m_lock};
|
std::scoped_lock lk{m_lock};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -68,6 +68,7 @@ public:
|
|||||||
Result SetLayerZIndex(u64 layer_id, s32 z_index);
|
Result SetLayerZIndex(u64 layer_id, s32 z_index);
|
||||||
Result GetLayerZIndex(u64 layer_id, s32* out_z_index);
|
Result GetLayerZIndex(u64 layer_id, s32* out_z_index);
|
||||||
Result SetLayerIsOverlay(u64 layer_id, bool is_overlay);
|
Result SetLayerIsOverlay(u64 layer_id, bool is_overlay);
|
||||||
|
Result SetLayerStackMask(u64 layer_id, u32 layer_stack_mask);
|
||||||
|
|
||||||
void LinkVsyncEvent(u64 display_id, Event* event);
|
void LinkVsyncEvent(u64 display_id, Event* event);
|
||||||
void UnlinkVsyncEvent(u64 display_id, Event* event);
|
void UnlinkVsyncEvent(u64 display_id, Event* event);
|
||||||
|
|||||||
@@ -4,9 +4,15 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging.h"
|
||||||
|
#include "common/scratch_buffer.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/k_page_group.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_system_resource.h"
|
#include "core/hle/kernel/k_system_resource.h"
|
||||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||||
@@ -47,7 +53,7 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
|
|||||||
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
|
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
|
||||||
|
|
||||||
for (; start < end; start++) {
|
for (; start < end; start++) {
|
||||||
*start = 0xFF0000FF;
|
*start = 0x00000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +174,14 @@ constexpr u32 SharedBufferBlockLinearWidth = 1280;
|
|||||||
constexpr u32 SharedBufferBlockLinearHeight = 768;
|
constexpr u32 SharedBufferBlockLinearHeight = 768;
|
||||||
constexpr u32 SharedBufferBlockLinearStride =
|
constexpr u32 SharedBufferBlockLinearStride =
|
||||||
SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
|
SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
|
||||||
constexpr u32 SharedBufferNumSlots = 7;
|
|
||||||
|
constexpr u32 SharedBufferNumCaptureSlots = 3;
|
||||||
|
constexpr u32 SharedBufferSlotsPerSession = 2;
|
||||||
|
constexpr u32 SharedBufferMaxSessions = 2;
|
||||||
|
|
||||||
|
constexpr u32 SharedBufferNumSlots =
|
||||||
|
SharedBufferNumCaptureSlots + SharedBufferSlotsPerSession * SharedBufferMaxSessions;
|
||||||
|
static_assert(SharedBufferNumSlots <= 16, "Shared buffer pool exceeds the maximum texture count");
|
||||||
|
|
||||||
constexpr u32 SharedBufferWidth = 1280;
|
constexpr u32 SharedBufferWidth = 1280;
|
||||||
constexpr u32 SharedBufferHeight = 720;
|
constexpr u32 SharedBufferHeight = 720;
|
||||||
@@ -192,7 +205,52 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
|
|||||||
return layout;
|
return layout;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
|
constexpr u32 GetCaptureSlot(CaptureKind kind) {
|
||||||
|
return static_cast<u32>(kind);
|
||||||
|
}
|
||||||
|
static_assert(static_cast<u32>(CaptureKind::CallerApplet) + 1 == SharedBufferNumCaptureSlots,
|
||||||
|
"Capture slot count does not match CaptureKind");
|
||||||
|
|
||||||
|
constexpr u32 GetPresentationSlot(u32 slot_base, u32 index) {
|
||||||
|
return SharedBufferNumCaptureSlots + slot_base + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr u32 ColorOpaqueBlackRgba32 = 0xFF000000;
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void ForEachPoolChunk(Core::System& system, Kernel::KPageGroup& page_group, u64 offset, u64 size,
|
||||||
|
F&& writer) {
|
||||||
|
Common::ScratchBuffer<u32> scratch;
|
||||||
|
const u64 range_end = offset + size;
|
||||||
|
u64 pool_pos = 0;
|
||||||
|
|
||||||
|
for (auto& block : page_group) {
|
||||||
|
const u64 block_begin = pool_pos;
|
||||||
|
const u64 block_end = block_begin + block.GetSize();
|
||||||
|
pool_pos = block_end;
|
||||||
|
|
||||||
|
if (block_end <= offset) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (block_begin >= range_end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u64 chunk_begin = (std::max)(block_begin, offset);
|
||||||
|
const u64 chunk_end = (std::min)(block_end, range_end);
|
||||||
|
const u64 chunk_size = chunk_end - chunk_begin;
|
||||||
|
|
||||||
|
u8* const dst =
|
||||||
|
system.DeviceMemory().GetPointer<u8>(block.GetAddress()) + (chunk_begin - block_begin);
|
||||||
|
|
||||||
|
writer(dst, chunk_begin - offset, chunk_size);
|
||||||
|
|
||||||
|
system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(
|
||||||
|
dst, scratch, [&](DAddr addr) { system.GPU().InvalidateRegion(addr, chunk_size); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 producer_slot, u32 pool_slot, u32 handle) {
|
||||||
auto buffer = std::make_shared<android::NvGraphicBuffer>();
|
auto buffer = std::make_shared<android::NvGraphicBuffer>();
|
||||||
buffer->width = SharedBufferWidth;
|
buffer->width = SharedBufferWidth;
|
||||||
buffer->height = SharedBufferHeight;
|
buffer->height = SharedBufferHeight;
|
||||||
@@ -200,8 +258,8 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
|
|||||||
buffer->format = SharedBufferBlockLinearFormat;
|
buffer->format = SharedBufferBlockLinearFormat;
|
||||||
buffer->external_format = SharedBufferBlockLinearFormat;
|
buffer->external_format = SharedBufferBlockLinearFormat;
|
||||||
buffer->buffer_id = handle;
|
buffer->buffer_id = handle;
|
||||||
buffer->offset = slot * SharedBufferSlotSize;
|
buffer->offset = pool_slot * SharedBufferSlotSize;
|
||||||
ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
|
ASSERT(producer.SetPreallocatedBuffer(producer_slot, buffer) == android::Status::NoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -215,59 +273,91 @@ SharedBufferManager::~SharedBufferManager() = default;
|
|||||||
Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
|
Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
|
||||||
u64* out_layer_handle, u64 display_id,
|
u64* out_layer_handle, u64 display_id,
|
||||||
bool enable_blending) {
|
bool enable_blending) {
|
||||||
std::scoped_lock lk{m_guard};
|
{
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
|
||||||
// Ensure we haven't already created.
|
// Ensure we haven't already created.
|
||||||
const u64 aruid = owner_process->GetProcessId();
|
const u64 aruid = owner_process->GetProcessId();
|
||||||
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
|
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
|
||||||
|
|
||||||
// Allocate memory for the shared buffer if needed.
|
// Allocate memory for the shared buffer if needed.
|
||||||
if (!m_buffer_page_group) {
|
if (!m_buffer_page_group) {
|
||||||
R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
|
R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
|
||||||
SharedBufferSize));
|
SharedBufferSize));
|
||||||
|
|
||||||
// Record buffer id.
|
// Record buffer id.
|
||||||
m_buffer_id = m_next_buffer_id++;
|
m_buffer_id = m_next_buffer_id++;
|
||||||
|
|
||||||
// Record display id.
|
// Record display id.
|
||||||
m_display_id = display_id;
|
m_display_id = display_id;
|
||||||
|
|
||||||
|
for (u32 slot = 0; slot < SharedBufferNumCaptureSlots; slot++) {
|
||||||
|
ForEachPoolChunk(m_system, *m_buffer_page_group, u64{slot} * SharedBufferSlotSize,
|
||||||
|
SharedBufferSlotSize, [](u8* dst, u64, u64 length) {
|
||||||
|
std::fill_n(reinterpret_cast<u32*>(dst), length / sizeof(u32),
|
||||||
|
ColorOpaqueBlackRgba32);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim a presentation slot range.
|
||||||
|
u32 slot_base = 0;
|
||||||
|
|
||||||
|
std::array<bool, SharedBufferMaxSessions> in_use{};
|
||||||
|
for (const auto& [existing_aruid, existing] : m_sessions) {
|
||||||
|
const u32 index = existing.presentation_slot_base / SharedBufferSlotsPerSession;
|
||||||
|
|
||||||
|
if (index < in_use.size())
|
||||||
|
in_use[index] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
while (index < in_use.size() && in_use[index])
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (index >= in_use.size()) {
|
||||||
|
LOG_ERROR(Service_VI, "Out of shared buffer presentation slots ({} sessions)", SharedBufferMaxSessions);
|
||||||
|
R_THROW(VI::ResultOperationFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
slot_base = index * SharedBufferSlotsPerSession;
|
||||||
|
|
||||||
|
// Map into process.
|
||||||
|
Common::ProcessAddress map_address{};
|
||||||
|
R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
|
||||||
|
owner_process, m_system));
|
||||||
|
|
||||||
|
// Create new session.
|
||||||
|
auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
|
||||||
|
auto& session = it->second;
|
||||||
|
session.presentation_slot_base = slot_base;
|
||||||
|
|
||||||
|
auto& container = m_nvdrv->GetContainer();
|
||||||
|
session.session_id = container.OpenSession(owner_process);
|
||||||
|
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
|
||||||
|
|
||||||
|
// Create an nvmap handle for the buffer and assign the memory to it.
|
||||||
|
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
|
||||||
|
session.nvmap_fd, map_address, SharedBufferSize));
|
||||||
|
|
||||||
|
// Create and open a layer for the display.
|
||||||
|
s32 producer_binder_id;
|
||||||
|
R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
|
||||||
|
std::addressof(session.layer_id), display_id));
|
||||||
|
|
||||||
|
// Configure blending and z-index
|
||||||
|
R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
|
||||||
|
|
||||||
|
// Get the producer and set preallocated buffers.
|
||||||
|
std::shared_ptr<android::BufferQueueProducer> producer;
|
||||||
|
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
|
||||||
|
for (u32 i = 0; i < SharedBufferSlotsPerSession; i++)
|
||||||
|
MakeGraphicBuffer(*producer, i, GetPresentationSlot(session.presentation_slot_base, i), session.buffer_nvmap_handle);
|
||||||
|
|
||||||
|
// Assign outputs.
|
||||||
|
*out_buffer_id = m_buffer_id;
|
||||||
|
*out_layer_handle = session.layer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map into process.
|
|
||||||
Common::ProcessAddress map_address{};
|
|
||||||
R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
|
|
||||||
owner_process, m_system));
|
|
||||||
|
|
||||||
// Create new session.
|
|
||||||
auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
|
|
||||||
auto& session = it->second;
|
|
||||||
|
|
||||||
auto& container = m_nvdrv->GetContainer();
|
|
||||||
session.session_id = container.OpenSession(owner_process);
|
|
||||||
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
|
|
||||||
|
|
||||||
// Create an nvmap handle for the buffer and assign the memory to it.
|
|
||||||
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
|
|
||||||
session.nvmap_fd, map_address, SharedBufferSize));
|
|
||||||
|
|
||||||
// Create and open a layer for the display.
|
|
||||||
s32 producer_binder_id;
|
|
||||||
R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
|
|
||||||
std::addressof(session.layer_id), display_id));
|
|
||||||
|
|
||||||
// Configure blending and z-index
|
|
||||||
R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
|
|
||||||
|
|
||||||
// Get the producer and set preallocated buffers.
|
|
||||||
std::shared_ptr<android::BufferQueueProducer> producer;
|
|
||||||
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
|
|
||||||
MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle);
|
|
||||||
MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle);
|
|
||||||
|
|
||||||
// Assign outputs.
|
|
||||||
*out_buffer_id = m_buffer_id;
|
|
||||||
*out_layer_handle = session.layer_id;
|
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -336,14 +426,51 @@ Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
|
|||||||
SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
|
SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
|
||||||
VI::ResultOperationFailed);
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
// Assign remaining outputs.
|
out_slot_indexes.fill(-1);
|
||||||
*out_target_slot = slot;
|
|
||||||
out_slot_indexes = {0, 1, -1, -1};
|
{
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
const auto* const session = this->FindSessionByLayerIdLocked(layer_id);
|
||||||
|
if (session == nullptr) {
|
||||||
|
producer->CancelBuffer(slot, *out_fence);
|
||||||
|
// LOG_DEBUG(Service_VI, "No Session found");
|
||||||
|
R_THROW(VI::ResultNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < SharedBufferSlotsPerSession; i++)
|
||||||
|
out_slot_indexes[i] =
|
||||||
|
static_cast<s32>(GetPresentationSlot(session->presentation_slot_base, i));
|
||||||
|
|
||||||
|
*out_target_slot = static_cast<s64>(
|
||||||
|
GetPresentationSlot(session->presentation_slot_base, static_cast<u32>(slot)));
|
||||||
|
}
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result SharedBufferManager::GetProducerSlotLocked(s32* out_producer_slot, u64 layer_id,
|
||||||
|
s64 pool_slot) const {
|
||||||
|
const auto* const session = this->FindSessionByLayerIdLocked(layer_id);
|
||||||
|
R_UNLESS(session != nullptr, VI::ResultNotFound);
|
||||||
|
|
||||||
|
const s64 base = GetPresentationSlot(session->presentation_slot_base, 0);
|
||||||
|
const s64 producer_slot = pool_slot - base;
|
||||||
|
R_UNLESS(producer_slot >= 0 && producer_slot < SharedBufferSlotsPerSession,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
*out_producer_slot = static_cast<s32>(producer_slot);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
const SharedBufferSession* SharedBufferManager::FindSessionByLayerIdLocked(u64 layer_id) const {
|
||||||
|
for (const auto& [aruid, session] : m_sessions)
|
||||||
|
if (session.layer_id == layer_id)
|
||||||
|
return std::addressof(session);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
|
Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
|
||||||
Common::Rectangle<s32> crop_region,
|
Common::Rectangle<s32> crop_region,
|
||||||
u32 transform, s32 swap_interval, u64 layer_id,
|
u32 transform, s32 swap_interval, u64 layer_id,
|
||||||
@@ -352,14 +479,20 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
|
|||||||
std::shared_ptr<android::BufferQueueProducer> producer;
|
std::shared_ptr<android::BufferQueueProducer> producer;
|
||||||
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
|
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
|
||||||
|
|
||||||
|
s32 producer_slot;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
R_TRY(this->GetProducerSlotLocked(std::addressof(producer_slot), layer_id, slot));
|
||||||
|
}
|
||||||
|
|
||||||
// Request to queue the buffer.
|
// Request to queue the buffer.
|
||||||
std::shared_ptr<android::GraphicBuffer> buffer;
|
std::shared_ptr<android::GraphicBuffer> buffer;
|
||||||
R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
|
R_UNLESS(producer->RequestBuffer(producer_slot, std::addressof(buffer)) ==
|
||||||
android::Status::NoError,
|
android::Status::NoError,
|
||||||
VI::ResultOperationFailed);
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
ON_RESULT_FAILURE {
|
ON_RESULT_FAILURE {
|
||||||
producer->CancelBuffer(static_cast<s32>(slot), fence);
|
producer->CancelBuffer(producer_slot, fence);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Queue the buffer to the producer.
|
// Queue the buffer to the producer.
|
||||||
@@ -369,12 +502,10 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
|
|||||||
input.fence = fence;
|
input.fence = fence;
|
||||||
input.transform = static_cast<android::NativeWindowTransform>(transform);
|
input.transform = static_cast<android::NativeWindowTransform>(transform);
|
||||||
input.swap_interval = swap_interval;
|
input.swap_interval = swap_interval;
|
||||||
R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
|
R_UNLESS(producer->QueueBuffer(producer_slot, input, std::addressof(output)) ==
|
||||||
android::Status::NoError,
|
android::Status::NoError,
|
||||||
VI::ResultOperationFailed);
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
(void)m_container.SetLayerZIndex(layer_id, 100000);
|
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -384,8 +515,14 @@ Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
|
|||||||
std::shared_ptr<android::BufferQueueProducer> producer;
|
std::shared_ptr<android::BufferQueueProducer> producer;
|
||||||
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
|
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
|
||||||
|
|
||||||
|
s32 producer_slot;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
R_TRY(this->GetProducerSlotLocked(std::addressof(producer_slot), layer_id, slot));
|
||||||
|
}
|
||||||
|
|
||||||
// Cancel.
|
// Cancel.
|
||||||
producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence());
|
producer->CancelBuffer(producer_slot, android::Fence::NoFence());
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -404,31 +541,47 @@ Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadabl
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
|
Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index, CaptureKind kind) {
|
||||||
std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
|
std::scoped_lock lk{m_guard};
|
||||||
Common::ScratchBuffer<u32> scratch;
|
R_UNLESS(m_buffer_page_group != nullptr, VI::ResultNotFound);
|
||||||
|
|
||||||
// TODO: this could be optimized
|
const std::vector<u8> capture = m_system.GPU().GetAppletCaptureBuffer();
|
||||||
s64 e = -1280 * 768 * 4;
|
const u32 slot = GetCaptureSlot(kind);
|
||||||
for (auto& block : *m_buffer_page_group) {
|
|
||||||
u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
|
|
||||||
u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
|
|
||||||
|
|
||||||
for (; start < end; start++) {
|
if (capture.size() < SharedBufferSlotSize) {
|
||||||
*start = 0;
|
//LOG_WARNING(Service_VI, "Capture buffer is {} bytes, expected at least {}; not writing",
|
||||||
if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
|
// capture.size(), SharedBufferSlotSize);
|
||||||
*start = capture_buffer[e];
|
*out_was_written = false;
|
||||||
}
|
*out_layer_index = static_cast<s32>(slot);
|
||||||
e++;
|
R_SUCCEED();
|
||||||
}
|
|
||||||
|
|
||||||
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
|
|
||||||
m_system.GPU().InvalidateRegion(addr, end - start);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForEachPoolChunk(m_system, *m_buffer_page_group, u64{slot} * SharedBufferSlotSize,
|
||||||
|
SharedBufferSlotSize,
|
||||||
|
[&](u8* dst, u64 src_offset, u64 length) {
|
||||||
|
std::memcpy(dst, capture.data() + src_offset, length);
|
||||||
|
});
|
||||||
|
|
||||||
*out_was_written = true;
|
*out_was_written = true;
|
||||||
*out_layer_index = 1;
|
*out_layer_index = static_cast<s32>(slot);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SharedBufferManager::ClearAppletCaptureBuffer(s32 layer_index, u32 color) {
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
R_UNLESS(m_buffer_page_group != nullptr, VI::ResultNotFound);
|
||||||
|
|
||||||
|
if (layer_index < 0 || layer_index >= static_cast<s32>(SharedBufferNumCaptureSlots)) {
|
||||||
|
LOG_WARNING(Service_VI, "Couldnt clear non-capture slot {}", layer_index);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ForEachPoolChunk(m_system, *m_buffer_page_group, u64{static_cast<u32>(layer_index)} * SharedBufferSlotSize,
|
||||||
|
SharedBufferSlotSize, [&](u8* dst, u64 src_offset, u64 length) {
|
||||||
|
ASSERT(src_offset % sizeof(u32) == 0 && length % sizeof(u32) == 0);
|
||||||
|
std::fill_n(reinterpret_cast<u32*>(dst), length / sizeof(u32), color);
|
||||||
|
});
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user