summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2020-09-27 16:11:56 +0200
committerLéo Lam <leo@leolam.fr>2020-10-04 02:00:38 +0200
commit12e6979b6c175d7b9d8b871cb50bbbe9b545a74e (patch)
tree23c778e41c0c96eeabaa5e60341ee2f127cfc59f /src
parentf8db98617c3ccdac22276a2f0e7e9c033b4b62f2 (diff)
ksys/res: Implement more Cache functions
Diffstat (limited to 'src')
-rw-r--r--src/KingSystem/Resource/resCache.cpp167
-rw-r--r--src/KingSystem/Resource/resCache.h13
-rw-r--r--src/KingSystem/Resource/resCacheCriticalSection.cpp8
-rw-r--r--src/KingSystem/Resource/resCacheCriticalSection.h3
-rw-r--r--src/KingSystem/Resource/resHandle.h16
-rw-r--r--src/KingSystem/Resource/resResourceMgrTask.h19
-rw-r--r--src/KingSystem/Resource/resUnit.cpp6
-rw-r--r--src/KingSystem/Resource/resUnit.h53
-rw-r--r--src/KingSystem/Utils/StrTreeMap.h3
9 files changed, 267 insertions, 21 deletions
diff --git a/src/KingSystem/Resource/resCache.cpp b/src/KingSystem/Resource/resCache.cpp
index 4f7abb62..55535d65 100644
--- a/src/KingSystem/Resource/resCache.cpp
+++ b/src/KingSystem/Resource/resCache.cpp
@@ -1,6 +1,10 @@
#include "KingSystem/Resource/resCache.h"
#include <prim/seadScopedLock.h>
#include "KingSystem/Resource/resCacheCriticalSection.h"
+#include "KingSystem/Resource/resControlTask.h"
+#include "KingSystem/Resource/resResourceMgrTask.h"
+#include "KingSystem/Resource/resSystem.h"
+#include "KingSystem/Utils/Debug.h"
namespace ksys::res {
@@ -14,6 +18,125 @@ ResourceUnit* Cache::findUnit(const util::StrTreeMapNode::KeyType& key) const {
return node ? node->getUnit() : nullptr;
}
+Handle::Status Cache::loadResource(const ControlTaskData& data) {
+ auto* handle = data.mResHandle;
+ if (handle->isLinked()) {
+ stubbedLogFunction();
+ return Handle::Status::_8;
+ }
+
+ {
+ const auto path = data.mResLoadReq.mPath;
+ ResourceUnit* unit = data.mPackResUnit;
+ auto lock = sead::makeScopedLock(gCacheCriticalSection);
+ bool remove_from_cache_if_needed = true;
+ if (!unit) {
+ unit = findUnit(path);
+ remove_from_cache_if_needed = [&] {
+ if (!unit)
+ return false;
+
+ if (unit->mStatusFlags.isOn(ResourceUnit::StatusFlag::_80)) {
+ unit->removeFromCache();
+ if (returnFalse())
+ stubbedLogFunction();
+ return false;
+ }
+
+ if (unit->isStatusFlag1000Set()) {
+ unit->removeFromCache();
+ return false;
+ }
+
+ if (unit->isStatus0()) {
+ sead::FormatFixedSafeString<256> message("↓↓↓\nリソース名 : %s\n↑↑↑\n",
+ path.cstr());
+ util::PrintDebug(message);
+ return false;
+ }
+
+ return true;
+ }();
+ }
+
+ if (remove_from_cache_if_needed) {
+ const bool removed = unit->removeTask3FromQueue();
+ if (unit->isLinkedToResourceMgr()) {
+ unit->removeFromCache();
+ } else if (removed) {
+ unit->updateStatus();
+ unit->attachHandle(handle);
+ return unit->getRefCount() == 1 ? Handle::Status::_6 : Handle::Status::_5;
+ }
+ }
+ }
+
+ if (data.mHasResLoadReq)
+ return Handle::Status::_8;
+
+ ResourceUnit* result;
+
+ {
+ sead::FixedSafeString<128 + 7> new_path;
+ sead::SafeString path = data.mResLoadReq.mPath;
+
+ bool set_flag_4 = false;
+ if (data.mResLoadReq.mLoadCompressed) {
+ auto it = data.mResLoadReq.mPath.rfindIterator(".");
+ if (it.getIndex() == -1)
+ return Handle::Status::_1;
+
+ ++it;
+ sead::SafeString extension;
+ extension = &*it;
+ set_flag_4 = ResourceMgrTask::instance()->dropSFromExtensionIfNeeded(
+ data.mResLoadReq.mPath, new_path, it.getIndex() - 1, extension);
+ }
+
+ if (!new_path.isEmpty())
+ path = new_path;
+
+ ResourceUnit::InitArg init_arg(false, false, set_flag_4, data.mResLoadReq._26,
+ data.mResLoadReq._28, handle, this, nullptr, nullptr,
+ &data.mResLoadReq, data.mResLoadReq.mArena,
+ data.mResLoadReq.mBufferSize, path);
+
+ ResourceMgrTask::GetUnitArg arg;
+ arg.unit_init_arg = &init_arg;
+ arg.arena = data.mResLoadReq.mArena;
+
+ result = ResourceMgrTask::instance()->clearCachesAndGetUnit(arg);
+ }
+
+ if (!result)
+ return Handle::Status::_3;
+
+ {
+ auto lock = sead::makeScopedLock(gCacheCriticalSection);
+ mMap.insert(&result->mMapNode);
+ result->setIsLinkedToCache(true);
+ }
+
+ u8 lane_id = 0xff;
+ if (data.mResLoadReq._c <= 2) {
+ const bool x = result->mStatusFlags.isOn(ResourceUnit::StatusFlag::LoadFromArchive);
+#ifdef MATCHING_HACK_NX_CLANG
+ // This makes absolutely no sense at all, but this prevents InstCombine from
+ // turning (x & 0x20) >> 5 into (x >> 5) & 1 by adding a fake-use.
+ // LLVM (4.0.1 at least) doesn't do anything with this piece of information
+ // so the conditional still works fine.
+ __builtin_assume(x);
+#endif
+ lane_id = 2 * data.mResLoadReq._c + (x ? 1 : 2);
+ }
+
+ ResourceUnit::RequestLoadArg load_arg;
+ load_arg.lane_id = lane_id;
+ load_arg.has_handle = data.mResLoadReq._8;
+ result->requestLoad(load_arg);
+ return Handle::Status::_7;
+}
+
void Cache::eraseUnit(ResourceUnit* unit) {
auto lock = sead::makeScopedLock(gCacheCriticalSection);
if (unit->isLinkedToCache()) {
@@ -22,4 +145,48 @@ void Cache::eraseUnit(ResourceUnit* unit) {
}
}
+void Cache::removeUnitAndClearCache_(ResourceUnit* unit) {
+ ResourceMgrTask::ClearCacheArg arg{unit};
+ unit->mStatusFlags.reset(ResourceUnit::StatusFlag::_20000);
+ if (unit->isStatusFlag8000Set()) {
+ ResourceMgrTask::instance()->eraseUnit(unit);
+ ResourceMgrTask::instance()->clearCache(arg);
+ }
+}
+
+namespace detail::cache {
+struct ForEachContextData {
+ ForEachContextData() = default;
+ virtual ~ForEachContextData() = default;
+ virtual void invoke(const util::StrTreeMapKey&, ResourceUnit*& value) {
+ (value->getCache()->*fn)(value);
+ }
+
+ void (Cache::*fn0)(ResourceUnit* unit);
+ void (Cache::*fn)(ResourceUnit* unit);
+};
+KSYS_CHECK_SIZE_NX150(ForEachContextData, 0x28);
+
+struct ForEachContext {
+ void deleteUnit(util::StrTreeMapNode* node_) {
+ auto* node = static_cast<ResourceUnitMapNode*>(node_);
+ data->invoke(node->key(), node->getUnit());
+ }
+
+ ForEachContextData* data;
+};
+KSYS_CHECK_SIZE_NX150(ForEachContext, 0x8);
+} // namespace detail::cache
+
+void Cache::eraseUnits() {
+ using namespace detail::cache;
+ ForEachContextData data{};
+ data.fn = &Cache::removeUnitAndClearCache_;
+ auto lock = sead::makeScopedLock(gCacheCriticalSection);
+ ForEachContext context{&data};
+ sead::Delegate1<ForEachContext, util::StrTreeMapNode*> delegate{&context,
+ &ForEachContext::deleteUnit};
+ mMap.forEach(delegate);
+}
+
} // namespace ksys::res
diff --git a/src/KingSystem/Resource/resCache.h b/src/KingSystem/Resource/resCache.h
index a0a2da91..3f01b5d9 100644
--- a/src/KingSystem/Resource/resCache.h
+++ b/src/KingSystem/Resource/resCache.h
@@ -1,13 +1,14 @@
#pragma once
#include <hostio/seadHostIONode.h>
+#include "KingSystem/Resource/resHandle.h"
#include "KingSystem/Resource/resUnit.h"
#include "KingSystem/Utils/StrTreeMap.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::res {
-struct LoadContext;
+class ControlTaskData;
class Cache : public sead::hostio::Node {
public:
@@ -15,14 +16,16 @@ public:
virtual ~Cache() = default;
void init();
-
ResourceUnit* findUnit(const ResourceUnitMapNode::KeyType& key) const;
- void eraseUnit(ResourceUnit* unit);
+ Handle::Status loadResource(const ControlTaskData& data);
- // FIXME: return type
- s32 loadResource(const LoadContext& context);
+ void eraseUnit(ResourceUnit* unit);
+ void eraseUnits();
private:
+ void removeUnitAndClearCache_(ResourceUnit* unit);
+
+ // This seems to be unused.
[[maybe_unused]] u8 _8 = 2;
util::StrTreeMap<ResourceUnitMapNode> mMap;
};
diff --git a/src/KingSystem/Resource/resCacheCriticalSection.cpp b/src/KingSystem/Resource/resCacheCriticalSection.cpp
index eb2a12db..e6bf0138 100644
--- a/src/KingSystem/Resource/resCacheCriticalSection.cpp
+++ b/src/KingSystem/Resource/resCacheCriticalSection.cpp
@@ -6,4 +6,12 @@ namespace ksys::res {
[[maybe_unused]] static util::InitTimeInfo sInitTimeInfo;
sead::CriticalSection gCacheCriticalSection;
+void lockCacheCriticalSection() {
+ gCacheCriticalSection.lock();
+}
+
+void unlockCacheCriticalSection() {
+ gCacheCriticalSection.unlock();
+}
+
} // namespace ksys::res
diff --git a/src/KingSystem/Resource/resCacheCriticalSection.h b/src/KingSystem/Resource/resCacheCriticalSection.h
index 339a34be..89f37497 100644
--- a/src/KingSystem/Resource/resCacheCriticalSection.h
+++ b/src/KingSystem/Resource/resCacheCriticalSection.h
@@ -6,4 +6,7 @@ namespace ksys::res {
extern sead::CriticalSection gCacheCriticalSection;
+void lockCacheCriticalSection();
+void unlockCacheCriticalSection();
+
} // namespace ksys::res
diff --git a/src/KingSystem/Resource/resHandle.h b/src/KingSystem/Resource/resHandle.h
index f31dcb67..c6747b7e 100644
--- a/src/KingSystem/Resource/resHandle.h
+++ b/src/KingSystem/Resource/resHandle.h
@@ -1,5 +1,6 @@
#pragma once
+#include <container/seadListImpl.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadSafeString.h>
#include <prim/seadTypedBitFlag.h>
@@ -21,6 +22,14 @@ class Handle {
public:
enum class Status {
_0 = 0,
+ _1 = 1,
+ _2 = 2,
+ _3 = 3,
+ _4 = 4,
+ _5 = 5,
+ _6 = 6,
+ _7 = 7,
+ _8 = 8,
};
Handle();
@@ -35,6 +44,10 @@ public:
void setUnit(ResourceUnit* unit) { mUnit = unit; }
+ bool isLinked() const { return mListNode.isLinked(); }
+
+ static size_t getListNodeOffset() { return offsetof(Handle, mListNode); }
+
private:
enum class Flag : u8 {
_1 = 0x1,
@@ -44,8 +57,7 @@ private:
Status mStatus = Status::_0;
ResourceUnit* mUnit = nullptr;
util::ManagedTaskHandle mTaskHandle;
- void* _40 = nullptr;
- void* _48 = nullptr;
+ sead::ListNode mListNode;
};
KSYS_CHECK_SIZE_NX150(Handle, 0x50);
diff --git a/src/KingSystem/Resource/resResourceMgrTask.h b/src/KingSystem/Resource/resResourceMgrTask.h
index 18ea07f0..08051522 100644
--- a/src/KingSystem/Resource/resResourceMgrTask.h
+++ b/src/KingSystem/Resource/resResourceMgrTask.h
@@ -1,5 +1,7 @@
#pragma once
+#include "KingSystem/Resource/resUnit.h"
+
namespace sead {
class Heap;
}
@@ -24,6 +26,23 @@ public:
util::TaskThread* makeResourceLoadingThread(sead::Heap* heap, bool use_game_task_thread);
+ struct GetUnitArg {
+ const ResourceUnit::InitArg* unit_init_arg;
+ OverlayArena* arena;
+ };
+ ResourceUnit* clearCachesAndGetUnit(const GetUnitArg& arg);
+
+ void eraseUnit(ResourceUnit* unit);
+
+ struct ClearCacheArg {
+ ResourceUnit* unit;
+ };
+ void clearCache(ClearCacheArg& arg, void* x = nullptr);
+
+ bool dropSFromExtensionIfNeeded(const sead::SafeString& path,
+ sead::BufferedSafeString& new_path, s32 dot_idx,
+ const sead::SafeString& extension);
+
private:
static ResourceMgrTask* sInstance;
};
diff --git a/src/KingSystem/Resource/resUnit.cpp b/src/KingSystem/Resource/resUnit.cpp
index 8ddc4f34..1c2f0e1c 100644
--- a/src/KingSystem/Resource/resUnit.cpp
+++ b/src/KingSystem/Resource/resUnit.cpp
@@ -78,7 +78,13 @@ bool ResourceUnit::init(const ResourceUnit::InitArg& arg) {
mFlags.change(Flag::_2, arg.set_flag_2);
mFlags.change(Flag::_4, arg.set_flag_4);
+#ifdef MATCHING_HACK_NX_CLANG
+ mStatusFlags.change(StatusFlag::_20000,
+ arg.load_req_field_26 &&
+ !*static_cast<const volatile bool*>(&arg.load_req_field_28));
+#else
mStatusFlags.change(StatusFlag::_20000, arg.load_req_field_26 && !arg.load_req_field_28);
+#endif
mStatusFlags.change(StatusFlag::_40000, arg.load_req->_27);
mStatusFlags.change(StatusFlag::HasHeap, arg.heap != nullptr);
mStatusFlags.change(StatusFlag::_80000, arg.load_req_field_28);
diff --git a/src/KingSystem/Resource/resUnit.h b/src/KingSystem/Resource/resUnit.h
index 4f81f919..67a615f2 100644
--- a/src/KingSystem/Resource/resUnit.h
+++ b/src/KingSystem/Resource/resUnit.h
@@ -18,12 +18,15 @@ class DirectResource;
class FileDevice;
} // namespace sead
+namespace ksys {
+class OverlayArena;
+}
+
namespace ksys::res {
class Cache;
class Handle;
class LoadRequest;
-class OverlayArena;
class ResourceUnit;
class ResourceUnitMapNode : public util::StrTreeMapNode {
@@ -32,6 +35,7 @@ public:
~ResourceUnitMapNode() override { ; }
void erase_() override { util::StrTreeMapNode::erase_(); }
+ ResourceUnit*& getUnit() { return mUnit; }
ResourceUnit* getUnit() const { return mUnit; }
util::StrTreeMapKey& key() { return mKey; }
const util::StrTreeMapKey& key() const { return mKey; }
@@ -63,22 +67,38 @@ public:
};
struct InitArg {
- bool set_flag_1;
- bool set_flag_2;
- bool set_flag_4;
- sead::Atomic<bool> load_req_field_26;
- sead::Atomic<bool> load_req_field_28;
- Handle* handle;
- Cache* cache;
- void* _18;
- sead::Heap* heap;
- LoadRequest* load_req;
- OverlayArena* arena;
- u32 alloc_size;
+ InitArg() = default;
+ InitArg(bool set_flag_1, bool set_flag_2, bool set_flag_4, bool load_req_field_26,
+ bool load_req_field_28, Handle* handle, Cache* cache, void* _18, sead::Heap* heap,
+ const LoadRequest* load_req, OverlayArena* arena, u32 alloc_size,
+ sead::SafeString path)
+ : set_flag_1(set_flag_1), set_flag_2(set_flag_2), set_flag_4(set_flag_4),
+ load_req_field_26(load_req_field_26), load_req_field_28(load_req_field_28),
+ handle(handle), cache(cache), _18(_18), heap(heap), load_req(load_req), arena(arena),
+ alloc_size(alloc_size), path(path) {}
+
+ bool set_flag_1 = false;
+ bool set_flag_2 = false;
+ bool set_flag_4 = false;
+ bool load_req_field_26 = false;
+ bool load_req_field_28 = false;
+ Handle* handle = nullptr;
+ Cache* cache = nullptr;
+ void* _18 = nullptr;
+ sead::Heap* heap = nullptr;
+ const LoadRequest* load_req = nullptr;
+ OverlayArena* arena = nullptr;
+ u32 alloc_size = 0;
sead::SafeString path;
};
KSYS_CHECK_SIZE_NX150(InitArg, 0x50);
+ struct RequestLoadArg {
+ u8 lane_id;
+ bool has_handle;
+ };
+ KSYS_CHECK_SIZE_NX150(RequestLoadArg, 0x2);
+
explicit ResourceUnit(const InitArg& arg);
ResourceUnit();
virtual ~ResourceUnit();
@@ -107,11 +127,16 @@ public:
bool isLinkedToCache() const;
void setIsLinkedToCache(bool linked);
+ Cache* getCache() const { return mCache; }
const auto& getCacheKey() const { return mMapNode.key(); }
void removeFromCache();
bool removeTask3FromQueue();
+ void requestLoad(const RequestLoadArg& arg);
+
+ bool isStatusFlag1000Set() const;
+
static size_t getArenaUnitListNodeOffset() {
return offsetof(ResourceUnit, mArenaUnitListNode);
}
@@ -125,6 +150,7 @@ public:
}
private:
+ friend class Cache;
friend class Handle;
enum class CacheFlag : u8 {
@@ -142,6 +168,7 @@ private:
BufferSizeIsNonZero = 0x10,
LoadFromArchive = 0x20,
LoadReqField24IsTrue = 0x40,
+ _80 = 0x80,
FailedMaybe = 0x100,
FileSizeIsZero = 0x200,
FileSizeExceedsAllocSize = 0x800,
diff --git a/src/KingSystem/Utils/StrTreeMap.h b/src/KingSystem/Utils/StrTreeMap.h
index 62c4dd09..52f72f4d 100644
--- a/src/KingSystem/Utils/StrTreeMap.h
+++ b/src/KingSystem/Utils/StrTreeMap.h
@@ -3,6 +3,7 @@
#include <basis/seadTypes.h>
#include <codec/seadHashCRC32.h>
#include <container/seadTreeMap.h>
+#include <prim/seadDelegate.h>
namespace ksys::util {
@@ -10,7 +11,7 @@ class StrTreeMapKey {
public:
StrTreeMapKey() = default;
StrTreeMapKey(u32 key_hash, const sead::SafeString& key) : mKeyHash(key_hash), mKey(key) {}
- explicit StrTreeMapKey(const sead::SafeString& key)
+ StrTreeMapKey(const sead::SafeString& key)
: StrTreeMapKey(sead::HashCRC32::calcStringHash(key.cstr()), key) {}
const sead::SafeString& key() const { return mKey; }