cdrom_async_reader.h (2849B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 #include "util/cd_image.h" 6 #include "types.h" 7 #include <array> 8 #include <atomic> 9 #include <condition_variable> 10 #include <thread> 11 12 class ProgressCallback; 13 14 class CDROMAsyncReader 15 { 16 public: 17 using SectorBuffer = std::array<u8, CDImage::RAW_SECTOR_SIZE>; 18 19 struct BufferSlot 20 { 21 CDImage::LBA lba; 22 SectorBuffer data; 23 CDImage::SubChannelQ subq; 24 bool result; 25 }; 26 27 CDROMAsyncReader(); 28 ~CDROMAsyncReader(); 29 30 CDImage::LBA GetLastReadSector() const { return m_buffers[m_buffer_front.load()].lba; } 31 const SectorBuffer& GetSectorBuffer() const { return m_buffers[m_buffer_front.load()].data; } 32 const CDImage::SubChannelQ& GetSectorSubQ() const { return m_buffers[m_buffer_front.load()].subq; } 33 u32 GetBufferedSectorCount() const { return m_buffer_count.load(); } 34 bool HasBufferedSectors() const { return (m_buffer_count.load() > 0); } 35 u32 GetReadaheadCount() const { return static_cast<u32>(m_buffers.size()); } 36 37 bool HasMedia() const { return static_cast<bool>(m_media); } 38 const CDImage* GetMedia() const { return m_media.get(); } 39 CDImage* GetMedia() { return m_media.get(); } 40 const std::string& GetMediaFileName() const { return m_media->GetFileName(); } 41 42 bool IsUsingThread() const { return m_read_thread.joinable(); } 43 void StartThread(u32 readahead_count = 8); 44 void StopThread(); 45 46 void SetMedia(std::unique_ptr<CDImage> media); 47 std::unique_ptr<CDImage> RemoveMedia(); 48 49 /// Precaches image, either to memory, or using the underlying image precache. 50 bool Precache(ProgressCallback* callback); 51 52 void QueueReadSector(CDImage::LBA lba); 53 54 bool WaitForReadToComplete(); 55 void WaitForIdle(); 56 57 /// Bypasses the sector cache and reads directly from the image. 58 bool ReadSectorUncached(CDImage::LBA lba, CDImage::SubChannelQ* subq, SectorBuffer* data); 59 60 private: 61 void EmptyBuffers(); 62 bool ReadSectorIntoBuffer(std::unique_lock<std::mutex>& lock); 63 void ReadSectorNonThreaded(CDImage::LBA lba); 64 bool InternalReadSectorUncached(CDImage::LBA lba, CDImage::SubChannelQ* subq, SectorBuffer* data); 65 void CancelReadahead(); 66 67 void WorkerThreadEntryPoint(); 68 69 std::unique_ptr<CDImage> m_media; 70 71 std::mutex m_mutex; 72 std::thread m_read_thread; 73 std::condition_variable m_do_read_cv; 74 std::condition_variable m_notify_read_complete_cv; 75 76 std::atomic<CDImage::LBA> m_next_position{}; 77 std::atomic_bool m_next_position_set{false}; 78 std::atomic_bool m_shutdown_flag{true}; 79 80 std::atomic_bool m_is_reading{false}; 81 std::atomic_bool m_can_readahead{false}; 82 std::atomic_bool m_seek_error{false}; 83 84 std::vector<BufferSlot> m_buffers; 85 std::atomic<u32> m_buffer_front{0}; 86 std::atomic<u32> m_buffer_back{0}; 87 std::atomic<u32> m_buffer_count{0}; 88 };