DVDInterface: Don't evict cache block i unless block i + 2 was read

Intends to fix https://bugs.dolphin-emu.org/issues/12279.
I have hardware tested the behavior, but I haven't tested the game.
This commit is contained in:
JosJuice 2021-06-27 17:24:53 +02:00
parent c77a5f7e32
commit c6ede09035

View File

@ -1512,27 +1512,38 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
dvd_offset += DVD_ECC_BLOCK_SIZE; dvd_offset += DVD_ECC_BLOCK_SIZE;
} while (length > 0); } while (length > 0);
// Update the buffer based on this read. Based on experimental testing, // Evict blocks from the buffer which are unlikely to be used again after this read,
// we will only reuse the old buffer while reading forward. Note that the // so that the buffer gets space for prefetching new blocks. Based on hardware testing,
// buffer start we calculate here is not the actual start of the buffer - // the blocks which are kept are the most recently accessed block, the block immediately
// it is just the start of the portion we need to read. // before it, and all blocks after it.
//
// If the block immediately before the most recently accessed block is not kept, loading
// screens in Pitfall: The Lost Expedition are longer than they should be.
// https://bugs.dolphin-emu.org/issues/12279
const u64 last_block = dvd_offset; const u64 last_block = dvd_offset;
if (last_block == buffer_start + DVD_ECC_BLOCK_SIZE && buffer_start != buffer_end) constexpr u32 BUFFER_BACKWARD_SEEK_LIMIT = DVD_ECC_BLOCK_SIZE * 2;
if (last_block - buffer_start <= BUFFER_BACKWARD_SEEK_LIMIT && buffer_start != buffer_end)
{ {
// Special case: reading less than one block at the start of the // Special case: reading the first two blocks of the buffer doesn't change the buffer state
// buffer won't change the buffer state
} }
else else
{ {
// Note that the s_read_buffer_start_offset value we calculate here is not the
// actual start of the buffer - it is just the start of the portion we need to read.
// The actual start of the buffer is s_read_buffer_end_offset - STREAMING_BUFFER_SIZE.
if (last_block >= buffer_end) if (last_block >= buffer_end)
{
// Full buffer read // Full buffer read
s_read_buffer_start_offset = last_block; s_read_buffer_start_offset = last_block;
}
else else
{
// Partial buffer read // Partial buffer read
s_read_buffer_start_offset = buffer_end; s_read_buffer_start_offset = buffer_end;
}
s_read_buffer_end_offset = last_block + STREAMING_BUFFER_SIZE - DVD_ECC_BLOCK_SIZE; s_read_buffer_end_offset = last_block + STREAMING_BUFFER_SIZE - BUFFER_BACKWARD_SEEK_LIMIT;
// Assume the buffer starts reading right after the end of the last operation // Assume the buffer starts prefetching new blocks right after the end of the last operation
s_read_buffer_start_time = current_time + ticks_until_completion; s_read_buffer_start_time = current_time + ticks_until_completion;
s_read_buffer_end_time = s_read_buffer_end_time =
s_read_buffer_start_time + s_read_buffer_start_time +