mirror of https://github.com/PCSX2/pcsx2.git
Merge pull request #505 from unknownbrackets/cso
Small optimization to CSO support, add notes
This commit is contained in:
commit
ce8626150e
|
@ -140,28 +140,44 @@ bool CsoFileReader::InitializeBuffers() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_z_stream = new z_stream;
|
||||||
|
m_z_stream->zalloc = Z_NULL;
|
||||||
|
m_z_stream->zfree = Z_NULL;
|
||||||
|
m_z_stream->opaque = Z_NULL;
|
||||||
|
if (inflateInit2(m_z_stream, -15) != Z_OK) {
|
||||||
|
Console.Error("Unable to initialize zlib for CSO decompression.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CsoFileReader::Close() {
|
void CsoFileReader::Close() {
|
||||||
m_filename.Empty();
|
m_filename.Empty();
|
||||||
|
#if CSO_USE_CHUNKSCACHE
|
||||||
|
m_cache.Clear();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (m_src) {
|
if (m_src) {
|
||||||
fclose(m_src);
|
fclose(m_src);
|
||||||
m_src = 0;
|
m_src = NULL;
|
||||||
|
}
|
||||||
|
if (m_z_stream) {
|
||||||
|
inflateEnd(m_z_stream);
|
||||||
|
m_z_stream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_readBuffer) {
|
if (m_readBuffer) {
|
||||||
delete[] m_readBuffer;
|
delete[] m_readBuffer;
|
||||||
m_readBuffer = 0;
|
m_readBuffer = NULL;
|
||||||
}
|
}
|
||||||
if (m_zlibBuffer) {
|
if (m_zlibBuffer) {
|
||||||
delete[] m_zlibBuffer;
|
delete[] m_zlibBuffer;
|
||||||
m_zlibBuffer = 0;
|
m_zlibBuffer = NULL;
|
||||||
}
|
}
|
||||||
if (m_index) {
|
if (m_index) {
|
||||||
delete[] m_index;
|
delete[] m_index;
|
||||||
m_index = 0;
|
m_index = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +186,9 @@ int CsoFileReader::ReadSync(void* pBuffer, uint sector, uint count) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
u8* dest = (u8*)pBuffer;
|
||||||
// We do it this way in case m_blocksize is not well aligned to our frame size.
|
// We do it this way in case m_blocksize is not well aligned to our frame size.
|
||||||
u64 pos = (u64)sector * (u64)m_blocksize;
|
u64 pos = (u64)sector * (u64)m_blocksize;
|
||||||
|
@ -177,18 +196,37 @@ int CsoFileReader::ReadSync(void* pBuffer, uint sector, uint count) {
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
int readBytes = ReadFromFrame(dest + bytes, pos + bytes, remaining);
|
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) {
|
if (readBytes == 0) {
|
||||||
// We hit EOF.
|
// We hit EOF.
|
||||||
break;
|
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;
|
bytes += readBytes;
|
||||||
remaining -= readBytes;
|
remaining -= readBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CsoFileReader::ReadFromFrame(u8 *dest, u64 pos, u64 maxBytes) {
|
int CsoFileReader::ReadFromFrame(u8 *dest, u64 pos, int maxBytes) {
|
||||||
if (pos >= m_totalSize) {
|
if (pos >= m_totalSize) {
|
||||||
// Can't read anything passed the end.
|
// Can't read anything passed the end.
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -238,41 +276,33 @@ int CsoFileReader::ReadFromFrame(u8 *dest, u64 pos, u64 maxBytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CsoFileReader::DecompressFrame(u32 frame, u32 readBufferSize) {
|
bool CsoFileReader::DecompressFrame(u32 frame, u32 readBufferSize) {
|
||||||
z_stream z;
|
m_z_stream->next_in = m_readBuffer;
|
||||||
z.zalloc = Z_NULL;
|
m_z_stream->avail_in = readBufferSize;
|
||||||
z.zfree = Z_NULL;
|
m_z_stream->next_out = m_zlibBuffer;
|
||||||
z.opaque = Z_NULL;
|
m_z_stream->avail_out = m_frameSize;
|
||||||
if (inflateInit2(&z, -15) != Z_OK) {
|
|
||||||
Console.Error("Unable to initialize zlib for CSO decompression.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
z.next_in = m_readBuffer;
|
|
||||||
z.avail_in = readBufferSize;
|
|
||||||
z.next_out = m_zlibBuffer;
|
|
||||||
z.avail_out = m_frameSize;
|
|
||||||
|
|
||||||
int status = inflate(&z, Z_FINISH);
|
|
||||||
if (status != Z_STREAM_END || z.total_out != m_frameSize) {
|
|
||||||
inflateEnd(&z);
|
|
||||||
Console.Error("Unable to decompress CSO frame using zlib.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
inflateEnd(&z);
|
|
||||||
|
|
||||||
|
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.
|
// Our buffer now contains this frame.
|
||||||
m_zlibBufferFrame = frame;
|
m_zlibBufferFrame = frame;
|
||||||
return true;
|
} 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) {
|
void CsoFileReader::BeginRead(void* pBuffer, uint sector, uint count) {
|
||||||
// TODO: No async support yet, implement as sync.
|
// TODO: No async support yet, implement as sync.
|
||||||
mBytesRead = ReadSync(pBuffer, sector, count);
|
m_bytesRead = ReadSync(pBuffer, sector, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CsoFileReader::FinishRead() {
|
int CsoFileReader::FinishRead() {
|
||||||
int res = mBytesRead;
|
int res = m_bytesRead;
|
||||||
mBytesRead = -1;
|
m_bytesRead = -1;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,22 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Based on testing, the overhead of using this cache is high.
|
||||||
|
//
|
||||||
|
// The test was done with CSO files using a block size of 16KB.
|
||||||
|
// Cache hit rates were observed in the range of 25%.
|
||||||
|
// Cache overhead added 35% to the overall read time.
|
||||||
|
//
|
||||||
|
// For this reason, it's currently disabled.
|
||||||
|
#define CSO_USE_CHUNKSCACHE 0
|
||||||
|
|
||||||
#include "AsyncFileReader.h"
|
#include "AsyncFileReader.h"
|
||||||
|
#include "ChunksCache.h"
|
||||||
|
|
||||||
struct CsoHeader;
|
struct CsoHeader;
|
||||||
|
typedef struct z_stream_s z_stream;
|
||||||
|
|
||||||
|
static const uint CSO_CHUNKCACHE_SIZE_MB = 200;
|
||||||
|
|
||||||
class CsoFileReader : public AsyncFileReader
|
class CsoFileReader : public AsyncFileReader
|
||||||
{
|
{
|
||||||
|
@ -28,7 +41,12 @@ public:
|
||||||
m_zlibBuffer(0),
|
m_zlibBuffer(0),
|
||||||
m_index(0),
|
m_index(0),
|
||||||
m_totalSize(0),
|
m_totalSize(0),
|
||||||
m_src(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;
|
m_blocksize = 2048;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,7 +74,7 @@ private:
|
||||||
static bool ValidateHeader(const CsoHeader& hdr);
|
static bool ValidateHeader(const CsoHeader& hdr);
|
||||||
bool ReadFileHeader();
|
bool ReadFileHeader();
|
||||||
bool InitializeBuffers();
|
bool InitializeBuffers();
|
||||||
int ReadFromFrame(u8 *dest, u64 pos, u64 maxBytes);
|
int ReadFromFrame(u8 *dest, u64 pos, int maxBytes);
|
||||||
bool DecompressFrame(u32 frame, u32 readBufferSize);
|
bool DecompressFrame(u32 frame, u32 readBufferSize);
|
||||||
|
|
||||||
u32 m_frameSize;
|
u32 m_frameSize;
|
||||||
|
@ -69,6 +87,12 @@ private:
|
||||||
u64 m_totalSize;
|
u64 m_totalSize;
|
||||||
// The actual source cso file handle.
|
// The actual source cso file handle.
|
||||||
FILE* m_src;
|
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().
|
// The result of a read is stored here between BeginRead() and FinishRead().
|
||||||
int mBytesRead;
|
int m_bytesRead;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue