mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-18 09:15:46 -04:00
CDROMAsyncReader: Support reading ahead more sectors
This commit is contained in:
@ -99,8 +99,8 @@ void CDROM::Initialize()
|
||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<CDROM*>(param)->ExecuteDrive(ticks_late); },
|
||||
this, false);
|
||||
|
||||
if (g_settings.cdrom_read_thread)
|
||||
m_reader.StartThread();
|
||||
if (g_settings.cdrom_readahead_sectors > 0)
|
||||
m_reader.StartThread(g_settings.cdrom_readahead_sectors);
|
||||
|
||||
Reset();
|
||||
}
|
||||
@ -232,7 +232,8 @@ void CDROM::SoftReset(TickCount ticks_late)
|
||||
{
|
||||
m_drive_state = DriveState::SeekingImplicit;
|
||||
m_drive_event->SetIntervalAndSchedule(total_ticks);
|
||||
m_reader.QueueReadSector(0);
|
||||
m_requested_lba = 0;
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
m_seek_start_lba = m_current_lba;
|
||||
m_seek_end_lba = 0;
|
||||
}
|
||||
@ -306,14 +307,12 @@ bool CDROM::DoState(StateWrapper& sw)
|
||||
}
|
||||
|
||||
sw.Do(&m_audio_fifo);
|
||||
|
||||
u32 requested_sector = (sw.IsWriting() ? (m_reader.WaitForReadToComplete(), m_reader.GetLastReadSector()) : 0);
|
||||
sw.Do(&requested_sector);
|
||||
sw.Do(&m_requested_lba);
|
||||
|
||||
if (sw.IsReading())
|
||||
{
|
||||
if (m_reader.HasMedia())
|
||||
m_reader.QueueReadSector(requested_sector);
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
UpdateCommandEvent();
|
||||
m_drive_event->SetState(!IsDriveIdle());
|
||||
}
|
||||
@ -397,15 +396,18 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool force /* = false */)
|
||||
return image;
|
||||
}
|
||||
|
||||
void CDROM::SetUseReadThread(bool enabled)
|
||||
void CDROM::SetReadaheadSectors(u32 readahead_sectors)
|
||||
{
|
||||
if (enabled == m_reader.IsUsingThread())
|
||||
const bool want_thread = (readahead_sectors > 0);
|
||||
if (want_thread == m_reader.IsUsingThread() && m_reader.GetReadaheadCount() == readahead_sectors)
|
||||
return;
|
||||
|
||||
if (enabled)
|
||||
m_reader.StartThread();
|
||||
if (want_thread)
|
||||
m_reader.StartThread(readahead_sectors);
|
||||
else
|
||||
m_reader.StopThread();
|
||||
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
}
|
||||
|
||||
void CDROM::CPUClockChanged()
|
||||
@ -1417,8 +1419,6 @@ void CDROM::ExecuteCommand(TickCount ticks_late)
|
||||
Log_DebugPrintf("CDROM GetTN command");
|
||||
if (CanReadMedia())
|
||||
{
|
||||
m_reader.WaitForReadToComplete();
|
||||
|
||||
Log_DevPrintf("GetTN -> %u %u", m_reader.GetMedia()->GetFirstTrackNumber(),
|
||||
m_reader.GetMedia()->GetLastTrackNumber());
|
||||
|
||||
@ -1757,7 +1757,8 @@ void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = fa
|
||||
m_current_read_sector_buffer = 0;
|
||||
m_current_write_sector_buffer = 0;
|
||||
|
||||
m_reader.QueueReadSector(m_current_lba);
|
||||
m_requested_lba = m_current_lba;
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
}
|
||||
|
||||
void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_seek /* = false */)
|
||||
@ -1799,7 +1800,8 @@ void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_se
|
||||
m_current_read_sector_buffer = 0;
|
||||
m_current_write_sector_buffer = 0;
|
||||
|
||||
m_reader.QueueReadSector(m_current_lba);
|
||||
m_requested_lba = m_current_lba;
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
}
|
||||
|
||||
void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek)
|
||||
@ -1828,7 +1830,8 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
|
||||
|
||||
m_seek_start_lba = m_current_lba;
|
||||
m_seek_end_lba = seek_lba;
|
||||
m_reader.QueueReadSector(seek_lba);
|
||||
m_requested_lba = seek_lba;
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
}
|
||||
|
||||
void CDROM::UpdatePositionWhileSeeking()
|
||||
@ -2022,9 +2025,10 @@ bool CDROM::CompleteSeek()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_current_lba = m_reader.GetLastReadSector();
|
||||
}
|
||||
|
||||
m_current_lba = m_reader.GetLastReadSector();
|
||||
m_physical_lba = m_current_lba;
|
||||
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||
m_physical_lba_update_carry = 0;
|
||||
@ -2275,7 +2279,8 @@ void CDROM::DoSectorRead()
|
||||
is_data_sector ? "data" : "audio", is_data_sector ? "reading" : "playing");
|
||||
}
|
||||
|
||||
m_reader.QueueReadSector(next_sector);
|
||||
m_requested_lba = next_sector;
|
||||
m_reader.QueueReadSector(m_requested_lba);
|
||||
}
|
||||
|
||||
void CDROM::ProcessDataSectorHeader(const u8* raw_sector)
|
||||
@ -2698,12 +2703,13 @@ void CDROM::DrawDebugWindow()
|
||||
|
||||
if (media->HasSubImages())
|
||||
{
|
||||
ImGui::Text("Filename: %s [Subimage %u of %u]", media->GetFileName().c_str(), media->GetCurrentSubImage() + 1u,
|
||||
media->GetSubImageCount());
|
||||
ImGui::Text("Filename: %s [Subimage %u of %u] [%u buffered sectors]", media->GetFileName().c_str(),
|
||||
media->GetCurrentSubImage() + 1u, media->GetSubImageCount(), m_reader.GetBufferedSectorCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("Filename: %s", media->GetFileName().c_str());
|
||||
ImGui::Text("Filename: %s [%u buffered sectors]", media->GetFileName().c_str(),
|
||||
m_reader.GetBufferedSectorCount());
|
||||
}
|
||||
|
||||
ImGui::Text("Disc Position: MSF[%02u:%02u:%02u] LBA[%u]", disc_position.minute, disc_position.second,
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
// Render statistics debug window.
|
||||
void DrawDebugWindow();
|
||||
|
||||
void SetUseReadThread(bool enabled);
|
||||
void SetReadaheadSectors(u32 readahead_sectors);
|
||||
|
||||
/// Reads a frame from the audio FIFO, used by the SPU.
|
||||
ALWAYS_INLINE std::tuple<s16, s16> GetAudioFrame()
|
||||
@ -347,6 +347,7 @@ private:
|
||||
u8 m_pending_async_interrupt = 0;
|
||||
|
||||
CDImage::Position m_setloc_position = {};
|
||||
CDImage::LBA m_requested_lba{};
|
||||
CDImage::LBA m_current_lba{}; // this is the hold position
|
||||
CDImage::LBA m_seek_start_lba{};
|
||||
CDImage::LBA m_seek_end_lba{};
|
||||
|
@ -11,13 +11,18 @@ CDROMAsyncReader::~CDROMAsyncReader()
|
||||
StopThread();
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::StartThread()
|
||||
void CDROMAsyncReader::StartThread(u32 readahead_count)
|
||||
{
|
||||
if (IsUsingThread())
|
||||
return;
|
||||
StopThread();
|
||||
|
||||
m_buffers.clear();
|
||||
m_buffers.resize(readahead_count);
|
||||
EmptyBuffers();
|
||||
|
||||
m_shutdown_flag.store(false);
|
||||
m_read_thread = std::thread(&CDROMAsyncReader::WorkerThreadEntryPoint, this);
|
||||
Log_InfoPrintf("Read thread started with readahead of %u sectors", readahead_count);
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::StopThread()
|
||||
@ -27,25 +32,28 @@ void CDROMAsyncReader::StopThread()
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_sector_read_pending.load())
|
||||
m_notify_read_complete_cv.wait(lock, [this]() { return !m_sector_read_pending.load(); });
|
||||
|
||||
m_shutdown_flag.store(true);
|
||||
m_do_read_cv.notify_one();
|
||||
}
|
||||
|
||||
m_read_thread.join();
|
||||
EmptyBuffers();
|
||||
m_buffers.clear();
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::SetMedia(std::unique_ptr<CDImage> media)
|
||||
{
|
||||
WaitForReadToComplete();
|
||||
if (IsUsingThread())
|
||||
CancelReadahead();
|
||||
|
||||
m_media = std::move(media);
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDROMAsyncReader::RemoveMedia()
|
||||
{
|
||||
WaitForReadToComplete();
|
||||
if (IsUsingThread())
|
||||
CancelReadahead();
|
||||
|
||||
return std::move(m_media);
|
||||
}
|
||||
|
||||
@ -53,26 +61,39 @@ void CDROMAsyncReader::QueueReadSector(CDImage::LBA lba)
|
||||
{
|
||||
if (!IsUsingThread())
|
||||
{
|
||||
m_sector_read_pending.store(true);
|
||||
m_next_position_set.store(true);
|
||||
m_next_position = lba;
|
||||
DoSectorRead();
|
||||
ReadSectorNonThreaded(lba);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_sector_read_pending.load())
|
||||
m_notify_read_complete_cv.wait(lock, [this]() { return !m_sector_read_pending.load(); });
|
||||
|
||||
// don't re-read the same sector if it was the last one we read
|
||||
// the CDC code does this when seeking->reading
|
||||
if (m_last_read_sector == lba && m_sector_read_result.load())
|
||||
const u32 buffer_count = m_buffer_count.load();
|
||||
if (buffer_count > 0)
|
||||
{
|
||||
Log_DebugPrintf("Skipping re-reading same sector %u", lba);
|
||||
return;
|
||||
// don't re-read the same sector if it was the last one we read
|
||||
// the CDC code does this when seeking->reading
|
||||
const u32 buffer_front = m_buffer_front.load();
|
||||
if (m_buffers[buffer_front].lba == lba)
|
||||
{
|
||||
Log_DebugPrintf("Skipping re-reading same sector %u", lba);
|
||||
return;
|
||||
}
|
||||
|
||||
// did we readahead to the correct sector?
|
||||
const u32 next_buffer = (buffer_front + 1) % static_cast<u32>(m_buffers.size());
|
||||
if (m_buffer_count > 1 && m_buffers[next_buffer].lba == lba)
|
||||
{
|
||||
// great, don't need a seek, but still kick the thread to start reading ahead again
|
||||
Log_DebugPrintf("Readahead buffer hit for sector %u", lba);
|
||||
m_buffer_front.store(next_buffer);
|
||||
m_buffer_count.fetch_sub(1);
|
||||
m_can_readahead.store(true);
|
||||
m_do_read_cv.notify_one();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_sector_read_pending.store(true);
|
||||
// we need to toss away our readahead and start fresh
|
||||
Log_DebugPrintf("Readahead buffer miss, queueing seek to %u", lba);
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_next_position_set.store(true);
|
||||
m_next_position = lba;
|
||||
m_do_read_cv.notify_one();
|
||||
@ -80,7 +101,8 @@ void CDROMAsyncReader::QueueReadSector(CDImage::LBA lba)
|
||||
|
||||
bool CDROMAsyncReader::ReadSectorUncached(CDImage::LBA lba, CDImage::SubChannelQ* subq, SectorBuffer* data)
|
||||
{
|
||||
WaitForReadToComplete();
|
||||
if (IsUsingThread())
|
||||
CancelReadahead();
|
||||
|
||||
if (m_media->GetPositionOnDisc() != lba && !m_media->Seek(lba))
|
||||
{
|
||||
@ -97,88 +119,203 @@ bool CDROMAsyncReader::ReadSectorUncached(CDImage::LBA lba, CDImage::SubChannelQ
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::QueueReadNextSector()
|
||||
{
|
||||
if (!IsUsingThread())
|
||||
{
|
||||
m_sector_read_pending.store(true);
|
||||
DoSectorRead();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_sector_read_pending.load())
|
||||
m_notify_read_complete_cv.wait(lock, [this]() { return !m_sector_read_pending.load(); });
|
||||
|
||||
m_sector_read_pending.store(true);
|
||||
m_do_read_cv.notify_one();
|
||||
}
|
||||
|
||||
bool CDROMAsyncReader::WaitForReadToComplete()
|
||||
{
|
||||
if (!IsUsingThread())
|
||||
return m_sector_read_result.load();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_sector_read_pending.load())
|
||||
// Safe without locking with memory_order_seq_cst.
|
||||
if (!m_next_position_set.load() && m_buffer_count.load() > 0)
|
||||
{
|
||||
Log_DebugPrintf("Sector read pending, waiting");
|
||||
|
||||
Common::Timer wait_timer;
|
||||
m_notify_read_complete_cv.wait(lock, [this]() { return !m_sector_read_pending.load(); });
|
||||
|
||||
const double wait_time = wait_timer.GetTimeMilliseconds();
|
||||
if (wait_time > 1.0f)
|
||||
Log_WarningPrintf("Had to wait %.2f msec for LBA %u", wait_time, m_last_read_sector);
|
||||
Log_TracePrintf("Returning sector %u", m_buffers[m_buffer_front.load()].lba);
|
||||
return m_buffers[m_buffer_front.load()].result;
|
||||
}
|
||||
|
||||
return m_sector_read_result.load();
|
||||
Common::Timer wait_timer;
|
||||
Log_DebugPrintf("Sector read pending, waiting");
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_notify_read_complete_cv.wait(
|
||||
lock, [this]() { return (m_buffer_count.load() > 0 || m_seek_error.load()) && !m_next_position_set.load(); });
|
||||
if (m_seek_error.load())
|
||||
{
|
||||
m_seek_error.store(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 front = m_buffer_front.load();
|
||||
const double wait_time = wait_timer.GetTimeMilliseconds();
|
||||
if (wait_time > 1.0f)
|
||||
Log_WarningPrintf("Had to wait %.2f msec for LBA %u", wait_time, m_buffers[front].lba);
|
||||
|
||||
Log_TracePrintf("Returning sector %u after waiting", m_buffers[front].lba);
|
||||
return m_buffers[front].result;
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::DoSectorRead()
|
||||
void CDROMAsyncReader::WaitForIdle()
|
||||
{
|
||||
if (!IsUsingThread())
|
||||
return;
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_notify_read_complete_cv.wait(lock, [this]() { return (!m_is_reading.load() && !m_next_position_set.load()); });
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::EmptyBuffers()
|
||||
{
|
||||
m_buffer_front.store(0);
|
||||
m_buffer_back.store(0);
|
||||
m_buffer_count.store(0);
|
||||
}
|
||||
|
||||
bool CDROMAsyncReader::ReadSectorIntoBuffer(std::unique_lock<std::mutex>& lock)
|
||||
{
|
||||
Common::Timer timer;
|
||||
|
||||
if (m_next_position_set.load())
|
||||
const u32 slot = m_buffer_back.load();
|
||||
m_buffer_back.store((slot + 1) % static_cast<u32>(m_buffers.size()));
|
||||
|
||||
BufferSlot& buffer = m_buffers[slot];
|
||||
buffer.lba = m_media->GetPositionOnDisc();
|
||||
m_is_reading.store(true);
|
||||
lock.unlock();
|
||||
|
||||
Log_TracePrintf("Reading LBA %u...", buffer.lba);
|
||||
|
||||
buffer.result = m_media->ReadRawSector(buffer.data.data(), &buffer.subq);
|
||||
if (buffer.result)
|
||||
{
|
||||
if (m_media->GetPositionOnDisc() != m_next_position && !m_media->Seek(m_next_position))
|
||||
{
|
||||
Log_WarningPrintf("Seek to LBA %u failed", m_next_position);
|
||||
m_sector_read_result.store(false);
|
||||
return;
|
||||
}
|
||||
const double read_time = timer.GetTimeMilliseconds();
|
||||
if (read_time > 1.0f)
|
||||
Log_DevPrintf("Read LBA %u took %.2f msec", buffer.lba, read_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrintf("Read of LBA %u failed", buffer.lba);
|
||||
}
|
||||
|
||||
const CDImage::LBA pos = m_media->GetPositionOnDisc();
|
||||
if (!m_media->ReadRawSector(m_sector_buffer.data(), &m_subq))
|
||||
lock.lock();
|
||||
m_is_reading.store(false);
|
||||
m_buffer_count.fetch_add(1);
|
||||
m_notify_read_complete_cv.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::ReadSectorNonThreaded(CDImage::LBA lba)
|
||||
{
|
||||
Common::Timer timer;
|
||||
|
||||
m_buffers.resize(1);
|
||||
m_seek_error.store(false);
|
||||
EmptyBuffers();
|
||||
|
||||
if (m_media->GetPositionOnDisc() != lba && !m_media->Seek(lba))
|
||||
{
|
||||
m_sector_read_result.store(false);
|
||||
Log_WarningPrintf("Read of LBA %u failed", pos);
|
||||
Log_WarningPrintf("Seek to LBA %u failed", lba);
|
||||
m_seek_error.store(true);
|
||||
return;
|
||||
}
|
||||
|
||||
m_last_read_sector = pos;
|
||||
m_sector_read_result.store(true);
|
||||
BufferSlot& buffer = m_buffers.front();
|
||||
buffer.lba = m_media->GetPositionOnDisc();
|
||||
|
||||
const double read_time = timer.GetTimeMilliseconds();
|
||||
if (read_time > 1.0f)
|
||||
Log_DevPrintf("Read LBA %u took %.2f msec", pos, read_time);
|
||||
Log_TracePrintf("Reading LBA %u...", buffer.lba);
|
||||
|
||||
buffer.result = m_media->ReadRawSector(buffer.data.data(), &buffer.subq);
|
||||
if (buffer.result)
|
||||
{
|
||||
const double read_time = timer.GetTimeMilliseconds();
|
||||
if (read_time > 1.0f)
|
||||
Log_DevPrintf("Read LBA %u took %.2f msec", buffer.lba, read_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrintf("Read of LBA %u failed", buffer.lba);
|
||||
}
|
||||
|
||||
m_buffer_count.fetch_add(1);
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::CancelReadahead()
|
||||
{
|
||||
Log_DevPrintf("Cancelling readahead");
|
||||
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
// wait until the read thread is idle
|
||||
m_notify_read_complete_cv.wait(lock, [this]() { return !m_is_reading.load(); });
|
||||
|
||||
// prevent it from doing any more when it re-acquires the lock
|
||||
m_can_readahead.store(false);
|
||||
EmptyBuffers();
|
||||
}
|
||||
|
||||
void CDROMAsyncReader::WorkerThreadEntryPoint()
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
while (!m_shutdown_flag.load())
|
||||
for (;;)
|
||||
{
|
||||
m_do_read_cv.wait(lock, [this]() { return (m_shutdown_flag.load() || m_sector_read_pending.load()); });
|
||||
if (m_sector_read_pending.load())
|
||||
m_do_read_cv.wait(
|
||||
lock, [this]() { return (m_shutdown_flag.load() || m_next_position_set.load() || m_can_readahead.load()); });
|
||||
if (m_shutdown_flag.load())
|
||||
break;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
lock.unlock();
|
||||
DoSectorRead();
|
||||
lock.lock();
|
||||
m_sector_read_pending.store(false);
|
||||
m_notify_read_complete_cv.notify_one();
|
||||
if (m_next_position_set.load())
|
||||
{
|
||||
// discard buffers, we're seeking to a new location
|
||||
const CDImage::LBA seek_location = m_next_position.load();
|
||||
EmptyBuffers();
|
||||
m_next_position_set.store(false);
|
||||
m_seek_error.store(false);
|
||||
m_is_reading.store(true);
|
||||
lock.unlock();
|
||||
|
||||
// seek without lock held in case it takes time
|
||||
Log_DebugPrintf("Seeking to LBA %u...", seek_location);
|
||||
const bool seek_result = (m_media->GetPositionOnDisc() == seek_location || m_media->Seek(seek_location));
|
||||
|
||||
lock.lock();
|
||||
m_is_reading.store(false);
|
||||
|
||||
// did another request come in? abort if so
|
||||
if (m_next_position_set.load())
|
||||
continue;
|
||||
|
||||
// did we fail the seek?
|
||||
if (!seek_result)
|
||||
{
|
||||
// add the error result, and don't try to read ahead
|
||||
Log_WarningPrintf("Seek to LBA %u failed", seek_location);
|
||||
m_seek_error.store(true);
|
||||
m_notify_read_complete_cv.notify_all();
|
||||
break;
|
||||
}
|
||||
|
||||
// go go read ahead!
|
||||
m_can_readahead.store(true);
|
||||
}
|
||||
|
||||
if (!m_can_readahead.load())
|
||||
break;
|
||||
|
||||
// readahead time! read as many sectors as we have space for
|
||||
Log_DebugPrintf("Reading ahead %u sectors...", static_cast<u32>(m_buffers.size()) - m_buffer_count.load());
|
||||
while (m_buffer_count.load() < static_cast<u32>(m_buffers.size()))
|
||||
{
|
||||
if (m_next_position_set.load())
|
||||
{
|
||||
// a seek request came in while we're reading, so bail out
|
||||
break;
|
||||
}
|
||||
|
||||
// stop reading if we hit the end or get an error
|
||||
if (!ReadSectorIntoBuffer(lock))
|
||||
break;
|
||||
}
|
||||
|
||||
// readahead buffer is full or errored at this point
|
||||
m_can_readahead.store(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,33 +11,49 @@ class CDROMAsyncReader
|
||||
public:
|
||||
using SectorBuffer = std::array<u8, CDImage::RAW_SECTOR_SIZE>;
|
||||
|
||||
struct BufferSlot
|
||||
{
|
||||
CDImage::LBA lba;
|
||||
SectorBuffer data;
|
||||
CDImage::SubChannelQ subq;
|
||||
bool result;
|
||||
};
|
||||
|
||||
CDROMAsyncReader();
|
||||
~CDROMAsyncReader();
|
||||
|
||||
const CDImage::LBA GetLastReadSector() const { return m_last_read_sector; }
|
||||
const SectorBuffer& GetSectorBuffer() const { return m_sector_buffer; }
|
||||
const CDImage::SubChannelQ& GetSectorSubQ() const { return m_subq; }
|
||||
const CDImage::LBA GetLastReadSector() const { return m_buffers[m_buffer_front.load()].lba; }
|
||||
const SectorBuffer& GetSectorBuffer() const { return m_buffers[m_buffer_front.load()].data; }
|
||||
const CDImage::SubChannelQ& GetSectorSubQ() const { return m_buffers[m_buffer_front.load()].subq; }
|
||||
const u32 GetBufferedSectorCount() const { return m_buffer_count.load(); }
|
||||
const bool HasBufferedSectors() const { return (m_buffer_count.load() > 0); }
|
||||
const u32 GetReadaheadCount() const { return static_cast<u32>(m_buffers.size()); }
|
||||
|
||||
const bool HasMedia() const { return static_cast<bool>(m_media); }
|
||||
const CDImage* GetMedia() const { return m_media.get(); }
|
||||
const std::string& GetMediaFileName() const { return m_media->GetFileName(); }
|
||||
|
||||
bool IsUsingThread() const { return m_read_thread.joinable(); }
|
||||
void StartThread();
|
||||
void StartThread(u32 readahead_count = 8);
|
||||
void StopThread();
|
||||
|
||||
void SetMedia(std::unique_ptr<CDImage> media);
|
||||
std::unique_ptr<CDImage> RemoveMedia();
|
||||
|
||||
void QueueReadSector(CDImage::LBA lba);
|
||||
void QueueReadNextSector();
|
||||
|
||||
bool WaitForReadToComplete();
|
||||
void WaitForIdle();
|
||||
|
||||
/// Bypasses the sector cache and reads directly from the image.
|
||||
bool ReadSectorUncached(CDImage::LBA lba, CDImage::SubChannelQ* subq, SectorBuffer* data);
|
||||
|
||||
private:
|
||||
void DoSectorRead();
|
||||
void EmptyBuffers();
|
||||
bool ReadSectorIntoBuffer(std::unique_lock<std::mutex>& lock);
|
||||
void ReadSectorNonThreaded(CDImage::LBA lba);
|
||||
void CancelReadahead();
|
||||
|
||||
void WorkerThreadEntryPoint();
|
||||
|
||||
std::unique_ptr<CDImage> m_media;
|
||||
@ -47,13 +63,16 @@ private:
|
||||
std::condition_variable m_do_read_cv;
|
||||
std::condition_variable m_notify_read_complete_cv;
|
||||
|
||||
CDImage::LBA m_next_position{};
|
||||
std::atomic<CDImage::LBA> m_next_position{};
|
||||
std::atomic_bool m_next_position_set{false};
|
||||
std::atomic_bool m_sector_read_pending{false};
|
||||
std::atomic_bool m_shutdown_flag{true};
|
||||
|
||||
CDImage::LBA m_last_read_sector{};
|
||||
CDImage::SubChannelQ m_subq{};
|
||||
SectorBuffer m_sector_buffer{};
|
||||
std::atomic_bool m_sector_read_result{false};
|
||||
std::atomic_bool m_is_reading{ false };
|
||||
std::atomic_bool m_can_readahead{ false };
|
||||
std::atomic_bool m_seek_error{ false };
|
||||
|
||||
std::vector<BufferSlot> m_buffers;
|
||||
std::atomic<u32> m_buffer_front{ 0 };
|
||||
std::atomic<u32> m_buffer_back{ 0 };
|
||||
std::atomic<u32> m_buffer_count{ 0 };
|
||||
};
|
||||
|
@ -565,7 +565,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
|
||||
si.SetStringValue("Display", "PostProcessChain", "");
|
||||
si.SetFloatValue("Display", "MaxFPS", Settings::DEFAULT_DISPLAY_MAX_FPS);
|
||||
|
||||
si.SetBoolValue("CDROM", "ReadThread", true);
|
||||
si.SetIntValue("CDROM", "ReadaheadSectors", Settings::DEFAULT_CDROM_READAHEAD_SECTORS);
|
||||
si.SetBoolValue("CDROM", "RegionCheck", false);
|
||||
si.SetBoolValue("CDROM", "LoadImageToRAM", false);
|
||||
si.SetBoolValue("CDROM", "MuteCDAudio", false);
|
||||
@ -853,8 +853,8 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
|
||||
PGXP::Initialize();
|
||||
}
|
||||
|
||||
if (g_settings.cdrom_read_thread != old_settings.cdrom_read_thread)
|
||||
g_cdrom.SetUseReadThread(g_settings.cdrom_read_thread);
|
||||
if (g_settings.cdrom_readahead_sectors != old_settings.cdrom_readahead_sectors)
|
||||
g_cdrom.SetReadaheadSectors(g_settings.cdrom_readahead_sectors);
|
||||
|
||||
if (g_settings.memory_card_types != old_settings.memory_card_types ||
|
||||
g_settings.memory_card_paths != old_settings.memory_card_paths ||
|
||||
|
@ -242,7 +242,7 @@ void Settings::Load(SettingsInterface& si)
|
||||
display_post_process_chain = si.GetStringValue("Display", "PostProcessChain", "");
|
||||
display_max_fps = si.GetFloatValue("Display", "MaxFPS", DEFAULT_DISPLAY_MAX_FPS);
|
||||
|
||||
cdrom_read_thread = si.GetBoolValue("CDROM", "ReadThread", true);
|
||||
cdrom_readahead_sectors = static_cast<u8>(si.GetIntValue("CDROM", "ReadaheadSectors", DEFAULT_CDROM_READAHEAD_SECTORS));
|
||||
cdrom_region_check = si.GetBoolValue("CDROM", "RegionCheck", false);
|
||||
cdrom_load_image_to_ram = si.GetBoolValue("CDROM", "LoadImageToRAM", false);
|
||||
cdrom_mute_cd_audio = si.GetBoolValue("CDROM", "MuteCDAudio", false);
|
||||
@ -419,7 +419,7 @@ void Settings::Save(SettingsInterface& si) const
|
||||
si.SetStringValue("Display", "PostProcessChain", display_post_process_chain.c_str());
|
||||
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
|
||||
|
||||
si.SetBoolValue("CDROM", "ReadThread", cdrom_read_thread);
|
||||
si.SetIntValue("CDROM", "ReadaheadSectors", cdrom_readahead_sectors);
|
||||
si.SetBoolValue("CDROM", "RegionCheck", cdrom_region_check);
|
||||
si.SetBoolValue("CDROM", "LoadImageToRAM", cdrom_load_image_to_ram);
|
||||
si.SetBoolValue("CDROM", "MuteCDAudio", cdrom_mute_cd_audio);
|
||||
|
@ -152,7 +152,7 @@ struct Settings
|
||||
float gpu_pgxp_tolerance = -1.0f;
|
||||
float gpu_pgxp_depth_clear_threshold = 300.0f / 4096.0f;
|
||||
|
||||
bool cdrom_read_thread = true;
|
||||
u8 cdrom_readahead_sectors = DEFAULT_CDROM_READAHEAD_SECTORS;
|
||||
bool cdrom_region_check = false;
|
||||
bool cdrom_load_image_to_ram = false;
|
||||
bool cdrom_mute_cd_audio = false;
|
||||
@ -379,6 +379,9 @@ struct Settings
|
||||
|
||||
static constexpr DisplayCropMode DEFAULT_DISPLAY_CROP_MODE = DisplayCropMode::Overscan;
|
||||
static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto;
|
||||
|
||||
static constexpr u8 DEFAULT_CDROM_READAHEAD_SECTORS = 8;
|
||||
|
||||
static constexpr ControllerType DEFAULT_CONTROLLER_1_TYPE = ControllerType::DigitalController;
|
||||
static constexpr ControllerType DEFAULT_CONTROLLER_2_TYPE = ControllerType::None;
|
||||
static constexpr MemoryCardType DEFAULT_MEMORY_CARD_1_TYPE = MemoryCardType::PerGameTitle;
|
||||
|
Reference in New Issue
Block a user