TimingEvents: Remove pointer indirection
Probably should move this to one big array for locality.
This commit is contained in:
parent
56dd9878e1
commit
4f7ddfaae6
|
@ -299,10 +299,12 @@ static void CreateFileMap();
|
|||
static void CreateFileMap(IsoReader& iso, std::string_view dir);
|
||||
static const std::string* LookupFileMap(u32 lba, u32* start_lba, u32* end_lba);
|
||||
|
||||
static std::unique_ptr<TimingEvent> s_command_event;
|
||||
static std::unique_ptr<TimingEvent> s_command_second_response_event;
|
||||
static std::unique_ptr<TimingEvent> s_async_interrupt_event;
|
||||
static std::unique_ptr<TimingEvent> s_drive_event;
|
||||
static TimingEvent s_command_event{"CDROM Command Event", 1, 1, &CDROM::ExecuteCommand, nullptr};
|
||||
static TimingEvent s_command_second_response_event{"CDROM Command Second Response Event", 1, 1,
|
||||
&CDROM::ExecuteCommandSecondResponse, nullptr};
|
||||
static TimingEvent s_async_interrupt_event{"CDROM Async Interrupt Event", INTERRUPT_DELAY_CYCLES, 1,
|
||||
&CDROM::DeliverAsyncInterrupt, nullptr};
|
||||
static TimingEvent s_drive_event{"CDROM Drive Event", 1, 1, &CDROM::ExecuteDrive, nullptr};
|
||||
|
||||
static Command s_command = Command::None;
|
||||
static Command s_command_second_response = Command::None;
|
||||
|
@ -443,14 +445,6 @@ static std::array<CommandInfo, 255> s_command_info = {{
|
|||
|
||||
void CDROM::Initialize()
|
||||
{
|
||||
s_command_event =
|
||||
TimingEvents::CreateTimingEvent("CDROM Command Event", 1, 1, &CDROM::ExecuteCommand, nullptr, false);
|
||||
s_command_second_response_event = TimingEvents::CreateTimingEvent(
|
||||
"CDROM Command Second Response Event", 1, 1, &CDROM::ExecuteCommandSecondResponse, nullptr, false);
|
||||
s_async_interrupt_event = TimingEvents::CreateTimingEvent("CDROM Async Interrupt Event", INTERRUPT_DELAY_CYCLES, 1,
|
||||
&CDROM::DeliverAsyncInterrupt, nullptr, false);
|
||||
s_drive_event = TimingEvents::CreateTimingEvent("CDROM Drive Event", 1, 1, &CDROM::ExecuteDrive, nullptr, false);
|
||||
|
||||
if (g_settings.cdrom_readahead_sectors > 0)
|
||||
s_reader.StartThread(g_settings.cdrom_readahead_sectors);
|
||||
|
||||
|
@ -463,10 +457,10 @@ void CDROM::Shutdown()
|
|||
s_file_map_created = false;
|
||||
s_show_current_file = false;
|
||||
|
||||
s_drive_event.reset();
|
||||
s_async_interrupt_event.reset();
|
||||
s_command_second_response_event.reset();
|
||||
s_command_event.reset();
|
||||
s_drive_event.Deactivate();
|
||||
s_async_interrupt_event.Deactivate();
|
||||
s_command_second_response_event.Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
s_reader.StopThread();
|
||||
s_reader.RemoveMedia();
|
||||
}
|
||||
|
@ -474,7 +468,7 @@ void CDROM::Shutdown()
|
|||
void CDROM::Reset()
|
||||
{
|
||||
s_command = Command::None;
|
||||
s_command_event->Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
ClearCommandSecondResponse();
|
||||
ClearDriveState();
|
||||
s_status.bits = 0;
|
||||
|
@ -569,7 +563,7 @@ void CDROM::SoftReset(TickCount ticks_late)
|
|||
if (s_current_lba != 0)
|
||||
{
|
||||
s_drive_state = DriveState::SeekingImplicit;
|
||||
s_drive_event->SetIntervalAndSchedule(total_ticks);
|
||||
s_drive_event.SetIntervalAndSchedule(total_ticks);
|
||||
s_requested_lba = 0;
|
||||
s_reader.QueueReadSector(s_requested_lba);
|
||||
s_seek_start_lba = s_current_lba;
|
||||
|
@ -578,7 +572,7 @@ void CDROM::SoftReset(TickCount ticks_late)
|
|||
else
|
||||
{
|
||||
s_drive_state = DriveState::ChangingSpeedOrTOCRead;
|
||||
s_drive_event->Schedule(total_ticks);
|
||||
s_drive_event.Schedule(total_ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -697,10 +691,10 @@ bool CDROM::DoState(StateWrapper& sw)
|
|||
if (s_reader.HasMedia())
|
||||
s_reader.QueueReadSector(s_requested_lba);
|
||||
UpdateCommandEvent();
|
||||
s_drive_event->SetState(!IsDriveIdle());
|
||||
s_drive_event.SetState(!IsDriveIdle());
|
||||
|
||||
// Time will get fixed up later.
|
||||
s_command_second_response_event->SetState(s_command_second_response != Command::None);
|
||||
s_command_second_response_event.SetState(s_command_second_response != Command::None);
|
||||
}
|
||||
|
||||
return !sw.HasError();
|
||||
|
@ -824,7 +818,7 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
|
|||
ClearDriveState();
|
||||
ClearCommandSecondResponse();
|
||||
s_command = Command::None;
|
||||
s_command_event->Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
|
||||
// The console sends an interrupt when the shell is opened regardless of whether a command was executing.
|
||||
ClearAsyncInterrupt();
|
||||
|
@ -834,7 +828,7 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
|
|||
if (for_disc_swap)
|
||||
{
|
||||
s_drive_state = DriveState::ShellOpening;
|
||||
s_drive_event->SetIntervalAndSchedule(stop_ticks);
|
||||
s_drive_event.SetIntervalAndSchedule(stop_ticks);
|
||||
}
|
||||
|
||||
return image;
|
||||
|
@ -890,7 +884,7 @@ void CDROM::CPUClockChanged()
|
|||
{
|
||||
// reschedule the disc read event
|
||||
if (IsReadingOrPlaying())
|
||||
s_drive_event->SetInterval(GetTicksForRead());
|
||||
s_drive_event.SetInterval(GetTicksForRead());
|
||||
}
|
||||
|
||||
u8 CDROM::ReadRegister(u32 offset)
|
||||
|
@ -1115,7 +1109,7 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
|||
sizeof(s_cd_audio_volume_matrix)) != 0))
|
||||
{
|
||||
if (HasPendingDiscEvent())
|
||||
s_drive_event->InvokeEarly();
|
||||
s_drive_event.InvokeEarly();
|
||||
SPU::GeneratePendingSamples();
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1204,7 @@ void CDROM::SetAsyncInterrupt(Interrupt interrupt)
|
|||
void CDROM::ClearAsyncInterrupt()
|
||||
{
|
||||
s_pending_async_interrupt = 0;
|
||||
s_async_interrupt_event->Deactivate();
|
||||
s_async_interrupt_event.Deactivate();
|
||||
s_async_response_fifo.Clear();
|
||||
}
|
||||
|
||||
|
@ -1235,7 +1229,7 @@ void CDROM::QueueDeliverAsyncInterrupt()
|
|||
{
|
||||
DEV_LOG("Delaying async interrupt {} because it's been {} cycles since last interrupt", s_pending_async_interrupt,
|
||||
diff);
|
||||
s_async_interrupt_event->Schedule(INTERRUPT_DELAY_CYCLES);
|
||||
s_async_interrupt_event.Schedule(INTERRUPT_DELAY_CYCLES);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1244,12 +1238,12 @@ void CDROM::DeliverAsyncInterrupt(void*, TickCount ticks, TickCount ticks_late)
|
|||
if (HasPendingInterrupt())
|
||||
{
|
||||
// This shouldn't really happen, because we should block command execution.. but just in case.
|
||||
if (!s_async_interrupt_event->IsActive())
|
||||
s_async_interrupt_event->Schedule(INTERRUPT_DELAY_CYCLES);
|
||||
if (!s_async_interrupt_event.IsActive())
|
||||
s_async_interrupt_event.Schedule(INTERRUPT_DELAY_CYCLES);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_async_interrupt_event->Deactivate();
|
||||
s_async_interrupt_event.Deactivate();
|
||||
|
||||
Assert(s_pending_async_interrupt != 0 && !HasPendingInterrupt());
|
||||
DEBUG_LOG("Delivering async interrupt {}", s_pending_async_interrupt);
|
||||
|
@ -1308,7 +1302,7 @@ void CDROM::UpdateInterruptRequest()
|
|||
|
||||
bool CDROM::HasPendingDiscEvent()
|
||||
{
|
||||
return (s_drive_event->IsActive() && s_drive_event->GetTicksUntilNextExecution() <= 0);
|
||||
return (s_drive_event.IsActive() && s_drive_event.GetTicksUntilNextExecution() <= 0);
|
||||
}
|
||||
|
||||
TickCount CDROM::GetAckDelayForCommand(Command command)
|
||||
|
@ -1336,7 +1330,7 @@ TickCount CDROM::GetTicksForIDRead()
|
|||
{
|
||||
TickCount ticks = ID_READ_TICKS;
|
||||
if (s_drive_state == DriveState::SpinningUp)
|
||||
ticks += s_drive_event->GetTicksUntilNextExecution();
|
||||
ticks += s_drive_event.GetTicksUntilNextExecution();
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
@ -1376,7 +1370,7 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
|||
if (!IsMotorOn())
|
||||
{
|
||||
ticks +=
|
||||
(s_drive_state == DriveState::SpinningUp) ? s_drive_event->GetTicksUntilNextExecution() : GetTicksForSpinUp();
|
||||
(s_drive_state == DriveState::SpinningUp) ? s_drive_event.GetTicksUntilNextExecution() : GetTicksForSpinUp();
|
||||
if (s_drive_state == DriveState::ShellOpening || s_drive_state == DriveState::SpinningUp)
|
||||
ClearDriveState();
|
||||
}
|
||||
|
@ -1416,7 +1410,7 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
|||
if (s_drive_state == DriveState::ChangingSpeedOrTOCRead && !ignore_speed_change)
|
||||
{
|
||||
// we're still reading the TOC, so add that time in
|
||||
const TickCount remaining_change_ticks = s_drive_event->GetTicksUntilNextExecution();
|
||||
const TickCount remaining_change_ticks = s_drive_event.GetTicksUntilNextExecution();
|
||||
ticks += remaining_change_ticks;
|
||||
|
||||
DEV_LOG("Seek time for {} LBAs: {} ({:.3f} ms) ({} for speed change/implicit TOC read)", lba_diff, ticks,
|
||||
|
@ -1492,16 +1486,16 @@ void CDROM::BeginCommand(Command command)
|
|||
s_command_info[static_cast<u8>(command)].name);
|
||||
|
||||
// subtract the currently-elapsed ack ticks from the new command
|
||||
if (s_command_event->IsActive())
|
||||
if (s_command_event.IsActive())
|
||||
{
|
||||
const TickCount elapsed_ticks = s_command_event->GetInterval() - s_command_event->GetTicksUntilNextExecution();
|
||||
const TickCount elapsed_ticks = s_command_event.GetInterval() - s_command_event.GetTicksUntilNextExecution();
|
||||
ack_delay = std::max(ack_delay - elapsed_ticks, 1);
|
||||
s_command_event->Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
s_command = command;
|
||||
s_command_event->SetIntervalAndSchedule(ack_delay);
|
||||
s_command_event.SetIntervalAndSchedule(ack_delay);
|
||||
UpdateCommandEvent();
|
||||
UpdateStatusRegister();
|
||||
}
|
||||
|
@ -1511,7 +1505,7 @@ void CDROM::EndCommand()
|
|||
s_param_fifo.Clear();
|
||||
|
||||
s_command = Command::None;
|
||||
s_command_event->Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
UpdateStatusRegister();
|
||||
}
|
||||
|
||||
|
@ -1633,7 +1627,7 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
|
|||
if (s_drive_state == DriveState::ChangingSpeedOrTOCRead)
|
||||
{
|
||||
// cancel the speed change if it's less than a quarter complete
|
||||
if (s_drive_event->GetTicksUntilNextExecution() >= (GetTicksForSpeedChange() / 4))
|
||||
if (s_drive_event.GetTicksUntilNextExecution() >= (GetTicksForSpeedChange() / 4))
|
||||
{
|
||||
DEV_LOG("Cancelling speed change event");
|
||||
ClearDriveState();
|
||||
|
@ -1648,19 +1642,19 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
|
|||
DEV_LOG("Drive is {}, delaying event by {} ticks for speed change to {}-speed",
|
||||
s_drive_state_names[static_cast<u8>(s_drive_state)], change_ticks,
|
||||
s_mode.double_speed ? "double" : "single");
|
||||
s_drive_event->Delay(change_ticks);
|
||||
s_drive_event.Delay(change_ticks);
|
||||
|
||||
if (IsReadingOrPlaying())
|
||||
{
|
||||
WARNING_LOG("Speed change while reading/playing, reads will be temporarily delayed.");
|
||||
s_drive_event->SetInterval(GetTicksForRead());
|
||||
s_drive_event.SetInterval(GetTicksForRead());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEV_LOG("Drive is idle, speed change takes {} ticks", change_ticks);
|
||||
s_drive_state = DriveState::ChangingSpeedOrTOCRead;
|
||||
s_drive_event->Schedule(change_ticks);
|
||||
s_drive_event.Schedule(change_ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1736,7 +1730,7 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
|
|||
|
||||
s_async_command_parameter = session;
|
||||
s_drive_state = DriveState::ChangingSession;
|
||||
s_drive_event->Schedule(GetTicksForTOCRead());
|
||||
s_drive_event.Schedule(GetTicksForTOCRead());
|
||||
}
|
||||
|
||||
EndCommand();
|
||||
|
@ -1870,7 +1864,7 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
|
|||
{
|
||||
// Stop reading.
|
||||
s_drive_state = DriveState::Idle;
|
||||
s_drive_event->Deactivate();
|
||||
s_drive_event.Deactivate();
|
||||
s_secondary_status.ClearActiveBits();
|
||||
}
|
||||
|
||||
|
@ -2119,7 +2113,7 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
|
|||
|
||||
// According to nocash this doesn't clear the parameter FIFO.
|
||||
s_command = Command::None;
|
||||
s_command_event->Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
UpdateStatusRegister();
|
||||
}
|
||||
break;
|
||||
|
@ -2283,14 +2277,14 @@ void CDROM::ExecuteCommandSecondResponse(void*, TickCount ticks, TickCount ticks
|
|||
}
|
||||
|
||||
s_command_second_response = Command::None;
|
||||
s_command_second_response_event->Deactivate();
|
||||
s_command_second_response_event.Deactivate();
|
||||
}
|
||||
|
||||
void CDROM::QueueCommandSecondResponse(Command command, TickCount ticks)
|
||||
{
|
||||
ClearCommandSecondResponse();
|
||||
s_command_second_response = command;
|
||||
s_command_second_response_event->Schedule(ticks);
|
||||
s_command_second_response_event.Schedule(ticks);
|
||||
}
|
||||
|
||||
void CDROM::ClearCommandSecondResponse()
|
||||
|
@ -2301,7 +2295,7 @@ void CDROM::ClearCommandSecondResponse()
|
|||
s_command_info[static_cast<u16>(s_command_second_response)].name);
|
||||
}
|
||||
|
||||
s_command_second_response_event->Deactivate();
|
||||
s_command_second_response_event.Deactivate();
|
||||
s_command_second_response = Command::None;
|
||||
}
|
||||
|
||||
|
@ -2311,12 +2305,12 @@ void CDROM::UpdateCommandEvent()
|
|||
// so deactivate it until the interrupt is acknowledged
|
||||
if (!HasPendingCommand() || HasPendingInterrupt() || HasPendingAsyncInterrupt())
|
||||
{
|
||||
s_command_event->Deactivate();
|
||||
s_command_event.Deactivate();
|
||||
return;
|
||||
}
|
||||
else if (HasPendingCommand())
|
||||
{
|
||||
s_command_event->Activate();
|
||||
s_command_event.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2395,7 +2389,7 @@ void CDROM::ExecuteDrive(void*, TickCount ticks, TickCount ticks_late)
|
|||
void CDROM::ClearDriveState()
|
||||
{
|
||||
s_drive_state = DriveState::Idle;
|
||||
s_drive_event->Deactivate();
|
||||
s_drive_event.Deactivate();
|
||||
}
|
||||
|
||||
void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = false */)
|
||||
|
@ -2411,7 +2405,7 @@ void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = fa
|
|||
if (IsSeeking())
|
||||
{
|
||||
DEV_LOG("Read command while seeking, scheduling read after seek {} -> {} finishes in {} ticks", s_seek_start_lba,
|
||||
s_seek_end_lba, s_drive_event->GetTicksUntilNextExecution());
|
||||
s_seek_end_lba, s_drive_event.GetTicksUntilNextExecution());
|
||||
|
||||
// Implicit seeks won't trigger the read, so swap it for a logical.
|
||||
if (s_drive_state == DriveState::SeekingImplicit)
|
||||
|
@ -2433,8 +2427,8 @@ void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = fa
|
|||
ResetAudioDecoder();
|
||||
|
||||
s_drive_state = DriveState::Reading;
|
||||
s_drive_event->SetInterval(ticks);
|
||||
s_drive_event->Schedule(first_sector_ticks);
|
||||
s_drive_event.SetInterval(ticks);
|
||||
s_drive_event.Schedule(first_sector_ticks);
|
||||
|
||||
s_requested_lba = s_current_lba;
|
||||
s_reader.QueueReadSector(s_requested_lba);
|
||||
|
@ -2476,8 +2470,8 @@ void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_se
|
|||
ResetAudioDecoder();
|
||||
|
||||
s_drive_state = DriveState::Playing;
|
||||
s_drive_event->SetInterval(ticks);
|
||||
s_drive_event->Schedule(first_sector_ticks);
|
||||
s_drive_event.SetInterval(ticks);
|
||||
s_drive_event.Schedule(first_sector_ticks);
|
||||
|
||||
s_requested_lba = s_current_lba;
|
||||
s_reader.QueueReadSector(s_requested_lba);
|
||||
|
@ -2509,7 +2503,7 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
|
|||
s_last_sector_header_valid = false;
|
||||
|
||||
s_drive_state = logical ? DriveState::SeekingLogical : DriveState::SeekingPhysical;
|
||||
s_drive_event->SetIntervalAndSchedule(seek_time);
|
||||
s_drive_event.SetIntervalAndSchedule(seek_time);
|
||||
|
||||
s_seek_start_lba = s_current_lba;
|
||||
s_seek_end_lba = seek_lba;
|
||||
|
@ -2521,8 +2515,8 @@ void CDROM::UpdatePositionWhileSeeking()
|
|||
{
|
||||
DebugAssert(IsSeeking());
|
||||
|
||||
const float completed_frac = 1.0f - std::min(static_cast<float>(s_drive_event->GetTicksUntilNextExecution()) /
|
||||
static_cast<float>(s_drive_event->GetInterval()),
|
||||
const float completed_frac = 1.0f - std::min(static_cast<float>(s_drive_event.GetTicksUntilNextExecution()) /
|
||||
static_cast<float>(s_drive_event.GetInterval()),
|
||||
1.0f);
|
||||
|
||||
CDImage::LBA current_lba;
|
||||
|
@ -2804,7 +2798,7 @@ void CDROM::DoSpinUpComplete()
|
|||
{
|
||||
DEBUG_LOG("Spinup complete");
|
||||
s_drive_state = DriveState::Idle;
|
||||
s_drive_event->Deactivate();
|
||||
s_drive_event.Deactivate();
|
||||
s_secondary_status.ClearActiveBits();
|
||||
s_secondary_status.motor_on = true;
|
||||
}
|
||||
|
@ -2813,7 +2807,7 @@ void CDROM::DoSpeedChangeOrImplicitTOCReadComplete()
|
|||
{
|
||||
DEBUG_LOG("Speed change/implicit TOC read complete");
|
||||
s_drive_state = DriveState::Idle;
|
||||
s_drive_event->Deactivate();
|
||||
s_drive_event.Deactivate();
|
||||
}
|
||||
|
||||
void CDROM::DoIDRead()
|
||||
|
@ -2878,7 +2872,7 @@ void CDROM::StartMotor()
|
|||
|
||||
DEV_LOG("Starting motor");
|
||||
s_drive_state = DriveState::SpinningUp;
|
||||
s_drive_event->Schedule(GetTicksForSpinUp());
|
||||
s_drive_event.Schedule(GetTicksForSpinUp());
|
||||
}
|
||||
|
||||
void CDROM::StopMotor()
|
||||
|
@ -3387,7 +3381,7 @@ void CDROM::CheckForSectorBufferReadComplete()
|
|||
DEV_LOG("Sending additional INT1 for missed sector in buffer {}", s_current_write_sector_buffer);
|
||||
s_async_response_fifo.Push(s_secondary_status.bits);
|
||||
s_pending_async_interrupt = static_cast<u8>(Interrupt::DataReady);
|
||||
s_async_interrupt_event->Schedule(INTERRUPT_DELAY_CYCLES);
|
||||
s_async_interrupt_event.Schedule(INTERRUPT_DELAY_CYCLES);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3669,7 +3663,7 @@ void CDROM::DrawDebugWindow()
|
|||
{
|
||||
ImGui::TextColored(active_color, "Command: %s (0x%02X) (%d ticks remaining)",
|
||||
s_command_info[static_cast<u8>(s_command)].name, static_cast<u8>(s_command),
|
||||
s_command_event->IsActive() ? s_command_event->GetTicksUntilNextExecution() : 0);
|
||||
s_command_event.IsActive() ? s_command_event.GetTicksUntilNextExecution() : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3684,7 +3678,7 @@ void CDROM::DrawDebugWindow()
|
|||
{
|
||||
ImGui::TextColored(active_color, "Drive: %s (%d ticks remaining)",
|
||||
s_drive_state_names[static_cast<u8>(s_drive_state)],
|
||||
s_drive_event->IsActive() ? s_drive_event->GetTicksUntilNextExecution() : 0);
|
||||
s_drive_event.IsActive() ? s_drive_event.GetTicksUntilNextExecution() : 0);
|
||||
}
|
||||
|
||||
ImGui::Text("Interrupt Enable Register: 0x%02X", s_interrupt_enable_register);
|
||||
|
|
|
@ -204,7 +204,7 @@ struct DMAState
|
|||
TickCount halt_ticks = 100;
|
||||
|
||||
std::vector<u32> transfer_buffer;
|
||||
std::unique_ptr<TimingEvent> unhalt_event;
|
||||
TimingEvent unhalt_event{"DMA Transfer Unhalt", 1, 1, &DMA::UnhaltTransfer, nullptr};
|
||||
TickCount halt_ticks_remaining = 0;
|
||||
|
||||
std::array<ChannelState, NUM_CHANNELS> channels;
|
||||
|
@ -243,22 +243,20 @@ void DMA::Initialize()
|
|||
{
|
||||
s_state.max_slice_ticks = g_settings.dma_max_slice_ticks;
|
||||
s_state.halt_ticks = g_settings.dma_halt_ticks;
|
||||
|
||||
s_state.unhalt_event = TimingEvents::CreateTimingEvent("DMA Transfer Unhalt", 1, s_state.max_slice_ticks,
|
||||
&DMA::UnhaltTransfer, nullptr, false);
|
||||
s_state.unhalt_event.SetInterval(s_state.max_slice_ticks);
|
||||
Reset();
|
||||
}
|
||||
|
||||
void DMA::Shutdown()
|
||||
{
|
||||
ClearState();
|
||||
s_state.unhalt_event.reset();
|
||||
s_state.unhalt_event.Deactivate();
|
||||
}
|
||||
|
||||
void DMA::Reset()
|
||||
{
|
||||
ClearState();
|
||||
s_state.unhalt_event->Deactivate();
|
||||
s_state.unhalt_event.Deactivate();
|
||||
}
|
||||
|
||||
void DMA::ClearState()
|
||||
|
@ -297,9 +295,9 @@ bool DMA::DoState(StateWrapper& sw)
|
|||
if (sw.IsReading())
|
||||
{
|
||||
if (s_state.halt_ticks_remaining > 0)
|
||||
s_state.unhalt_event->SetIntervalAndSchedule(s_state.halt_ticks_remaining);
|
||||
s_state.unhalt_event.SetIntervalAndSchedule(s_state.halt_ticks_remaining);
|
||||
else
|
||||
s_state.unhalt_event->Deactivate();
|
||||
s_state.unhalt_event.Deactivate();
|
||||
}
|
||||
|
||||
return !sw.HasError();
|
||||
|
@ -502,7 +500,7 @@ ALWAYS_INLINE_RELEASE bool DMA::CanTransferChannel(Channel channel, bool ignore_
|
|||
|
||||
bool DMA::IsTransferHalted()
|
||||
{
|
||||
return s_state.unhalt_event->IsActive();
|
||||
return s_state.unhalt_event.IsActive();
|
||||
}
|
||||
|
||||
void DMA::UpdateIRQ()
|
||||
|
@ -733,7 +731,7 @@ bool DMA::TransferChannel()
|
|||
if (cs.request)
|
||||
{
|
||||
// we got halted
|
||||
if (!s_state.unhalt_event->IsActive())
|
||||
if (!s_state.unhalt_event.IsActive())
|
||||
HaltTransfer(s_state.halt_ticks);
|
||||
|
||||
return false;
|
||||
|
@ -757,18 +755,18 @@ void DMA::HaltTransfer(TickCount duration)
|
|||
{
|
||||
s_state.halt_ticks_remaining += duration;
|
||||
DEBUG_LOG("Halting DMA for {} ticks", s_state.halt_ticks_remaining);
|
||||
if (s_state.unhalt_event->IsActive())
|
||||
if (s_state.unhalt_event.IsActive())
|
||||
return;
|
||||
|
||||
DebugAssert(!s_state.unhalt_event->IsActive());
|
||||
s_state.unhalt_event->SetIntervalAndSchedule(s_state.halt_ticks_remaining);
|
||||
DebugAssert(!s_state.unhalt_event.IsActive());
|
||||
s_state.unhalt_event.SetIntervalAndSchedule(s_state.halt_ticks_remaining);
|
||||
}
|
||||
|
||||
void DMA::UnhaltTransfer(void*, TickCount ticks, TickCount ticks_late)
|
||||
{
|
||||
DEBUG_LOG("Resuming DMA after {} ticks, {} ticks late", ticks, -(s_state.halt_ticks_remaining - ticks));
|
||||
s_state.halt_ticks_remaining -= ticks;
|
||||
s_state.unhalt_event->Deactivate();
|
||||
s_state.unhalt_event.Deactivate();
|
||||
|
||||
// TODO: Use channel priority. But doing it in ascending order is probably good enough.
|
||||
// Main thing is that OTC happens after GPU, because otherwise it'll wipe out the LL.
|
||||
|
|
|
@ -60,12 +60,22 @@ static u32 s_active_gpu_cycles_frames = 0;
|
|||
static constexpr GPUTexture::Format DISPLAY_INTERNAL_POSTFX_FORMAT = GPUTexture::Format::RGBA8;
|
||||
|
||||
GPU::GPU()
|
||||
: m_crtc_tick_event(
|
||||
"GPU CRTC Tick", 1, 1,
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<GPU*>(param)->CRTCTickEvent(ticks); }, this),
|
||||
m_command_tick_event(
|
||||
"GPU Command Tick", 1, 1,
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<GPU*>(param)->CommandTickEvent(ticks); },
|
||||
this)
|
||||
{
|
||||
ResetStatistics();
|
||||
}
|
||||
|
||||
GPU::~GPU()
|
||||
{
|
||||
m_command_tick_event.Deactivate();
|
||||
m_crtc_tick_event.Deactivate();
|
||||
|
||||
JoinScreenshotThreads();
|
||||
DestroyDeinterlaceTextures();
|
||||
g_gpu_device->RecycleTexture(std::move(m_chroma_smoothing_texture));
|
||||
|
@ -78,14 +88,7 @@ bool GPU::Initialize()
|
|||
{
|
||||
m_force_progressive_scan = g_settings.gpu_disable_interlacing;
|
||||
m_force_ntsc_timings = g_settings.gpu_force_ntsc_timings;
|
||||
m_crtc_tick_event = TimingEvents::CreateTimingEvent(
|
||||
"GPU CRTC Tick", 1, 1,
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<GPU*>(param)->CRTCTickEvent(ticks); }, this,
|
||||
true);
|
||||
m_command_tick_event = TimingEvents::CreateTimingEvent(
|
||||
"GPU Command Tick", 1, 1,
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<GPU*>(param)->CommandTickEvent(ticks); }, this,
|
||||
true);
|
||||
m_crtc_tick_event.Activate();
|
||||
m_fifo_size = g_settings.gpu_fifo_size;
|
||||
m_max_run_ahead = g_settings.gpu_max_run_ahead;
|
||||
m_console_is_pal = System::IsPALRegion();
|
||||
|
@ -187,8 +190,8 @@ void GPU::Reset(bool clear_vram)
|
|||
m_blitter_state = BlitterState::Idle;
|
||||
|
||||
// Force event to reschedule itself.
|
||||
m_crtc_tick_event->Deactivate();
|
||||
m_command_tick_event->Deactivate();
|
||||
m_crtc_tick_event.Deactivate();
|
||||
m_command_tick_event.Deactivate();
|
||||
|
||||
SoftReset();
|
||||
UpdateDisplay();
|
||||
|
@ -455,7 +458,7 @@ u32 GPU::ReadRegister(u32 offset)
|
|||
if (IsCRTCScanlinePending())
|
||||
SynchronizeCRTC();
|
||||
if (IsCommandCompletionPending())
|
||||
m_command_tick_event->InvokeEarly();
|
||||
m_command_tick_event.InvokeEarly();
|
||||
|
||||
return m_GPUSTAT.bits;
|
||||
}
|
||||
|
@ -547,7 +550,7 @@ void GPU::AddCommandTicks(TickCount ticks)
|
|||
|
||||
void GPU::SynchronizeCRTC()
|
||||
{
|
||||
m_crtc_tick_event->InvokeEarly();
|
||||
m_crtc_tick_event.InvokeEarly();
|
||||
}
|
||||
|
||||
float GPU::ComputeHorizontalFrequency() const
|
||||
|
@ -833,17 +836,17 @@ void GPU::UpdateCRTCDisplayParameters()
|
|||
|
||||
TickCount GPU::GetPendingCRTCTicks() const
|
||||
{
|
||||
const TickCount pending_sysclk_ticks = m_crtc_tick_event->GetTicksSinceLastExecution();
|
||||
const TickCount pending_sysclk_ticks = m_crtc_tick_event.GetTicksSinceLastExecution();
|
||||
TickCount fractional_ticks = m_crtc_state.fractional_ticks;
|
||||
return SystemTicksToCRTCTicks(pending_sysclk_ticks, &fractional_ticks);
|
||||
}
|
||||
|
||||
TickCount GPU::GetPendingCommandTicks() const
|
||||
{
|
||||
if (!m_command_tick_event->IsActive())
|
||||
if (!m_command_tick_event.IsActive())
|
||||
return 0;
|
||||
|
||||
return SystemTicksToGPUTicks(m_command_tick_event->GetTicksSinceLastExecution());
|
||||
return SystemTicksToGPUTicks(m_command_tick_event.GetTicksSinceLastExecution());
|
||||
}
|
||||
|
||||
void GPU::UpdateCRTCTickEvent()
|
||||
|
@ -900,7 +903,7 @@ void GPU::UpdateCRTCTickEvent()
|
|||
ticks_until_event = std::min(ticks_until_event, ticks_until_hblank_start_or_end);
|
||||
}
|
||||
|
||||
m_crtc_tick_event->Schedule(CRTCTicksToSystemTicks(ticks_until_event, m_crtc_state.fractional_ticks));
|
||||
m_crtc_tick_event.Schedule(CRTCTicksToSystemTicks(ticks_until_event, m_crtc_state.fractional_ticks));
|
||||
}
|
||||
|
||||
bool GPU::IsCRTCScanlinePending() const
|
||||
|
@ -1080,11 +1083,11 @@ void GPU::UpdateCommandTickEvent()
|
|||
if (m_pending_command_ticks <= 0)
|
||||
{
|
||||
m_pending_command_ticks = 0;
|
||||
m_command_tick_event->Deactivate();
|
||||
m_command_tick_event.Deactivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_command_tick_event->SetIntervalAndSchedule(GPUTicksToSystemTicks(m_pending_command_ticks));
|
||||
m_command_tick_event.SetIntervalAndSchedule(GPUTicksToSystemTicks(m_pending_command_ticks));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1209,7 +1212,7 @@ void GPU::WriteGP1(u32 value)
|
|||
case 0x00: // Reset GPU
|
||||
{
|
||||
DEBUG_LOG("GP1 reset GPU");
|
||||
m_command_tick_event->InvokeEarly();
|
||||
m_command_tick_event.InvokeEarly();
|
||||
SynchronizeCRTC();
|
||||
SoftReset();
|
||||
}
|
||||
|
@ -1218,7 +1221,7 @@ void GPU::WriteGP1(u32 value)
|
|||
case 0x01: // Clear FIFO
|
||||
{
|
||||
DEBUG_LOG("GP1 clear FIFO");
|
||||
m_command_tick_event->InvokeEarly();
|
||||
m_command_tick_event.InvokeEarly();
|
||||
SynchronizeCRTC();
|
||||
|
||||
// flush partial writes
|
||||
|
@ -1232,7 +1235,7 @@ void GPU::WriteGP1(u32 value)
|
|||
m_blit_buffer.clear();
|
||||
m_blit_remaining_words = 0;
|
||||
m_pending_command_ticks = 0;
|
||||
m_command_tick_event->Deactivate();
|
||||
m_command_tick_event.Deactivate();
|
||||
UpdateDMARequest();
|
||||
UpdateGPUIdle();
|
||||
}
|
||||
|
@ -1350,7 +1353,7 @@ void GPU::WriteGP1(u32 value)
|
|||
{
|
||||
// Have to be careful when setting this because Synchronize() can modify GPUSTAT.
|
||||
static constexpr u32 SET_MASK = UINT32_C(0b00000000011111110100000000000000);
|
||||
m_command_tick_event->InvokeEarly();
|
||||
m_command_tick_event.InvokeEarly();
|
||||
SynchronizeCRTC();
|
||||
m_GPUSTAT.bits = (m_GPUSTAT.bits & ~SET_MASK) | (new_GPUSTAT.bits & SET_MASK);
|
||||
UpdateCRTCConfig();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "gpu_types.h"
|
||||
#include "timers.h"
|
||||
#include "types.h"
|
||||
#include "timing_event.h"
|
||||
|
||||
#include "util/gpu_texture.h"
|
||||
|
||||
|
@ -29,7 +30,6 @@ class GPUTexture;
|
|||
class GPUPipeline;
|
||||
|
||||
struct Settings;
|
||||
class TimingEvent;
|
||||
|
||||
namespace Threading {
|
||||
class Thread;
|
||||
|
@ -370,8 +370,8 @@ protected:
|
|||
AddCommandTicks(std::max(drawn_width, drawn_height));
|
||||
}
|
||||
|
||||
std::unique_ptr<TimingEvent> m_crtc_tick_event;
|
||||
std::unique_ptr<TimingEvent> m_command_tick_event;
|
||||
TimingEvent m_crtc_tick_event;
|
||||
TimingEvent m_command_tick_event;
|
||||
|
||||
union GPUSTAT
|
||||
{
|
||||
|
|
|
@ -28,16 +28,21 @@ static u32 s_irq_current_line;
|
|||
#endif
|
||||
|
||||
static constexpr std::array<u8, static_cast<size_t>(Justifier::Binding::ButtonCount)> s_button_indices = {{15, 3, 14}};
|
||||
static constexpr std::array<const char*, NUM_CONTROLLER_AND_CARD_PORTS> s_event_names = {
|
||||
{"Justifier IRQ P0", "Justifier IRQ P1", "Justifier IRQ P2", "Justifier IRQ P3", "Justifier IRQ P4",
|
||||
"Justifier IRQ P5", "Justifier IRQ P6", "Justifier IRQ P7"}};
|
||||
|
||||
Justifier::Justifier(u32 index) : Controller(index)
|
||||
Justifier::Justifier(u32 index)
|
||||
: Controller(index), m_irq_event(
|
||||
s_event_names[index], 1, 1,
|
||||
[](void* param, TickCount, TickCount) { static_cast<Justifier*>(param)->IRQEvent(); }, this)
|
||||
{
|
||||
m_irq_event = TimingEvents::CreateTimingEvent(
|
||||
"Justifier IRQ", 1, 1, [](void* param, TickCount, TickCount) { static_cast<Justifier*>(param)->IRQEvent(); }, this,
|
||||
false);
|
||||
}
|
||||
|
||||
Justifier::~Justifier()
|
||||
{
|
||||
m_irq_event.Deactivate();
|
||||
|
||||
if (!m_cursor_path.empty())
|
||||
{
|
||||
const u32 cursor_index = GetSoftwarePointerIndex();
|
||||
|
@ -245,7 +250,7 @@ void Justifier::UpdatePosition()
|
|||
void Justifier::UpdateIRQEvent()
|
||||
{
|
||||
// TODO: Avoid deactivate and event sort.
|
||||
m_irq_event->Deactivate();
|
||||
m_irq_event.Deactivate();
|
||||
|
||||
if (!m_position_valid)
|
||||
return;
|
||||
|
@ -261,7 +266,7 @@ void Justifier::UpdateIRQEvent()
|
|||
|
||||
const TickCount ticks_until_pos = g_gpu->GetSystemTicksUntilTicksAndLine(m_irq_tick, target_line);
|
||||
DEBUG_LOG("Triggering IRQ in {} ticks @ tick {} line {}", ticks_until_pos, m_irq_tick, target_line);
|
||||
m_irq_event->Schedule(ticks_until_pos);
|
||||
m_irq_event.Schedule(ticks_until_pos);
|
||||
}
|
||||
|
||||
void Justifier::IRQEvent()
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "controller.h"
|
||||
#include "timing_event.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
@ -77,8 +80,6 @@ private:
|
|||
static constexpr u8 DEFAULT_OFFSCREEN_TRIGGER_FRAMES = 5;
|
||||
static constexpr u8 DEFAULT_OFFSCREEN_RELEASE_FRAMES = 5;
|
||||
|
||||
std::unique_ptr<TimingEvent> m_irq_event;
|
||||
|
||||
s8 m_first_line_offset = 0;
|
||||
s8 m_last_line_offset = 0;
|
||||
s16 m_tick_offset = 0;
|
||||
|
@ -98,6 +99,8 @@ private:
|
|||
|
||||
TransferState m_transfer_state = TransferState::Idle;
|
||||
|
||||
TimingEvent m_irq_event;
|
||||
|
||||
bool m_has_relative_binds = false;
|
||||
float m_relative_pos[4] = {};
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ struct MDECState
|
|||
u16 current_q_scale = 0;
|
||||
|
||||
alignas(16) std::array<u32, 256> block_rgb{};
|
||||
std::unique_ptr<TimingEvent> block_copy_out_event;
|
||||
TimingEvent block_copy_out_event{"MDEC Block Copy Out", 1, 1, &MDEC::CopyOutBlock, nullptr};
|
||||
|
||||
u32 total_blocks_decoded = 0;
|
||||
};
|
||||
|
@ -162,20 +162,18 @@ ALIGN_TO_CACHE_LINE static MDECState s_state;
|
|||
|
||||
void MDEC::Initialize()
|
||||
{
|
||||
s_state.block_copy_out_event =
|
||||
TimingEvents::CreateTimingEvent("MDEC Block Copy Out", 1, 1, &MDEC::CopyOutBlock, nullptr, false);
|
||||
s_state.total_blocks_decoded = 0;
|
||||
Reset();
|
||||
}
|
||||
|
||||
void MDEC::Shutdown()
|
||||
{
|
||||
s_state.block_copy_out_event.reset();
|
||||
s_state.block_copy_out_event.Deactivate();
|
||||
}
|
||||
|
||||
void MDEC::Reset()
|
||||
{
|
||||
s_state.block_copy_out_event->Deactivate();
|
||||
s_state.block_copy_out_event.Deactivate();
|
||||
SoftReset();
|
||||
}
|
||||
|
||||
|
@ -211,7 +209,7 @@ bool MDEC::DoState(StateWrapper& sw)
|
|||
bool block_copy_out_pending = HasPendingBlockCopyOut();
|
||||
sw.Do(&block_copy_out_pending);
|
||||
if (sw.IsReading())
|
||||
s_state.block_copy_out_event->SetState(block_copy_out_pending);
|
||||
s_state.block_copy_out_event.SetState(block_copy_out_pending);
|
||||
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
@ -304,7 +302,7 @@ void MDEC::DMAWrite(const u32* words, u32 word_count)
|
|||
|
||||
bool MDEC::HasPendingBlockCopyOut()
|
||||
{
|
||||
return s_state.block_copy_out_event->IsActive();
|
||||
return s_state.block_copy_out_event.IsActive();
|
||||
}
|
||||
|
||||
void MDEC::SoftReset()
|
||||
|
@ -319,7 +317,7 @@ void MDEC::SoftReset()
|
|||
s_state.current_block = 0;
|
||||
s_state.current_coefficient = 64;
|
||||
s_state.current_q_scale = 0;
|
||||
s_state.block_copy_out_event->Deactivate();
|
||||
s_state.block_copy_out_event.Deactivate();
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
|
@ -358,7 +356,7 @@ u32 MDEC::ReadDataRegister()
|
|||
if (HasPendingBlockCopyOut())
|
||||
{
|
||||
DEV_LOG("MDEC data out FIFO empty on read - stalling CPU");
|
||||
CPU::AddPendingTicks(s_state.block_copy_out_event->GetTicksUntilNextExecution());
|
||||
CPU::AddPendingTicks(s_state.block_copy_out_event.GetTicksUntilNextExecution());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -617,13 +615,13 @@ void MDEC::ScheduleBlockCopyOut(TickCount ticks)
|
|||
DebugAssert(!HasPendingBlockCopyOut());
|
||||
DEBUG_LOG("Scheduling block copy out in {} ticks", ticks);
|
||||
|
||||
s_state.block_copy_out_event->SetIntervalAndSchedule(ticks);
|
||||
s_state.block_copy_out_event.SetIntervalAndSchedule(ticks);
|
||||
}
|
||||
|
||||
void MDEC::CopyOutBlock(void* param, TickCount ticks, TickCount ticks_late)
|
||||
{
|
||||
Assert(s_state.state == State::WritingMacroblock);
|
||||
s_state.block_copy_out_event->Deactivate();
|
||||
s_state.block_copy_out_event.Deactivate();
|
||||
|
||||
switch (s_state.status.data_output_depth)
|
||||
{
|
||||
|
|
|
@ -22,13 +22,12 @@
|
|||
Log_SetChannel(MemoryCard);
|
||||
|
||||
MemoryCard::MemoryCard()
|
||||
: m_save_event(
|
||||
"Memory Card Host Flush", GetSaveDelayInTicks(), GetSaveDelayInTicks(),
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<MemoryCard*>(param)->SaveIfChanged(true); },
|
||||
this)
|
||||
{
|
||||
m_FLAG.no_write_yet = true;
|
||||
|
||||
m_save_event = TimingEvents::CreateTimingEvent(
|
||||
"Memory Card Host Flush", GetSaveDelayInTicks(), GetSaveDelayInTicks(),
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<MemoryCard*>(param)->SaveIfChanged(true); },
|
||||
this, false);
|
||||
}
|
||||
|
||||
MemoryCard::~MemoryCard()
|
||||
|
@ -285,7 +284,7 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
|||
|
||||
bool MemoryCard::IsOrWasRecentlyWriting() const
|
||||
{
|
||||
return (m_state == State::WriteData || m_save_event->IsActive());
|
||||
return (m_state == State::WriteData || m_save_event.IsActive());
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryCard> MemoryCard::Create()
|
||||
|
@ -324,7 +323,7 @@ bool MemoryCard::LoadFromFile()
|
|||
|
||||
bool MemoryCard::SaveIfChanged(bool display_osd_message)
|
||||
{
|
||||
m_save_event->Deactivate();
|
||||
m_save_event.Deactivate();
|
||||
|
||||
if (!m_changed)
|
||||
return true;
|
||||
|
@ -369,9 +368,9 @@ bool MemoryCard::SaveIfChanged(bool display_osd_message)
|
|||
void MemoryCard::QueueFileSave()
|
||||
{
|
||||
// skip if the event is already pending, or we don't have a backing file
|
||||
if (m_save_event->IsActive() || m_filename.empty())
|
||||
if (m_save_event.IsActive() || m_filename.empty())
|
||||
return;
|
||||
|
||||
// save in one second, that should be long enough for everything to finish writing
|
||||
m_save_event->Schedule(GetSaveDelayInTicks());
|
||||
m_save_event.Schedule(GetSaveDelayInTicks());
|
||||
}
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "common/bitfield.h"
|
||||
|
||||
#include "controller.h"
|
||||
#include "memory_card_image.h"
|
||||
#include "timing_event.h"
|
||||
|
||||
#include "common/bitfield.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class TimingEvent;
|
||||
|
||||
class MemoryCard final
|
||||
{
|
||||
public:
|
||||
|
@ -97,8 +99,6 @@ private:
|
|||
bool SaveIfChanged(bool display_osd_message);
|
||||
void QueueFileSave();
|
||||
|
||||
std::unique_ptr<TimingEvent> m_save_event;
|
||||
|
||||
State m_state = State::Idle;
|
||||
FLAG m_FLAG = {};
|
||||
u16 m_address = 0;
|
||||
|
@ -107,7 +107,8 @@ private:
|
|||
u8 m_last_byte = 0;
|
||||
bool m_changed = false;
|
||||
|
||||
MemoryCardImage::DataArray m_data{};
|
||||
|
||||
TimingEvent m_save_event;
|
||||
std::string m_filename;
|
||||
|
||||
MemoryCardImage::DataArray m_data{};
|
||||
};
|
||||
|
|
|
@ -117,7 +117,7 @@ static std::array<std::unique_ptr<MemoryCard>, NUM_CONTROLLER_AND_CARD_PORTS> s_
|
|||
|
||||
static std::array<Multitap, NUM_MULTITAPS> s_multitaps;
|
||||
|
||||
static std::unique_ptr<TimingEvent> s_transfer_event;
|
||||
static TimingEvent s_transfer_event{"Pad Serial Transfer", 1, 1, &Pad::TransferEvent, nullptr};
|
||||
static State s_state = State::Idle;
|
||||
|
||||
static JOY_CTRL s_JOY_CTRL = {};
|
||||
|
@ -140,7 +140,6 @@ static std::unique_ptr<MemoryCard> s_dummy_card;
|
|||
|
||||
void Pad::Initialize()
|
||||
{
|
||||
s_transfer_event = TimingEvents::CreateTimingEvent("Pad Serial Transfer", 1, 1, &Pad::TransferEvent, nullptr, false);
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
@ -148,7 +147,7 @@ void Pad::Shutdown()
|
|||
{
|
||||
s_memory_card_backup.reset();
|
||||
|
||||
s_transfer_event.reset();
|
||||
s_transfer_event.Deactivate();
|
||||
|
||||
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
|
||||
{
|
||||
|
@ -533,7 +532,7 @@ bool Pad::DoState(StateWrapper& sw, bool is_memory_state)
|
|||
sw.Do(&s_transmit_buffer_full);
|
||||
|
||||
if (sw.IsReading() && IsTransmitting())
|
||||
s_transfer_event->Activate();
|
||||
s_transfer_event.Activate();
|
||||
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
@ -581,7 +580,7 @@ u32 Pad::ReadRegister(u32 offset)
|
|||
case 0x00: // JOY_DATA
|
||||
{
|
||||
if (IsTransmitting())
|
||||
s_transfer_event->InvokeEarly();
|
||||
s_transfer_event.InvokeEarly();
|
||||
|
||||
const u8 value = s_receive_buffer_full ? s_receive_buffer : 0xFF;
|
||||
DEBUG_LOG("JOY_DATA (R) -> 0x{:02X}{}", value, s_receive_buffer_full ? "" : "(EMPTY)");
|
||||
|
@ -595,7 +594,7 @@ u32 Pad::ReadRegister(u32 offset)
|
|||
case 0x04: // JOY_STAT
|
||||
{
|
||||
if (IsTransmitting())
|
||||
s_transfer_event->InvokeEarly();
|
||||
s_transfer_event.InvokeEarly();
|
||||
|
||||
const u32 bits = s_JOY_STAT.bits;
|
||||
s_JOY_STAT.ACKINPUT = false;
|
||||
|
@ -763,7 +762,7 @@ void Pad::BeginTransfer()
|
|||
// until after (4) and (5) have been completed.
|
||||
|
||||
s_state = State::Transmitting;
|
||||
s_transfer_event->SetPeriodAndSchedule(GetTransferTicks());
|
||||
s_transfer_event.SetPeriodAndSchedule(GetTransferTicks());
|
||||
}
|
||||
|
||||
void Pad::DoTransfer(TickCount ticks_late)
|
||||
|
@ -882,7 +881,7 @@ void Pad::DoTransfer(TickCount ticks_late)
|
|||
const TickCount ack_timer = GetACKTicks(memcard_transfer);
|
||||
DEBUG_LOG("Delaying ACK for {} ticks", ack_timer);
|
||||
s_state = State::WaitingForACK;
|
||||
s_transfer_event->SetPeriodAndSchedule(ack_timer);
|
||||
s_transfer_event.SetPeriodAndSchedule(ack_timer);
|
||||
}
|
||||
|
||||
UpdateJoyStat();
|
||||
|
@ -912,7 +911,7 @@ void Pad::EndTransfer()
|
|||
DEBUG_LOG("Ending transfer");
|
||||
|
||||
s_state = State::Idle;
|
||||
s_transfer_event->Deactivate();
|
||||
s_transfer_event.Deactivate();
|
||||
}
|
||||
|
||||
void Pad::ResetDeviceTransferState()
|
||||
|
|
|
@ -355,8 +355,9 @@ static void CreateOutputStream();
|
|||
namespace {
|
||||
struct SPUState
|
||||
{
|
||||
std::unique_ptr<TimingEvent> s_tick_event;
|
||||
std::unique_ptr<TimingEvent> transfer_event;
|
||||
TimingEvent transfer_event{"SPU Transfer", TRANSFER_TICKS_PER_HALFWORD, TRANSFER_TICKS_PER_HALFWORD,
|
||||
&SPU::ExecuteTransfer, nullptr};
|
||||
TimingEvent tick_event{"SPU Sample", SYSCLK_TICKS_PER_SPU_TICK, SYSCLK_TICKS_PER_SPU_TICK, &SPU::Execute, nullptr};
|
||||
|
||||
TickCount ticks_carry = 0;
|
||||
TickCount cpu_ticks_per_spu_tick = 0;
|
||||
|
@ -426,10 +427,8 @@ void SPU::Initialize()
|
|||
// (X * D) / N / 768 -> (X * D) / (N * 768)
|
||||
s_state.cpu_ticks_per_spu_tick = System::ScaleTicksToOverclock(SYSCLK_TICKS_PER_SPU_TICK);
|
||||
s_state.cpu_tick_divider = static_cast<TickCount>(g_settings.cpu_overclock_numerator * SYSCLK_TICKS_PER_SPU_TICK);
|
||||
s_state.s_tick_event = TimingEvents::CreateTimingEvent("SPU Sample", s_state.cpu_ticks_per_spu_tick,
|
||||
s_state.cpu_ticks_per_spu_tick, &SPU::Execute, nullptr, false);
|
||||
s_state.transfer_event = TimingEvents::CreateTimingEvent(
|
||||
"SPU Transfer", TRANSFER_TICKS_PER_HALFWORD, TRANSFER_TICKS_PER_HALFWORD, &SPU::ExecuteTransfer, nullptr, false);
|
||||
s_state.tick_event.SetInterval(s_state.cpu_ticks_per_spu_tick);
|
||||
s_state.tick_event.SetPeriod(s_state.cpu_ticks_per_spu_tick);
|
||||
s_state.null_audio_stream = AudioStream::CreateNullStream(SAMPLE_RATE, g_settings.audio_stream_parameters.buffer_ms);
|
||||
|
||||
CreateOutputStream();
|
||||
|
@ -482,8 +481,8 @@ void SPU::CPUClockChanged()
|
|||
void SPU::Shutdown()
|
||||
{
|
||||
StopDumpingAudio();
|
||||
s_state.s_tick_event.reset();
|
||||
s_state.transfer_event.reset();
|
||||
s_state.tick_event.Deactivate();
|
||||
s_state.transfer_event.Deactivate();
|
||||
s_state.audio_stream.reset();
|
||||
}
|
||||
|
||||
|
@ -539,8 +538,8 @@ void SPU::Reset()
|
|||
v.ignore_loop_address = false;
|
||||
}
|
||||
|
||||
s_state.s_tick_event->Deactivate();
|
||||
s_state.transfer_event->Deactivate();
|
||||
s_state.tick_event.Deactivate();
|
||||
s_state.transfer_event.Deactivate();
|
||||
s_state.transfer_fifo.Clear();
|
||||
s_ram.fill(0);
|
||||
UpdateEventInterval();
|
||||
|
@ -885,7 +884,7 @@ void SPU::WriteRegister(u32 offset, u16 value)
|
|||
case 0x1F801DA6 - SPU_BASE:
|
||||
{
|
||||
DEBUG_LOG("SPU transfer address register <- 0x{:04X}", value);
|
||||
s_state.transfer_event->InvokeEarly();
|
||||
s_state.transfer_event.InvokeEarly();
|
||||
s_state.transfer_address_reg = value;
|
||||
s_state.transfer_address = ZeroExtend32(value) * 8;
|
||||
if (IsRAMIRQTriggerable() && CheckRAMIRQ(s_state.transfer_address))
|
||||
|
@ -1283,14 +1282,14 @@ void SPU::ExecuteTransfer(void* param, TickCount ticks, TickCount ticks_late)
|
|||
if (s_state.transfer_fifo.IsFull())
|
||||
{
|
||||
s_state.SPUSTAT.transfer_busy = false;
|
||||
s_state.transfer_event->Deactivate();
|
||||
s_state.transfer_event.Deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
s_state.SPUSTAT.transfer_busy = true;
|
||||
const TickCount ticks_until_complete =
|
||||
TickCount(s_state.transfer_fifo.GetSpace() * u32(TRANSFER_TICKS_PER_HALFWORD)) + ((ticks < 0) ? -ticks : 0);
|
||||
s_state.transfer_event->Schedule(ticks_until_complete);
|
||||
s_state.transfer_event.Schedule(ticks_until_complete);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1307,14 +1306,14 @@ void SPU::ExecuteTransfer(void* param, TickCount ticks, TickCount ticks_late)
|
|||
if (s_state.transfer_fifo.IsEmpty())
|
||||
{
|
||||
s_state.SPUSTAT.transfer_busy = false;
|
||||
s_state.transfer_event->Deactivate();
|
||||
s_state.transfer_event.Deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
s_state.SPUSTAT.transfer_busy = true;
|
||||
const TickCount ticks_until_complete =
|
||||
TickCount(s_state.transfer_fifo.GetSize() * u32(TRANSFER_TICKS_PER_HALFWORD)) + ((ticks < 0) ? -ticks : 0);
|
||||
s_state.transfer_event->Schedule(ticks_until_complete);
|
||||
s_state.transfer_event.Schedule(ticks_until_complete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1343,26 +1342,26 @@ void SPU::UpdateTransferEvent()
|
|||
const RAMTransferMode mode = s_state.SPUCNT.ram_transfer_mode;
|
||||
if (mode == RAMTransferMode::Stopped)
|
||||
{
|
||||
s_state.transfer_event->Deactivate();
|
||||
s_state.transfer_event.Deactivate();
|
||||
}
|
||||
else if (mode == RAMTransferMode::DMARead)
|
||||
{
|
||||
// transfer event fills the fifo
|
||||
if (s_state.transfer_fifo.IsFull())
|
||||
s_state.transfer_event->Deactivate();
|
||||
else if (!s_state.transfer_event->IsActive())
|
||||
s_state.transfer_event->Schedule(TickCount(s_state.transfer_fifo.GetSpace() * u32(TRANSFER_TICKS_PER_HALFWORD)));
|
||||
s_state.transfer_event.Deactivate();
|
||||
else if (!s_state.transfer_event.IsActive())
|
||||
s_state.transfer_event.Schedule(TickCount(s_state.transfer_fifo.GetSpace() * u32(TRANSFER_TICKS_PER_HALFWORD)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// transfer event copies from fifo to ram
|
||||
if (s_state.transfer_fifo.IsEmpty())
|
||||
s_state.transfer_event->Deactivate();
|
||||
else if (!s_state.transfer_event->IsActive())
|
||||
s_state.transfer_event->Schedule(TickCount(s_state.transfer_fifo.GetSize() * u32(TRANSFER_TICKS_PER_HALFWORD)));
|
||||
s_state.transfer_event.Deactivate();
|
||||
else if (!s_state.transfer_event.IsActive())
|
||||
s_state.transfer_event.Schedule(TickCount(s_state.transfer_fifo.GetSize() * u32(TRANSFER_TICKS_PER_HALFWORD)));
|
||||
}
|
||||
|
||||
s_state.SPUSTAT.transfer_busy = s_state.transfer_event->IsActive();
|
||||
s_state.SPUSTAT.transfer_busy = s_state.transfer_event.IsActive();
|
||||
}
|
||||
|
||||
void SPU::UpdateDMARequest()
|
||||
|
@ -1480,10 +1479,10 @@ void SPU::DMAWrite(const u32* words, u32 word_count)
|
|||
|
||||
void SPU::GeneratePendingSamples()
|
||||
{
|
||||
if (s_state.transfer_event->IsActive())
|
||||
s_state.transfer_event->InvokeEarly();
|
||||
if (s_state.transfer_event.IsActive())
|
||||
s_state.transfer_event.InvokeEarly();
|
||||
|
||||
const TickCount ticks_pending = s_state.s_tick_event->GetTicksSinceLastExecution();
|
||||
const TickCount ticks_pending = s_state.tick_event.GetTicksSinceLastExecution();
|
||||
TickCount frames_to_execute;
|
||||
if (g_settings.cpu_overclock_active)
|
||||
{
|
||||
|
@ -1494,11 +1493,11 @@ void SPU::GeneratePendingSamples()
|
|||
else
|
||||
{
|
||||
frames_to_execute =
|
||||
(s_state.s_tick_event->GetTicksSinceLastExecution() + s_state.ticks_carry) / SYSCLK_TICKS_PER_SPU_TICK;
|
||||
(s_state.tick_event.GetTicksSinceLastExecution() + s_state.ticks_carry) / SYSCLK_TICKS_PER_SPU_TICK;
|
||||
}
|
||||
|
||||
const bool force_exec = (frames_to_execute > 0);
|
||||
s_state.s_tick_event->InvokeEarly(force_exec);
|
||||
s_state.tick_event.InvokeEarly(force_exec);
|
||||
}
|
||||
|
||||
bool SPU::IsDumpingAudio()
|
||||
|
@ -2446,18 +2445,18 @@ void SPU::UpdateEventInterval()
|
|||
// TODO: Make this predict how long until the interrupt will be hit instead...
|
||||
const u32 interval = (s_state.SPUCNT.enable && s_state.SPUCNT.irq9_enable) ? 1 : max_slice_frames;
|
||||
const TickCount interval_ticks = static_cast<TickCount>(interval) * s_state.cpu_ticks_per_spu_tick;
|
||||
if (s_state.s_tick_event->IsActive() && s_state.s_tick_event->GetInterval() == interval_ticks)
|
||||
if (s_state.tick_event.IsActive() && s_state.tick_event.GetInterval() == interval_ticks)
|
||||
return;
|
||||
|
||||
// Ensure all pending ticks have been executed, since we won't get them back after rescheduling.
|
||||
s_state.s_tick_event->InvokeEarly(true);
|
||||
s_state.s_tick_event->SetInterval(interval_ticks);
|
||||
s_state.tick_event.InvokeEarly(true);
|
||||
s_state.tick_event.SetInterval(interval_ticks);
|
||||
|
||||
TickCount downcount = interval_ticks;
|
||||
if (!g_settings.cpu_overclock_active)
|
||||
downcount -= s_state.ticks_carry;
|
||||
|
||||
s_state.s_tick_event->Schedule(downcount);
|
||||
s_state.tick_event.Schedule(downcount);
|
||||
}
|
||||
|
||||
void SPU::DrawDebugStateWindow()
|
||||
|
@ -2534,7 +2533,7 @@ void SPU::DrawDebugStateWindow()
|
|||
|
||||
ImGui::Text("Transfer FIFO: ");
|
||||
ImGui::SameLine(offsets[0]);
|
||||
ImGui::TextColored(s_state.transfer_event->IsActive() ? active_color : inactive_color, "%u halfwords (%u bytes)",
|
||||
ImGui::TextColored(s_state.transfer_event.IsActive() ? active_color : inactive_color, "%u halfwords (%u bytes)",
|
||||
s_state.transfer_fifo.GetSize(), s_state.transfer_fifo.GetSize() * 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ static void UpdateSysClkEvent();
|
|||
namespace {
|
||||
struct TimersState
|
||||
{
|
||||
std::unique_ptr<TimingEvent> sysclk_event;
|
||||
TimingEvent sysclk_event{ "Timer SysClk Interrupt", 1, 1, &Timers::AddSysClkTicks, nullptr };
|
||||
|
||||
std::array<CounterState, NUM_TIMERS> counters{};
|
||||
TickCount sysclk_ticks_carry = 0; // 0 unless overclocking is enabled
|
||||
|
@ -88,14 +88,12 @@ ALIGN_TO_CACHE_LINE static TimersState s_state;
|
|||
|
||||
void Timers::Initialize()
|
||||
{
|
||||
s_state.sysclk_event =
|
||||
TimingEvents::CreateTimingEvent("Timer SysClk Interrupt", 1, 1, &Timers::AddSysClkTicks, nullptr, false);
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Timers::Shutdown()
|
||||
{
|
||||
s_state.sysclk_event.reset();
|
||||
s_state.sysclk_event.Deactivate();
|
||||
}
|
||||
|
||||
void Timers::Reset()
|
||||
|
@ -112,7 +110,7 @@ void Timers::Reset()
|
|||
cs.irq_done = false;
|
||||
}
|
||||
|
||||
s_state.sysclk_event->Deactivate();
|
||||
s_state.sysclk_event.Deactivate();
|
||||
s_state.sysclk_ticks_carry = 0;
|
||||
s_state.sysclk_div_8_carry = 0;
|
||||
UpdateSysClkEvent();
|
||||
|
@ -176,7 +174,7 @@ void Timers::SetGate(u32 timer, bool state)
|
|||
// Because the gate prevents counting in or outside of the gate, we need a correct counter.
|
||||
// For reset, we _can_ skip it, until the gate clears.
|
||||
if (!cs.use_external_clock && (cs.mode.sync_mode != SyncMode::ResetOnGateEnd || !state))
|
||||
s_state.sysclk_event->InvokeEarly();
|
||||
s_state.sysclk_event.InvokeEarly();
|
||||
|
||||
switch (cs.mode.sync_mode)
|
||||
{
|
||||
|
@ -321,7 +319,7 @@ u32 Timers::ReadRegister(u32 offset)
|
|||
g_gpu->SynchronizeCRTC();
|
||||
}
|
||||
|
||||
s_state.sysclk_event->InvokeEarly();
|
||||
s_state.sysclk_event.InvokeEarly();
|
||||
|
||||
return cs.counter;
|
||||
}
|
||||
|
@ -335,7 +333,7 @@ u32 Timers::ReadRegister(u32 offset)
|
|||
g_gpu->SynchronizeCRTC();
|
||||
}
|
||||
|
||||
s_state.sysclk_event->InvokeEarly();
|
||||
s_state.sysclk_event.InvokeEarly();
|
||||
|
||||
const u32 bits = cs.mode.bits;
|
||||
cs.mode.reached_overflow = false;
|
||||
|
@ -371,7 +369,7 @@ void Timers::WriteRegister(u32 offset, u32 value)
|
|||
g_gpu->SynchronizeCRTC();
|
||||
}
|
||||
|
||||
s_state.sysclk_event->InvokeEarly();
|
||||
s_state.sysclk_event.InvokeEarly();
|
||||
|
||||
// Strictly speaking these IRQ checks should probably happen on the next tick.
|
||||
switch (port_offset)
|
||||
|
@ -488,7 +486,7 @@ TickCount Timers::GetTicksUntilNextInterrupt()
|
|||
|
||||
void Timers::UpdateSysClkEvent()
|
||||
{
|
||||
s_state.sysclk_event->Schedule(GetTicksUntilNextInterrupt());
|
||||
s_state.sysclk_event.Schedule(GetTicksUntilNextInterrupt());
|
||||
}
|
||||
|
||||
void Timers::DrawDebugStateWindow()
|
||||
|
|
|
@ -60,18 +60,6 @@ void TimingEvents::Shutdown()
|
|||
Assert(s_state.active_event_count == 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<TimingEvent> TimingEvents::CreateTimingEvent(std::string name, TickCount period, TickCount interval,
|
||||
TimingEventCallback callback, void* callback_param,
|
||||
bool activate)
|
||||
{
|
||||
std::unique_ptr<TimingEvent> event =
|
||||
std::make_unique<TimingEvent>(std::move(name), period, interval, callback, callback_param);
|
||||
if (activate)
|
||||
event->Activate();
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void TimingEvents::UpdateCPUDowncount()
|
||||
{
|
||||
const u32 event_downcount = s_state.active_events_head->GetDowncount();
|
||||
|
@ -377,7 +365,7 @@ bool TimingEvents::DoState(StateWrapper& sw)
|
|||
|
||||
for (u32 i = 0; i < event_count; i++)
|
||||
{
|
||||
std::string event_name;
|
||||
TinyString event_name;
|
||||
TickCount downcount, time_since_last_run, period, interval;
|
||||
sw.Do(&event_name);
|
||||
sw.Do(&downcount);
|
||||
|
@ -430,17 +418,16 @@ bool TimingEvents::DoState(StateWrapper& sw)
|
|||
return !sw.HasError();
|
||||
}
|
||||
|
||||
TimingEvent::TimingEvent(std::string name, TickCount period, TickCount interval, TimingEventCallback callback,
|
||||
void* callback_param)
|
||||
TimingEvent::TimingEvent(const std::string_view name, TickCount period, TickCount interval,
|
||||
TimingEventCallback callback, void* callback_param)
|
||||
: m_callback(callback), m_callback_param(callback_param), m_downcount(interval), m_time_since_last_run(0),
|
||||
m_period(period), m_interval(interval), m_name(std::move(name))
|
||||
m_period(period), m_interval(interval), m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
TimingEvent::~TimingEvent()
|
||||
{
|
||||
if (m_active)
|
||||
TimingEvents::RemoveActiveEvent(this);
|
||||
DebugAssert(!m_active);
|
||||
}
|
||||
|
||||
TickCount TimingEvent::GetTicksSinceLastExecution() const
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
class StateWrapper;
|
||||
|
||||
// Event callback type. Second parameter is the number of cycles the event was executed "late".
|
||||
|
@ -17,11 +15,11 @@ using TimingEventCallback = void (*)(void* param, TickCount ticks, TickCount tic
|
|||
class TimingEvent
|
||||
{
|
||||
public:
|
||||
TimingEvent(std::string name, TickCount period, TickCount interval, TimingEventCallback callback,
|
||||
TimingEvent(const std::string_view name, TickCount period, TickCount interval, TimingEventCallback callback,
|
||||
void* callback_param);
|
||||
~TimingEvent();
|
||||
|
||||
ALWAYS_INLINE const std::string& GetName() const { return m_name; }
|
||||
ALWAYS_INLINE const std::string_view GetName() const { return m_name; }
|
||||
ALWAYS_INLINE bool IsActive() const { return m_active; }
|
||||
|
||||
// Returns the number of ticks between each event.
|
||||
|
@ -75,7 +73,7 @@ public:
|
|||
TickCount m_interval;
|
||||
bool m_active = false;
|
||||
|
||||
std::string m_name;
|
||||
std::string_view m_name;
|
||||
};
|
||||
|
||||
namespace TimingEvents {
|
||||
|
@ -87,11 +85,6 @@ void Initialize();
|
|||
void Reset();
|
||||
void Shutdown();
|
||||
|
||||
/// Creates a new event.
|
||||
std::unique_ptr<TimingEvent> CreateTimingEvent(std::string name, TickCount period, TickCount interval,
|
||||
TimingEventCallback callback, void* callback_param, bool activate);
|
||||
|
||||
/// Serialization.
|
||||
bool DoState(StateWrapper& sw);
|
||||
|
||||
bool IsRunningEvents();
|
||||
|
|
|
@ -77,6 +77,14 @@ void StateWrapper::Do(SmallStringBase* value_ptr)
|
|||
value_ptr->update_size();
|
||||
}
|
||||
|
||||
void StateWrapper::Do(std::string_view* value_ptr)
|
||||
{
|
||||
Assert(m_mode == Mode::Write);
|
||||
u32 length = static_cast<u32>(value_ptr->length());
|
||||
Do(&length);
|
||||
DoBytes(const_cast<char*>(value_ptr->data()), length);
|
||||
}
|
||||
|
||||
bool StateWrapper::DoMarker(const char* marker)
|
||||
{
|
||||
SmallString file_value(marker);
|
||||
|
|
|
@ -108,6 +108,7 @@ public:
|
|||
|
||||
void Do(bool* value_ptr);
|
||||
void Do(std::string* value_ptr);
|
||||
void Do(std::string_view* value_ptr);
|
||||
void Do(SmallStringBase* value_ptr);
|
||||
|
||||
template<typename T, size_t N>
|
||||
|
|
Loading…
Reference in New Issue