diff --git a/docs/dynarmic/Design.md b/docs/dynarmic/Design.md index b46e7e5348..020cfd65bd 100644 --- a/docs/dynarmic/Design.md +++ b/docs/dynarmic/Design.md @@ -311,9 +311,8 @@ dispatcher, which will return control to the host. SetTerm(IR::Term::LinkBlockFast{next}) ``` -This terminal instruction jumps to the basic block described by `next` unconditionally. This promises guarantees that must be held at runtime - i.e that the program wont hang, - -This is a valid expression if contained within another block (say a `Terminal::If`) and the semantics allow it to be so. +This terminal instruction jumps to the basic block described by `next` unconditionally. +This promises guarantees that must be held at runtime - i.e that the program wont hang, ### Terminal: PopRSBHint 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 af37fb4685..45a69eca03 100644 --- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp +++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp @@ -29,96 +29,8 @@ 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); - // 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; - } - } - }); + main_thread = std::jthread([this](std::stop_token stop_token) { Main(stop_token); }); mailbox.Send(Direction::DSP, Message::InitializeOK); if (mailbox.Receive(Direction::Host) != Message::InitializeOK) { @@ -217,4 +129,95 @@ 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 a7a21e76af..4e128187a7 100644 --- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h +++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h @@ -82,6 +82,11 @@ 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 1ce81d287a..8a009c04c7 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp @@ -37,9 +37,7 @@ 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() { @@ -66,203 +64,206 @@ u32 OpusDecoder::Receive(Direction dir, std::stop_token stop_token) { return mailbox.Receive(dir, stop_token); } -void OpusDecoder::Init(std::stop_token rc_stop_token) { +void OpusDecoder::Init(std::stop_token stop_token) { Common::SetCurrentThreadName("DSP_OpusDecoder_Init"); - if (Receive(Direction::DSP, rc_stop_token) != Message::Start) { - LOG_ERROR(Service_Audio, "DSP OpusDecoder failed to receive Start message. Opus initialization failed."); + if (Receive(Direction::DSP, stop_token) != Message::Start) { + LOG_ERROR(Service_Audio, + "DSP OpusDecoder failed to receive Start message. Opus initialization failed."); return; } - // 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(); - } + main_thread = std::jthread([this](std::stop_token st) { Main(st); }); + running = true; + Send(Direction::Host, Message::StartOK); +} - if (error_code == OPUS_OK) { - error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, - input_data, input_data_size); - } +void OpusDecoder::Main(std::stop_token stop_token) { + Common::SetCurrentThreadName("DSP_OpusDecoder_Main"); - if (error_code == OPUS_OK) { - if (final_range && decoder_object.GetFinalRange() != final_range) { - error_code = OPUS_INVALID_PACKET; - } - } + while (!stop_token.stop_requested()) { + auto msg = Receive(Direction::DSP, stop_token); + switch (msg) { + case Shutdown: + Send(Direction::Host, Message::ShutdownOK); + return; - 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(); - } + case GetWorkBufferSize: { + auto channel_count = static_cast(shared_memory->host_send_data[0]); - if (error_code == OPUS_OK) { - error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, - input_data, input_data_size); - } + 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(); - if (error_code == OPUS_OK) { - if (final_range && decoder_object.GetFinalRange() != final_range) { - error_code = OPUS_INVALID_PACKET; - } + 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(); + 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(); + } - Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK); - } break; + if (error_code == OPUS_OK) { + error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, + input_data, input_data_size); + } - default: - LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg); - continue; + 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); + } } } // 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 d554586703..5b3f22bf4c 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.h +++ b/src/audio_core/adsp/apps/opus/opus_decoder.h @@ -72,6 +72,10 @@ 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 03c12a1505..4408abae4d 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -277,17 +277,7 @@ private: state.store(State::Processing); evt_processing->Signal(system.Kernel()); - 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); - }); + worker = std::thread(&IScanRequest::WorkerThread, this); IPC::ResponseBuilder{ctx, 2}.Push(ResultSuccess); } @@ -318,6 +308,21 @@ 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/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp index adef1adbec..63b40b8c31 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp @@ -17,14 +17,10 @@ bool TranslatorVisitor::arm_B(Cond cond, Imm<24> imm24) { if (!ArmConditionPassed(cond)) { return true; } + const u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8; const auto new_location = ir.current_location.AdvancePC(imm32); - // pattern match => b . - if (imm32 == 0) { - ir.SetTerm(IR::Term::LinkBlock{new_location}); - } else { - ir.SetTerm(IR::Term::LinkBlockFast{new_location}); - } + ir.SetTerm(IR::Term::LinkBlock{new_location}); return false; } @@ -39,7 +35,7 @@ bool TranslatorVisitor::arm_BL(Cond cond, Imm<24> imm24) { const u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8; const auto new_location = ir.current_location.AdvancePC(imm32); - ir.SetTerm(IR::Term::LinkBlockFast{new_location}); + ir.SetTerm(IR::Term::LinkBlock{new_location}); return false; } @@ -50,7 +46,7 @@ bool TranslatorVisitor::arm_BLX_imm(bool H, Imm<24> imm24) { const u32 imm32 = mcl::bit::sign_extend<26, u32>((imm24.ZeroExtend() << 2)) + (H ? 2 : 0) + 8; const auto new_location = ir.current_location.AdvancePC(imm32).SetTFlag(true); - ir.SetTerm(IR::Term::LinkBlockFast{new_location}); + ir.SetTerm(IR::Term::LinkBlock{new_location}); return false; } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp index bd52d3d4a9..7a0640598c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp @@ -56,10 +56,11 @@ bool TranslatorVisitor::arm_MSR_imm(Cond cond, unsigned mask, int rotate, Imm<8> if (write_e) { const bool E = (imm32 & 0x00000200) != 0; if (E != ir.current_location.EFlag()) { - ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).SetEFlag(E)}); + ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(4).SetEFlag(E)}); return false; } } + return true; } @@ -111,7 +112,7 @@ bool TranslatorVisitor::arm_RFE() { // SETEND bool TranslatorVisitor::arm_SETEND(bool E) { - ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).SetEFlag(E)}); + ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(4).SetEFlag(E)}); return false; } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp index e7bb36f285..082cd30db2 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp @@ -803,7 +803,7 @@ bool TranslatorVisitor::thumb16_SETEND(bool E) { return true; } - ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).SetEFlag(E).AdvanceIT()}); + ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(2).SetEFlag(E).AdvanceIT()}); return false; } @@ -906,8 +906,9 @@ bool TranslatorVisitor::thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Re ir.SetCheckBit(ir.IsZero(rn)); const auto [cond_pass, cond_fail] = [this, imm, nonzero] { - const auto skip = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).AdvanceIT()}; - const auto branch = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm + 4).AdvanceIT()}; + const auto skip = IR::Term::LinkBlock{ir.current_location.AdvancePC(2).AdvanceIT()}; + const auto branch = IR::Term::LinkBlock{ir.current_location.AdvancePC(imm + 4).AdvanceIT()}; + if (nonzero) { return std::make_pair(skip, branch); } else { @@ -974,10 +975,10 @@ bool TranslatorVisitor::thumb16_B_t1(Cond cond, Imm<8> imm8) { } const s32 imm32 = static_cast((imm8.SignExtend() << 1) + 4); - const auto then_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm32).AdvanceIT()}; - const auto else_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).AdvanceIT()}; + const auto then_location = ir.current_location.AdvancePC(imm32).AdvanceIT(); + const auto else_location = ir.current_location.AdvancePC(2).AdvanceIT(); - ir.SetTerm(IR::Term::If{cond, then_, else_}); + ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}}); return false; } @@ -989,12 +990,8 @@ bool TranslatorVisitor::thumb16_B_t2(Imm<11> imm11) { const s32 imm32 = static_cast((imm11.SignExtend() << 1) + 4); const auto next_location = ir.current_location.AdvancePC(imm32).AdvanceIT(); - // pattern (b +#0) - if (imm32 == 0) { - ir.SetTerm(IR::Term::LinkBlock{next_location}); - } else { - ir.SetTerm(IR::Term::LinkBlockFast{next_location}); - } + + ir.SetTerm(IR::Term::LinkBlock{next_location}); return false; } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp index 4b19449872..1c2c4792c1 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp @@ -23,8 +23,10 @@ bool TranslatorVisitor::thumb32_BL_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1)); const s32 imm32 = static_cast((concatenate(S, i1, i2, hi, lo).SignExtend() << 1) + 4); - auto const new_location = ir.current_location.AdvancePC(imm32).AdvanceIT(); - ir.SetTerm(IR::Term::LinkBlockFast{new_location}); + const auto new_location = ir.current_location + .AdvancePC(imm32) + .AdvanceIT(); + ir.SetTerm(IR::Term::LinkBlock{new_location}); return false; } @@ -45,8 +47,11 @@ bool TranslatorVisitor::thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1)); const s32 imm32 = static_cast(concatenate(S, i1, i2, hi, lo).SignExtend() << 1); - const auto new_location = ir.current_location.SetPC(ir.AlignPC(4) + imm32).SetTFlag(false).AdvanceIT(); - ir.SetTerm(IR::Term::LinkBlockFast{new_location}); + const auto new_location = ir.current_location + .SetPC(ir.AlignPC(4) + imm32) + .SetTFlag(false) + .AdvanceIT(); + ir.SetTerm(IR::Term::LinkBlock{new_location}); return false; } @@ -59,13 +64,10 @@ bool TranslatorVisitor::thumb32_B(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Im } const s32 imm32 = static_cast((concatenate(S, i1, i2, hi, lo).SignExtend() << 1) + 4); - auto const new_location = ir.current_location.AdvancePC(imm32).AdvanceIT(); - // Pattern to halt execution (b +#0) - if (imm32 == 0) { - ir.SetTerm(IR::Term::LinkBlock{new_location}); - } else { - ir.SetTerm(IR::Term::LinkBlockFast{new_location}); - } + const auto new_location = ir.current_location + .AdvancePC(imm32) + .AdvanceIT(); + ir.SetTerm(IR::Term::LinkBlock{new_location}); return false; } @@ -76,9 +78,13 @@ bool TranslatorVisitor::thumb32_B_cond(Imm<1> S, Cond cond, Imm<6> hi, Imm<1> i1 // Note: i1 and i2 were not inverted from encoding and are opposite compared to the other B instructions. const s32 imm32 = static_cast((concatenate(S, i2, i1, hi, lo).SignExtend() << 1) + 4); - const auto then_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm32).AdvanceIT()}; - const auto else_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).AdvanceIT()}; - ir.SetTerm(IR::Term::If{cond, then_, else_}); + const auto then_location = ir.current_location + .AdvancePC(imm32) + .AdvanceIT(); + const auto else_location = ir.current_location + .AdvancePC(4) + .AdvanceIT(); + ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}}); return false; } diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp index a07160394c..36b91f13e9 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp @@ -14,8 +14,8 @@ bool TranslatorVisitor::B_cond(Imm<19> imm19, Cond cond) { const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend(); const u64 target = ir.PC() + offset; - const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}; - const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)}; + const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)}; + const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)}; ir.SetTerm(IR::Term::If{cond, cond_pass, cond_fail}); return false; } @@ -26,9 +26,9 @@ bool TranslatorVisitor::B_uncond(Imm<26> imm26) { // Pattern to halt execution (B .) if (target == ir.PC()) { ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)}); - } else { - ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}); + return false; } + ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}); return false; } @@ -79,8 +79,8 @@ bool TranslatorVisitor::CBZ(bool sf, Imm<19> imm19, Reg Rt) { ir.SetCheckBit(ir.IsZero(operand1)); const u64 target = ir.PC() + offset; - const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}; - const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)}; + const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)}; + const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)}; ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail}); return false; } @@ -94,8 +94,8 @@ bool TranslatorVisitor::CBNZ(bool sf, Imm<19> imm19, Reg Rt) { ir.SetCheckBit(ir.IsZero(operand1)); const u64 target = ir.PC() + offset; - const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)}; - const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}; + const auto cond_pass = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)}; + const auto cond_fail = IR::Term::LinkBlock{ir.current_location->SetPC(target)}; ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail}); return false; } @@ -110,8 +110,8 @@ bool TranslatorVisitor::TBZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) { ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos))); const u64 target = ir.PC() + offset; - const auto cond_1 = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)}; - const auto cond_0 = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}; + const auto cond_1 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)}; + const auto cond_0 = IR::Term::LinkBlock{ir.current_location->SetPC(target)}; ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0}); return false; } @@ -126,8 +126,8 @@ bool TranslatorVisitor::TBNZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) { ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos))); const u64 target = ir.PC() + offset; - const auto cond_1 = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}; - const auto cond_0 = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)}; + const auto cond_1 = IR::Term::LinkBlock{ir.current_location->SetPC(target)}; + const auto cond_0 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)}; ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0}); return false; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 48268df708..3bf7a9ac78 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -60,57 +60,7 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_) AcquireNewChunk(); AllocateWorkerCommandBuffer(); - 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)); - } - } - }); + worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); }); } Scheduler::~Scheduler() = default; @@ -248,6 +198,59 @@ 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 6f471f6247..51ccd102f8 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -251,6 +251,8 @@ private: bool needs_state_enable_refresh = false; }; + void WorkerThread(std::stop_token stop_token); + void AllocateWorkerCommandBuffer(); u64 SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);