diff --git a/Core/Config.cpp b/Core/Config.cpp index ef19b9ca70..3ee86667db 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -458,7 +458,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true), ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), - ReportedConfigSetting("FrameRate", &g_Config.iFpsLimit, 0, true, true), + ConfigSetting("FrameRate", &g_Config.iFpsLimit, 0, true, true), #ifdef _WIN32 ConfigSetting("FrameSkipUnthrottle", &g_Config.bFrameSkipUnthrottle, false, true, true), ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), diff --git a/Core/FileLoaders/CachingFileLoader.cpp b/Core/FileLoaders/CachingFileLoader.cpp index 1c46c99dbb..1b9e269a47 100644 --- a/Core/FileLoaders/CachingFileLoader.cpp +++ b/Core/FileLoaders/CachingFileLoader.cpp @@ -84,7 +84,7 @@ void CachingFileLoader::Seek(s64 absolutePos) { filepos_ = absolutePos; } -size_t CachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { +size_t CachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { Prepare(); if (absolutePos >= filesize_) { bytes = 0; @@ -92,19 +92,25 @@ size_t CachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { bytes = filesize_ - absolutePos; } - size_t readSize = ReadFromCache(absolutePos, bytes, data); - // While in case the cache size is too small for the entire read. - while (readSize < bytes) { - SaveIntoCache(absolutePos + readSize, bytes - readSize); - size_t bytesFromCache = ReadFromCache(absolutePos + readSize, bytes - readSize, (u8 *)data + readSize); - readSize += bytesFromCache; - if (bytesFromCache == 0) { - // We can't read any more. - break; + size_t readSize = 0; + if ((flags & Flags::HINT_UNCACHED) != 0) { + lock_guard guard(backendMutex_); + readSize = backend_->ReadAt(absolutePos, bytes, data, flags); + } else { + readSize = ReadFromCache(absolutePos, bytes, data); + // While in case the cache size is too small for the entire read. + while (readSize < bytes) { + SaveIntoCache(absolutePos + readSize, bytes - readSize, flags); + size_t bytesFromCache = ReadFromCache(absolutePos + readSize, bytes - readSize, (u8 *)data + readSize); + readSize += bytesFromCache; + if (bytesFromCache == 0) { + // We can't read any more. + break; + } } - } - StartReadAhead(absolutePos + readSize); + StartReadAhead(absolutePos + readSize); + } filepos_ = absolutePos + readSize; return readSize; @@ -158,7 +164,7 @@ size_t CachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) { return readSize; } -void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, bool readingAhead) { +void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, Flags flags, bool readingAhead) { s64 cacheStartPos = pos >> BLOCK_SHIFT; s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT; @@ -184,7 +190,7 @@ void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, bool readingAhead) u8 *buf = new u8[BLOCK_SIZE]; backendMutex_.lock(); - backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, BLOCK_SIZE, buf); + backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, BLOCK_SIZE, buf, flags); backendMutex_.unlock(); blocksMutex_.lock(); @@ -200,7 +206,7 @@ void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, bool readingAhead) u8 *wholeRead = new u8[blocksToRead << BLOCK_SHIFT]; backendMutex_.lock(); - backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, blocksToRead << BLOCK_SHIFT, wholeRead); + backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, blocksToRead << BLOCK_SHIFT, wholeRead, flags); backendMutex_.unlock(); blocksMutex_.lock(); @@ -288,7 +294,7 @@ void CachingFileLoader::StartReadAhead(s64 pos) { auto block = blocks_.find(i); if (block == blocks_.end()) { blocksMutex_.unlock(); - SaveIntoCache(i << BLOCK_SHIFT, BLOCK_SIZE * BLOCK_READAHEAD, true); + SaveIntoCache(i << BLOCK_SHIFT, BLOCK_SIZE * BLOCK_READAHEAD, Flags::NONE, true); break; } } diff --git a/Core/FileLoaders/CachingFileLoader.h b/Core/FileLoaders/CachingFileLoader.h index e3c2cc9b4a..5ff12b2d89 100644 --- a/Core/FileLoaders/CachingFileLoader.h +++ b/Core/FileLoaders/CachingFileLoader.h @@ -25,25 +25,25 @@ class CachingFileLoader : public FileLoader { public: CachingFileLoader(FileLoader *backend); - virtual ~CachingFileLoader() override; + ~CachingFileLoader() override; - virtual bool Exists() override; - virtual bool ExistsFast() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual std::string Path() const override; + bool Exists() override; + bool ExistsFast() override; + bool IsDirectory() override; + s64 FileSize() override; + std::string Path() const override; - virtual void Seek(s64 absolutePos) override; - virtual size_t Read(size_t bytes, size_t count, void *data) override { - return ReadAt(filepos_, bytes, count, data); + void Seek(s64 absolutePos) override; + size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, count, data, flags); } - virtual size_t Read(size_t bytes, void *data) override { - return ReadAt(filepos_, bytes, data); + size_t Read(size_t bytes, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, data, flags); } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override { - return ReadAt(absolutePos, bytes * count, data) / bytes; + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override; + size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; private: void Prepare(); @@ -51,7 +51,7 @@ private: void ShutdownCache(); size_t ReadFromCache(s64 pos, size_t bytes, void *data); // Guaranteed to read at least one block into the cache. - void SaveIntoCache(s64 pos, size_t bytes, bool readingAhead = false); + void SaveIntoCache(s64 pos, size_t bytes, Flags flags, bool readingAhead = false); bool MakeCacheSpaceFor(size_t blocks, bool readingAhead); void StartReadAhead(s64 pos); diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index 2efaff810c..27c512ce3f 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -89,7 +89,7 @@ void DiskCachingFileLoader::Seek(s64 absolutePos) { filepos_ = absolutePos; } -size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { +size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { Prepare(); size_t readSize; @@ -99,11 +99,11 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) bytes = filesize_ - absolutePos; } - if (cache_ && cache_->IsValid()) { + if (cache_ && cache_->IsValid() && (flags & Flags::HINT_UNCACHED) == 0) { readSize = cache_->ReadFromCache(absolutePos, bytes, data); // While in case the cache size is too small for the entire read. while (readSize < bytes) { - readSize += cache_->SaveIntoCache(backend_, absolutePos + readSize, bytes - readSize, (u8 *)data + readSize); + readSize += cache_->SaveIntoCache(backend_, absolutePos + readSize, bytes - readSize, (u8 *)data + readSize, flags); // If there are already-cached blocks afterward, we have to read them. size_t bytesFromCache = cache_->ReadFromCache(absolutePos + readSize, bytes - readSize, (u8 *)data + readSize); readSize += bytesFromCache; @@ -113,7 +113,7 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) } } } else { - readSize = backend_->ReadAt(absolutePos, bytes, data); + readSize = backend_->ReadAt(absolutePos, bytes, data, flags); } filepos_ = absolutePos + readSize; @@ -256,12 +256,12 @@ size_t DiskCachingFileLoaderCache::ReadFromCache(s64 pos, size_t bytes, void *da return readSize; } -size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data) { +size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data, FileLoader::Flags flags) { lock_guard guard(lock_); if (!f_) { // Just to keep things working. - return backend->ReadAt(pos, bytes, data); + return backend->ReadAt(pos, bytes, data, flags); } s64 cacheStartPos = pos / blockSize_; @@ -290,7 +290,7 @@ size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, s auto &info = index_[cacheStartPos]; u8 *buf = new u8[blockSize_]; - size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blockSize_, buf); + size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blockSize_, buf, flags); // Check if it was written while we were busy. Might happen if we thread. if (info.block == INVALID_BLOCK && readBytes != 0) { @@ -306,7 +306,7 @@ size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, s delete [] buf; } else { u8 *wholeRead = new u8[blocksToRead * blockSize_]; - size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blocksToRead * blockSize_, wholeRead); + size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blocksToRead * blockSize_, wholeRead, flags); for (size_t i = 0; i < blocksToRead; ++i) { auto &info = index_[cacheStartPos + i]; diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index e0ca3e9adc..8c845c8146 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -28,25 +28,25 @@ class DiskCachingFileLoaderCache; class DiskCachingFileLoader : public FileLoader { public: DiskCachingFileLoader(FileLoader *backend); - virtual ~DiskCachingFileLoader() override; + ~DiskCachingFileLoader() override; - virtual bool Exists() override; - virtual bool ExistsFast() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual std::string Path() const override; + bool Exists() override; + bool ExistsFast() override; + bool IsDirectory() override; + s64 FileSize() override; + std::string Path() const override; - virtual void Seek(s64 absolutePos) override; - virtual size_t Read(size_t bytes, size_t count, void *data) override { - return ReadAt(filepos_, bytes, count, data); + void Seek(s64 absolutePos) override; + size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, count, data, flags); } - virtual size_t Read(size_t bytes, void *data) override { - return ReadAt(filepos_, bytes, data); + size_t Read(size_t bytes, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, data, flags); } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override { - return ReadAt(absolutePos, bytes * count, data) / bytes; + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override; + size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; static std::vector GetCachedPathsInUse(); @@ -90,7 +90,7 @@ public: size_t ReadFromCache(s64 pos, size_t bytes, void *data); // Guaranteed to read at least one block into the cache. - size_t SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data); + size_t SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data, FileLoader::Flags flags); bool HasData() const; diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index 725f6b0cad..8e51d38f40 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -123,7 +123,7 @@ void HTTPFileLoader::Seek(s64 absolutePos) { filepos_ = absolutePos; } -size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { +size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { Prepare(); s64 absoluteEnd = std::min(absolutePos + (s64)bytes, filesize_); if (absolutePos >= filesize_ || bytes == 0) { diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index 69c0ce5e50..38acb461ed 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -35,16 +35,16 @@ public: virtual std::string Path() const override; virtual void Seek(s64 absolutePos) override; - virtual size_t Read(size_t bytes, size_t count, void *data) override { - return ReadAt(filepos_, bytes, count, data); + virtual size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, count, data, flags); } - virtual size_t Read(size_t bytes, void *data) override { - return ReadAt(filepos_, bytes, data); + virtual size_t Read(size_t bytes, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, data, flags); } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override { - return ReadAt(absolutePos, bytes * count, data) / bytes; + virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override; + virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; private: void Prepare(); diff --git a/Core/FileLoaders/LocalFileLoader.cpp b/Core/FileLoaders/LocalFileLoader.cpp index bcf3c69901..4d94918e21 100644 --- a/Core/FileLoaders/LocalFileLoader.cpp +++ b/Core/FileLoaders/LocalFileLoader.cpp @@ -81,7 +81,7 @@ void LocalFileLoader::Seek(s64 absolutePos) { #endif } -size_t LocalFileLoader::Read(size_t bytes, size_t count, void *data) { +size_t LocalFileLoader::Read(size_t bytes, size_t count, void *data, Flags flags) { #ifdef ANDROID return read(fd_, data, bytes * count) / bytes; #else @@ -89,7 +89,7 @@ size_t LocalFileLoader::Read(size_t bytes, size_t count, void *data) { #endif } -size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) { +size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags) { Seek(absolutePos); return Read(bytes, count, data); } diff --git a/Core/FileLoaders/LocalFileLoader.h b/Core/FileLoaders/LocalFileLoader.h index 284a805dc0..46b694736d 100644 --- a/Core/FileLoaders/LocalFileLoader.h +++ b/Core/FileLoaders/LocalFileLoader.h @@ -31,8 +31,8 @@ public: virtual std::string Path() const override; virtual void Seek(s64 absolutePos) override; - virtual size_t Read(size_t bytes, size_t count, void *data) override; - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override; + virtual size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; + virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; private: // First only used by Android, but we can keep it here for everyone. diff --git a/Core/FileLoaders/RamCachingFileLoader.cpp b/Core/FileLoaders/RamCachingFileLoader.cpp index b9e75e1c2f..a465aacda6 100644 --- a/Core/FileLoaders/RamCachingFileLoader.cpp +++ b/Core/FileLoaders/RamCachingFileLoader.cpp @@ -77,16 +77,16 @@ void RamCachingFileLoader::Seek(s64 absolutePos) { filepos_ = absolutePos; } -size_t RamCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { +size_t RamCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { size_t readSize = 0; - if (cache_ == nullptr) { + if (cache_ == nullptr || (flags & Flags::HINT_UNCACHED) != 0) { lock_guard guard(backendMutex_); - readSize = backend_->ReadAt(absolutePos, bytes, data); + readSize = backend_->ReadAt(absolutePos, bytes, data, flags); } else { readSize = ReadFromCache(absolutePos, bytes, data); // While in case the cache size is too small for the entire read. while (readSize < bytes) { - SaveIntoCache(absolutePos + readSize, bytes - readSize); + SaveIntoCache(absolutePos + readSize, bytes - readSize, flags); size_t bytesFromCache = ReadFromCache(absolutePos + readSize, bytes - readSize, (u8 *)data + readSize); readSize += bytesFromCache; if (bytesFromCache == 0) { @@ -94,9 +94,9 @@ size_t RamCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { break; } } - } - StartReadAhead(absolutePos + readSize); + StartReadAhead(absolutePos + readSize); + } filepos_ = absolutePos + readSize; return readSize; @@ -172,7 +172,7 @@ size_t RamCachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) { return readSize; } -void RamCachingFileLoader::SaveIntoCache(s64 pos, size_t bytes) { +void RamCachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, Flags flags) { s64 cacheStartPos = pos >> BLOCK_SHIFT; s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT; if ((size_t)cacheEndPos >= blocks_.size()) { @@ -194,7 +194,7 @@ void RamCachingFileLoader::SaveIntoCache(s64 pos, size_t bytes) { backendMutex_.lock(); s64 cacheFilePos = cacheStartPos << BLOCK_SHIFT; - size_t bytesRead = backend_->ReadAt(cacheFilePos, blocksToRead << BLOCK_SHIFT, &cache_[cacheFilePos]); + size_t bytesRead = backend_->ReadAt(cacheFilePos, blocksToRead << BLOCK_SHIFT, &cache_[cacheFilePos], flags); backendMutex_.unlock(); // In case there was an error, let's not mark blocks that failed to read as read. @@ -247,7 +247,7 @@ void RamCachingFileLoader::StartReadAhead(s64 pos) { for (u32 i = cacheStartPos; i <= cacheEndPos; ++i) { if (blocks_[i] == 0) { - SaveIntoCache((u64)i << BLOCK_SHIFT, BLOCK_SIZE * BLOCK_READAHEAD); + SaveIntoCache((u64)i << BLOCK_SHIFT, BLOCK_SIZE * BLOCK_READAHEAD, Flags::NONE); break; } } diff --git a/Core/FileLoaders/RamCachingFileLoader.h b/Core/FileLoaders/RamCachingFileLoader.h index 38d05826f7..fd25a68edf 100644 --- a/Core/FileLoaders/RamCachingFileLoader.h +++ b/Core/FileLoaders/RamCachingFileLoader.h @@ -34,23 +34,23 @@ public: std::string Path() const override; void Seek(s64 absolutePos) override; - size_t Read(size_t bytes, size_t count, void *data) override { - return ReadAt(filepos_, bytes, count, data); + size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, count, data, flags); } - size_t Read(size_t bytes, void *data) override { - return ReadAt(filepos_, bytes, data); + size_t Read(size_t bytes, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, data, flags); } - size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override { - return ReadAt(absolutePos, bytes * count, data) / bytes; + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override; + size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; private: void InitCache(); void ShutdownCache(); size_t ReadFromCache(s64 pos, size_t bytes, void *data); // Guaranteed to read at least one block into the cache. - void SaveIntoCache(s64 pos, size_t bytes); + void SaveIntoCache(s64 pos, size_t bytes, Flags flags); void StartReadAhead(s64 pos); u32 NextAheadBlock(); diff --git a/Core/FileLoaders/RetryingFileLoader.cpp b/Core/FileLoaders/RetryingFileLoader.cpp index 28fa17a955..28d78ff09b 100644 --- a/Core/FileLoaders/RetryingFileLoader.cpp +++ b/Core/FileLoaders/RetryingFileLoader.cpp @@ -64,13 +64,13 @@ void RetryingFileLoader::Seek(s64 absolutePos) { filepos_ = absolutePos; } -size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) { - size_t readSize = backend_->ReadAt(absolutePos, bytes, data); +size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) { + size_t readSize = backend_->ReadAt(absolutePos, bytes, data, flags); int retries = 0; while (readSize < bytes && retries < MAX_RETRIES) { u8 *p = (u8 *)data; - readSize += backend_->ReadAt(absolutePos + readSize, bytes - readSize, p + readSize); + readSize += backend_->ReadAt(absolutePos + readSize, bytes - readSize, p + readSize, flags); ++retries; } diff --git a/Core/FileLoaders/RetryingFileLoader.h b/Core/FileLoaders/RetryingFileLoader.h index 24cd0c284a..646af1371e 100644 --- a/Core/FileLoaders/RetryingFileLoader.h +++ b/Core/FileLoaders/RetryingFileLoader.h @@ -23,25 +23,25 @@ class RetryingFileLoader : public FileLoader { public: RetryingFileLoader(FileLoader *backend); - virtual ~RetryingFileLoader() override; + ~RetryingFileLoader() override; - virtual bool Exists() override; - virtual bool ExistsFast() override; - virtual bool IsDirectory() override; - virtual s64 FileSize() override; - virtual std::string Path() const override; + bool Exists() override; + bool ExistsFast() override; + bool IsDirectory() override; + s64 FileSize() override; + std::string Path() const override; - virtual void Seek(s64 absolutePos) override; - virtual size_t Read(size_t bytes, size_t count, void *data) override { - return ReadAt(filepos_, bytes, count, data); + void Seek(s64 absolutePos) override; + size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, count, data, flags); } - virtual size_t Read(size_t bytes, void *data) override { - return ReadAt(filepos_, bytes, data); + size_t Read(size_t bytes, void *data, Flags flags = Flags::NONE) override { + return ReadAt(filepos_, bytes, data, flags); } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override { - return ReadAt(absolutePos, bytes * count, data) / bytes; + size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override { + return ReadAt(absolutePos, bytes * count, data, flags) / bytes; } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override; + size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; private: enum { diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index 2f0a290d72..ac50efb5f7 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -45,6 +45,21 @@ BlockDevice *constructBlockDevice(FileLoader *fileLoader) { return new FileBlockDevice(fileLoader); } +u32 BlockDevice::CalculateCRC() { + u32 crc = crc32(0, Z_NULL, 0); + + u8 block[2048]; + for (u32 i = 0; i < GetNumBlocks(); ++i) { + if (!ReadBlock(i, block, true)) { + ERROR_LOG(HLE, "Failed to read block for CRC"); + return 0; + } + crc = crc32(crc, block, 2048); + } + + return crc; +} + FileBlockDevice::FileBlockDevice(FileLoader *fileLoader) : fileLoader_(fileLoader) { @@ -54,8 +69,9 @@ FileBlockDevice::FileBlockDevice(FileLoader *fileLoader) FileBlockDevice::~FileBlockDevice() { } -bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) { - if (fileLoader_->ReadAt((u64)blockNumber * (u64)GetBlockSize(), 1, 2048, outPtr) != 2048) { +bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { + FileLoader::Flags flags = uncached ? FileLoader::Flags::HINT_UNCACHED : FileLoader::Flags::NONE; + if (fileLoader_->ReadAt((u64)blockNumber * (u64)GetBlockSize(), 1, 2048, outPtr, flags) != 2048) { DEBUG_LOG(FILESYS, "Could not read 2048 bytes from block"); return false; } @@ -178,8 +194,9 @@ CISOFileBlockDevice::~CISOFileBlockDevice() delete [] zlibBuffer; } -bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) +bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { + FileLoader::Flags flags = uncached ? FileLoader::Flags::HINT_UNCACHED : FileLoader::Flags::NONE; if ((u32)blockNumber >= numBlocks) { memset(outPtr, 0, GetBlockSize()); @@ -200,7 +217,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) const int plain = idx & 0x80000000; if (plain) { - int readSize = (u32)fileLoader_->ReadAt(compressedReadPos + compressedOffset, 1, GetBlockSize(), outPtr); + int readSize = (u32)fileLoader_->ReadAt(compressedReadPos + compressedOffset, 1, GetBlockSize(), outPtr, flags); if (readSize < GetBlockSize()) memset(outPtr + readSize, 0, GetBlockSize() - readSize); } @@ -211,7 +228,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) } else { - const u32 readSize = (u32)fileLoader_->ReadAt(compressedReadPos, 1, compressedReadSize, readBuffer); + const u32 readSize = (u32)fileLoader_->ReadAt(compressedReadPos, 1, compressedReadSize, readBuffer, flags); z.zalloc = Z_NULL; z.zfree = Z_NULL; @@ -423,8 +440,9 @@ NPDRMDemoBlockDevice::~NPDRMDemoBlockDevice() int lzrc_decompress(void *out, int out_len, void *in, int in_len); -bool NPDRMDemoBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) +bool NPDRMDemoBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { + FileLoader::Flags flags = uncached ? FileLoader::Flags::HINT_UNCACHED : FileLoader::Flags::NONE; lock_guard guard(mutex_); CIPHER_KEY ckey; int block, lba, lzsize; @@ -453,7 +471,7 @@ bool NPDRMDemoBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) else readBuf = blockBuf; - readSize = fileLoader_->ReadAt(psarOffset+table[block].offset, 1, table[block].size, readBuf); + readSize = fileLoader_->ReadAt(psarOffset+table[block].offset, 1, table[block].size, readBuf, flags); if(readSize != (size_t)table[block].size){ if((u32)block==(numBlocks-1)) return true; diff --git a/Core/FileSystems/BlockDevices.h b/Core/FileSystems/BlockDevices.h index c11d15b24e..81f5465515 100644 --- a/Core/FileSystems/BlockDevices.h +++ b/Core/FileSystems/BlockDevices.h @@ -33,7 +33,7 @@ class BlockDevice { public: virtual ~BlockDevice() {} - virtual bool ReadBlock(int blockNumber, u8 *outPtr) = 0; + virtual bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) = 0; virtual bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) { for (int b = 0; b < count; ++b) { if (!ReadBlock(minBlock + b, outPtr)) { @@ -45,6 +45,8 @@ public: } int GetBlockSize() const { return 2048;} // forced, it cannot be changed by subclasses virtual u32 GetNumBlocks() = 0; + + u32 CalculateCRC(); }; @@ -53,7 +55,7 @@ class CISOFileBlockDevice : public BlockDevice public: CISOFileBlockDevice(FileLoader *fileLoader); ~CISOFileBlockDevice(); - bool ReadBlock(int blockNumber, u8 *outPtr) override; + bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override; bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override; u32 GetNumBlocks() override { return numBlocks; } @@ -76,7 +78,7 @@ class FileBlockDevice : public BlockDevice public: FileBlockDevice(FileLoader *fileLoader); ~FileBlockDevice(); - bool ReadBlock(int blockNumber, u8 *outPtr) override; + bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override; bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override; u32 GetNumBlocks() override {return (u32)(filesize_ / GetBlockSize());} @@ -102,7 +104,7 @@ public: NPDRMDemoBlockDevice(FileLoader *fileLoader); ~NPDRMDemoBlockDevice(); - bool ReadBlock(int blockNumber, u8 *outPtr) override; + bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override; u32 GetNumBlocks() override {return (u32)lbaSize;} private: diff --git a/Core/Loaders.h b/Core/Loaders.h index 2fe2e8cc46..a584092b8d 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -51,6 +51,12 @@ enum IdentifiedFileType { class FileLoader { public: + enum class Flags { + NONE, + // Not necessary to read from / store into cache. + HINT_UNCACHED, + }; + virtual ~FileLoader() {} virtual bool Exists() = 0; @@ -71,16 +77,20 @@ public: } virtual void Seek(s64 absolutePos) = 0; - virtual size_t Read(size_t bytes, size_t count, void *data) = 0; - virtual size_t Read(size_t bytes, void *data) { - return Read(1, bytes, data); + virtual size_t Read(size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) = 0; + virtual size_t Read(size_t bytes, void *data, Flags flags = Flags::NONE) { + return Read(1, bytes, data, flags); } - virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) = 0; - virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) { - return ReadAt(absolutePos, 1, bytes, data); + virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) = 0; + virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) { + return ReadAt(absolutePos, 1, bytes, data, flags); } }; +inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) { + return (u32)a & (u32)b; +} + FileLoader *ConstructFileLoader(const std::string &filename); // Resolve to the target binary, ISO, or other file (e.g. from a directory.) FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader); diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 300774c978..9b6012b07b 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -21,8 +21,10 @@ #include "Core/CoreTiming.h" #include "Core/Config.h" #include "Core/CwCheat.h" +#include "Core/Loaders.h" #include "Core/SaveState.h" #include "Core/System.h" +#include "Core/FileSystems/BlockDevices.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceKernelMemory.h" @@ -37,6 +39,7 @@ #include "base/stringutil.h" #include "base/buffer.h" #include "thread/thread.h" +#include "thread/threadutil.h" #include "file/zip_read.h" #include @@ -59,6 +62,8 @@ namespace Reporting static bool everUnsupported = false; // Support is cached here to avoid checking it on every single request. static bool currentSupported = false; + // Whether the most recent server request seemed successful. + static bool serverWorking = true; enum class RequestType { @@ -79,6 +84,68 @@ namespace Reporting static Payload payloadBuffer[PAYLOAD_BUFFER_SIZE]; static int payloadBufferPos = 0; + static recursive_mutex crcLock; + static condition_variable crcCond; + static std::string crcFilename; + static std::map crcResults; + + static int CalculateCRCThread() { + setCurrentThreadName("ReportCRC"); + + // TODO: Use the blockDevice from pspFileSystem? + FileLoader *fileLoader = ConstructFileLoader(crcFilename); + BlockDevice *blockDevice = constructBlockDevice(fileLoader); + + u32 crc = 0; + if (blockDevice) { + crc = blockDevice->CalculateCRC(); + } + + delete blockDevice; + delete fileLoader; + + lock_guard guard(crcLock); + crcResults[crcFilename] = crc; + crcCond.notify_one(); + + return 0; + } + + void QueueCRC() { + lock_guard guard(crcLock); + + const std::string &gamePath = PSP_CoreParameter().fileToStart; + auto it = crcResults.find(gamePath); + if (it != crcResults.end()) { + // Nothing to do, we've already calculated it. + // Note: we assume it stays static until the app is closed. + return; + } + + if (crcFilename == gamePath) { + // Already in process. + return; + } + + crcFilename = gamePath; + std::thread th(CalculateCRCThread); + th.detach(); + } + + u32 RetrieveCRC() { + const std::string &gamePath = PSP_CoreParameter().fileToStart; + QueueCRC(); + + lock_guard guard(crcLock); + auto it = crcResults.find(gamePath); + while (it == crcResults.end()) { + crcCond.wait(crcLock); + it = crcResults.find(gamePath); + } + + return it->second; + } + // Returns the full host (e.g. report.ppsspp.org:80.) std::string ServerHost() { @@ -162,9 +229,10 @@ namespace Reporting if (http.Resolve(serverHost, ServerPort())) { http.Connect(); - http.POST(uri, data, mimeType, output); + int result = http.POST(uri, data, mimeType, output); http.Disconnect(); - return true; + + return result >= 200 && result < 300; } else { return false; } @@ -324,7 +392,10 @@ namespace Reporting int Process(int pos) { + setCurrentThreadName("Report"); + Payload &payload = payloadBuffer[pos]; + Buffer output; MultipartFormDataEncoder postdata; AddSystemInfo(postdata); @@ -335,6 +406,7 @@ namespace Reporting switch (payload.type) { case RequestType::MESSAGE: + // TODO: Add CRC? postdata.Add("message", payload.string1); postdata.Add("value", payload.string2); // We tend to get corrupted data, this acts as a very primitive verification check. @@ -343,7 +415,9 @@ namespace Reporting payload.string2.clear(); postdata.Finish(); - SendReportRequest("/report/message", postdata.ToString(), postdata.GetMimeType()); + serverWorking = true; + if (!SendReportRequest("/report/message", postdata.ToString(), postdata.GetMimeType())) + serverWorking = false; break; case RequestType::COMPAT: @@ -353,12 +427,23 @@ namespace Reporting postdata.Add("graphics", StringFromFormat("%d", payload.int1)); postdata.Add("speed", StringFromFormat("%d", payload.int2)); postdata.Add("gameplay", StringFromFormat("%d", payload.int3)); + postdata.Add("crc", StringFromFormat("%08x", RetrieveCRC())); AddScreenshotData(postdata, payload.string2); payload.string1.clear(); payload.string2.clear(); postdata.Finish(); - SendReportRequest("/report/compat", postdata.ToString(), postdata.GetMimeType()); + serverWorking = true; + if (!SendReportRequest("/report/compat", postdata.ToString(), postdata.GetMimeType(), &output)) { + serverWorking = false; + } else { + char res = 0; + if (!output.empty()) { + output.Take(1, &res); + } + if (res == 0) + serverWorking = false; + } break; case RequestType::NONE: @@ -427,6 +512,20 @@ namespace Reporting g_Config.sReportHost = "default"; } + Status GetStatus() + { + if (!serverWorking) + return Status::FAILING; + + for (int pos = 0; pos < PAYLOAD_BUFFER_SIZE; ++pos) + { + if (payloadBuffer[pos].type != RequestType::NONE) + return Status::BUSY; + } + + return Status::WORKING; + } + int NextFreePos() { int start = payloadBufferPos % PAYLOAD_BUFFER_SIZE; @@ -484,7 +583,7 @@ namespace Reporting th.detach(); } - void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, std::string screenshotFilename) + void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, const std::string &screenshotFilename) { if (!IsEnabled()) return; @@ -503,5 +602,4 @@ namespace Reporting std::thread th(Process, pos); th.detach(); } - } diff --git a/Core/Reporting.h b/Core/Reporting.h index d8141cdcf9..c58ae2bae0 100644 --- a/Core/Reporting.h +++ b/Core/Reporting.h @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#pragma once + #include "Common/CommonTypes.h" #include "Common/Log.h" #include @@ -70,11 +72,20 @@ namespace Reporting void ReportMessageFormatted(const char *message, const char *formatted); // Report the compatibility of the current game / configuration. - void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, std::string screenshotFilename); + void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, const std::string &screenshotFilename); // Returns true if that identifier has not been logged yet. bool ShouldLogOnce(const char *identifier); + enum class Status { + WORKING, + BUSY, + FAILING, + }; + + // Whether server requests appear to be working. + Status GetStatus(); + // Return the currently active host (or blank if not active.) std::string ServerHost(); diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index a8e630face..3e3e5994af 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -223,6 +223,10 @@ void ReportScreen::CreateViews() { reportingNotice_ = nullptr; } +#ifdef MOBILE_DEVICE + leftColumnItems->Add(new TextView(rp->T("FeedbackIncludeCRC", "Note: Battery will be used to send a disc CRC"), new LinearLayoutParams(Margins(12, 5, 0, 5))))->SetEnabledPtr(&enableReporting_); +#endif + std::string path = GetSysDirectory(DIRECTORY_SCREENSHOT); if (!File::Exists(path)) { File::CreateDir(path); @@ -294,7 +298,7 @@ EventReturn ReportScreen::HandleBrowser(EventParams &e) { } ReportFinishScreen::ReportFinishScreen(const std::string &gamePath) - : UIScreenWithGameBackground(gamePath) { + : UIScreenWithGameBackground(gamePath), resultNotice_(nullptr), setStatus_(false) { } void ReportFinishScreen::CreateViews() { @@ -309,6 +313,7 @@ void ReportFinishScreen::CreateViews() { LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL); leftColumnItems->Add(new TextView(rp->T("FeedbackThanks", "Thanks for your feedback."), new LinearLayoutParams(Margins(12, 5, 0, 5)))); + resultNotice_ = leftColumnItems->Add(new TextView(rp->T("FeedbackDelayInfo", "Your data is being submitted in the background."), new LinearLayoutParams(Margins(12, 5, 0, 5)))); rightColumnItems->SetSpacing(0.0f); rightColumnItems->Add(new Choice(rp->T("View Feedback")))->OnClick.Handle(this, &ReportFinishScreen::HandleViewFeedback); @@ -324,6 +329,30 @@ void ReportFinishScreen::CreateViews() { rightColumn->Add(rightColumnItems); } +void ReportFinishScreen::update(InputState &input) { + I18NCategory *rp = GetI18NCategory("Reporting"); + + if (!setStatus_) { + Reporting::Status status = Reporting::GetStatus(); + switch (status) { + case Reporting::Status::WORKING: + resultNotice_->SetText(rp->T("FeedbackSubmitDone", "Your data has been submitted.")); + break; + + case Reporting::Status::FAILING: + resultNotice_->SetText(rp->T("FeedbackSubmitFail", "Could not submit data to server. Try updating PPSSPP.")); + break; + + case Reporting::Status::BUSY: + default: + // Can't update yet. + break; + } + } + + UIScreenWithGameBackground::update(input); +} + UI::EventReturn ReportFinishScreen::HandleViewFeedback(UI::EventParams &e) { const std::string url = "http://" + Reporting::ServerHost() + "/game/" + Reporting::CurrentGameID(); LaunchBrowser(url.c_str()); diff --git a/UI/ReportScreen.h b/UI/ReportScreen.h index 66725eec08..0808907f32 100644 --- a/UI/ReportScreen.h +++ b/UI/ReportScreen.h @@ -55,7 +55,11 @@ public: ReportFinishScreen(const std::string &gamePath); protected: + void update(InputState &input) override; void CreateViews() override; UI::EventReturn HandleViewFeedback(UI::EventParams &e); + + UI::TextView *resultNotice_; + bool setStatus_; };