mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 01:29:41 +01:00
Merge pull request #8221 from unknownbrackets/disk-cache
Improve and enable URL disk cache by default
This commit is contained in:
commit
63769a2383
14 files changed
+312
-57
No files matched your search
@@ -923,6 +923,8 @@ add_library(native STATIC
|
||||
ext/native/file/fd_util.h
|
||||
ext/native/file/file_util.cpp
|
||||
ext/native/file/file_util.h
|
||||
ext/native/file/free.cpp
|
||||
ext/native/file/free.h
|
||||
ext/native/file/ini_file.cpp
|
||||
ext/native/file/ini_file.h
|
||||
ext/native/file/path.cpp
|
||||
|
||||
@@ -16,13 +16,19 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string.h>
|
||||
#include "file/file_util.h"
|
||||
#include "file/free.h"
|
||||
#include "util/text/utf8.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/FileLoaders/DiskCachingFileLoader.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
static const char *CACHEFILE_MAGIC = "ppssppDC";
|
||||
static const s64 SAFETY_FREE_DISK_SPACE = 768 * 1024 * 1024; // 768 MB
|
||||
// Aim to allow this many files cached at once.
|
||||
static const u32 CACHE_SPACE_FLEX = 4;
|
||||
|
||||
std::string DiskCachingFileLoaderCache::cacheDir_;
|
||||
|
||||
@@ -84,6 +90,17 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data)
|
||||
return readSize;
|
||||
}
|
||||
|
||||
std::vector<std::string> DiskCachingFileLoader::GetCachedPathsInUse() {
|
||||
// This is on the file loader so that it can manage the caches_.
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto it : caches_) {
|
||||
files.push_back(it.first);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
void DiskCachingFileLoader::InitCache() {
|
||||
std::string path = backend_->Path();
|
||||
auto &entry = caches_[path];
|
||||
@@ -117,6 +134,7 @@ void DiskCachingFileLoaderCache::InitCache(const std::string &path) {
|
||||
cacheSize_ = 0;
|
||||
indexCount_ = 0;
|
||||
oldestGeneration_ = 0;
|
||||
maxBlocks_ = MAX_BLOCKS_LOWER_BOUND;
|
||||
generation_ = 0;
|
||||
|
||||
const std::string cacheFilePath = MakeCacheFilePath(path);
|
||||
@@ -147,6 +165,10 @@ void DiskCachingFileLoaderCache::ShutdownCache() {
|
||||
size_t DiskCachingFileLoaderCache::ReadFromCache(s64 pos, size_t bytes, void *data) {
|
||||
lock_guard guard(lock_);
|
||||
|
||||
if (!f_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 cacheStartPos = pos / blockSize_;
|
||||
s64 cacheEndPos = (pos + bytes - 1) / blockSize_;
|
||||
size_t readSize = 0;
|
||||
@@ -164,7 +186,9 @@ size_t DiskCachingFileLoaderCache::ReadFromCache(s64 pos, size_t bytes, void *da
|
||||
}
|
||||
|
||||
size_t toRead = std::min(bytes - readSize, (size_t)blockSize_ - offset);
|
||||
ReadBlockData(p + readSize, info, offset, toRead);
|
||||
if (!ReadBlockData(p + readSize, info, offset, toRead)) {
|
||||
return readSize;
|
||||
}
|
||||
readSize += toRead;
|
||||
|
||||
// Don't need an offset after the first read.
|
||||
@@ -176,6 +200,11 @@ size_t DiskCachingFileLoaderCache::ReadFromCache(s64 pos, size_t bytes, void *da
|
||||
size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data) {
|
||||
lock_guard guard(lock_);
|
||||
|
||||
if (!f_) {
|
||||
// Just to keep things working.
|
||||
return backend->ReadAt(pos, bytes, data);
|
||||
}
|
||||
|
||||
s64 cacheStartPos = pos / blockSize_;
|
||||
s64 cacheEndPos = (pos + bytes - 1) / blockSize_;
|
||||
size_t readSize = 0;
|
||||
@@ -248,7 +277,7 @@ size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, s
|
||||
}
|
||||
|
||||
bool DiskCachingFileLoaderCache::MakeCacheSpaceFor(size_t blocks) {
|
||||
size_t goal = MAX_BLOCKS_CACHED - blocks;
|
||||
size_t goal = (size_t)maxBlocks_ - blocks;
|
||||
|
||||
while (cacheSize_ > goal) {
|
||||
u16 minGeneration = generation_;
|
||||
@@ -323,12 +352,7 @@ u32 DiskCachingFileLoaderCache::AllocateBlock(u32 indexPos) {
|
||||
return INVALID_BLOCK;
|
||||
}
|
||||
|
||||
std::string DiskCachingFileLoaderCache::MakeCacheFilePath(const std::string &path) {
|
||||
std::string dir = cacheDir_;
|
||||
if (dir.empty()) {
|
||||
dir = GetSysDirectory(DIRECTORY_CACHE);
|
||||
}
|
||||
|
||||
std::string DiskCachingFileLoaderCache::MakeCacheFilename(const std::string &path) {
|
||||
static const char *const invalidChars = "?*:/\\^|<>\"'";
|
||||
std::string filename = path;
|
||||
for (size_t i = 0; i < filename.size(); ++i) {
|
||||
@@ -338,11 +362,20 @@ std::string DiskCachingFileLoaderCache::MakeCacheFilePath(const std::string &pat
|
||||
}
|
||||
}
|
||||
|
||||
return filename + ".ppdc";
|
||||
}
|
||||
|
||||
std::string DiskCachingFileLoaderCache::MakeCacheFilePath(const std::string &path) {
|
||||
std::string dir = cacheDir_;
|
||||
if (dir.empty()) {
|
||||
dir = GetSysDirectory(DIRECTORY_CACHE);
|
||||
}
|
||||
|
||||
if (!File::Exists(dir)) {
|
||||
File::CreateFullPath(dir);
|
||||
}
|
||||
|
||||
return dir + "/" + filename;
|
||||
return dir + "/" + MakeCacheFilename(path);
|
||||
}
|
||||
|
||||
s64 DiskCachingFileLoaderCache::GetBlockOffset(u32 block) {
|
||||
@@ -352,49 +385,84 @@ s64 DiskCachingFileLoaderCache::GetBlockOffset(u32 block) {
|
||||
return blockOffset + (s64)block * (s64)blockSize_;
|
||||
}
|
||||
|
||||
void DiskCachingFileLoaderCache::ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size) {
|
||||
bool DiskCachingFileLoaderCache::ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size) {
|
||||
if (!f_) {
|
||||
return false;
|
||||
}
|
||||
s64 blockOffset = GetBlockOffset(info.block);
|
||||
|
||||
bool failed = false;
|
||||
#ifdef ANDROID
|
||||
if (lseek64(fd_, blockOffset, SEEK_SET) != blockOffset) {
|
||||
ERROR_LOG(LOADER, "Unable to read disk cache data entry.");
|
||||
failed = true;
|
||||
} else if (read(fd_, dest + offset, size) != (ssize_t)size) {
|
||||
ERROR_LOG(LOADER, "Unable to read disk cache data entry.");
|
||||
failed = true;
|
||||
}
|
||||
#else
|
||||
if (fseeko(f_, blockOffset, SEEK_SET) != 0) {
|
||||
ERROR_LOG(LOADER, "Unable to read disk cache data entry.");
|
||||
failed = true;
|
||||
} else if (fread(dest + offset, size, 1, f_) != 1) {
|
||||
ERROR_LOG(LOADER, "Unable to read disk cache data entry.");
|
||||
failed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (failed) {
|
||||
ERROR_LOG(LOADER, "Unable to read disk cache data entry.");
|
||||
fclose(f_);
|
||||
f_ = nullptr;
|
||||
fd_ = 0;
|
||||
}
|
||||
return !failed;
|
||||
}
|
||||
|
||||
void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, u8 *src) {
|
||||
if (!f_) {
|
||||
return;
|
||||
}
|
||||
s64 blockOffset = GetBlockOffset(info.block);
|
||||
|
||||
bool failed = false;
|
||||
#ifdef ANDROID
|
||||
if (lseek64(fd_, blockOffset, SEEK_SET) != blockOffset) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache data entry.");
|
||||
failed = true;
|
||||
} else if (write(fd_, src, blockSize_) != (ssize_t)blockSize_) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache data entry.");
|
||||
failed = true;
|
||||
}
|
||||
#else
|
||||
if (fseeko(f_, blockOffset, SEEK_SET) != 0) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache data entry.");
|
||||
failed = true;
|
||||
} else if (fwrite(src, blockSize_, 1, f_) != 1) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache data entry.");
|
||||
failed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (failed) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache data entry.");
|
||||
fclose(f_);
|
||||
f_ = nullptr;
|
||||
fd_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DiskCachingFileLoaderCache::WriteIndexData(u32 indexPos, BlockInfo &info) {
|
||||
if (!f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 offset = (u32)sizeof(FileHeader) + indexPos * (u32)sizeof(BlockInfo);
|
||||
|
||||
bool failed = false;
|
||||
if (fseek(f_, offset, SEEK_SET) != 0) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache index entry.");
|
||||
failed = true;
|
||||
} else if (fwrite(&info, sizeof(BlockInfo), 1, f_) != 1) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
ERROR_LOG(LOADER, "Unable to write disk cache index entry.");
|
||||
fclose(f_);
|
||||
f_ = nullptr;
|
||||
fd_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,6 +482,9 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const std::string &path) {
|
||||
valid = false;
|
||||
} else if (header.filesize != filesize_) {
|
||||
valid = false;
|
||||
} else if (header.maxBlocks < MAX_BLOCKS_LOWER_BOUND || header.maxBlocks > MAX_BLOCKS_UPPER_BOUND) {
|
||||
// This means it's not in our safety bounds, reject.
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// If it's valid, retain the file pointer.
|
||||
@@ -427,6 +498,7 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const std::string &path) {
|
||||
|
||||
// Now let's load the index.
|
||||
blockSize_ = header.blockSize;
|
||||
maxBlocks_ = header.maxBlocks;
|
||||
LoadCacheIndex();
|
||||
} else {
|
||||
ERROR_LOG(LOADER, "Disk cache file header did not match, recreating cache file");
|
||||
@@ -446,8 +518,8 @@ void DiskCachingFileLoaderCache::LoadCacheIndex() {
|
||||
|
||||
indexCount_ = (filesize_ + blockSize_ - 1) / blockSize_;
|
||||
index_.resize(indexCount_);
|
||||
blockIndexLookup_.resize(MAX_BLOCKS_CACHED);
|
||||
memset(&blockIndexLookup_[0], INVALID_INDEX, MAX_BLOCKS_CACHED * sizeof(blockIndexLookup_[0]));
|
||||
blockIndexLookup_.resize(maxBlocks_);
|
||||
memset(&blockIndexLookup_[0], INVALID_INDEX, maxBlocks_ * sizeof(blockIndexLookup_[0]));
|
||||
|
||||
if (fread(&index_[0], sizeof(BlockInfo), indexCount_, f_) != indexCount_) {
|
||||
fclose(f_);
|
||||
@@ -462,7 +534,7 @@ void DiskCachingFileLoaderCache::LoadCacheIndex() {
|
||||
cacheSize_ = 0;
|
||||
|
||||
for (size_t i = 0; i < index_.size(); ++i) {
|
||||
if (index_[i].block > MAX_BLOCKS_CACHED) {
|
||||
if (index_[i].block > maxBlocks_) {
|
||||
index_[i].block = INVALID_BLOCK;
|
||||
}
|
||||
if (index_[i].block == INVALID_BLOCK) {
|
||||
@@ -482,6 +554,18 @@ void DiskCachingFileLoaderCache::LoadCacheIndex() {
|
||||
}
|
||||
|
||||
void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) {
|
||||
maxBlocks_ = DetermineMaxBlocks();
|
||||
if (maxBlocks_ < MAX_BLOCKS_LOWER_BOUND) {
|
||||
GarbageCollectCacheFiles(MAX_BLOCKS_LOWER_BOUND * DEFAULT_BLOCK_SIZE);
|
||||
maxBlocks_ = DetermineMaxBlocks();
|
||||
}
|
||||
if (maxBlocks_ < MAX_BLOCKS_LOWER_BOUND) {
|
||||
// There's not enough free space to cache, disable.
|
||||
f_ = nullptr;
|
||||
ERROR_LOG(LOADER, "Not enough free space; disabling disk cache");
|
||||
return;
|
||||
}
|
||||
|
||||
f_ = File::OpenCFile(path, "wb+");
|
||||
if (!f_) {
|
||||
ERROR_LOG(LOADER, "Could not create disk cache file");
|
||||
@@ -499,6 +583,7 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) {
|
||||
header.version = CACHE_VERSION;
|
||||
header.blockSize = blockSize_;
|
||||
header.filesize = filesize_;
|
||||
header.maxBlocks = maxBlocks_;
|
||||
|
||||
if (fwrite(&header, sizeof(header), 1, f_) != 1) {
|
||||
fclose(f_);
|
||||
@@ -509,8 +594,8 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) {
|
||||
|
||||
indexCount_ = (filesize_ + blockSize_ - 1) / blockSize_;
|
||||
index_.resize(indexCount_);
|
||||
blockIndexLookup_.resize(MAX_BLOCKS_CACHED);
|
||||
memset(&blockIndexLookup_[0], INVALID_INDEX, MAX_BLOCKS_CACHED * sizeof(blockIndexLookup_[0]));
|
||||
blockIndexLookup_.resize(maxBlocks_);
|
||||
memset(&blockIndexLookup_[0], INVALID_INDEX, maxBlocks_ * sizeof(blockIndexLookup_[0]));
|
||||
|
||||
if (fwrite(&index_[0], sizeof(BlockInfo), indexCount_, f_) != indexCount_) {
|
||||
fclose(f_);
|
||||
@@ -519,3 +604,101 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const std::string &path) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
u64 DiskCachingFileLoaderCache::FreeDiskSpace() {
|
||||
std::string dir = cacheDir_;
|
||||
if (dir.empty()) {
|
||||
dir = GetSysDirectory(DIRECTORY_CACHE);
|
||||
}
|
||||
|
||||
uint64_t result = 0;
|
||||
if (free_disk_space(dir, result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// We can't know for sure how much is free, so we have to assume none.
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 DiskCachingFileLoaderCache::DetermineMaxBlocks() {
|
||||
const s64 freeBytes = FreeDiskSpace();
|
||||
// We want to leave them some room for other stuff.
|
||||
const u64 availBytes = std::max(0LL, freeBytes - SAFETY_FREE_DISK_SPACE);
|
||||
const u64 freeBlocks = availBytes / (u64)DEFAULT_BLOCK_SIZE;
|
||||
|
||||
const u32 alreadyCachedCount = CountCachedFiles();
|
||||
// This is how many more files of free space we will aim for.
|
||||
const u32 flex = CACHE_SPACE_FLEX > alreadyCachedCount ? CACHE_SPACE_FLEX - alreadyCachedCount : 1;
|
||||
|
||||
const u64 freeBlocksWithFlex = freeBlocks / flex;
|
||||
if (freeBlocksWithFlex > MAX_BLOCKS_LOWER_BOUND) {
|
||||
if (freeBlocksWithFlex > MAX_BLOCKS_UPPER_BOUND) {
|
||||
return MAX_BLOCKS_UPPER_BOUND;
|
||||
}
|
||||
// This might be smaller than what's free, but if they try to launch a second game,
|
||||
// they'll be happier when it can be cached too.
|
||||
return freeBlocksWithFlex;
|
||||
}
|
||||
|
||||
// Might be lower than LOWER_BOUND, but that's okay. That means not enough space.
|
||||
// We abandon the idea of flex since there's not enough space free anyway.
|
||||
return freeBlocks;
|
||||
}
|
||||
|
||||
u32 DiskCachingFileLoaderCache::CountCachedFiles() {
|
||||
std::string dir = cacheDir_;
|
||||
if (dir.empty()) {
|
||||
dir = GetSysDirectory(DIRECTORY_CACHE);
|
||||
}
|
||||
|
||||
std::vector<FileInfo> files;
|
||||
return (u32)getFilesInDir(dir.c_str(), &files, "ppdc:");
|
||||
}
|
||||
|
||||
void DiskCachingFileLoaderCache::GarbageCollectCacheFiles(u64 goalBytes) {
|
||||
// We attempt to free up at least enough files from the cache to get goalBytes more space.
|
||||
const std::vector<std::string> usedPaths = DiskCachingFileLoader::GetCachedPathsInUse();
|
||||
std::set<std::string> used;
|
||||
for (std::string path : usedPaths) {
|
||||
used.insert(MakeCacheFilename(path));
|
||||
}
|
||||
|
||||
std::string dir = cacheDir_;
|
||||
if (dir.empty()) {
|
||||
dir = GetSysDirectory(DIRECTORY_CACHE);
|
||||
}
|
||||
|
||||
std::vector<FileInfo> files;
|
||||
getFilesInDir(dir.c_str(), &files, "ppdc:");
|
||||
|
||||
u64 remaining = goalBytes;
|
||||
// TODO: Could order by LRU or etc.
|
||||
for (FileInfo file : files) {
|
||||
if (file.isDirectory) {
|
||||
continue;
|
||||
}
|
||||
if (used.find(file.name) != used.end()) {
|
||||
// In use, must leave alone.
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const std::wstring w32path = ConvertUTF8ToWString(file.fullName);
|
||||
bool success = DeleteFileW(w32path.c_str()) != 0;
|
||||
#else
|
||||
bool success = unlink(file.fullName.c_str()) == 0;
|
||||
#endif
|
||||
|
||||
if (success) {
|
||||
if (file.size > remaining) {
|
||||
// We're done, huzzah.
|
||||
break;
|
||||
}
|
||||
|
||||
// A little bit more.
|
||||
remaining -= file.size;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we've done all we can.
|
||||
}
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
}
|
||||
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override;
|
||||
|
||||
static std::vector<std::string> GetCachedPathsInUse();
|
||||
|
||||
private:
|
||||
void InitCache();
|
||||
void ShutdownCache();
|
||||
@@ -94,34 +96,41 @@ private:
|
||||
u32 AllocateBlock(u32 indexPos);
|
||||
|
||||
struct BlockInfo;
|
||||
void ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size);
|
||||
bool ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size);
|
||||
void WriteBlockData(BlockInfo &info, u8 *src);
|
||||
void WriteIndexData(u32 indexPos, BlockInfo &info);
|
||||
s64 GetBlockOffset(u32 block);
|
||||
|
||||
std::string MakeCacheFilePath(const std::string &path);
|
||||
std::string MakeCacheFilename(const std::string &path);
|
||||
bool LoadCacheFile(const std::string &path);
|
||||
void LoadCacheIndex();
|
||||
void CreateCacheFile(const std::string &path);
|
||||
|
||||
u64 FreeDiskSpace();
|
||||
u32 DetermineMaxBlocks();
|
||||
u32 CountCachedFiles();
|
||||
void GarbageCollectCacheFiles(u64 goalBytes);
|
||||
|
||||
// File format:
|
||||
// 64 magic
|
||||
// 32 version
|
||||
// 32 blockSize
|
||||
// 64 filesize
|
||||
// 32 maxBlocks
|
||||
// index[filesize / blockSize] <-- ~500 KB for 4GB
|
||||
// 32 (fileoffset - headersize) / blockSize -> -1=not present
|
||||
// 16 generation?
|
||||
// 16 hits?
|
||||
// blocks[MAX_BLOCKS]
|
||||
// blocks[up to maxBlocks]
|
||||
// 8 * blockSize
|
||||
|
||||
enum {
|
||||
CACHE_VERSION = 1,
|
||||
CACHE_VERSION = 2,
|
||||
DEFAULT_BLOCK_SIZE = 65536,
|
||||
MAX_BLOCKS_PER_READ = 16,
|
||||
// TODO: Dynamic.
|
||||
MAX_BLOCKS_CACHED = 4096, // 256 MB
|
||||
MAX_BLOCKS_LOWER_BOUND = 256, // 16 MB
|
||||
MAX_BLOCKS_UPPER_BOUND = 8192, // 512 MB
|
||||
INVALID_BLOCK = 0xFFFFFFFF,
|
||||
INVALID_INDEX = 0xFFFFFFFF,
|
||||
};
|
||||
@@ -131,6 +140,7 @@ private:
|
||||
u32 blockSize_;
|
||||
u16 generation_;
|
||||
u16 oldestGeneration_;
|
||||
u32 maxBlocks_;
|
||||
size_t cacheSize_;
|
||||
size_t indexCount_;
|
||||
recursive_mutex lock_;
|
||||
@@ -140,6 +150,7 @@ private:
|
||||
u32_le version;
|
||||
u32_le blockSize;
|
||||
s64_le filesize;
|
||||
u32_le maxBlocks;
|
||||
};
|
||||
|
||||
struct BlockInfo {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <limits>
|
||||
#include "file/free.h"
|
||||
#include "file/zip_read.h"
|
||||
#include "i18n/i18n.h"
|
||||
#include "util/text/utf8.h"
|
||||
@@ -798,35 +799,18 @@ std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
|
||||
}
|
||||
|
||||
u64 DirectoryFileSystem::FreeSpace(const std::string &path) {
|
||||
#ifdef _WIN32
|
||||
const std::wstring w32path = ConvertUTF8ToWString(GetLocalPath(path));
|
||||
ULARGE_INTEGER free;
|
||||
if (GetDiskFreeSpaceExW(w32path.c_str(), &free, nullptr, nullptr))
|
||||
return free.QuadPart;
|
||||
#elif defined(__SYMBIAN32__)
|
||||
QSystemStorageInfo storageInfo;
|
||||
return (u64)storageInfo.availableDiskSpace("E");
|
||||
#else
|
||||
std::string localPath = GetLocalPath(path);
|
||||
struct statvfs diskstat;
|
||||
int res = statvfs(localPath.c_str(), &diskstat);
|
||||
uint64_t result = 0;
|
||||
if (free_disk_space(GetLocalPath(path), result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#if HOST_IS_CASE_SENSITIVE
|
||||
std::string fixedCase = path;
|
||||
if (res != 0 && FixPathCase(basePath, fixedCase, FPC_FILE_MUST_EXIST)) {
|
||||
if (FixPathCase(basePath, fixedCase, FPC_FILE_MUST_EXIST)) {
|
||||
// May have failed due to case sensitivity, try again.
|
||||
localPath = GetLocalPath(fixedCase);
|
||||
res = statvfs(localPath.c_str(), &diskstat);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (res == 0) {
|
||||
#ifndef ANDROID
|
||||
if (diskstat.f_flag & ST_RDONLY) {
|
||||
return 0;
|
||||
if (free_disk_space(GetLocalPath(fixedCase), result)) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return (u64)diskstat.f_bavail * (u64)diskstat.f_frsize;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ void SasReverb::ProcessReverb(int16_t *output, const int16_t *input, size_t inpu
|
||||
// This runs at 22khz.
|
||||
// Very unoptimized, straight from the description. Can probably be reformulated into something way more efficient.
|
||||
// Or we could actually template the whole thing with the parameters as template arguments, as the presets are fixed.
|
||||
for (int i = 0; i < inputSize; i++) {
|
||||
for (size_t i = 0; i < inputSize; i++) {
|
||||
// Dividing by two here is an incorrect hack. Some multiplication factor is needed to prevent the reverb from getting too loud, though.
|
||||
int16_t LeftInput = input[i * 2] >> 1;
|
||||
int16_t RightInput = input[i * 2 + 1] >> 1;
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
|
||||
FileLoader *ConstructFileLoader(const std::string &filename) {
|
||||
if (filename.find("http://") == 0 || filename.find("https://") == 0)
|
||||
return new CachingFileLoader(new RetryingFileLoader(new HTTPFileLoader(filename)));
|
||||
return new CachingFileLoader(new DiskCachingFileLoader(new RetryingFileLoader(new HTTPFileLoader(filename))));
|
||||
return new LocalFileLoader(filename);
|
||||
}
|
||||
|
||||
|
||||
@@ -457,6 +457,9 @@ ReplaceBlendType ReplaceBlendWithShader(bool allowShaderBlend, GEBufferFormat bu
|
||||
return REPLACE_BLEND_STANDARD;
|
||||
}
|
||||
}
|
||||
|
||||
// Should never get here.
|
||||
return REPLACE_BLEND_STANDARD;
|
||||
}
|
||||
|
||||
LogicOpReplaceType ReplaceLogicOpType() {
|
||||
|
||||
@@ -41,6 +41,7 @@ LOCAL_SRC_FILES :=\
|
||||
file/fd_util.cpp \
|
||||
file/chunk_file.cpp \
|
||||
file/file_util.cpp \
|
||||
file/free.cpp \
|
||||
file/path.cpp \
|
||||
file/ini_file.cpp \
|
||||
file/zip_read.cpp \
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
set(SRCS
|
||||
chunk_file.cpp
|
||||
zip_read.cpp
|
||||
file_util.cpp)
|
||||
file_util.cpp
|
||||
free.cpp)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const
|
||||
(virtualName[2] == '\0')))
|
||||
continue;
|
||||
|
||||
// Remove dotfiles (should be made optional?)
|
||||
// Remove dotfiles (optional with flag.)
|
||||
if (!(flags & GETFILES_GETHIDDEN) && virtualName[0] == '.')
|
||||
continue;
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <sys/stat.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(ANDROID)
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
#define statvfs statfs
|
||||
#elif defined(__SYMBIAN32__)
|
||||
#include <mw/QSystemStorageInfo>
|
||||
QTM_USE_NAMESPACE
|
||||
#else
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
bool free_disk_space(const std::string &dir, uint64_t &space) {
|
||||
#ifdef _WIN32
|
||||
const std::wstring w32path = ConvertUTF8ToWString(dir);
|
||||
ULARGE_INTEGER free;
|
||||
if (GetDiskFreeSpaceExW(w32path.c_str(), &free, nullptr, nullptr)) {
|
||||
space = free.QuadPart;
|
||||
return true;
|
||||
}
|
||||
#elif defined(__SYMBIAN32__)
|
||||
QSystemStorageInfo storageInfo;
|
||||
space = (uint64_t)storageInfo.availableDiskSpace("E");
|
||||
return true;
|
||||
#else
|
||||
struct statvfs diskstat;
|
||||
int res = statvfs(dir.c_str(), &diskstat);
|
||||
|
||||
if (res == 0) {
|
||||
#ifndef ANDROID
|
||||
if (diskstat.f_flag & ST_RDONLY) {
|
||||
space = 0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
space = (uint64_t)diskstat.f_bavail * (uint64_t)diskstat.f_frsize;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// We can't know how much is free.
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "base/basictypes.h"
|
||||
|
||||
bool free_disk_space(const std::string &dir, uint64_t &space);
|
||||
@@ -226,6 +226,7 @@
|
||||
<ClInclude Include="file\ini_file.h" />
|
||||
<ClInclude Include="file\vfs.h" />
|
||||
<ClInclude Include="file\zip_read.h" />
|
||||
<ClInclude Include="file\free.h" />
|
||||
<ClInclude Include="gfx\gl_common.h" />
|
||||
<ClInclude Include="gfx\gl_debug_log.h" />
|
||||
<ClInclude Include="gfx\gl_lost_manager.h" />
|
||||
@@ -680,6 +681,7 @@
|
||||
<ClCompile Include="file\path.cpp" />
|
||||
<ClCompile Include="file\ini_file.cpp" />
|
||||
<ClCompile Include="file\zip_read.cpp" />
|
||||
<ClCompile Include="file\free.cpp" />
|
||||
<ClCompile Include="gfx\gl_debug_log.cpp" />
|
||||
<ClCompile Include="gfx\gl_lost_manager.cpp" />
|
||||
<ClCompile Include="gfx\texture_atlas.cpp" />
|
||||
|
||||
@@ -302,6 +302,9 @@
|
||||
<ClInclude Include="input\keycodes.h">
|
||||
<Filter>input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="file\free.h">
|
||||
<Filter>file</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="gfx\gl_debug_log.cpp">
|
||||
@@ -736,6 +739,9 @@
|
||||
<ClCompile Include="base\QtMain.cpp">
|
||||
<Filter>base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="file\free.cpp">
|
||||
<Filter>file</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="gfx">
|
||||
|
||||
Reference in new issue
Block a user