From e87f68b2b58f86c0a0c456e2ecd337f55bfa3fa7 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Tue, 14 Feb 2023 04:34:48 +0000 Subject: [PATCH] Open fewer files concurrently at load time For `MultiFileLoader` and `LoadMultipleCl2Sheet`, we now open one file at a time. This can help on platforms that limit the number of concurrently open files, such as the PS2. --- Source/engine/assets.hpp | 17 ++++++++++++++++- Source/engine/load_cl2.hpp | 25 ++++++++++++++++++------- Source/engine/load_file.hpp | 23 +++++++++++++++++------ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/Source/engine/assets.hpp b/Source/engine/assets.hpp index 2b9fd89fd..66092cd7e 100644 --- a/Source/engine/assets.hpp +++ b/Source/engine/assets.hpp @@ -212,12 +212,27 @@ struct AssetHandle { }; #endif +[[noreturn]] inline void FailedToOpenFileError(const char *path, const char *error) +{ + app_fatal(StrCat("Failed to open file:\n", path, "\n\n", error)); +} + +inline bool ValidatAssetRef(const char *path, const AssetRef &ref) +{ + if (ref.ok()) + return true; + if (!HeadlessMode) { + FailedToOpenFileError(path, ref.error()); + } + return false; +} + inline bool ValidateHandle(const char *path, const AssetHandle &handle) { if (handle.ok()) return true; if (!HeadlessMode) { - app_fatal(StrCat("Failed to open file:\n", path, "\n\n", handle.error())); + FailedToOpenFileError(path, handle.error()); } return false; } diff --git a/Source/engine/load_cl2.hpp b/Source/engine/load_cl2.hpp index 9e0a836f6..3e280f79a 100644 --- a/Source/engine/load_cl2.hpp +++ b/Source/engine/load_cl2.hpp @@ -1,12 +1,15 @@ #pragma once +#include #include +#include #include #include "appfat.h" #include "engine/clx_sprite.hpp" #include "engine/load_file.hpp" +#include "mpq/mpq_common.hpp" #include "utils/cl2_to_clx.hpp" #include "utils/endian.hpp" #include "utils/pointer_value_union.hpp" @@ -26,17 +29,23 @@ OwnedClxSpriteListOrSheet LoadCl2ListOrSheet(const char *pszName, PointerOrValue template OwnedClxSpriteSheet LoadMultipleCl2Sheet(tl::function_ref filenames, size_t count, uint16_t width) { - StaticVector files; + StaticVector, MaxCount> paths; + StaticVector files; StaticVector fileSizes; const size_t sheetHeaderSize = 4 * count; size_t totalSize = sheetHeaderSize; for (size_t i = 0; i < count; ++i) { - const char *filename = filenames(i); - size_t size; - files.emplace_back(OpenAsset(filename, size)); + { + const char *path = filenames(i); + paths.emplace_back(); + memcpy(paths.back().data(), path, strlen(path) + 1); + } + const char *path = paths.back().data(); + files.emplace_back(FindAsset(path)); if (!files.back().ok()) { - app_fatal(StrCat("Failed to open file:\n", filename, "\n\n", files.back().error())); + FailedToOpenFileError(path, files.back().error()); } + const size_t size = files.back().size(); fileSizes.emplace_back(size); totalSize += size; } @@ -47,8 +56,10 @@ OwnedClxSpriteSheet LoadMultipleCl2Sheet(tl::function_ref size_t accumulatedSize = sheetHeaderSize; for (size_t i = 0; i < count; ++i) { const size_t size = fileSizes[i]; - if (!files[i].read(&data[accumulatedSize], size)) - app_fatal(StrCat("Read failed:\n", files[i].error())); + AssetHandle handle = OpenAsset(std::move(files[i])); + if (!handle.ok() || !handle.read(&data[accumulatedSize], size)) { + FailedToOpenFileError(paths[i].data(), handle.error()); + } WriteLE32(&data[i * 4], accumulatedSize); #ifndef UNPACKED_MPQS [[maybe_unused]] const uint16_t numLists = Cl2ToClx(&data[accumulatedSize], size, frameWidth); diff --git a/Source/engine/load_file.hpp b/Source/engine/load_file.hpp index dcc7b54ca..9168afe53 100644 --- a/Source/engine/load_file.hpp +++ b/Source/engine/load_file.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,6 +11,7 @@ #include "appfat.h" #include "diablo.h" #include "engine/assets.hpp" +#include "mpq/mpq_common.hpp" #include "utils/static_vector.hpp" #include "utils/stdcompat/cstddef.hpp" #include "utils/str_cat.hpp" @@ -99,18 +101,24 @@ struct MultiFileLoader { [[nodiscard]] std::unique_ptr operator()(size_t numFiles, PathFn &&pathFn, uint32_t *outOffsets, FilterFn filterFn = DefaultFilterFn {}) { - StaticVector files; + StaticVector, MaxFiles> paths; + StaticVector files; StaticVector sizes; size_t totalSize = 0; for (size_t i = 0, j = 0; i < numFiles; ++i) { if (!filterFn(i)) continue; - size_t size; - const char *path = pathFn(i); - files.emplace_back(OpenAsset(path, size)); - if (!ValidateHandle(path, files.back())) + { + const char *path = pathFn(i); + paths.emplace_back(); + memcpy(paths.back().data(), path, strlen(path) + 1); + } + const char *path = paths.back().data(); + files.emplace_back(FindAsset(path)); + if (!ValidatAssetRef(path, files.back())) return nullptr; + const size_t size = files.back().size(); sizes.emplace_back(static_cast(size)); outOffsets[j] = static_cast(totalSize); totalSize += size; @@ -121,7 +129,10 @@ struct MultiFileLoader { for (size_t i = 0, j = 0; i < numFiles; ++i) { if (!filterFn(i)) continue; - files[j].read(&buf[outOffsets[j]], sizes[j]); + AssetHandle handle = OpenAsset(std::move(files[j])); + if (!handle.ok() || !handle.read(&buf[outOffsets[j]], sizes[j])) { + FailedToOpenFileError(paths[j].data(), handle.error()); + } ++j; } return buf;