Compare commits

..

1 Commits

Author SHA1 Message Date
xbzk a9cabafbdf payload based fence sync 2026-03-31 01:14:16 +02:00
26 changed files with 377 additions and 310 deletions
+2 -6
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,11 +8,10 @@
namespace AudioCore {
AudioCore::AudioCore(Core::System& system) {
audio_manager.emplace();
AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>()} {
CreateSinks();
// Must be created after the sinks
adsp.emplace(system, *output_sink);
adsp = std::make_unique<ADSP::ADSP>(system, *output_sink);
}
AudioCore ::~AudioCore() {
+14 -9
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,7 +15,10 @@ class System;
namespace AudioCore {
/// @brief Main audio class, stored inside the core, and holding the audio manager, all sinks, and the ADSP.
class AudioManager;
/**
* Main audio class, stored inside the core, and holding the audio manager, all sinks, and the ADSP.
*/
class AudioCore {
public:
explicit AudioCore(Core::System& system);
@@ -50,22 +50,27 @@ public:
*/
Sink::Sink& GetInputSink();
/// @brief Get the ADSP.
/// @return Ref to the ADSP.
/**
* Get the ADSP.
*
* @return Ref to the ADSP.
*/
ADSP::ADSP& ADSP();
private:
/// @brief Create the sinks on startup.
/**
* Create the sinks on startup.
*/
void CreateSinks();
/// Main audio manager for audio in/out
std::optional<AudioManager> audio_manager;
std::unique_ptr<AudioManager> audio_manager;
/// Sink used for audio renderer and audio out
std::unique_ptr<Sink::Sink> output_sink;
/// Sink used for audio input
std::unique_ptr<Sink::Sink> input_sink;
/// The ADSP in the sysmodule
std::optional<ADSP::ADSP> adsp;
std::unique_ptr<ADSP::ADSP> adsp;
};
} // namespace AudioCore
+2 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -44,7 +41,8 @@ void Manager::ReleaseSessionId(const size_t session_id) {
Result Manager::LinkToManager() {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
AudioManager& manager{system.AudioCore().GetAudioManager()};
manager.SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true;
}
+52 -48
View File
@@ -1,77 +1,81 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/audio_manager.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/hle/service/audio/errors.h"
namespace AudioCore {
AudioManager::AudioManager() {
thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("AudioManager");
std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents();
while (!stop_token.stop_requested()) {
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
if (events.CheckAudioEventSet(Event::Type::Max)) {
break;
}
for (size_t i = 0; i < buffer_events.size(); i++) {
const auto event_type = Event::Type(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i]();
}
}
events.SetAudioEvent(event_type, false);
}
}
});
thread = std::jthread([this]() { ThreadFunc(); });
}
void AudioManager::Shutdown() {
running = false;
events.SetAudioEvent(Event::Type::Max, true);
if (thread.joinable()) {
thread.request_stop();
thread.join();
}
thread.join();
}
Result AudioManager::SetOutManager(BufferEventFunc buffer_func) {
if (thread.joinable()) {
std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioOutManager, true);
}
return ResultSuccess;
if (!running) {
return Service::Audio::ResultOperationFailed;
}
return Service::Audio::ResultOperationFailed;
std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioOutManager, true);
}
return ResultSuccess;
}
Result AudioManager::SetInManager(BufferEventFunc buffer_func) {
if (thread.joinable()) {
std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioInManager, true);
}
return ResultSuccess;
if (!running) {
return Service::Audio::ResultOperationFailed;
}
return Service::Audio::ResultOperationFailed;
std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioInManager, true);
}
return ResultSuccess;
}
void AudioManager::SetEvent(const Event::Type type, const bool signalled) {
events.SetAudioEvent(type, signalled);
}
void AudioManager::ThreadFunc() {
std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents();
running = true;
while (running) {
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
if (events.CheckAudioEventSet(Event::Type::Max)) {
break;
}
for (size_t i = 0; i < buffer_events.size(); i++) {
const auto event_type = static_cast<Event::Type>(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i]();
}
}
events.SetAudioEvent(event_type, false);
}
}
}
} // namespace AudioCore
+7 -3
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -69,6 +66,13 @@ public:
void SetEvent(Event::Type type, bool signalled);
private:
/**
* Main thread, waiting on a manager signal and calling the registered function.
*/
void ThreadFunc();
/// Is the main thread running?
std::atomic<bool> running{};
/// Unused
bool needs_update{};
/// Events to be set and signalled
+2 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -43,7 +40,8 @@ void Manager::ReleaseSessionId(const size_t session_id) {
Result Manager::LinkToManager() {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
AudioManager& manager{system.AudioCore().GetAudioManager()};
manager.SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true;
}
+1 -1
View File
@@ -347,7 +347,7 @@ struct System::Impl {
// Register with applet manager
// All threads are started, begin main process execution, now that we're in the clear
applet_manager.CreateAndInsertByFrontendAppletParameters(std::make_unique<Service::Process>(*std::move(process)), params);
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
+1 -1
View File
@@ -268,7 +268,7 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
if (Settings::values.enable_overlay && m_window_system->GetOverlayDisplayApplet() == nullptr) {
if (auto overlay_process = CreateProcess(m_system, static_cast<u64>(AppletProgramId::OverlayDisplay), 0, 0)) {
auto overlay_applet = std::make_shared<Applet>(m_system, std::make_unique<Service::Process>(*std::move(overlay_process)), false);
auto overlay_applet = std::make_shared<Applet>(m_system, std::move(overlay_process), false);
overlay_applet->program_id = static_cast<u64>(AppletProgramId::OverlayDisplay);
overlay_applet->applet_id = AppletId::OverlayDisplay;
overlay_applet->type = AppletType::OverlayApplet;
+37 -34
View File
@@ -1,11 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/thread.h"
#include "core/core.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/button_poller.h"
@@ -36,15 +34,16 @@ ButtonPressDuration ClassifyPressDuration(std::chrono::steady_clock::time_point
} // namespace
ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system) {
ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system)
: m_window_system(window_system) {
// TODO: am reads this from the home button state in hid, which is controller-agnostic.
Core::HID::ControllerUpdateCallback engine_callback{
.on_change = [this, &window_system](Core::HID::ControllerTriggerType type) {
if (type == Core::HID::ControllerTriggerType::Button) {
std::unique_lock lk{m_mutex};
OnButtonStateChanged(window_system);
}
},
.on_change =
[this](Core::HID::ControllerTriggerType type) {
if (type == Core::HID::ControllerTriggerType::Button) {
this->OnButtonStateChanged();
}
},
.is_npad_service = true,
};
@@ -53,35 +52,25 @@ ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system) {
m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_player1_key = m_player1->SetCallback(engine_callback);
m_thread = std::jthread([this, &window_system](std::stop_token stop_token) {
Common::SetCurrentThreadName("ButtonPoller");
while (!stop_token.stop_requested()) {
using namespace std::chrono_literals;
std::unique_lock lk{m_mutex};
m_cv.wait_for(lk, 50ms);
if (stop_token.stop_requested())
break;
OnButtonStateChanged(window_system);
std::this_thread::sleep_for(5ms);
}
});
m_thread = std::thread([this] { this->ThreadLoop(); });
}
ButtonPoller::~ButtonPoller() {
m_handheld->DeleteCallback(m_handheld_key);
m_player1->DeleteCallback(m_player1_key);
m_stop = true;
m_cv.notify_all();
if (m_thread.joinable()) {
m_thread.request_stop();
m_thread.join();
}
}
void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
auto const home_button = m_handheld->GetHomeButtons().home.Value()
|| m_player1->GetHomeButtons().home.Value();
auto const capture_button = m_handheld->GetCaptureButtons().capture.Value()
|| m_player1->GetCaptureButtons().capture.Value();
void ButtonPoller::OnButtonStateChanged() {
std::lock_guard lk{m_mutex};
const bool home_button =
m_handheld->GetHomeButtons().home.Value() || m_player1->GetHomeButtons().home.Value();
const bool capture_button = m_handheld->GetCaptureButtons().capture.Value() ||
m_player1->GetCaptureButtons().capture.Value();
// Buttons pressed which were not previously pressed
if (home_button && !m_home_button_press_start) {
@@ -101,7 +90,7 @@ void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
if (home_button && m_home_button_press_start && !m_home_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_home_button_press_start);
if (duration != ButtonPressDuration::ShortPressing) {
window_system.OnSystemButtonPress(SystemButtonType::HomeButtonLongPressing);
m_window_system.OnSystemButtonPress(SystemButtonType::HomeButtonLongPressing);
m_home_button_long_sent = true;
}
}
@@ -109,7 +98,7 @@ void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
if (capture_button && m_capture_button_press_start && !m_capture_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_capture_button_press_start);
if (duration != ButtonPressDuration::ShortPressing) {
window_system.OnSystemButtonPress(SystemButtonType::CaptureButtonLongPressing);
m_window_system.OnSystemButtonPress(SystemButtonType::CaptureButtonLongPressing);
m_capture_button_long_sent = true;
}
}
@@ -118,8 +107,9 @@ void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
if (!home_button && m_home_button_press_start) {
if(!m_home_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_home_button_press_start);
window_system.OnSystemButtonPress(duration == ButtonPressDuration::ShortPressing
? SystemButtonType::HomeButtonShortPressing : SystemButtonType::HomeButtonLongPressing);
m_window_system.OnSystemButtonPress(
duration == ButtonPressDuration::ShortPressing ? SystemButtonType::HomeButtonShortPressing
: SystemButtonType::HomeButtonLongPressing);
}
m_home_button_press_start = std::nullopt;
m_home_button_long_sent = false;
@@ -127,8 +117,9 @@ void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
if (!capture_button && m_capture_button_press_start) {
if (!m_capture_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_capture_button_press_start);
window_system.OnSystemButtonPress(duration == ButtonPressDuration::ShortPressing
? SystemButtonType::CaptureButtonShortPressing : SystemButtonType::CaptureButtonLongPressing);
m_window_system.OnSystemButtonPress(
duration == ButtonPressDuration::ShortPressing ? SystemButtonType::CaptureButtonShortPressing
: SystemButtonType::CaptureButtonLongPressing);
}
m_capture_button_press_start = std::nullopt;
m_capture_button_long_sent = false;
@@ -139,4 +130,16 @@ void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
// }
}
void ButtonPoller::ThreadLoop() {
using namespace std::chrono_literals;
std::unique_lock lk{m_mutex};
while (!m_stop) {
m_cv.wait_for(lk, 50ms);
if (m_stop) break;
lk.unlock();
OnButtonStateChanged();
lk.lock();
}
}
} // namespace Service::AM
+20 -12
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -30,23 +30,31 @@ class ButtonPoller {
public:
explicit ButtonPoller(Core::System& system, WindowSystem& window_system);
~ButtonPoller();
void OnButtonStateChanged(WindowSystem& window_system);
private:
std::mutex m_mutex;
std::condition_variable m_cv;
std::jthread m_thread;
void OnButtonStateChanged();
void ThreadLoop();
private:
WindowSystem& m_window_system;
Core::HID::EmulatedController* m_handheld{};
int m_handheld_key{};
Core::HID::EmulatedController* m_player1{};
int m_player1_key{};
std::optional<std::chrono::steady_clock::time_point> m_home_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_capture_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_power_button_press_start{};
Core::HID::EmulatedController* m_handheld{};
Core::HID::EmulatedController* m_player1{};
int32_t m_handheld_key{};
int32_t m_player1_key{};
bool m_home_button_long_sent : 1 = false;
bool m_capture_button_long_sent : 1 = false;
bool m_power_button_long_sent : 1 = false;
bool m_home_button_long_sent{};
bool m_capture_button_long_sent{};
bool m_power_button_long_sent{};
std::thread m_thread;
std::atomic<bool> m_stop{false};
std::condition_variable m_cv;
std::mutex m_mutex;
};
} // namespace Service::AM
+16 -18
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,24 +15,12 @@ enum class UserDataTag : u32 {
};
EventObserver::EventObserver(Core::System& system, WindowSystem& window_system)
: m_system(system), m_context(system, "am:EventObserver")
, m_window_system(window_system)
, m_wakeup_event(m_context)
, m_wakeup_holder(m_wakeup_event.GetHandle())
{
: m_system(system), m_context(system, "am:EventObserver"), m_window_system(window_system),
m_wakeup_event(m_context), m_wakeup_holder(m_wakeup_event.GetHandle()) {
m_window_system.SetEventObserver(this);
m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent));
m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait));
m_thread = std::thread([this] {
Common::SetCurrentThreadName("am:EventObserver");
while (true) {
auto* signaled_holder = this->WaitSignaled();
if (!signaled_holder) {
break;
}
this->Process(signaled_holder);
}
});
m_thread = std::thread([&] { this->ThreadFunc(); });
}
EventObserver::~EventObserver() {
@@ -161,4 +146,17 @@ void EventObserver::DestroyAppletProcessHolderLocked(ProcessHolder* holder) {
delete holder;
}
void EventObserver::ThreadFunc() {
Common::SetCurrentThreadName("am:EventObserver");
while (true) {
auto* signaled_holder = this->WaitSignaled();
if (!signaled_holder) {
break;
}
this->Process(signaled_holder);
}
}
} // namespace Service::AM
+3 -3
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -44,6 +41,9 @@ private:
private:
void DestroyAppletProcessHolderLocked(ProcessHolder* holder);
private:
void ThreadFunc();
private:
// System reference and context.
Core::System& m_system;
+57 -42
View File
@@ -1,10 +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-License-Identifier: GPL-2.0-or-later
#include <optional>
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
@@ -20,7 +16,7 @@ namespace Service::AM {
namespace {
[[nodiscard]] FileSys::StorageId GetStorageIdForFrontendSlot(
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
@@ -40,23 +36,31 @@ namespace {
}
}
[[nodiscard]] inline std::optional<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
std::unique_ptr<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
// Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, file, program_id, program_index);
// Ensure we have a loader which can parse the NCA.
if (out_loader) {
// Try to load the process.
auto process = std::make_optional<Process>(system);
if (process->Initialize(*out_loader, out_load_result)) {
return process;
}
if (!out_loader) {
return nullptr;
}
return std::nullopt;
// Try to load the process.
auto process = std::make_unique<Process>(system);
if (process->Initialize(*out_loader, out_load_result)) {
return process;
}
return nullptr;
}
} // Anonymous namespace
std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation) {
// Attempt to load program NCA.
FileSys::VirtualFile nca_raw{};
@@ -66,7 +70,7 @@ std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 mi
// Ensure we retrieved a program NCA.
if (!nca_raw) {
return std::nullopt;
return nullptr;
}
// Ensure we have a suitable version.
@@ -75,8 +79,9 @@ std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 mi
if (nca.GetStatus() == Loader::ResultStatus::Success &&
(nca.GetKeyGeneration() < minimum_key_generation ||
nca.GetKeyGeneration() > maximum_key_generation)) {
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id, nca.GetKeyGeneration());
return std::nullopt;
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
nca.GetKeyGeneration());
return nullptr;
}
}
@@ -85,32 +90,42 @@ std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 mi
return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
}
std::optional<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
if (auto process = CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index); process) {
FileSys::NACP nacp;
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
std::fill(out_control.begin(), out_control.end(), (u8) 0);
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
auto process =
CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
if (!process) {
return nullptr;
}
return std::nullopt;
FileSys::NACP nacp;
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
std::fill(out_control.begin(), out_control.end(), (u8) 0);
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(
storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
}
} // namespace Service::AM
+7 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -27,7 +24,12 @@ class Process;
namespace Service::AM {
std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
std::optional<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index);
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation);
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index);
} // namespace Service::AM
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -21,7 +21,8 @@ namespace Service::AM {
namespace {
Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_application_accessor, Core::System& system, WindowSystem& window_system, u64 program_id) {
Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_application_accessor,
Core::System& system, WindowSystem& window_system, u64 program_id) {
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
@@ -34,10 +35,11 @@ Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_applicati
std::vector<u8> control;
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus result;
auto process = CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
R_UNLESS(process != std::nullopt, ResultUnknown);
auto process =
CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
R_UNLESS(process != nullptr, ResultUnknown);
const auto applet = std::make_shared<Applet>(system, std::make_unique<Service::Process>(*std::move(process)), true);
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
applet->program_id = program_id;
applet->applet_id = AppletId::Application;
applet->type = AppletType::Application;
@@ -45,7 +47,8 @@ Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_applicati
window_system.TrackApplet(applet, true);
*out_application_accessor = std::make_shared<IApplicationAccessor>(system, applet, window_system);
*out_application_accessor =
std::make_shared<IApplicationAccessor>(system, applet, window_system);
R_SUCCEED();
}
@@ -87,10 +90,12 @@ Result IApplicationCreator::CreateSystemApplication(
std::vector<u8> control;
std::unique_ptr<Loader::AppLoader> loader;
auto process = CreateProcess(system, application_id, 1, 21);
R_UNLESS(process != std::nullopt, ResultUnknown);
const auto applet = std::make_shared<Applet>(system, std::make_unique<Service::Process>(*std::move(process)), true);
auto process =
CreateProcess(system, application_id, 1, 21);
R_UNLESS(process != nullptr, ResultUnknown);
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
applet->program_id = application_id;
applet->applet_id = AppletId::Starter;
applet->type = AppletType::LibraryApplet;
@@ -98,7 +103,8 @@ Result IApplicationCreator::CreateSystemApplication(
m_window_system.TrackApplet(applet, true);
*out_application_accessor = std::make_shared<IApplicationAccessor>(system, applet, m_window_system);
*out_application_accessor =
std::make_shared<IApplicationAccessor>(system, applet, m_window_system);
Core::LaunchTimestampCache::SaveLaunchTimestamp(application_id);
R_SUCCEED();
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -121,23 +121,26 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
};
auto process = CreateProcess(system, program_id, Firmware1400, Firmware2100);
if (process) {
const auto applet = std::make_shared<Applet>(system, std::make_unique<Service::Process>(*std::move(process)), false);
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
caller_applet->child_applets.push_back(applet);
window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
if (!process) {
// Couldn't initialize the guest process
return {};
}
// Couldn't initialize the guest process
return {};
const auto applet = std::make_shared<Applet>(system, std::move(process), false);
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
caller_applet->child_applets.push_back(applet);
window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -14,9 +14,7 @@ namespace Service::Audio {
using namespace AudioCore::AudioOut;
IAudioOutManager::IAudioOutManager(Core::System& system_)
: ServiceFramework{system_, "audout:u"}
, impl(system_)
{
: ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -43,7 +43,7 @@ private:
AudioCore::AudioOut::AudioOutParameter parameter,
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
std::optional<AudioCore::AudioOut::Manager> impl;
std::unique_ptr<AudioCore::AudioOut::Manager> impl;
};
} // namespace Service::Audio
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,9 +15,7 @@ namespace Service::Audio {
using namespace AudioCore::Renderer;
IAudioRendererManager::IAudioRendererManager(Core::System& system_)
: ServiceFramework{system_, "audren:u"}
, impl(system_)
{
: ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,7 +30,7 @@ private:
Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device,
u32 revision, ClientAppletResourceUserId aruid);
std::optional<AudioCore::Renderer::Manager> impl;
std::unique_ptr<AudioCore::Renderer::Manager> impl;
u32 num_audio_devices{0};
};
+8 -3
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -13,6 +10,14 @@
namespace Service {
Process::Process(Core::System& system)
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
m_process_started() {}
Process::~Process() {
this->Finalize();
}
bool Process::Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result) {
// First, ensure we are not holding another process.
this->Finalize();
+3 -6
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -25,8 +22,8 @@ namespace Service {
class Process {
public:
inline explicit Process(Core::System& system) noexcept : m_system(system) {}
inline ~Process() { this->Finalize(); }
explicit Process(Core::System& system);
~Process();
bool Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result);
void Finalize();
@@ -53,8 +50,8 @@ public:
private:
Core::System& m_system;
Kernel::KProcess* m_process{};
u64 m_main_thread_stack_size{};
s32 m_main_thread_priority{};
u64 m_main_thread_stack_size{};
bool m_process_started{};
};
+38 -38
View File
@@ -12,7 +12,6 @@
#include "common/logging.h"
#include "common/param_package.h"
#include "common/settings.h"
#include "common/thread.h"
#include "input_common/drivers/udp_client.h"
#include "input_common/helpers/udp_protocol.h"
@@ -136,7 +135,6 @@ private:
};
static void SocketLoop(Socket* socket) {
Common::SetCurrentThreadName("cemuhookWorker");
socket->StartReceive();
socket->StartSend(Socket::clock::now());
socket->Loop();
@@ -332,11 +330,9 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
}
void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) {
SocketCallback callback{
[this](Response::Version version) { OnVersion(version); },
[this](Response::PortInfo info) { OnPortInfo(info); },
[this, client](Response::PadData data) { OnPadData(data, client); }
};
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
[this](Response::PortInfo info) { OnPortInfo(info); },
[this, client](Response::PadData data) { OnPadData(data, client); }};
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
clients[client].uuid = GetHostUUID(host);
clients[client].host = host;
@@ -574,7 +570,9 @@ bool UDPClient::IsStickInverted(const Common::ParamPackage& params) {
return true;
}
void TestCommunication(const std::string& host, u16 port, const std::function<void()>& success_callback, const std::function<void()>& failure_callback) {
void TestCommunication(const std::string& host, u16 port,
const std::function<void()>& success_callback,
const std::function<void()>& failure_callback) {
std::thread([=] {
Common::Event success_event;
SocketCallback callback{
@@ -607,38 +605,40 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
u16 max_y{};
Status current_status{Status::Initialized};
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, [&](Response::PadData data) {
constexpr u16 CALIBRATION_THRESHOLD = 100;
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {},
[&](Response::PadData data) {
constexpr u16 CALIBRATION_THRESHOLD = 100;
if (current_status == Status::Initialized) {
// Receiving data means the communication is ready now
current_status = Status::Ready;
status_callback(current_status);
}
if (data.touch[0].is_active == 0) {
return;
}
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, data.touch[0].y);
min_x = (std::min)(min_x, u16(data.touch[0].x));
min_y = (std::min)(min_y, u16(data.touch[0].y));
if (current_status == Status::Ready) {
// First touch - min data (min_x/min_y)
current_status = Status::Stage1Completed;
status_callback(current_status);
}
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
data.touch[0].y - min_y > CALIBRATION_THRESHOLD) {
// Set the current position as max value and finishes
// configuration
max_x = data.touch[0].x;
max_y = data.touch[0].y;
current_status = Status::Completed;
data_callback(min_x, min_y, max_x, max_y);
status_callback(current_status);
if (current_status == Status::Initialized) {
// Receiving data means the communication is ready now
current_status = Status::Ready;
status_callback(current_status);
}
if (data.touch[0].is_active == 0) {
return;
}
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x,
data.touch[0].y);
min_x = (std::min)(min_x, static_cast<u16>(data.touch[0].x));
min_y = (std::min)(min_y, static_cast<u16>(data.touch[0].y));
if (current_status == Status::Ready) {
// First touch - min data (min_x/min_y)
current_status = Status::Stage1Completed;
status_callback(current_status);
}
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
data.touch[0].y - min_y > CALIBRATION_THRESHOLD) {
// Set the current position as max value and finishes
// configuration
max_x = data.touch[0].x;
max_y = data.touch[0].y;
current_status = Status::Completed;
data_callback(min_x, min_y, max_x, max_y);
status_callback(current_status);
complete_event.Set();
}
}};
complete_event.Set();
}
}};
Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
complete_event.Wait();
+10 -3
View File
@@ -260,7 +260,8 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
};
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
bool is_synced = !Settings::IsGPULevelHigh() && is_fence;
const bool is_payload = counter_type == QueryType::Payload;
const bool is_synced = !(Settings::getDebugKnobAt(0) && is_payload) && !Settings::IsGPULevelHigh() && is_fence;
std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,
pointer, pointer_timestamp] {
if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
@@ -292,9 +293,15 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
}
});
if (is_fence) {
impl->rasterizer.SignalFence(std::move(operation));
if (Settings::getDebugKnobAt(0) && is_payload) {
impl->rasterizer.SyncOperation(std::move(operation));
std::function<void()> noop([] {});
impl->rasterizer.SignalFence(std::move(noop));
} else {
impl->rasterizer.SignalFence(std::move(operation));
}
} else {
if (!Settings::IsGPULevelHigh() && counter_type == QueryType::Payload) {
if (!Settings::IsGPULevelHigh() && is_payload) {
if (has_timestamp) {
u64 timestamp = impl->gpu.GetTicks();
u64 value = static_cast<u64>(payload);
@@ -126,14 +126,16 @@ public:
current_query = nullptr;
amend_value = 0;
accumulation_value = 0;
queries_prefix_scan_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
queries_prefix_scan_pass = std::make_unique<QueriesPrefixScanPass>(
device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = 8,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
@@ -590,7 +592,8 @@ private:
VideoCommon::HostQueryBase* current_query;
bool has_started{};
std::mutex flush_guard;
std::optional<QueriesPrefixScanPass> queries_prefix_scan_pass;
std::unique_ptr<QueriesPrefixScanPass> queries_prefix_scan_pass;
};
// Transform feedback queries
@@ -1173,21 +1176,35 @@ private:
} // namespace
struct QueryCacheRuntimeImpl {
QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_, Vulkan::BufferCache& buffer_cache_, const Device& device_, const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, StagingBufferPool& staging_pool_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
: rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_}
, device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}
, staging_pool{staging_pool_}, guest_streamer(0, runtime)
, sample_streamer(size_t(QueryType::ZPassPixelCount64), runtime, rasterizer, texture_cache_, device, scheduler, memory_allocator, compute_pass_descriptor_queue, descriptor_pool)
, tfb_streamer(size_t(QueryType::StreamingByteCount), runtime, device, scheduler, memory_allocator, staging_pool)
, primitives_succeeded_streamer(size_t(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer, device_memory_)
, primitives_needed_minus_succeeded_streamer(size_t(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u)
, hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_,
Tegra::MaxwellDeviceMemoryManager& device_memory_,
Vulkan::BufferCache& buffer_cache_, const Device& device_,
const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
StagingBufferPool& staging_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
: rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_},
device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
staging_pool{staging_pool_}, guest_streamer(0, runtime),
sample_streamer(static_cast<size_t>(QueryType::ZPassPixelCount64), runtime, rasterizer,
texture_cache_, device, scheduler, memory_allocator,
compute_pass_descriptor_queue, descriptor_pool),
tfb_streamer(static_cast<size_t>(QueryType::StreamingByteCount), runtime, device,
scheduler, memory_allocator, staging_pool),
primitives_succeeded_streamer(
static_cast<size_t>(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer,
device_memory_),
primitives_needed_minus_succeeded_streamer(
static_cast<size_t>(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u),
hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
hcr_setup.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
hcr_setup.pNext = nullptr;
hcr_setup.flags = 0;
conditional_resolve_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
conditional_resolve_pass = std::make_unique<ConditionalRenderingResolvePass>(
device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -1224,7 +1241,7 @@ struct QueryCacheRuntimeImpl {
std::vector<std::vector<VkBufferCopy>> copies_setup;
// Host conditional rendering data
std::optional<ConditionalRenderingResolvePass> conditional_resolve_pass;
std::unique_ptr<ConditionalRenderingResolvePass> conditional_resolve_pass;
vk::Buffer hcr_resolve_buffer;
VkConditionalRenderingBeginInfoEXT hcr_setup;
VkBuffer hcr_buffer;
@@ -1236,7 +1253,13 @@ struct QueryCacheRuntimeImpl {
Maxwell3D* maxwell3d;
};
QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory_, Vulkan::BufferCache& buffer_cache_, const Device& device_, const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, StagingBufferPool& staging_pool_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer,
Tegra::MaxwellDeviceMemoryManager& device_memory_,
Vulkan::BufferCache& buffer_cache_, const Device& device_,
const MemoryAllocator& memory_allocator_,
Scheduler& scheduler_, StagingBufferPool& staging_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
impl = std::make_unique<QueryCacheRuntimeImpl>(
*this, rasterizer, device_memory_, buffer_cache_, device_, memory_allocator_, scheduler_,
staging_pool_, compute_pass_descriptor_queue, descriptor_pool, texture_cache_);
@@ -1461,11 +1484,13 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
impl->scheduler.RequestOutsideRenderPassOperationContext();
if (is_prebarrier) {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
});
} else {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
});
}
}
@@ -1558,7 +1583,8 @@ void QueryCacheRuntime::SyncValues(std::span<SyncValuesType> values, VkBuffer ba
}
impl->scheduler.RequestOutsideRenderPassOperationContext();
impl->scheduler.Record([src_buffer, dst_buffers = std::move(impl->buffers_to_upload_to), vk_copies = std::move(impl->copies_setup)](vk::CommandBuffer cmdbuf) {
impl->scheduler.Record([src_buffer, dst_buffers = std::move(impl->buffers_to_upload_to),
vk_copies = std::move(impl->copies_setup)](vk::CommandBuffer cmdbuf) {
size_t size = dst_buffers.size();
for (size_t i = 0; i < size; i++) {
cmdbuf.CopyBuffer(src_buffer, dst_buffers[i].first, vk_copies[i]);
@@ -1,13 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <variant>
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
@@ -15,15 +12,20 @@ namespace Vulkan {
class Device;
class Scheduler;
union DescriptorUpdateEntry {
struct DescriptorUpdateEntry {
struct Empty {};
DescriptorUpdateEntry() = default;
DescriptorUpdateEntry(VkDescriptorImageInfo image_) : image{image_} {}
DescriptorUpdateEntry(VkDescriptorBufferInfo buffer_) : buffer{buffer_} {}
DescriptorUpdateEntry(VkBufferView texel_buffer_) : texel_buffer{texel_buffer_} {}
std::monostate empty{};
VkDescriptorImageInfo image;
VkDescriptorBufferInfo buffer;
VkBufferView texel_buffer;
union {
Empty empty{};
VkDescriptorImageInfo image;
VkDescriptorBufferInfo buffer;
VkBufferView texel_buffer;
};
};
class UpdateDescriptorQueue final {