ksys/res: Start adding ResourceUnit and Cache

This commit is contained in:
Léo Lam
2020-09-25 17:49:07 +02:00
parent 26baae29de
commit b1926813b7
16 changed files with 573 additions and 43 deletions
+7 -2
View File
@@ -82,6 +82,10 @@ target_sources(uking PRIVATE
GeneralParamList/resGParamListObjectZora.h
GeneralParamList/resGParamListTraits.h
resCache.cpp
resCache.h
resCacheCriticalSection.cpp
resCacheCriticalSection.h
resCurrentResNameMgr.cpp
resCurrentResNameMgr.h
resEntryFactory.cpp
@@ -92,6 +96,9 @@ target_sources(uking PRIVATE
resLoadRequest.h
resOffsetReadFileDevice.cpp
resOffsetReadFileDevice.h
resSystem.h
resUnit.cpp
resUnit.h
resResource.cpp
resResource.h
@@ -111,6 +118,4 @@ target_sources(uking PRIVATE
resResourceLod.h
resResourceRecipe.cpp
resResourceRecipe.h
resSystem.h
)
+25
View File
@@ -0,0 +1,25 @@
#include "KingSystem/Resource/resCache.h"
#include <prim/seadScopedLock.h>
#include "KingSystem/Resource/resCacheCriticalSection.h"
namespace ksys::res {
Cache::Cache() = default;
void Cache::init() {}
ResourceUnit* Cache::findUnit(const util::StrTreeMapNode::KeyType& key) const {
auto lock = sead::makeScopedLock(gCacheCriticalSection);
ResourceUnitMapNode* node = mMap.find(key);
return node ? node->getUnit() : nullptr;
}
void Cache::eraseUnit(ResourceUnit* unit) {
auto lock = sead::makeScopedLock(gCacheCriticalSection);
if (unit->isLinkedToCache()) {
mMap.erase(unit->getCacheKey());
unit->setIsLinkedToCache(false);
}
}
} // namespace ksys::res
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <hostio/seadHostIONode.h>
#include "KingSystem/Resource/resUnit.h"
#include "KingSystem/Utils/StrTreeMap.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::res {
struct LoadContext;
class Cache : public sead::hostio::Node {
public:
Cache();
virtual ~Cache() = default;
void init();
ResourceUnit* findUnit(const ResourceUnitMapNode::KeyType& key) const;
void eraseUnit(ResourceUnit* unit);
// FIXME: return type
s32 loadResource(const LoadContext& context);
private:
[[maybe_unused]] u8 _8 = 2;
util::StrTreeMap<ResourceUnitMapNode> mMap;
};
KSYS_CHECK_SIZE_NX150(Cache, 0x18);
} // namespace ksys::res
@@ -0,0 +1,9 @@
#include "KingSystem/Resource/resCacheCriticalSection.h"
#include "KingSystem/Utils/InitTimeInfo.h"
namespace ksys::res {
[[maybe_unused]] static util::InitTimeInfo sInitTimeInfo;
sead::CriticalSection gCacheCriticalSection;
} // namespace ksys::res
@@ -0,0 +1,9 @@
#pragma once
#include <thread/seadCriticalSection.h>
namespace ksys::res {
extern sead::CriticalSection gCacheCriticalSection;
} // namespace ksys::res
+13
View File
@@ -1,12 +1,18 @@
#pragma once
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadSafeString.h>
#include <prim/seadTypedBitFlag.h>
#include "KingSystem/Utils/Thread/ManagedTaskHandle.h"
#include "KingSystem/Utils/Types.h"
namespace sead {
class DirectResource;
}
namespace ksys::res {
class ILoadRequest;
class ResourceUnit;
// FIXME: incomplete
@@ -22,6 +28,13 @@ public:
Status getStatus() const;
sead::DirectResource* load(const sead::SafeString& path, const ILoadRequest& request,
Status* out_status = nullptr);
void unload();
void setUnit(ResourceUnit* unit) { mUnit = unit; }
private:
enum class Flag : u8 {
_1 = 0x1,
+1 -1
View File
@@ -46,7 +46,7 @@ public:
bool _27 = true;
bool _28 = true;
s32 mLoadDataAlignment = 0;
u32 mAllocSize = 0;
u32 mBufferSize = 0;
u32 _34 = 0;
sead::FileDevice* mFileDevice = nullptr;
EntryFactoryBase* mEntryFactory = nullptr;
+221
View File
@@ -0,0 +1,221 @@
#include "KingSystem/Resource/resUnit.h"
#include <filedevice/seadArchiveFileDevice.h>
#include <resource/seadArchiveRes.h>
#include "KingSystem/Resource/resCache.h"
#include "KingSystem/Resource/resEntryFactory.h"
#include "KingSystem/Resource/resLoadRequest.h"
#include "KingSystem/Resource/resSystem.h"
namespace ksys::res {
ResourceUnit::ResourceUnit(const InitArg& arg)
: mArena(arg.arena), mLoadReqArena(arg.load_req->mArena), mLoadReqField68(arg.load_req->_68),
mCache(arg.cache), mFileDevice(arg.load_req->mFileDevice),
mLoadReqAllocSize(arg.load_req->_34), mAllocSize(arg.alloc_size), mPath(arg.path),
mHeap(arg.heap) {
init(arg);
}
ResourceUnit::ResourceUnit() = default;
bool ResourceUnit::init(const ResourceUnit::InitArg& arg) {
mCacheFlags.makeAllZero();
mFlags.makeAllZero();
mStatusFlags.makeAllZero();
mStatus = Status::_0;
mArena = arg.arena;
mArena1 = nullptr;
mArena2 = nullptr;
mLoadReqArena = arg.load_req->mArena;
mArchiveRes = nullptr;
mResource = nullptr;
mLoadReqField68 = arg.load_req->_68;
mCache = arg.cache;
mFileDevice = arg.load_req->mFileDevice;
mLoadReqAllocSize = arg.load_req->_34;
mAllocSize = arg.alloc_size;
mInfoAllocSize = 0;
mRefCount.storeNonAtomic(0);
mCounter.storeNonAtomic(0);
mEvent.resetSignal();
mLoadArg = {};
mPath = arg.path;
mHeap = arg.heap;
if (arg.load_req->mPackHandle) {
SimplePackedLoadRequest request;
request._8 = true;
request.mRequester = "ResourceUnit";
request._c = 2;
request.mPack = arg.load_req->mPackHandle;
mArchiveRes = sead::DynamicCast<sead::ArchiveRes>(mArchiveResHandle.load("", request));
}
mMapNode.key().setKey(mPath);
mLoadArg.path = mPath;
mLoadArg.instance_heap = nullptr;
mLoadArg.instance_alignment = sizeof(void*);
mLoadArg.load_data_heap = nullptr;
mLoadArg.load_data_alignment = arg.load_req->mLoadDataAlignment;
mLoadArg.load_data_buffer = nullptr;
mLoadArg.load_data_buffer_size = arg.load_req->mBufferSize;
mLoadArg.factory = arg.load_req->mEntryFactory;
mLoadArg.device = arg.load_req->mAocFileDevice;
mLoadArg.assert_on_alloc_fail = false;
bool load_from_archive;
if (sead::IsDerivedFrom<sead::ArchiveFileDevice>(mLoadArg.device))
load_from_archive = true;
else
load_from_archive = arg.load_req->mPackHandle != nullptr;
mStatusFlags.change(StatusFlag::BufferSizeIsNonZero, arg.load_req->mBufferSize != 0);
mStatusFlags.change(StatusFlag::LoadFromArchive, load_from_archive);
mStatusFlags.change(StatusFlag::LoadReqField24IsTrue, arg.load_req->_24);
mFlags.change(Flag::_1, arg.set_flag_1);
mFlags.change(Flag::_2, arg.set_flag_2);
mFlags.change(Flag::_4, arg.set_flag_4);
mStatusFlags.change(StatusFlag::_20000, arg.load_req_field_26 && !arg.load_req_field_28);
mStatusFlags.change(StatusFlag::_40000, arg.load_req->_27);
mStatusFlags.change(StatusFlag::HasHeap, arg.heap != nullptr);
mStatusFlags.change(StatusFlag::_80000, arg.load_req_field_28);
if (arg.handle) {
arg.handle->setUnit(this);
mRefCount.increment();
mStatusFlags.reset(StatusFlag::NeedToIncrementRefCount);
}
{
util::TaskDelegateSetter setter;
mTask1.setDelegate(setter);
}
{
util::TaskDelegateSetter setter;
mTask2.setDelegate(setter);
}
if (mStatusFlags.isOn(StatusFlag::_80000)) {
mRefCount.increment();
mStatusFlags.reset(StatusFlag::NeedToIncrementRefCount);
stubbedLogFunction();
}
return true;
}
ResourceUnit::~ResourceUnit() {
unloadArchiveRes();
}
void ResourceUnit::unloadArchiveRes() {
if (mArchiveRes) {
mArchiveRes = nullptr;
mArchiveResHandle.unload();
}
}
void ResourceUnit::attachHandle(Handle* handle) {
handle->setUnit(this);
mRefCount.increment();
mStatusFlags.reset(StatusFlag::NeedToIncrementRefCount);
}
s32 ResourceUnit::getRefCount() const {
return mRefCount;
}
ResourceUnit::Status ResourceUnit::getStatus() const {
return mStatus;
}
// NON_MATCHING: ldr + sxtw -> ldrsw
void ResourceUnit::updateStatus() {
static const Status sMap[] = {Status::_8, Status::_11, Status::_11, Status::_14, Status::_14};
if (Status::_2 <= mStatus && mStatus <= Status::_6)
mStatus = sMap[s32(mStatus)];
}
bool ResourceUnit::isTask1NotQueued() const {
return mTask1.getStatus() == util::Task::Status::RemovedFromQueue;
}
bool ResourceUnit::isStatus0() const {
return mStatus == Status::_0;
}
bool ResourceUnit::isTask1ActiveOrStatus7() const {
if (!mTask1.isInactive())
return true;
if (isTask1NotQueued())
return false;
return mStatus == Status::_7;
}
bool ResourceUnit::isStatus1() const {
return mStatus == Status::_1;
}
bool ResourceUnit::isStatus9_12_15() const {
return mStatus == Status::_9 || mStatus == Status::_12 || mStatus == Status::_15;
}
// NON_MATCHING: branching for the second if
bool ResourceUnit::isParseOk() const {
auto* ksys_res = sead::DynamicCast<res::Resource>(mResource);
if (mStatus == Status::_14)
return true;
if (mStatus == Status::_8 && !ksys_res)
return mResource != nullptr;
if (mStatus == Status::_8 && ksys_res)
return !ksys_res->needsParse();
return false;
}
bool ResourceUnit::isStatusFlag8000Set() const {
return mStatusFlags.isOn(StatusFlag::NeedToIncrementRefCount);
}
bool ResourceUnit::isLinkedToResourceMgr() const {
return mResMgrUnitListNode.isLinked();
}
size_t ResourceUnit::getHeapSize() const {
return mHeap ? mHeap->getSize() : 0;
}
sead::Heap* ResourceUnit::getHeap() const {
return mHeap;
}
bool ResourceUnit::isLinkedToCache() const {
return mCacheFlags.isOn(CacheFlag::IsLinkedToCache);
}
void ResourceUnit::setIsLinkedToCache(bool linked) {
mCacheFlags.change(CacheFlag::IsLinkedToCache, linked);
if (returnFalse())
stubbedLogFunction();
}
void ResourceUnit::removeFromCache() {
if (mCache)
mCache->eraseUnit(this);
else
stubbedLogFunction();
}
bool ResourceUnit::removeTask3FromQueue() {
mTask3.removeFromQueue();
return true;
}
} // namespace ksys::res
+191
View File
@@ -0,0 +1,191 @@
#pragma once
#include <KingSystem/Utils/StrTreeMap.h>
#include <hostio/seadHostIONode.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadSafeString.h>
#include <prim/seadTypedBitFlag.h>
#include <resource/seadResourceMgr.h>
#include <thread/seadAtomic.h>
#include "KingSystem/Resource/resHandle.h"
#include "KingSystem/Utils/Thread/Event.h"
#include "KingSystem/Utils/Thread/Task.h"
#include "KingSystem/Utils/Types.h"
namespace sead {
class ArchiveRes;
class DirectResource;
class FileDevice;
} // namespace sead
namespace ksys::res {
class Cache;
class Handle;
class LoadRequest;
class OverlayArena;
class ResourceUnit;
class ResourceUnitMapNode : public util::StrTreeMapNode {
public:
explicit ResourceUnitMapNode(ResourceUnit* unit) : mUnit(unit) {}
~ResourceUnitMapNode() override { ; }
void erase_() override { util::StrTreeMapNode::erase_(); }
ResourceUnit* getUnit() const { return mUnit; }
util::StrTreeMapKey& key() { return mKey; }
const util::StrTreeMapKey& key() const { return mKey; }
private:
ResourceUnit* mUnit = nullptr;
};
class ResourceUnit : public sead::hostio::Node {
SEAD_RTTI_BASE(ResourceUnit)
public:
enum class Status {
_0 = 0,
_1 = 1,
_2 = 2,
_3 = 3,
_4 = 4,
_5 = 5,
_6 = 6,
_7 = 7,
_8 = 8,
_9 = 9,
_10 = 10,
_11 = 11,
_12 = 12,
_13 = 13,
_14 = 14,
_15 = 15,
};
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;
sead::SafeString path;
};
KSYS_CHECK_SIZE_NX150(InitArg, 0x50);
explicit ResourceUnit(const InitArg& arg);
ResourceUnit();
virtual ~ResourceUnit();
bool init(const InitArg& arg);
void unloadArchiveRes();
void attachHandle(Handle* handle);
s32 getRefCount() const;
Status getStatus() const;
void updateStatus();
bool isTask1NotQueued() const;
bool isStatus0() const;
bool isTask1ActiveOrStatus7() const;
bool isStatus1() const;
bool isStatus9_12_15() const;
bool isParseOk() const;
bool isStatusFlag8000Set() const;
bool isLinkedToResourceMgr() const;
size_t getHeapSize() const;
sead::Heap* getHeap() const;
bool isLinkedToCache() const;
void setIsLinkedToCache(bool linked);
const auto& getCacheKey() const { return mMapNode.key(); }
void removeFromCache();
bool removeTask3FromQueue();
static size_t getArenaUnitListNodeOffset() {
return offsetof(ResourceUnit, mArenaUnitListNode);
}
static size_t getArenaUnitListNode2Offset() {
return offsetof(ResourceUnit, mArenaUnitListNode2);
}
static size_t getResMgrUnitListNodeOffset() {
return offsetof(ResourceUnit, mResMgrUnitListNode);
}
private:
friend class Handle;
enum class CacheFlag : u8 {
IsLinkedToCache = 0x1,
};
enum class Flag : u8 {
_1 = 0x1,
_2 = 0x2,
_4 = 0x4,
};
enum class StatusFlag {
HasHeap = 0x1,
BufferSizeIsNonZero = 0x10,
LoadFromArchive = 0x20,
LoadReqField24IsTrue = 0x40,
FailedMaybe = 0x100,
FileSizeIsZero = 0x200,
FileSizeExceedsAllocSize = 0x800,
_1000 = 0x1000,
FileOrResInstanceTooLargeForHeap = 0x2000,
LoadFailed = 0x4000,
NeedToIncrementRefCount = 0x8000,
_20000 = 0x20000,
_40000 = 0x40000,
_80000 = 0x80000,
};
sead::TypedBitFlag<CacheFlag> mCacheFlags;
sead::TypedBitFlag<Flag> mFlags;
sead::TypedBitFlag<StatusFlag> mStatusFlags;
Status mStatus = Status::_0;
OverlayArena* mArena = nullptr;
OverlayArena* mArena1 = nullptr;
OverlayArena* mArena2 = nullptr;
OverlayArena* mLoadReqArena = nullptr;
sead::DirectResource* mResource = nullptr;
Handle mArchiveResHandle;
sead::ArchiveRes* mArchiveRes = nullptr;
void* mLoadReqField68 = nullptr;
Cache* mCache = nullptr;
sead::FileDevice* mFileDevice = nullptr;
u32 mLoadReqAllocSize = 0;
u32 mAllocSize = 0;
u32 mInfoAllocSize = 0;
sead::Atomic<s32> mRefCount;
sead::ListNode mArenaUnitListNode;
sead::ListNode mArenaUnitListNode2;
sead::ListNode mResMgrUnitListNode;
util::Task mTask1;
util::Task mTask2;
util::Task mTask3;
ResourceUnitMapNode mMapNode{this};
sead::Atomic<s32> mCounter;
util::Event mEvent{nullptr,
sead::IDisposer::HeapNullOption::DoNotAppendDisposerIfNoHeapSpecified, true};
sead::ResourceMgr::LoadArg mLoadArg;
sead::FixedSafeString<128> mPath;
sead::Heap* mHeap = nullptr;
};
KSYS_CHECK_SIZE_NX150(ResourceUnit, 0x468);
} // namespace ksys::res
+3 -3
View File
@@ -2,13 +2,13 @@
#include <heap/seadExpHeap.h>
#include "KingSystem/Resource/resResourceMgrTask.h"
#include "KingSystem/Resource/resSystem.h"
#include "KingSystem/Resource/resUnit.h"
namespace ksys {
OverlayArena::OverlayArena() {
// FIXME: these should use offsetof()
mUnits.initOffset(0xc0);
mOffsetList2.initOffset(0xd0);
mUnits.initOffset(res::ResourceUnit::getArenaUnitListNodeOffset());
mOffsetList2.initOffset(res::ResourceUnit::getArenaUnitListNode2Offset());
}
OverlayArena::~OverlayArena() {
+1
View File
@@ -30,6 +30,7 @@ target_sources(uking PRIVATE
HashUtil.h
HeapUtil.cpp
HeapUtil.h
InitTimeInfo.h
ParamIO.h
StrTreeMap.h
Types.h
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <time/seadTickTime.h>
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class InitTimeInfo {
public:
InitTimeInfo() = default;
sead::TickTime getInitStartTime() const { return mInitStartTime; }
sead::TickSpan getInitDuration() const { return mInitDuration; }
void finish() { mInitDuration = sead::TickTime().diff(mInitStartTime); }
private:
sead::TickTime mInitStartTime;
sead::TickSpan mInitDuration;
};
KSYS_CHECK_SIZE_NX150(InitTimeInfo, 0x10);
} // namespace ksys::util
+1
View File
@@ -32,6 +32,7 @@ private:
class StrTreeMapNode : public sead::TreeMapNode<StrTreeMapKey> {
public:
using KeyType = StrTreeMapKey;
~StrTreeMapNode() override { ; }
void erase_() override { mLeft = mRight = nullptr; }
};
+1
View File
@@ -105,6 +105,7 @@ public:
explicit Task(sead::Heap* heap);
Task(sead::Heap* heap, sead::IDisposer::HeapNullOption heap_null_option);
Task() : Task(nullptr, sead::IDisposer::HeapNullOption::DoNotAppendDisposerIfNoHeapSpecified) {}
virtual ~Task();
bool setDelegate(const TaskDelegateSetter& setter);