From e3d1704979beb3fc4dc0db775d00aec420e926c7 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sun, 22 Feb 2009 16:48:54 +0000 Subject: [PATCH] Attempt to speed up drive reading by doing larger block reads - didn't help very much. we need to support async reads, I think. Also delete some copypasta in DriveBlob - it already inherits those functions so it doesn't need them itself. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2368 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DiscIO/DiscIO.vcproj | 2 +- Source/Core/DiscIO/Src/Blob.cpp | 38 ++++++++++++++--- Source/Core/DiscIO/Src/Blob.h | 28 +++++++----- Source/Core/DiscIO/Src/DriveBlob.cpp | 64 +++++++--------------------- Source/Core/DiscIO/Src/DriveBlob.h | 6 +-- 5 files changed, 68 insertions(+), 70 deletions(-) diff --git a/Source/Core/DiscIO/DiscIO.vcproj b/Source/Core/DiscIO/DiscIO.vcproj index 9306ed97e3..cdb2e797ec 100644 --- a/Source/Core/DiscIO/DiscIO.vcproj +++ b/Source/Core/DiscIO/DiscIO.vcproj @@ -719,7 +719,7 @@ > 0) { - const u8* data = GetBlockData(block); - if (!data) - return false; + // Check if we are ready to do a large block read. > instead of >= so we don't bother if remain is only one block. + if (positionInBlock == 0 && remain > m_blocksize) + { + u64 num_blocks = remain / m_blocksize; + ReadMultipleAlignedBlocks(block, num_blocks, out_ptr); + block += num_blocks; + out_ptr += num_blocks * m_blocksize; + remain -= num_blocks * m_blocksize; + } u32 toCopy = m_blocksize - positionInBlock; if (toCopy >= remain) { - // yay, we are done! + const u8* data = GetBlockData(block); + if (!data) + return false; + + // Yay, we are done! memcpy(out_ptr, data + positionInBlock, (size_t)remain); return true; } else { + const u8* data = GetBlockData(block); + if (!data) + return false; + memcpy(out_ptr, data + positionInBlock, toCopy); out_ptr += toCopy; remain -= toCopy; @@ -91,10 +106,21 @@ bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr) return true; } +bool SectorReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr) +{ + for (int i = 0; i < num_blocks; i++) + { + const u8 *data = GetBlockData(block_num + i); + if (!data) + return false; + memcpy(out_ptr, data, m_blocksize); + } + return true; +} IBlobReader* CreateBlobReader(const char* filename) { - if(File::IsDisk(filename)) + if (File::IsDisk(filename)) return DriveReader::Create(filename); if (!File::Exists(filename)) diff --git a/Source/Core/DiscIO/Src/Blob.h b/Source/Core/DiscIO/Src/Blob.h index 778cc1f8d9..af754459d3 100644 --- a/Source/Core/DiscIO/Src/Blob.h +++ b/Source/Core/DiscIO/Src/Blob.h @@ -25,7 +25,7 @@ // allow random access. Or you may store them on an odd device, like raw on a DVD. // Always read your BLOBs using an interface returned by CreateBlobReader(). It will -// detect whether the file is a compressed blob, or just a big hunk of data, and +// detect whether the file is a compressed blob, or just a big hunk of data, or a drive, and // automatically do the right thing. #include "Common.h" @@ -49,33 +49,41 @@ protected: // Provides caching and split-operation-to-block-operations facilities. // Used for compressed blob reading and direct drive reading. +// Currently only uses a single entry cache. +// Multi-block reads are not cached. class SectorReader : public IBlobReader { private: - virtual void GetBlock(u64 block_num, u8 *out) = 0; enum { CACHE_SIZE = 32 }; int m_blocksize; u8* cache[CACHE_SIZE]; u64 cache_tags[CACHE_SIZE]; int cache_age[CACHE_SIZE]; + protected: void SetSectorSize(int blocksize); + virtual void GetBlock(u64 block_num, u8 *out) = 0; + // This one is uncached. The default implementation is to simply call GetBlockData multiple times and memcpy. + virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr); + public: - ~SectorReader(); + virtual ~SectorReader(); + + // A pointer returned by GetBlockData is invalidated as soon as GetBlockData, Read, or ReadMultipleAlignedBlocks is called again. const u8 *GetBlockData(u64 block_num); - bool Read(u64 offset, u64 size, u8* out_ptr); + virtual bool Read(u64 offset, u64 size, u8 *out_ptr); friend class DriveReader; }; // Factory function - examines the path to choose the right type of IBlobReader, and returns one. -IBlobReader* CreateBlobReader(const char* filename); +IBlobReader* CreateBlobReader(const char *filename); -typedef void (*CompressCB)(const char* text, float percent, void* arg); +typedef void (*CompressCB)(const char *text, float percent, void* arg); -bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type = 0, int sector_size = 16384, - CompressCB callback = 0, void* arg = 0); -bool DecompressBlobToFile(const char* infile, const char* outfile, - CompressCB callback = 0, void* arg = 0); +bool CompressFileToBlob(const char *infile, const char *outfile, u32 sub_type = 0, int sector_size = 16384, + CompressCB callback = 0, void *arg = 0); +bool DecompressBlobToFile(const char *infile, const char *outfile, + CompressCB callback = 0, void *arg = 0); } // namespace diff --git a/Source/Core/DiscIO/Src/DriveBlob.cpp b/Source/Core/DiscIO/Src/DriveBlob.cpp index 61a253548c..1ebef3af55 100644 --- a/Source/Core/DiscIO/Src/DriveBlob.cpp +++ b/Source/Core/DiscIO/Src/DriveBlob.cpp @@ -49,7 +49,7 @@ namespace DiscIO #else file_ = fopen(drive, "rb"); if (!file_) - PanicAlert("Load from DVD backup failed"); + PanicAlert("Load from DVD backup failed"); else SetSectorSize(2048); #endif @@ -69,46 +69,13 @@ namespace DiscIO #else fclose(file_); #endif - } // DriveReader::~DriveReader - + } DriveReader * DriveReader::Create(const char *drive) { return new DriveReader(drive); } - bool DriveReader::Read(u64 offset, u64 nbytes, u8* out_ptr) - { - u64 startingBlock = offset / m_blocksize; - u64 remain = nbytes; - int positionInBlock = (int)(offset % m_blocksize); - u64 block = startingBlock; - - while (remain > 0) - { - const u8* data = GetBlockData(block); - if (!data) - return false; - - u32 toCopy = m_blocksize - positionInBlock; - if (toCopy >= remain) - { - // yay, we are done! - memcpy(out_ptr, data + positionInBlock, (size_t)remain); - return true; - } - else - { - memcpy(out_ptr, data + positionInBlock, toCopy); - out_ptr += toCopy; - remain -= toCopy; - positionInBlock = 0; - block++; - } - } - return true; - } // DriveReader::Read - void DriveReader::GetBlock(u64 block_num, u8 *out_ptr) { u32 NotUsed; @@ -124,23 +91,24 @@ namespace DiscIO fseek(file_, m_blocksize*block_num, SEEK_SET); fread(lpSector, 1, m_blocksize, file_); #endif - memcpy(out_ptr, lpSector, m_blocksize); delete lpSector; } - const u8 *DriveReader::GetBlockData(u64 block_num) + bool DriveReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr) { - if (SectorReader::cache_tags[0] == block_num) - { - return SectorReader::cache[0]; - } - else - { - GetBlock(block_num, cache[0]); - SectorReader::cache_tags[0] = block_num; - return SectorReader::cache[0]; - } + u32 NotUsed; +#ifdef _WIN32 + u64 offset = m_blocksize * block_num; + LONG off_low = (LONG)offset & 0xFFFFFFFF; + LONG off_high = (LONG)(offset >> 32); + SetFilePointer(hDisc, off_low, &off_high, FILE_BEGIN); + if (!ReadFile(hDisc, out_ptr, (DWORD)(m_blocksize * num_blocks), (LPDWORD)&NotUsed, NULL)) + PanicAlert("DRE"); +#else + fseek(file_, m_blocksize*block_num, SEEK_SET); + fread(out_ptr, 1, m_blocksize * num_blocks, file_); +#endif + return true; } - } // namespace diff --git a/Source/Core/DiscIO/Src/DriveBlob.h b/Source/Core/DiscIO/Src/DriveBlob.h index bd84fc3afa..80c7ec093c 100644 --- a/Source/Core/DiscIO/Src/DriveBlob.h +++ b/Source/Core/DiscIO/Src/DriveBlob.h @@ -48,14 +48,10 @@ public: ~DriveReader(); u64 GetDataSize() const { return size; } u64 GetRawSize() const { return size; } - bool Read(u64 offset, u64 nbytes, u8* out_ptr); - const u8 *GetBlockData(u64 block_num); + virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr); }; - - - } // namespace #endif // _DRIVE_BLOB_H