From 37b5cf60033b3624ed2b82a000568a5a2eda7b05 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 23 May 2026 21:16:28 +0200 Subject: [PATCH] [audio_core, hle, video_core] force inline of functions that only contain thread loops (#3970) traditionally, when doing jthread: ``` jthread() calls function parameter operator()() with args function operator()() calls the code within code within is, say { ThreadMain(); } 3 calls because why not ``` now this just makes it be 2 calls, mainly benefits non-LTO builds Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3970 Reviewed-by: crueter Reviewed-by: MaranBr --- .../apps/audio_renderer/audio_renderer.cpp | 181 ++++---- .../adsp/apps/audio_renderer/audio_renderer.h | 7 +- .../adsp/apps/opus/opus_decoder.cpp | 389 +++++++++--------- src/audio_core/adsp/apps/opus/opus_decoder.h | 7 +- src/core/hle/service/nifm/nifm.cpp | 27 +- .../renderer_vulkan/vk_scheduler.cpp | 105 +++-- src/video_core/renderer_vulkan/vk_scheduler.h | 2 - 7 files changed, 349 insertions(+), 369 deletions(-) diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp index 45a69eca03..af37fb4685 100644 --- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp +++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp @@ -29,8 +29,96 @@ void AudioRenderer::Start() { CreateSinkStreams(); mailbox.Initialize(AppMailboxId::AudioRenderer); + // Main AudioRenderer thread, responsible for processing the command lists. + main_thread = std::jthread([this](std::stop_token stop_token) { + Common::SetCurrentThreadName("DSP_AudioRenderer_Main"); + Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - main_thread = std::jthread([this](std::stop_token stop_token) { Main(stop_token); }); + // TODO: Create buffer map/unmap thread + mailbox + // TODO: Create gMix devices, initialize them here + + if (mailbox.Receive(Direction::DSP) != Message::InitializeOK) { + LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!"); + return; + } + + mailbox.Send(Direction::Host, Message::InitializeOK); + + // 0.12 seconds (2,304,000 / 19,200,000) + constexpr u64 max_process_time{2'304'000ULL}; + while (!stop_token.stop_requested()) { + auto msg{mailbox.Receive(Direction::DSP)}; + switch (msg) { + case Message::Shutdown: + mailbox.Send(Direction::Host, Message::Shutdown); + return; + + case Message::Render: { + if (system.IsShuttingDown()) { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + mailbox.Send(Direction::Host, Message::RenderResponse); + continue; + } + std::array buffers_reset{}; + std::array render_times_taken{}; + const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()}; + + for (u32 index = 0; index < MaxRendererSessions; index++) { + auto& command_buffer{command_buffers[index]}; + auto& command_list_processor{command_list_processors[index]}; + + // Check this buffer is valid, as it may not be used. + if (command_buffer.buffer != 0) { + // If there are no remaining commands (from the previous list), + // this is a new command list, initialize it. + if (command_buffer.remaining_command_count == 0) { + command_list_processor.Initialize(system, *command_buffer.process, + command_buffer.buffer, + command_buffer.size, streams[index]); + } + + if (command_buffer.reset_buffer && !buffers_reset[index]) { + streams[index]->ClearQueue(); + buffers_reset[index] = true; + } + + u64 max_time{max_process_time}; + if (index == 1 && command_buffer.applet_resource_user_id == + command_buffers[0].applet_resource_user_id) { + max_time = max_process_time - render_times_taken[0]; + if (render_times_taken[0] > max_process_time) { + max_time = 0; + } + } + + max_time = (std::min)(command_buffer.time_limit, max_time); + command_list_processor.SetProcessTimeMax(max_time); + + if (index == 0) { + streams[index]->WaitFreeSpace(stop_token); + } + + // Process the command list + { + render_times_taken[index] = + command_list_processor.Process(index) - start_time; + } + + const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()}; + + command_buffer.remaining_command_count = + command_list_processor.GetRemainingCommandCount(); + command_buffer.render_time_taken_us = end_time - start_time; + } + } + mailbox.Send(Direction::Host, Message::RenderResponse); + } break; + default: + LOG_WARNING(Service_Audio, "ADSP AudioRenderer received an invalid message, msg={:02X}!", msg); + break; + } + } + }); mailbox.Send(Direction::DSP, Message::InitializeOK); if (mailbox.Receive(Direction::Host) != Message::InitializeOK) { @@ -129,95 +217,4 @@ void AudioRenderer::CreateSinkStreams() { } } -void AudioRenderer::Main(std::stop_token stop_token) { - Common::SetCurrentThreadName("DSP_AudioRenderer_Main"); - Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - - // TODO: Create buffer map/unmap thread + mailbox - // TODO: Create gMix devices, initialize them here - - if (mailbox.Receive(Direction::DSP) != Message::InitializeOK) { - LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!"); - return; - } - - mailbox.Send(Direction::Host, Message::InitializeOK); - - // 0.12 seconds (2,304,000 / 19,200,000) - constexpr u64 max_process_time{2'304'000ULL}; - - while (!stop_token.stop_requested()) { - auto msg{mailbox.Receive(Direction::DSP)}; - switch (msg) { - case Message::Shutdown: - mailbox.Send(Direction::Host, Message::Shutdown); - return; - - case Message::Render: { - if (system.IsShuttingDown()) { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - mailbox.Send(Direction::Host, Message::RenderResponse); - continue; - } - std::array buffers_reset{}; - std::array render_times_taken{}; - const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()}; - - for (u32 index = 0; index < MaxRendererSessions; index++) { - auto& command_buffer{command_buffers[index]}; - auto& command_list_processor{command_list_processors[index]}; - - // Check this buffer is valid, as it may not be used. - if (command_buffer.buffer != 0) { - // If there are no remaining commands (from the previous list), - // this is a new command list, initialize it. - if (command_buffer.remaining_command_count == 0) { - command_list_processor.Initialize(system, *command_buffer.process, - command_buffer.buffer, - command_buffer.size, streams[index]); - } - - if (command_buffer.reset_buffer && !buffers_reset[index]) { - streams[index]->ClearQueue(); - buffers_reset[index] = true; - } - - u64 max_time{max_process_time}; - if (index == 1 && command_buffer.applet_resource_user_id == - command_buffers[0].applet_resource_user_id) { - max_time = max_process_time - render_times_taken[0]; - if (render_times_taken[0] > max_process_time) { - max_time = 0; - } - } - - max_time = (std::min)(command_buffer.time_limit, max_time); - command_list_processor.SetProcessTimeMax(max_time); - - if (index == 0) { - streams[index]->WaitFreeSpace(stop_token); - } - - // Process the command list - { - render_times_taken[index] = - command_list_processor.Process(index) - start_time; - } - - const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()}; - - command_buffer.remaining_command_count = - command_list_processor.GetRemainingCommandCount(); - command_buffer.render_time_taken_us = end_time - start_time; - } - } - mailbox.Send(Direction::Host, Message::RenderResponse); - } break; - default: - LOG_WARNING(Service_Audio, "ADSP AudioRenderer received an invalid message, msg={:02X}!", msg); - break; - } - } -} - } // namespace AudioCore::ADSP::AudioRenderer diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h index db6b893d43..a7a21e76af 100644 --- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h +++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h @@ -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-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -82,11 +82,6 @@ public: u64 GetRenderingStartTick(s32 session_id) const noexcept; private: - /** - * Main AudioRenderer thread, responsible for processing the command lists. - */ - void Main(std::stop_token stop_token); - /** * Creates the streams which will receive the processed samples. */ diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.cpp b/src/audio_core/adsp/apps/opus/opus_decoder.cpp index 8a009c04c7..1ce81d287a 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp @@ -37,7 +37,9 @@ bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_co } // namespace OpusDecoder::OpusDecoder(Core::System& system_) : system{system_} { - init_thread = std::jthread([this](std::stop_token stop_token) { Init(stop_token); }); + init_thread = std::jthread([this](std::stop_token stop_token) { + Init(stop_token); + }); } OpusDecoder::~OpusDecoder() { @@ -64,206 +66,203 @@ u32 OpusDecoder::Receive(Direction dir, std::stop_token stop_token) { return mailbox.Receive(dir, stop_token); } -void OpusDecoder::Init(std::stop_token stop_token) { +void OpusDecoder::Init(std::stop_token rc_stop_token) { Common::SetCurrentThreadName("DSP_OpusDecoder_Init"); - if (Receive(Direction::DSP, stop_token) != Message::Start) { - LOG_ERROR(Service_Audio, - "DSP OpusDecoder failed to receive Start message. Opus initialization failed."); + if (Receive(Direction::DSP, rc_stop_token) != Message::Start) { + LOG_ERROR(Service_Audio, "DSP OpusDecoder failed to receive Start message. Opus initialization failed."); return; } - main_thread = std::jthread([this](std::stop_token st) { Main(st); }); + // Main OpusDecoder thread, responsible for processing the incoming Opus packets. + main_thread = std::jthread([this](std::stop_token stop_token) { + Common::SetCurrentThreadName("DSP_OpusDecoder_Main"); + while (!stop_token.stop_requested()) { + auto msg = Receive(Direction::DSP, stop_token); + switch (msg) { + case Shutdown: + Send(Direction::Host, Message::ShutdownOK); + return; + + case GetWorkBufferSize: { + auto channel_count = static_cast(shared_memory->host_send_data[0]); + + ASSERT(IsValidChannelCount(channel_count)); + + shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count); + Send(Direction::Host, Message::GetWorkBufferSizeOK); + } break; + + case InitializeDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + auto buffer_size = shared_memory->host_send_data[1]; + auto sample_rate = static_cast(shared_memory->host_send_data[2]); + auto channel_count = static_cast(shared_memory->host_send_data[3]); + + ASSERT(sample_rate >= 0); + ASSERT(IsValidChannelCount(channel_count)); + ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count)); + + auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); + shared_memory->dsp_return_data[0] = + decoder_object.InitializeDecoder(sample_rate, channel_count); + + Send(Direction::Host, Message::InitializeDecodeObjectOK); + } break; + + case ShutdownDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + + auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); + shared_memory->dsp_return_data[0] = decoder_object.Shutdown(); + + Send(Direction::Host, Message::ShutdownDecodeObjectOK); + } break; + + case DecodeInterleaved: { + auto start_time = system.CoreTiming().GetGlobalTimeUs(); + + auto buffer = shared_memory->host_send_data[0]; + auto input_data = shared_memory->host_send_data[1]; + auto input_data_size = shared_memory->host_send_data[2]; + auto output_data = shared_memory->host_send_data[3]; + auto output_data_size = shared_memory->host_send_data[4]; + auto final_range = static_cast(shared_memory->host_send_data[5]); + auto reset_requested = shared_memory->host_send_data[6]; + + u32 decoded_samples{0}; + + auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); + s32 error_code{OPUS_OK}; + if (reset_requested) { + error_code = decoder_object.ResetDecoder(); + } + + if (error_code == OPUS_OK) { + error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, + input_data, input_data_size); + } + + if (error_code == OPUS_OK) { + if (final_range && decoder_object.GetFinalRange() != final_range) { + error_code = OPUS_INVALID_PACKET; + } + } + + auto end_time = system.CoreTiming().GetGlobalTimeUs(); + shared_memory->dsp_return_data[0] = error_code; + shared_memory->dsp_return_data[1] = decoded_samples; + shared_memory->dsp_return_data[2] = (end_time - start_time).count(); + + Send(Direction::Host, Message::DecodeInterleavedOK); + } break; + + case MapMemory: { + [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; + [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + Send(Direction::Host, Message::MapMemoryOK); + } break; + + case UnmapMemory: { + [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; + [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + Send(Direction::Host, Message::UnmapMemoryOK); + } break; + + case GetWorkBufferSizeForMultiStream: { + auto total_stream_count = static_cast(shared_memory->host_send_data[0]); + auto stereo_stream_count = static_cast(shared_memory->host_send_data[1]); + + ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count)); + + shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize( + total_stream_count, stereo_stream_count); + Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK); + } break; + + case InitializeMultiStreamDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + auto buffer_size = shared_memory->host_send_data[1]; + auto sample_rate = static_cast(shared_memory->host_send_data[2]); + auto channel_count = static_cast(shared_memory->host_send_data[3]); + auto total_stream_count = static_cast(shared_memory->host_send_data[4]); + auto stereo_stream_count = static_cast(shared_memory->host_send_data[5]); + // Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel + // mappings, but [6] is never set, and there is not enough room in the argument data for + // more than 40 channels, when 255 are possible. + // It also means the mapping values are undefined, though likely always 0, + // and the mappings given by the game are ignored. The mappings are copied to this + // dedicated buffer host side, so let's do as intended. + auto mappings = shared_memory->channel_mapping.data(); + + ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count)); + ASSERT(sample_rate >= 0); + ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize( + total_stream_count, stereo_stream_count)); + + auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); + shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder( + sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings); + + Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK); + } break; + + case ShutdownMultiStreamDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + + auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); + shared_memory->dsp_return_data[0] = decoder_object.Shutdown(); + + Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK); + } break; + + case DecodeInterleavedForMultiStream: { + auto start_time = system.CoreTiming().GetGlobalTimeUs(); + + auto buffer = shared_memory->host_send_data[0]; + auto input_data = shared_memory->host_send_data[1]; + auto input_data_size = shared_memory->host_send_data[2]; + auto output_data = shared_memory->host_send_data[3]; + auto output_data_size = shared_memory->host_send_data[4]; + auto final_range = static_cast(shared_memory->host_send_data[5]); + auto reset_requested = shared_memory->host_send_data[6]; + + u32 decoded_samples{0}; + + auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); + s32 error_code{OPUS_OK}; + if (reset_requested) { + error_code = decoder_object.ResetDecoder(); + } + + if (error_code == OPUS_OK) { + error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, + input_data, input_data_size); + } + + if (error_code == OPUS_OK) { + if (final_range && decoder_object.GetFinalRange() != final_range) { + error_code = OPUS_INVALID_PACKET; + } + } + + auto end_time = system.CoreTiming().GetGlobalTimeUs(); + shared_memory->dsp_return_data[0] = error_code; + shared_memory->dsp_return_data[1] = decoded_samples; + shared_memory->dsp_return_data[2] = (end_time - start_time).count(); + + Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK); + } break; + + default: + LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg); + continue; + } + } + }); running = true; Send(Direction::Host, Message::StartOK); } -void OpusDecoder::Main(std::stop_token stop_token) { - Common::SetCurrentThreadName("DSP_OpusDecoder_Main"); - - while (!stop_token.stop_requested()) { - auto msg = Receive(Direction::DSP, stop_token); - switch (msg) { - case Shutdown: - Send(Direction::Host, Message::ShutdownOK); - return; - - case GetWorkBufferSize: { - auto channel_count = static_cast(shared_memory->host_send_data[0]); - - ASSERT(IsValidChannelCount(channel_count)); - - shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count); - Send(Direction::Host, Message::GetWorkBufferSizeOK); - } break; - - case InitializeDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - auto buffer_size = shared_memory->host_send_data[1]; - auto sample_rate = static_cast(shared_memory->host_send_data[2]); - auto channel_count = static_cast(shared_memory->host_send_data[3]); - - ASSERT(sample_rate >= 0); - ASSERT(IsValidChannelCount(channel_count)); - ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count)); - - auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = - decoder_object.InitializeDecoder(sample_rate, channel_count); - - Send(Direction::Host, Message::InitializeDecodeObjectOK); - } break; - - case ShutdownDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - - auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = decoder_object.Shutdown(); - - Send(Direction::Host, Message::ShutdownDecodeObjectOK); - } break; - - case DecodeInterleaved: { - auto start_time = system.CoreTiming().GetGlobalTimeUs(); - - auto buffer = shared_memory->host_send_data[0]; - auto input_data = shared_memory->host_send_data[1]; - auto input_data_size = shared_memory->host_send_data[2]; - auto output_data = shared_memory->host_send_data[3]; - auto output_data_size = shared_memory->host_send_data[4]; - auto final_range = static_cast(shared_memory->host_send_data[5]); - auto reset_requested = shared_memory->host_send_data[6]; - - u32 decoded_samples{0}; - - auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); - s32 error_code{OPUS_OK}; - if (reset_requested) { - error_code = decoder_object.ResetDecoder(); - } - - if (error_code == OPUS_OK) { - error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, - input_data, input_data_size); - } - - if (error_code == OPUS_OK) { - if (final_range && decoder_object.GetFinalRange() != final_range) { - error_code = OPUS_INVALID_PACKET; - } - } - - auto end_time = system.CoreTiming().GetGlobalTimeUs(); - shared_memory->dsp_return_data[0] = error_code; - shared_memory->dsp_return_data[1] = decoded_samples; - shared_memory->dsp_return_data[2] = (end_time - start_time).count(); - - Send(Direction::Host, Message::DecodeInterleavedOK); - } break; - - case MapMemory: { - [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - Send(Direction::Host, Message::MapMemoryOK); - } break; - - case UnmapMemory: { - [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - Send(Direction::Host, Message::UnmapMemoryOK); - } break; - - case GetWorkBufferSizeForMultiStream: { - auto total_stream_count = static_cast(shared_memory->host_send_data[0]); - auto stereo_stream_count = static_cast(shared_memory->host_send_data[1]); - - ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count)); - - shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize( - total_stream_count, stereo_stream_count); - Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK); - } break; - - case InitializeMultiStreamDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - auto buffer_size = shared_memory->host_send_data[1]; - auto sample_rate = static_cast(shared_memory->host_send_data[2]); - auto channel_count = static_cast(shared_memory->host_send_data[3]); - auto total_stream_count = static_cast(shared_memory->host_send_data[4]); - auto stereo_stream_count = static_cast(shared_memory->host_send_data[5]); - // Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel - // mappings, but [6] is never set, and there is not enough room in the argument data for - // more than 40 channels, when 255 are possible. - // It also means the mapping values are undefined, though likely always 0, - // and the mappings given by the game are ignored. The mappings are copied to this - // dedicated buffer host side, so let's do as intended. - auto mappings = shared_memory->channel_mapping.data(); - - ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count)); - ASSERT(sample_rate >= 0); - ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize( - total_stream_count, stereo_stream_count)); - - auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder( - sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings); - - Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK); - } break; - - case ShutdownMultiStreamDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - - auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = decoder_object.Shutdown(); - - Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK); - } break; - - case DecodeInterleavedForMultiStream: { - auto start_time = system.CoreTiming().GetGlobalTimeUs(); - - auto buffer = shared_memory->host_send_data[0]; - auto input_data = shared_memory->host_send_data[1]; - auto input_data_size = shared_memory->host_send_data[2]; - auto output_data = shared_memory->host_send_data[3]; - auto output_data_size = shared_memory->host_send_data[4]; - auto final_range = static_cast(shared_memory->host_send_data[5]); - auto reset_requested = shared_memory->host_send_data[6]; - - u32 decoded_samples{0}; - - auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); - s32 error_code{OPUS_OK}; - if (reset_requested) { - error_code = decoder_object.ResetDecoder(); - } - - if (error_code == OPUS_OK) { - error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, - input_data, input_data_size); - } - - if (error_code == OPUS_OK) { - if (final_range && decoder_object.GetFinalRange() != final_range) { - error_code = OPUS_INVALID_PACKET; - } - } - - auto end_time = system.CoreTiming().GetGlobalTimeUs(); - shared_memory->dsp_return_data[0] = error_code; - shared_memory->dsp_return_data[1] = decoded_samples; - shared_memory->dsp_return_data[2] = (end_time - start_time).count(); - - Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK); - } break; - - default: - LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg); - continue; - } - } -} - } // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.h b/src/audio_core/adsp/apps/opus/opus_decoder.h index fcb89bb40e..d554586703 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.h +++ b/src/audio_core/adsp/apps/opus/opus_decoder.h @@ -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-License-Identifier: GPL-2.0-or-later @@ -69,10 +72,6 @@ private: * Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread. */ void Init(std::stop_token stop_token); - /** - * Main OpusDecoder thread, responsible for processing the incoming Opus packets. - */ - void Main(std::stop_token stop_token); /// Core system Core::System& system; diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index a0302a5841..7bd06e2e0f 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -277,7 +277,17 @@ private: state.store(State::Processing); evt_processing->Signal(); - worker = std::thread(&IScanRequest::WorkerThread, this); + worker = std::thread([this]() { + using namespace std::chrono_literals; + scan_results = Network::ScanWifiNetworks(3s); + { + std::scoped_lock lk{g_scan_mtx}; + g_last_scan_results = scan_results; + } + // choose result code + const bool ok = !scan_results.empty(); + Finish(ok ? ResultSuccess : ResultPendingConnection); + }); IPC::ResponseBuilder{ctx, 2}.Push(ResultSuccess); } @@ -308,21 +318,6 @@ private: enum class State { Idle, Processing, Finished }; - void WorkerThread() { - using namespace std::chrono_literals; - - scan_results = Network::ScanWifiNetworks(3s); - - { - std::scoped_lock lk{g_scan_mtx}; - g_last_scan_results = scan_results; - } - - // choose result code - const bool ok = !scan_results.empty(); - Finish(ok ? ResultSuccess : ResultPendingConnection); - } - void Finish(Result rc) { worker_result.store(rc); state.store(State::Finished); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index fdaf9baacc..abad831b69 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -59,7 +59,57 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_) AcquireNewChunk(); AllocateWorkerCommandBuffer(); - worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); }); + worker_thread = std::jthread([this](std::stop_token stop_token) { + Common::SetCurrentThreadName("VulkanWorker"); + const auto TryPopQueue{[this](auto& work) -> bool { + if (work_queue.empty()) { + return false; + } + + work = std::move(work_queue.front()); + work_queue.pop(); + event_cv.notify_all(); + return true; + }}; + + while (!stop_token.stop_requested()) { + std::unique_ptr work; + + { + std::unique_lock lk{queue_mutex}; + + // Wait for work. + event_cv.wait(lk, stop_token, [&] { return TryPopQueue(work); }); + + // If we've been asked to stop, we're done. + if (stop_token.stop_requested()) { + return; + } + + // Exchange lock ownership so that we take the execution lock before + // the queue lock goes out of scope. This allows us to force execution + // to complete in the next step. + std::exchange(lk, std::unique_lock{execution_mutex}); + + // Perform the work, tracking whether the chunk was a submission + // before executing. + const bool has_submit = work->HasSubmit(); + work->ExecuteAll(current_cmdbuf, current_upload_cmdbuf); + + // If the chunk was a submission, reallocate the command buffer. + if (has_submit) { + AllocateWorkerCommandBuffer(); + } + } + + { + std::scoped_lock rl{reserve_mutex}; + + // Recycle the chunk back to the reserve. + chunk_reserve.emplace_back(std::move(work)); + } + } + }); } Scheduler::~Scheduler() = default; @@ -187,59 +237,6 @@ bool Scheduler::UpdateRescaling(bool is_rescaling) { return true; } -void Scheduler::WorkerThread(std::stop_token stop_token) { - Common::SetCurrentThreadName("VulkanWorker"); - - const auto TryPopQueue{[this](auto& work) -> bool { - if (work_queue.empty()) { - return false; - } - - work = std::move(work_queue.front()); - work_queue.pop(); - event_cv.notify_all(); - return true; - }}; - - while (!stop_token.stop_requested()) { - std::unique_ptr work; - - { - std::unique_lock lk{queue_mutex}; - - // Wait for work. - event_cv.wait(lk, stop_token, [&] { return TryPopQueue(work); }); - - // If we've been asked to stop, we're done. - if (stop_token.stop_requested()) { - return; - } - - // Exchange lock ownership so that we take the execution lock before - // the queue lock goes out of scope. This allows us to force execution - // to complete in the next step. - std::exchange(lk, std::unique_lock{execution_mutex}); - - // Perform the work, tracking whether the chunk was a submission - // before executing. - const bool has_submit = work->HasSubmit(); - work->ExecuteAll(current_cmdbuf, current_upload_cmdbuf); - - // If the chunk was a submission, reallocate the command buffer. - if (has_submit) { - AllocateWorkerCommandBuffer(); - } - } - - { - std::scoped_lock rl{reserve_mutex}; - - // Recycle the chunk back to the reserve. - chunk_reserve.emplace_back(std::move(work)); - } - } -} - void Scheduler::AllocateWorkerCommandBuffer() { current_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader()); current_cmdbuf.Begin({ diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 0709c3a370..fc11be7c0e 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -251,8 +251,6 @@ private: bool needs_state_enable_refresh = false; }; - void WorkerThread(std::stop_token stop_token); - void AllocateWorkerCommandBuffer(); u64 SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);