aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/dynarmic/Design.md5
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp181
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.h5
-rw-r--r--src/audio_core/adsp/apps/opus/opus_decoder.cpp371
-rw-r--r--src/audio_core/adsp/apps/opus/opus_decoder.h4
-rw-r--r--src/core/hle/service/nifm/nifm.cpp27
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp12
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp5
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp21
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp34
-rw-r--r--src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp24
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp105
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h2
13 files changed, 409 insertions, 387 deletions
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<bool, MaxRendererSessions> buffers_reset{};
- std::array<u64, MaxRendererSessions> 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<bool, MaxRendererSessions> buffers_reset{};
+ std::array<u64, MaxRendererSessions> 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
@@ -83,6 +83,11 @@ public:
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.
*/
void CreateSinkStreams();
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<s32>(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<s32>(shared_memory->host_send_data[2]);
- auto channel_count = static_cast<s32>(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<u32>(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<s32>(shared_memory->host_send_data[0]);
- auto stereo_stream_count = static_cast<s32>(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<s32>(shared_memory->host_send_data[2]);
- auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
- auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[4]);
- auto stereo_stream_count = static_cast<s32>(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<u32>(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<s32>(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<s32>(shared_memory->host_send_data[2]);
+ auto channel_count = static_cast<s32>(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<u32>(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<s32>(shared_memory->host_send_data[0]);
+ auto stereo_stream_count = static_cast<s32>(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<s32>(shared_memory->host_send_data[2]);
+ auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
+ auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[4]);
+ auto stereo_stream_count = static_cast<s32>(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<u32>(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 <endian_specifier>
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<s32>((imm8.SignExtend<u32>() << 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<s32>((imm11.SignExtend<u32>() << 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<s32>((concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 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<s32>(concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 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<s32>((concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 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<s32>((concatenate(S, i2, i1, hi, lo).SignExtend<u32>() << 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<s64>();
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<CommandChunk> 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<CommandChunk> 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);