From ae945f49e3ea11ebea55f3ecff945f8c1b27d632 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Wed, 24 Mar 2021 04:21:21 -0500 Subject: [PATCH] CDVD: Make CSO file reader threaded --- pcsx2/CDVD/CsoFileReader.cpp | 169 ++++++++--------------------------- pcsx2/CDVD/CsoFileReader.h | 42 +++------ 2 files changed, 48 insertions(+), 163 deletions(-) diff --git a/pcsx2/CDVD/CsoFileReader.cpp b/pcsx2/CDVD/CsoFileReader.cpp index 50fd8b2113..44dd547ed2 100644 --- a/pcsx2/CDVD/CsoFileReader.cpp +++ b/pcsx2/CDVD/CsoFileReader.cpp @@ -85,9 +85,9 @@ bool CsoFileReader::ValidateHeader(const CsoHeader& hdr) return true; } -bool CsoFileReader::Open(const wxString& fileName) +bool CsoFileReader::Open2(const wxString& fileName) { - Close(); + Close2(); m_filename = fileName; m_src = PX_fopen_rb(m_filename); @@ -99,7 +99,7 @@ bool CsoFileReader::Open(const wxString& fileName) if (!success) { - Close(); + Close2(); return false; } return true; @@ -152,10 +152,6 @@ bool CsoFileReader::InitializeBuffers() m_readBuffer = new u8[m_frameSize + (1 << m_indexShift)]; } - // This is a buffer for the most recently decompressed frame. - m_zlibBuffer = new u8[m_frameSize + (1 << m_indexShift)]; - m_zlibBufferFrame = numFrames; - const u32 indexSize = numFrames + 1; m_index = new u32[indexSize]; if (fread(m_index, sizeof(u32), indexSize, m_src) != indexSize) @@ -177,12 +173,9 @@ bool CsoFileReader::InitializeBuffers() return true; } -void CsoFileReader::Close() +void CsoFileReader::Close2() { m_filename.Empty(); -#if CSO_USE_CHUNKSCACHE - m_cache.Clear(); -#endif if (m_src) { @@ -200,11 +193,6 @@ void CsoFileReader::Close() delete[] m_readBuffer; m_readBuffer = NULL; } - if (m_zlibBuffer) - { - delete[] m_zlibBuffer; - m_zlibBuffer = NULL; - } if (m_index) { delete[] m_index; @@ -212,68 +200,28 @@ void CsoFileReader::Close() } } -int CsoFileReader::ReadSync(void* pBuffer, uint sector, uint count) +ThreadedFileReader::Chunk CsoFileReader::ChunkForOffset(u64 offset) { - if (!m_src) + Chunk chunk = {0}; + if (offset >= m_totalSize) { - return 0; + chunk.chunkID = -1; } - - // Note that, in practice, count will always be 1. It seems one sector is read - // per interrupt, even if multiple are requested by the application. - - u8* dest = (u8*)pBuffer; - // We do it this way in case m_blocksize is not well aligned to our frame size. - u64 pos = (u64)sector * (u64)m_blocksize; - int remaining = count * m_blocksize; - int bytes = 0; - - while (remaining > 0) + else { - int readBytes; - -#if CSO_USE_CHUNKSCACHE - // Try first to read from the cache. - readBytes = m_cache.Read(dest + bytes, pos + bytes, remaining); -#else - readBytes = -1; -#endif - if (readBytes < 0) - { - readBytes = ReadFromFrame(dest + bytes, pos + bytes, remaining); - if (readBytes == 0) - { - // We hit EOF. - break; - } - -#if CSO_USE_CHUNKSCACHE - // Add the bytes into the cache. We need to allocate a buffer for it. - void* cached = malloc(readBytes); - memcpy(cached, dest + bytes, readBytes); - m_cache.Take(cached, pos + bytes, readBytes, readBytes); -#endif - } - - bytes += readBytes; - remaining -= readBytes; + chunk.chunkID = offset >> m_frameShift; + chunk.length = m_frameSize; + chunk.offset = chunk.chunkID << m_frameShift; } - - return bytes; + return chunk; } -int CsoFileReader::ReadFromFrame(u8* dest, u64 pos, int maxBytes) +int CsoFileReader::ReadChunk(void *dst, s64 chunkID) { - if (pos >= m_totalSize) - { - // Can't read anything passed the end. - return 0; - } + if (chunkID < 0) + return -1; - const u32 frame = (u32)(pos >> m_frameShift); - const u32 offset = (u32)(pos - (frame << m_frameShift)); - // This is how many bytes we will actually be reading from this frame. - const u32 bytes = (u32)(std::min(m_blocksize, static_cast(m_frameSize - offset))); + const u32 frame = chunkID; // Grab the index data for the frame we're about to read. const bool compressed = (m_index[frame + 0] & 0x80000000) == 0; @@ -287,77 +235,36 @@ int CsoFileReader::ReadFromFrame(u8* dest, u64 pos, int maxBytes) if (!compressed) { // Just read directly, easy. - if (PX_fseeko(m_src, m_dataoffset + frameRawPos + offset, SEEK_SET) != 0) + if (PX_fseeko(m_src, frameRawPos, SEEK_SET) != 0) { Console.Error("Unable to seek to uncompressed CSO data."); return 0; } - return fread(dest, 1, bytes, m_src); + return fread(dst, 1, m_frameSize, m_src); } else { - // We don't need to decompress if we already did this same frame last time. - if (m_zlibBufferFrame != frame) + if (PX_fseeko(m_src, frameRawPos, SEEK_SET) != 0) { - if (PX_fseeko(m_src, m_dataoffset + frameRawPos, SEEK_SET) != 0) - { - Console.Error("Unable to seek to compressed CSO data."); - return 0; - } - // This might be less bytes than frameRawSize in case of padding on the last frame. - // This is because the index positions must be aligned. - const u32 readRawBytes = fread(m_readBuffer, 1, frameRawSize, m_src); - if (!DecompressFrame(frame, readRawBytes)) - { - return 0; - } + Console.Error("Unable to seek to compressed CSO data."); + return 0; } + // This might be less bytes than frameRawSize in case of padding on the last frame. + // This is because the index positions must be aligned. + const u32 readRawBytes = fread(m_readBuffer, 1, frameRawSize, m_src); - // Now we just copy the offset data from the cache. - memcpy(dest, m_zlibBuffer + offset, bytes); + m_z_stream->next_in = m_readBuffer; + m_z_stream->avail_in = readRawBytes; + m_z_stream->next_out = static_cast(dst); + m_z_stream->avail_out = m_frameSize; + + int status = inflate(m_z_stream, Z_FINISH); + bool success = status == Z_STREAM_END && m_z_stream->total_out == m_frameSize; + + if (!success) + Console.Error("Unable to decompress CSO frame using zlib."); + inflateReset(m_z_stream); + + return success ? m_frameSize : 0; } - - return bytes; -} - -bool CsoFileReader::DecompressFrame(u32 frame, u32 readBufferSize) -{ - m_z_stream->next_in = m_readBuffer; - m_z_stream->avail_in = readBufferSize; - m_z_stream->next_out = m_zlibBuffer; - m_z_stream->avail_out = m_frameSize; - - int status = inflate(m_z_stream, Z_FINISH); - bool success = status == Z_STREAM_END && m_z_stream->total_out == m_frameSize; - if (success) - { - // Our buffer now contains this frame. - m_zlibBufferFrame = frame; - } - else - { - Console.Error("Unable to decompress CSO frame using zlib."); - m_zlibBufferFrame = (u32)-1; - } - - inflateReset(m_z_stream); - return success; -} - -void CsoFileReader::BeginRead(void* pBuffer, uint sector, uint count) -{ - // TODO: No async support yet, implement as sync. - m_bytesRead = ReadSync(pBuffer, sector, count); -} - -int CsoFileReader::FinishRead() -{ - int res = m_bytesRead; - m_bytesRead = -1; - return res; -} - -void CsoFileReader::CancelRead() -{ - // TODO: No async read support yet. } diff --git a/pcsx2/CDVD/CsoFileReader.h b/pcsx2/CDVD/CsoFileReader.h index dea0b93f19..f430fb6ac2 100644 --- a/pcsx2/CDVD/CsoFileReader.h +++ b/pcsx2/CDVD/CsoFileReader.h @@ -24,7 +24,7 @@ // For this reason, it's currently disabled. #define CSO_USE_CHUNKSCACHE 0 -#include "AsyncFileReader.h" +#include "ThreadedFileReader.h" #include "ChunksCache.h" struct CsoHeader; @@ -32,7 +32,7 @@ typedef struct z_stream_s z_stream; static const uint CSO_CHUNKCACHE_SIZE_MB = 200; -class CsoFileReader : public AsyncFileReader +class CsoFileReader : public ThreadedFileReader { DeclareNoncopyableObject(CsoFileReader); @@ -42,66 +42,44 @@ public: , m_frameShift(0) , m_indexShift(0) , m_readBuffer(0) - , m_zlibBuffer(0) - , m_zlibBufferFrame(0) , m_index(0) , m_totalSize(0) , m_src(0) , m_z_stream(0) - , -#if CSO_USE_CHUNKSCACHE - m_cache(CSO_CHUNKCACHE_SIZE_MB) - , -#endif - m_bytesRead(0) { m_blocksize = 2048; }; - virtual ~CsoFileReader(void) { Close(); }; + ~CsoFileReader(void) { Close(); }; static bool CanHandle(const wxString& fileName); - virtual bool Open(const wxString& fileName); + bool Open2(const wxString& fileName) override; - virtual int ReadSync(void* pBuffer, uint sector, uint count); + Chunk ChunkForOffset(u64 offset) override; + int ReadChunk(void *dst, s64 chunkID) override; - virtual void BeginRead(void* pBuffer, uint sector, uint count); - virtual int FinishRead(void); - virtual void CancelRead(void); + void Close2(void) override; - virtual void Close(void); - - virtual uint GetBlockCount(void) const + uint GetBlockCount(void) const override { return (m_totalSize - m_dataoffset) / m_blocksize; }; - virtual void SetBlockSize(uint bytes) { m_blocksize = bytes; } - virtual void SetDataOffset(int bytes) { m_dataoffset = bytes; } - private: static bool ValidateHeader(const CsoHeader& hdr); bool ReadFileHeader(); bool InitializeBuffers(); int ReadFromFrame(u8* dest, u64 pos, int maxBytes); + bool DecompressFrame(Bytef* dst, u32 frame, u32 readBufferSize); bool DecompressFrame(u32 frame, u32 readBufferSize); u32 m_frameSize; u8 m_frameShift; u8 m_indexShift; - u8* m_readBuffer; - u8* m_zlibBuffer; - u32 m_zlibBufferFrame; + u8* m_readBuffer;; u32* m_index; u64 m_totalSize; // The actual source cso file handle. FILE* m_src; z_stream* m_z_stream; - -#if CSO_USE_CHUNKSCACHE - ChunksCache m_cache; -#endif - - // The result of a read is stored here between BeginRead() and FinishRead(). - int m_bytesRead; };