CDROM: Improve SeekL -> ReadN timing

See comments - Mech stops at target Data - 2, or SubQ target.
This commit is contained in:
Stenzek 2024-12-02 17:23:46 +10:00
parent 71e1032605
commit 6756c96fa2
No known key found for this signature in database

View File

@ -46,6 +46,7 @@ enum : u32
SECTOR_HEADER_SIZE = CDImage::SECTOR_HEADER_SIZE, SECTOR_HEADER_SIZE = CDImage::SECTOR_HEADER_SIZE,
MODE1_HEADER_SIZE = CDImage::MODE1_HEADER_SIZE, MODE1_HEADER_SIZE = CDImage::MODE1_HEADER_SIZE,
MODE2_HEADER_SIZE = CDImage::MODE2_HEADER_SIZE, MODE2_HEADER_SIZE = CDImage::MODE2_HEADER_SIZE,
SUBQ_SECTOR_SKEW = 2,
XA_ADPCM_SAMPLES_PER_SECTOR_4BIT = 4032, // 28 words * 8 nibbles per word * 18 chunks XA_ADPCM_SAMPLES_PER_SECTOR_4BIT = 4032, // 28 words * 8 nibbles per word * 18 chunks
XA_ADPCM_SAMPLES_PER_SECTOR_8BIT = 2016, // 28 words * 4 bytes per word * 18 chunks XA_ADPCM_SAMPLES_PER_SECTOR_8BIT = 2016, // 28 words * 4 bytes per word * 18 chunks
XA_RESAMPLE_RING_BUFFER_SIZE = 32, XA_RESAMPLE_RING_BUFFER_SIZE = 32,
@ -2967,10 +2968,13 @@ bool CDROM::CompleteSeek()
if (seek_okay) if (seek_okay)
{ {
const CDImage::SubChannelQ& subq = GetSectorSubQ(s_reader.GetLastReadSector(), s_reader.GetSectorSubQ()); const CDImage::SubChannelQ& subq = GetSectorSubQ(s_reader.GetLastReadSector(), s_reader.GetSectorSubQ());
s_state.current_lba = s_reader.GetLastReadSector();
if (subq.IsCRCValid()) if (subq.IsCRCValid())
{ {
// seek and update sub-q for ReadP command // seek and update sub-q for ReadP command
s_state.last_subq = subq; s_state.last_subq = subq;
s_state.last_subq_needs_update = false;
const auto [seek_mm, seek_ss, seek_ff] = CDImage::Position::FromLBA(s_reader.GetLastReadSector()).ToBCD(); const auto [seek_mm, seek_ss, seek_ff] = CDImage::Position::FromLBA(s_reader.GetLastReadSector()).ToBCD();
seek_okay = (subq.absolute_minute_bcd == seek_mm && subq.absolute_second_bcd == seek_ss && seek_okay = (subq.absolute_minute_bcd == seek_mm && subq.absolute_second_bcd == seek_ss &&
subq.absolute_frame_bcd == seek_ff); subq.absolute_frame_bcd == seek_ff);
@ -2984,12 +2988,16 @@ bool CDROM::CompleteSeek()
seek_okay = (s_state.last_sector_header.minute == seek_mm && s_state.last_sector_header.second == seek_ss && seek_okay = (s_state.last_sector_header.minute == seek_mm && s_state.last_sector_header.second == seek_ss &&
s_state.last_sector_header.frame == seek_ff); s_state.last_sector_header.frame == seek_ff);
if (seek_okay) if (seek_okay && !s_state.play_after_seek && !s_state.read_after_seek)
{ {
// after reading the target, the mech immediately does a 1T reverse // This is pretty janky. The mech completes the seek when it "sees" a data header
const u32 spt = GetSectorsPerTrack(s_state.current_subq_lba); // 2 sectors before the seek target, so that a subsequent ReadN can complete nearly
SetHoldPosition(s_state.current_subq_lba, // immediately. Therefore when the seek completes, SubQ = Target, Data = Target - 2.
(spt <= s_state.current_subq_lba) ? (s_state.current_subq_lba - spt) : 0); // Hack the SubQ back by 2 frames so that following seeks will read forward. If we
// ever properly handle SubQ versus data positions, this can be removed.
s_state.current_subq_lba =
(s_state.current_lba >= SUBQ_SECTOR_SKEW) ? (s_state.current_lba - SUBQ_SECTOR_SKEW) : 0;
s_state.last_subq_needs_update = true;
} }
} }
} }
@ -3016,8 +3024,6 @@ bool CDROM::CompleteSeek()
} }
} }
} }
s_state.current_lba = s_reader.GetLastReadSector();
} }
return seek_okay; return seek_okay;
@ -3234,7 +3240,7 @@ void CDROM::DoSectorRead()
// so that multiple sectors could be read in one back, in which case we could just "look ahead" to grab the // so that multiple sectors could be read in one back, in which case we could just "look ahead" to grab the
// subq, but I haven't got around to it. It'll break libcrypt, but CC doesn't use it. One day I'll get around to // subq, but I haven't got around to it. It'll break libcrypt, but CC doesn't use it. One day I'll get around to
// doing the refactor.... but given this is the only game that relies on it, priorities. // doing the refactor.... but given this is the only game that relies on it, priorities.
s_reader.GetMedia()->GenerateSubChannelQ(&s_state.last_subq, s_state.current_lba + 2); s_reader.GetMedia()->GenerateSubChannelQ(&s_state.last_subq, s_state.current_lba + SUBQ_SECTOR_SKEW);
} }
} }
else else