mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-10-20 18:59:26 +02:00
3970 revert fixes crash caused by scheduler 4177 fix mario galaxy and metroid prime 4 not booting Co-authored-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4187 Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
parent
372bdfccbc
commit
3fd6eeaf9f
13 changed files with 418 additions and 396 deletions
|
|
@ -311,9 +311,8 @@ dispatcher, which will return control to the host.
|
||||||
SetTerm(IR::Term::LinkBlockFast{next})
|
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 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.
|
|
||||||
|
|
||||||
### Terminal: PopRSBHint
|
### Terminal: PopRSBHint
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,96 +29,8 @@ void AudioRenderer::Start() {
|
||||||
CreateSinkStreams();
|
CreateSinkStreams();
|
||||||
|
|
||||||
mailbox.Initialize(AppMailboxId::AudioRenderer);
|
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
|
main_thread = std::jthread([this](std::stop_token stop_token) { Main(stop_token); });
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mailbox.Send(Direction::DSP, Message::InitializeOK);
|
mailbox.Send(Direction::DSP, Message::InitializeOK);
|
||||||
if (mailbox.Receive(Direction::Host) != 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
|
} // namespace AudioCore::ADSP::AudioRenderer
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,11 @@ public:
|
||||||
u64 GetRenderingStartTick(s32 session_id) const noexcept;
|
u64 GetRenderingStartTick(s32 session_id) const noexcept;
|
||||||
|
|
||||||
private:
|
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.
|
* Creates the streams which will receive the processed samples.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_co
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
OpusDecoder::OpusDecoder(Core::System& system_) : system{system_} {
|
OpusDecoder::OpusDecoder(Core::System& system_) : system{system_} {
|
||||||
init_thread = std::jthread([this](std::stop_token stop_token) {
|
init_thread = std::jthread([this](std::stop_token stop_token) { Init(stop_token); });
|
||||||
Init(stop_token);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpusDecoder::~OpusDecoder() {
|
OpusDecoder::~OpusDecoder() {
|
||||||
|
|
@ -66,16 +64,22 @@ u32 OpusDecoder::Receive(Direction dir, std::stop_token stop_token) {
|
||||||
return mailbox.Receive(dir, 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");
|
Common::SetCurrentThreadName("DSP_OpusDecoder_Init");
|
||||||
|
|
||||||
if (Receive(Direction::DSP, rc_stop_token) != Message::Start) {
|
if (Receive(Direction::DSP, stop_token) != Message::Start) {
|
||||||
LOG_ERROR(Service_Audio, "DSP OpusDecoder failed to receive Start message. Opus initialization failed.");
|
LOG_ERROR(Service_Audio,
|
||||||
|
"DSP OpusDecoder failed to receive Start message. Opus initialization failed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Main OpusDecoder thread, responsible for processing the incoming Opus packets.
|
main_thread = std::jthread([this](std::stop_token st) { Main(st); });
|
||||||
main_thread = std::jthread([this](std::stop_token stop_token) {
|
running = true;
|
||||||
|
Send(Direction::Host, Message::StartOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpusDecoder::Main(std::stop_token stop_token) {
|
||||||
Common::SetCurrentThreadName("DSP_OpusDecoder_Main");
|
Common::SetCurrentThreadName("DSP_OpusDecoder_Main");
|
||||||
|
|
||||||
while (!stop_token.stop_requested()) {
|
while (!stop_token.stop_requested()) {
|
||||||
auto msg = Receive(Direction::DSP, stop_token);
|
auto msg = Receive(Direction::DSP, stop_token);
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
|
@ -260,9 +264,6 @@ void OpusDecoder::Init(std::stop_token rc_stop_token) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
running = true;
|
|
||||||
Send(Direction::Host, Message::StartOK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::ADSP::OpusDecoder
|
} // namespace AudioCore::ADSP::OpusDecoder
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,10 @@ private:
|
||||||
* Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread.
|
* Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread.
|
||||||
*/
|
*/
|
||||||
void Init(std::stop_token stop_token);
|
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
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
|
||||||
|
|
@ -277,17 +277,7 @@ private:
|
||||||
state.store(State::Processing);
|
state.store(State::Processing);
|
||||||
evt_processing->Signal(system.Kernel());
|
evt_processing->Signal(system.Kernel());
|
||||||
|
|
||||||
worker = std::thread([this]() {
|
worker = std::thread(&IScanRequest::WorkerThread, 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);
|
IPC::ResponseBuilder{ctx, 2}.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,6 +308,21 @@ private:
|
||||||
|
|
||||||
enum class State { Idle, Processing, Finished };
|
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) {
|
void Finish(Result rc) {
|
||||||
worker_result.store(rc);
|
worker_result.store(rc);
|
||||||
state.store(State::Finished);
|
state.store(State::Finished);
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,10 @@ bool TranslatorVisitor::arm_B(Cond cond, Imm<24> imm24) {
|
||||||
if (!ArmConditionPassed(cond)) {
|
if (!ArmConditionPassed(cond)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8;
|
const u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8;
|
||||||
const auto new_location = ir.current_location.AdvancePC(imm32);
|
const auto new_location = ir.current_location.AdvancePC(imm32);
|
||||||
// pattern match => b .
|
|
||||||
if (imm32 == 0) {
|
|
||||||
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||||
} else {
|
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{new_location});
|
|
||||||
}
|
|
||||||
return false;
|
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 u32 imm32 = mcl::bit::sign_extend<26, u32>(imm24.ZeroExtend() << 2) + 8;
|
||||||
const auto new_location = ir.current_location.AdvancePC(imm32);
|
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;
|
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 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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,11 @@ bool TranslatorVisitor::arm_MSR_imm(Cond cond, unsigned mask, int rotate, Imm<8>
|
||||||
if (write_e) {
|
if (write_e) {
|
||||||
const bool E = (imm32 & 0x00000200) != 0;
|
const bool E = (imm32 & 0x00000200) != 0;
|
||||||
if (E != ir.current_location.EFlag()) {
|
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 false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +112,7 @@ bool TranslatorVisitor::arm_RFE() {
|
||||||
|
|
||||||
// SETEND <endian_specifier>
|
// SETEND <endian_specifier>
|
||||||
bool TranslatorVisitor::arm_SETEND(bool E) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@ bool TranslatorVisitor::thumb16_SETEND(bool E) {
|
||||||
return true;
|
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;
|
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));
|
ir.SetCheckBit(ir.IsZero(rn));
|
||||||
|
|
||||||
const auto [cond_pass, cond_fail] = [this, imm, nonzero] {
|
const auto [cond_pass, cond_fail] = [this, imm, nonzero] {
|
||||||
const auto skip = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).AdvanceIT()};
|
const auto skip = IR::Term::LinkBlock{ir.current_location.AdvancePC(2).AdvanceIT()};
|
||||||
const auto branch = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm + 4).AdvanceIT()};
|
const auto branch = IR::Term::LinkBlock{ir.current_location.AdvancePC(imm + 4).AdvanceIT()};
|
||||||
|
|
||||||
if (nonzero) {
|
if (nonzero) {
|
||||||
return std::make_pair(skip, branch);
|
return std::make_pair(skip, branch);
|
||||||
} else {
|
} 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 s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
|
||||||
const auto then_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(imm32).AdvanceIT()};
|
const auto then_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
|
||||||
const auto else_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(2).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;
|
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 s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
|
||||||
const auto next_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
|
const auto next_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
|
||||||
// pattern (b +#0)
|
|
||||||
if (imm32 == 0) {
|
|
||||||
ir.SetTerm(IR::Term::LinkBlock{next_location});
|
ir.SetTerm(IR::Term::LinkBlock{next_location});
|
||||||
} else {
|
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{next_location});
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
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);
|
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();
|
const auto new_location = ir.current_location
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{new_location});
|
.AdvancePC(imm32)
|
||||||
|
.AdvanceIT();
|
||||||
|
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||||
return false;
|
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));
|
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 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();
|
const auto new_location = ir.current_location
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{new_location});
|
.SetPC(ir.AlignPC(4) + imm32)
|
||||||
|
.SetTFlag(false)
|
||||||
|
.AdvanceIT();
|
||||||
|
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||||
return false;
|
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);
|
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();
|
const auto new_location = ir.current_location
|
||||||
// Pattern to halt execution (b +#0)
|
.AdvancePC(imm32)
|
||||||
if (imm32 == 0) {
|
.AdvanceIT();
|
||||||
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||||
} else {
|
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{new_location});
|
|
||||||
}
|
|
||||||
return false;
|
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.
|
// 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 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 then_location = ir.current_location
|
||||||
const auto else_ = IR::Term::LinkBlockFast{ir.current_location.AdvancePC(4).AdvanceIT()};
|
.AdvancePC(imm32)
|
||||||
ir.SetTerm(IR::Term::If{cond, then_, else_});
|
.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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ bool TranslatorVisitor::B_cond(Imm<19> imm19, Cond cond) {
|
||||||
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
const u64 target = ir.PC() + offset;
|
const u64 target = ir.PC() + offset;
|
||||||
|
|
||||||
const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
|
const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
|
||||||
const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
|
const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
|
||||||
ir.SetTerm(IR::Term::If{cond, cond_pass, cond_fail});
|
ir.SetTerm(IR::Term::If{cond, cond_pass, cond_fail});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -26,9 +26,9 @@ bool TranslatorVisitor::B_uncond(Imm<26> imm26) {
|
||||||
// Pattern to halt execution (B .)
|
// Pattern to halt execution (B .)
|
||||||
if (target == ir.PC()) {
|
if (target == ir.PC()) {
|
||||||
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
|
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
|
||||||
} else {
|
return false;
|
||||||
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)});
|
|
||||||
}
|
}
|
||||||
|
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,8 +79,8 @@ bool TranslatorVisitor::CBZ(bool sf, Imm<19> imm19, Reg Rt) {
|
||||||
ir.SetCheckBit(ir.IsZero(operand1));
|
ir.SetCheckBit(ir.IsZero(operand1));
|
||||||
|
|
||||||
const u64 target = ir.PC() + offset;
|
const u64 target = ir.PC() + offset;
|
||||||
const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
|
const auto cond_pass = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
|
||||||
const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
|
const auto cond_fail = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
|
||||||
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
|
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -94,8 +94,8 @@ bool TranslatorVisitor::CBNZ(bool sf, Imm<19> imm19, Reg Rt) {
|
||||||
ir.SetCheckBit(ir.IsZero(operand1));
|
ir.SetCheckBit(ir.IsZero(operand1));
|
||||||
|
|
||||||
const u64 target = ir.PC() + offset;
|
const u64 target = ir.PC() + offset;
|
||||||
const auto cond_pass = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
|
const auto cond_pass = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
|
||||||
const auto cond_fail = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
|
const auto cond_fail = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
|
||||||
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
|
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
|
||||||
return false;
|
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)));
|
ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos)));
|
||||||
|
|
||||||
const u64 target = ir.PC() + offset;
|
const u64 target = ir.PC() + offset;
|
||||||
const auto cond_1 = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
|
const auto cond_1 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
|
||||||
const auto cond_0 = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
|
const auto cond_0 = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
|
||||||
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
|
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
|
||||||
return false;
|
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)));
|
ir.SetCheckBit(ir.TestBit(operand, ir.Imm8(bit_pos)));
|
||||||
|
|
||||||
const u64 target = ir.PC() + offset;
|
const u64 target = ir.PC() + offset;
|
||||||
const auto cond_1 = IR::Term::LinkBlockFast{ir.current_location->SetPC(target)};
|
const auto cond_1 = IR::Term::LinkBlock{ir.current_location->SetPC(target)};
|
||||||
const auto cond_0 = IR::Term::LinkBlockFast{ir.current_location->AdvancePC(4)};
|
const auto cond_0 = IR::Term::LinkBlock{ir.current_location->AdvancePC(4)};
|
||||||
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
|
ir.SetTerm(IR::Term::CheckBit{cond_1, cond_0});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,57 +60,7 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
|
||||||
|
|
||||||
AcquireNewChunk();
|
AcquireNewChunk();
|
||||||
AllocateWorkerCommandBuffer();
|
AllocateWorkerCommandBuffer();
|
||||||
worker_thread = std::jthread([this](std::stop_token stop_token) {
|
worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheduler::~Scheduler() = default;
|
Scheduler::~Scheduler() = default;
|
||||||
|
|
@ -248,6 +198,59 @@ bool Scheduler::UpdateRescaling(bool is_rescaling) {
|
||||||
return true;
|
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() {
|
void Scheduler::AllocateWorkerCommandBuffer() {
|
||||||
current_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader());
|
current_cmdbuf = vk::CommandBuffer(command_pool->Commit(), device.GetDispatchLoader());
|
||||||
current_cmdbuf.Begin({
|
current_cmdbuf.Begin({
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,8 @@ private:
|
||||||
bool needs_state_enable_refresh = false;
|
bool needs_state_enable_refresh = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void WorkerThread(std::stop_token stop_token);
|
||||||
|
|
||||||
void AllocateWorkerCommandBuffer();
|
void AllocateWorkerCommandBuffer();
|
||||||
|
|
||||||
u64 SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);
|
u64 SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue