Compare commits

...

8 Commits

Author SHA1 Message Date
TheLastRar
3b89020082 3rdparty/libchdr: Purge now unused patches 2024-12-18 16:23:49 -05:00
TheLastRar
a7b07eb53f ChdReader: Use core_file to implement precaching 2024-12-18 16:23:49 -05:00
TheLastRar
58d13dac34 FileSystem: Add ReadFileWithPartialProgress for multiple files 2024-12-18 16:23:49 -05:00
Ty Lamontagne
5a8921dd22 IOPBios: Defer to iopMemSafeReadBytes when HLEing writes 2024-12-18 16:15:07 -05:00
Ty Lamontagne
f964dfaa5e IOPBios: Defer to iopMemSafeWriteBytes when HLEing reads 2024-12-18 16:15:07 -05:00
PCSX2 Bot
17274eb397 [ci skip] Qt: Update Base Translation. 2024-12-17 20:54:52 -05:00
TheLastRar
2f0b00a7a1 ChdFileReader: Migrate libchdr patch into PCSX2
Added function didn't need to be in libchdr
2024-12-17 13:35:10 -05:00
Mrlinkwii
260380abec CI: disable builds on controller database update 2024-12-17 19:22:03 +01:00
9 changed files with 1726 additions and 1704 deletions

View File

@@ -22,7 +22,7 @@ jobs:
uses: peter-evans/create-pull-request@v7
with:
title: "PAD: Update to latest controller database"
commit-message: "PAD: Update to latest controller database."
commit-message: "[ci skip] PAD: Update to latest controller database."
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
body: "Weekly automatic update of SDL Controller DB."

View File

@@ -290,8 +290,7 @@ enum _chd_error
CHDERR_INVALID_STATE,
CHDERR_OPERATION_PENDING,
CHDERR_NO_ASYNC_OPERATION,
CHDERR_UNSUPPORTED_FORMAT,
CHDERR_CANCELLED,
CHDERR_UNSUPPORTED_FORMAT
};
typedef enum _chd_error chd_error;
@@ -383,7 +382,6 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent,
/* precache underlying file */
CHD_EXPORT chd_error chd_precache(chd_file *chd);
CHD_EXPORT chd_error chd_precache_progress(chd_file* chd, bool(*progress)(size_t pos, size_t total, void* param), void* param);
/* close a CHD file */
CHD_EXPORT void chd_close(chd_file *chd);
@@ -391,9 +389,6 @@ CHD_EXPORT void chd_close(chd_file *chd);
/* return the associated core_file */
CHD_EXPORT core_file *chd_core_file(chd_file *chd);
/* return the overall size of a CHD, and any of its parents */
CHD_EXPORT UINT64 chd_get_compressed_size(chd_file* chd);
/* return an error string for the given CHD error */
CHD_EXPORT const char *chd_error_string(chd_error err);
@@ -407,7 +402,6 @@ CHD_EXPORT const chd_header *chd_get_header(chd_file *chd);
CHD_EXPORT chd_error chd_read_header_core_file(core_file *file, chd_header *header);
CHD_EXPORT chd_error chd_read_header_file(FILE *file, chd_header *header);
CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header);
CHD_EXPORT bool chd_is_matching_parent(const chd_header* header, const chd_header* parent_header);

View File

@@ -1953,56 +1953,28 @@ cleanup:
CHD_EXPORT chd_error chd_precache(chd_file* chd)
{
return chd_precache_progress(chd, NULL, NULL);
}
INT64 count;
UINT64 size;
CHD_EXPORT chd_error chd_precache_progress(chd_file* chd, bool(*progress)(size_t pos, size_t total, void* param), void* param)
{
#define PRECACHE_CHUNK_SIZE 16 * 1024 * 1024
if (chd->file_cache == NULL)
{
const UINT64 size = core_fsize(chd->file);
if ((INT64)size <= 0)
return CHDERR_INVALID_DATA;
if (size > SIZE_MAX)
if (chd->file_cache == NULL)
{
size = core_fsize(chd->file);
if ((INT64)size <= 0)
return CHDERR_INVALID_DATA;
chd->file_cache = malloc(size);
if (chd->file_cache == NULL)
return CHDERR_OUT_OF_MEMORY;
chd->file_cache = malloc(size);
if (chd->file_cache == NULL)
return CHDERR_OUT_OF_MEMORY;
core_fseek(chd->file, 0, SEEK_SET);
UINT64 done = 0;
while (done < size)
core_fseek(chd->file, 0, SEEK_SET);
count = core_fread(chd->file, chd->file_cache, size);
if (count != size)
{
UINT64 req_count = size - done;
if (req_count > PRECACHE_CHUNK_SIZE)
req_count = PRECACHE_CHUNK_SIZE;
size_t count = core_fread(chd->file, chd->file_cache + (size_t)done, (size_t)req_count);
if (count != (size_t)req_count)
{
free(chd->file_cache);
chd->file_cache = NULL;
return CHDERR_READ_ERROR;
}
done += req_count;
if (progress != NULL)
{
if (!progress(done, size, param))
{
free(chd->file_cache);
chd->file_cache = NULL;
return CHDERR_CANCELLED;
}
}
free(chd->file_cache);
chd->file_cache = NULL;
return CHDERR_READ_ERROR;
}
}
}
return CHDERR_NONE;
return CHDERR_NONE;
}
/*-------------------------------------------------
@@ -2169,14 +2141,6 @@ CHD_EXPORT core_file *chd_core_file(chd_file *chd)
return chd->file;
}
CHD_EXPORT UINT64 chd_get_compressed_size(chd_file *chd)
{
UINT64 size = chd->file->fsize(chd->file);
if (chd->parent)
size += chd_get_compressed_size(chd->parent);
return size;
}
/*-------------------------------------------------
chd_error_string - return an error string for
the given CHD error
@@ -2281,27 +2245,6 @@ CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header)
return err;
}
CHD_EXPORT bool chd_is_matching_parent(const chd_header* header, const chd_header* parent_header)
{
/* check MD5 if it isn't empty */
if (memcmp(nullmd5, header->parentmd5, sizeof(header->parentmd5)) != 0 &&
memcmp(nullmd5, parent_header->md5, sizeof(parent_header->md5)) != 0 &&
memcmp(parent_header->md5, header->parentmd5, sizeof(header->parentmd5)) != 0)
{
return false;
}
/* check SHA1 if it isn't empty */
if (memcmp(nullsha1, header->parentsha1, sizeof(header->parentsha1)) != 0 &&
memcmp(nullsha1, parent_header->sha1, sizeof(parent_header->sha1)) != 0 &&
memcmp(parent_header->sha1, header->parentsha1, sizeof(header->parentsha1)) != 0)
{
return false;
}
return true;
}
/***************************************************************************
CORE DATA READ/WRITE
***************************************************************************/

View File

@@ -1230,6 +1230,14 @@ size_t FileSystem::ReadFileWithProgress(std::FILE* fp, void* dst, size_t length,
{
progress->SetProgressRange(100);
return FileSystem::ReadFileWithPartialProgress(fp, dst, length, progress, 0, 100, error, chunk_size);
}
size_t FileSystem::ReadFileWithPartialProgress(std::FILE* fp, void* dst, size_t length,
ProgressCallback* progress, int startPercent, int endPercent, Error* error, size_t chunk_size)
{
const int deltaPercent = endPercent - startPercent;
size_t done = 0;
while (done < length)
{
@@ -1243,7 +1251,7 @@ size_t FileSystem::ReadFileWithProgress(std::FILE* fp, void* dst, size_t length,
break;
}
progress->SetProgressValue((done * 100) / length);
progress->SetProgressValue(startPercent + (done * deltaPercent) / length);
done += read_size;
}

View File

@@ -144,6 +144,8 @@ namespace FileSystem
bool WriteStringToFile(const char* filename, const std::string_view sv);
size_t ReadFileWithProgress(std::FILE* fp, void* dst, size_t length, ProgressCallback* progress,
Error* error = nullptr, size_t chunk_size = 16 * 1024 * 1024);
size_t ReadFileWithPartialProgress(std::FILE* fp, void* dst, size_t length, ProgressCallback* progress,
int startPercent, int endPercent, Error* error = nullptr, size_t chunk_size = 16 * 1024 * 1024);
/// creates a directory in the local filesystem
/// if the directory already exists, the return value will be true.

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,7 @@ static std::vector<std::pair<std::string, chd_header>> s_chd_hash_cache; // <fil
static std::recursive_mutex s_chd_hash_cache_mutex;
// Provides an implementation of core_file which allows us to control if the underlying FILE handle is freed.
// Additionally, this class allows greater control and feedback while precaching CHD files.
// The lifetime of ChdCoreFileWrapper will be equal to that of the relevant chd_file,
// ChdCoreFileWrapper will also get destroyed if chd_open_core_file fails.
class ChdCoreFileWrapper
@@ -31,10 +32,15 @@ private:
core_file m_core;
std::FILE* m_file;
bool m_free_file = false;
ChdCoreFileWrapper* m_parent = nullptr;
std::unique_ptr<u8[]> m_file_cache;
s64 m_file_cache_size;
s64 m_file_cache_pos;
public:
ChdCoreFileWrapper(std::FILE* file)
ChdCoreFileWrapper(std::FILE* file, ChdCoreFileWrapper* parent)
: m_file{file}
, m_parent{parent}
{
m_core.argp = this;
m_core.fsize = FSize;
@@ -45,7 +51,7 @@ public:
~ChdCoreFileWrapper()
{
if (m_free_file)
if (m_free_file && m_file)
std::fclose(m_file);
}
@@ -64,15 +70,100 @@ public:
m_free_file = isOwner;
}
s64 GetPrecacheSize()
{
const s64 size = static_cast<size_t>(FileSystem::FSize64(m_file));
if (m_parent != nullptr)
return m_parent->GetPrecacheSize() + size;
else
return size;
}
bool Precache(ProgressCallback* progress, Error* error)
{
progress->SetProgressRange(100);
const s64 size = GetPrecacheSize();
return PrecacheInternal(progress, error, 0, size);
}
private:
bool PrecacheInternal(ProgressCallback* progress, Error* error, s64 startSize, s64 finalSize)
{
m_file_cache_size = FileSystem::FSize64(m_file);
if (m_file_cache_size <= 0)
{
Error::SetStringView(error, "Failed to determine file size.");
return false;
}
// Copy the current file position.
m_file_cache_pos = FileSystem::FTell64(m_file);
if (m_file_cache_pos <= 0)
{
Error::SetStringView(error, "Failed to determine file position.");
return false;
}
m_file_cache = std::make_unique_for_overwrite<u8[]>(m_file_cache_size);
if (FileSystem::FSeek64(m_file, 0, SEEK_SET) != 0 ||
FileSystem::ReadFileWithPartialProgress(
m_file, m_file_cache.get(), m_file_cache_size, progress,
(startSize * 100) / finalSize,
((startSize + m_file_cache_size) * 100) / finalSize,
error) != static_cast<size_t>(m_file_cache_size))
{
m_file_cache.reset();
// Precache failed, continue using file
// Restore file position incase it's used for subsequent reads
FileSystem::FSeek64(m_file, m_file_cache_pos, SEEK_SET);
Error::SetStringView(error, "Failed to read part of the file.");
return false;
}
startSize += m_file_cache_size;
if (m_parent)
{
if (!m_parent->PrecacheInternal(progress, error, startSize, finalSize))
{
// Precache failed, continue using file
// Restore file position incase it's used for subsequent reads
FileSystem::FSeek64(m_file, m_file_cache_pos, SEEK_SET);
m_file_cache.reset();
return false;
}
}
if (m_free_file)
std::fclose(m_file);
m_file = nullptr;
return true;
}
static u64 FSize(core_file* file)
{
return static_cast<u64>(FileSystem::FSize64(FromCoreFile(file)->m_file));
ChdCoreFileWrapper* fileWrapper = FromCoreFile(file);
if (fileWrapper->m_file_cache)
return fileWrapper->m_file_cache_size;
else
return static_cast<u64>(FileSystem::FSize64(fileWrapper->m_file));
}
static size_t FRead(void* buffer, size_t elmSize, size_t elmCount, core_file* file)
{
return std::fread(buffer, elmSize, elmCount, FromCoreFile(file)->m_file);
ChdCoreFileWrapper* fileWrapper = FromCoreFile(file);
if (fileWrapper->m_file_cache)
{
// While currently libchdr only uses an elmCount of 1, we can't guarantee that will always be the case.
elmCount = std::min<size_t>(elmCount, std::max<s64>(fileWrapper->m_file_cache_size - fileWrapper->m_file_cache_pos, 0) / elmSize);
const size_t size = elmSize * elmCount;
std::memcpy(buffer, &fileWrapper->m_file_cache[fileWrapper->m_file_cache_pos], size);
return elmCount;
}
else
return std::fread(buffer, elmSize, elmCount, fileWrapper->m_file);
}
static int FClose(core_file* file)
@@ -84,7 +175,28 @@ private:
static int FSeek(core_file* file, int64_t offset, int whence)
{
return FileSystem::FSeek64(FromCoreFile(file)->m_file, offset, whence);
ChdCoreFileWrapper* fileWrapper = FromCoreFile(file);
if (fileWrapper->m_file_cache)
{
switch (whence)
{
case SEEK_SET:
fileWrapper->m_file_cache_pos = offset;
break;
case SEEK_CUR:
fileWrapper->m_file_cache_pos += offset;
break;
case SEEK_END:
fileWrapper->m_file_cache_pos = fileWrapper->m_file_cache_size + offset;
break;
default:
return -1;
}
return 0;
}
else
return FileSystem::FSeek64(fileWrapper->m_file, offset, whence);
}
};
@@ -95,10 +207,34 @@ ChdFileReader::~ChdFileReader()
pxAssert(!ChdFile);
}
static bool IsHeaderParentCHD(const chd_header& header, const chd_header& parent_header)
{
static const u8 nullmd5[CHD_MD5_BYTES]{};
static const u8 nullsha1[CHD_SHA1_BYTES]{};
// Check MD5 if it isn't empty.
if (std::memcmp(nullmd5, header.parentmd5, CHD_MD5_BYTES) != 0 &&
std::memcmp(nullmd5, parent_header.md5, CHD_MD5_BYTES) != 0 &&
std::memcmp(parent_header.md5, header.parentmd5, CHD_MD5_BYTES) != 0)
{
return false;
}
// Check SHA1 if it isn't empty.
if (std::memcmp(nullsha1, header.parentsha1, CHD_SHA1_BYTES) != 0 &&
std::memcmp(nullsha1, parent_header.sha1, CHD_SHA1_BYTES) != 0 &&
std::memcmp(parent_header.sha1, header.parentsha1, CHD_SHA1_BYTES) != 0)
{
return false;
}
return true;
}
static chd_file* OpenCHD(const std::string& filename, FileSystem::ManagedCFilePtr fp, Error* error, u32 recursion_level)
{
chd_file* chd;
ChdCoreFileWrapper* core_wrapper = new ChdCoreFileWrapper(fp.get());
ChdCoreFileWrapper* core_wrapper = new ChdCoreFileWrapper(fp.get(), nullptr);
// libchdr will take ownership of core_wrapper, and will close/free it on failure.
chd_error err = chd_open_core_file(core_wrapper->GetCoreFile(), CHD_OPEN_READ, nullptr, &chd);
if (err == CHDERR_NONE)
@@ -144,14 +280,14 @@ static chd_file* OpenCHD(const std::string& filename, FileSystem::ManagedCFilePt
if (!StringUtil::compareNoCase(parent_dir, Path::GetDirectory(it->first)))
continue;
if (!chd_is_matching_parent(&header, &it->second))
if (!IsHeaderParentCHD(header, it->second))
continue;
// Re-check the header, it might have changed since we last opened.
chd_header parent_header;
auto parent_fp = FileSystem::OpenManagedSharedCFile(it->first.c_str(), "rb", FileSystem::FileShareMode::DenyWrite);
if (parent_fp && chd_read_header_file(parent_fp.get(), &parent_header) == CHDERR_NONE &&
chd_is_matching_parent(&header, &parent_header))
IsHeaderParentCHD(header, parent_header))
{
// Need to take a copy of the string, because the parent might add to the list and invalidate the iterator.
const std::string filename_to_open = it->first;
@@ -192,7 +328,7 @@ static chd_file* OpenCHD(const std::string& filename, FileSystem::ManagedCFilePt
else
s_chd_hash_cache.emplace_back(fd.FileName, parent_header);
if (!chd_is_matching_parent(&header, &parent_header))
if (!IsHeaderParentCHD(header, parent_header))
continue;
// Match! Open this one.
@@ -212,7 +348,7 @@ static chd_file* OpenCHD(const std::string& filename, FileSystem::ManagedCFilePt
}
// Our last core file wrapper got freed, so make a new one.
core_wrapper = new ChdCoreFileWrapper(fp.get());
core_wrapper = new ChdCoreFileWrapper(fp.get(), ChdCoreFileWrapper::FromCoreFile(chd_core_file(parent_chd)));
// Now try re-opening with the parent.
err = chd_open_core_file(core_wrapper->GetCoreFile(), CHD_OPEN_READ, parent_chd, &chd);
if (err != CHDERR_NONE)
@@ -266,28 +402,11 @@ bool ChdFileReader::Open2(std::string filename, Error* error)
bool ChdFileReader::Precache2(ProgressCallback* progress, Error* error)
{
if (!CheckAvailableMemoryForPrecaching(chd_get_compressed_size(ChdFile), error))
ChdCoreFileWrapper* fileWrapper = ChdCoreFileWrapper::FromCoreFile(chd_core_file(ChdFile));
if (!CheckAvailableMemoryForPrecaching(fileWrapper->GetPrecacheSize(), error))
return false;
progress->SetProgressRange(100);
const auto callback = [](size_t pos, size_t total, void* param) -> bool {
ProgressCallback* progress = static_cast<ProgressCallback*>(param);
const u32 percent = static_cast<u32>((pos * 100) / total);
progress->SetProgressValue(std::min<u32>(percent, 100));
return !progress->IsCancelled();
};
const chd_error cerror = chd_precache_progress(ChdFile, callback, progress);
if (cerror != CHDERR_NONE)
{
if (cerror != CHDERR_CANCELLED)
Error::SetStringView(error, "Failed to read part of the file.");
return false;
}
return true;
return fileWrapper->Precache(progress, error);
}
ThreadedFileReader::Chunk ChdFileReader::ChunkForOffset(u64 offset)

View File

@@ -7050,10 +7050,6 @@ TRANSLATE_NOOP("FullscreenUI", "Increases or decreases the virtual picture size
TRANSLATE_NOOP("FullscreenUI", "Crop");
TRANSLATE_NOOP("FullscreenUI", "Crops the image, while respecting aspect ratio.");
TRANSLATE_NOOP("FullscreenUI", "%dpx");
TRANSLATE_NOOP("FullscreenUI", "Enable Widescreen Patches");
TRANSLATE_NOOP("FullscreenUI", "Enables loading widescreen patches from pnach files.");
TRANSLATE_NOOP("FullscreenUI", "Enable No-Interlacing Patches");
TRANSLATE_NOOP("FullscreenUI", "Enables loading no-interlacing patches from pnach files.");
TRANSLATE_NOOP("FullscreenUI", "Bilinear Upscaling");
TRANSLATE_NOOP("FullscreenUI", "Smooths out the image when upscaling the console to the screen.");
TRANSLATE_NOOP("FullscreenUI", "Integer Upscaling");

View File

@@ -852,8 +852,16 @@ namespace R3000A
v0 = file->read(buf.get(), count);
for (s32 i = 0; i < (s32)v0; i++)
iopMemWrite8(data + i, buf[i]);
[[likely]]
if (v0 >= 0 && iopMemSafeWriteBytes(data, buf.get(), v0))
{
psxCpu->Clear(data, (v0 + 3) / 4);
}
else
{
for (s32 i = 0; i < static_cast<s32>(v0); i++)
iopMemWrite8(data + i, buf[i]);
}
pc = ra;
return 1;
@@ -899,8 +907,12 @@ namespace R3000A
{
auto buf = std::make_unique<char[]>(count);
for (u32 i = 0; i < count; i++)
buf[i] = iopMemRead8(data + i);
[[unlikely]]
if (!iopMemSafeReadBytes(data, buf.get(), count))
{
for (u32 i = 0; i < count; i++)
buf[i] = iopMemRead8(data + i);
}
v0 = file->write(buf.get(), count);