ksys/res: Implement some ResourceMgrTask prerequisites

This commit is contained in:
Léo Lam
2020-10-04 15:39:04 +02:00
parent 99de7fa009
commit 76655d85a9
12 changed files with 386 additions and 33 deletions
+7
View File
@@ -88,12 +88,16 @@ target_sources(uking PRIVATE
resCacheCriticalSection.h
resControlTask.cpp
resControlTask.h
resCounter.cpp
resCounter.h
resCurrentResNameMgr.cpp
resCurrentResNameMgr.h
resEntryFactory.cpp
resEntryFactory.h
resHandle.cpp
resHandle.h
resInfoContainer.cpp
resInfoContainer.h
resLoadRequest.cpp
resLoadRequest.h
resMemoryTask.cpp
@@ -102,11 +106,14 @@ target_sources(uking PRIVATE
resOffsetReadFileDevice.h
resResourceMgrTask.cpp
resResourceMgrTask.h
resSystem.cpp
resSystem.h
resTaskRequest.cpp
resTaskRequest.h
resUnit.cpp
resUnit.h
resUnitPool.cpp
resUnitPool.h
resResource.cpp
resResource.h
+40
View File
@@ -0,0 +1,40 @@
#include "KingSystem/Resource/resCounter.h"
namespace ksys::res {
CounterBase::CounterBase() = default;
CounterBase::~CounterBase() = default;
bool CounterBase::setData(const CounterBase::Data& data) {
return doSetData_(data);
}
void CounterBase::incrementRef() {
mRefCount.increment();
}
void CounterBase::decrementRef() {
if (mRefCount)
mRefCount.decrement();
}
void CounterBase::setFlag() {
mFlag = true;
}
void CounterBase::reset() {
[[maybe_unused]] const auto count = mRefCount;
mFlag = false;
}
bool CounterBase::isFlagSet() const {
return mFlag;
}
bool Counter::doSetData_(const CounterBase::Data& data) {
mData = data.mData;
return true;
}
} // namespace ksys::res
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <basis/seadTypes.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <thread/seadAtomic.h>
#include "KingSystem/Utils/Types.h"
namespace ksys::res {
class CounterBase {
public:
class DataBase {
SEAD_RTTI_BASE(DataBase)
};
class Data : public DataBase {
SEAD_RTTI_OVERRIDE(Data, DataBase)
public:
explicit Data(void* data) : mData(data) {}
virtual ~Data() = default;
void* mData;
};
CounterBase();
virtual ~CounterBase();
bool setData(const Data& data);
void incrementRef();
void decrementRef();
void setFlag();
void reset();
bool isFlagSet() const;
private:
virtual bool doSetData_(const Data& data) = 0;
bool mFlag = true;
sead::Atomic<s32> mRefCount;
};
class Counter : public CounterBase {
public:
Counter() = default;
~Counter() override = default;
private:
bool doSetData_(const Data& data) override;
void* mData = nullptr;
};
} // namespace ksys::res
@@ -0,0 +1,113 @@
#include "KingSystem/Resource/resInfoContainer.h"
#include <codec/seadHashCRC32.h>
#include <prim/seadBitUtil.h>
#include "KingSystem/Resource/resLoadRequest.h"
#include "KingSystem/Resource/resResource.h"
#include "KingSystem/Resource/resSystem.h"
namespace ksys::res {
ResourceInfoContainer::ResourceInfoContainer() = default;
ResourceInfoContainer::~ResourceInfoContainer() = default;
// NON_MATCHING: LoadRequest field write order
bool ResourceInfoContainer::loadResourceSizeTable() {
const auto load_res = [&] {
LoadRequest req;
req._68 = nullptr;
req.mArena = nullptr;
req.mPackHandle = nullptr;
req._22 = false;
req._20 = false;
req._21 = false;
req._26 = false;
req.mFileDevice = nullptr;
req.mLoadCompressed = true;
req._24 = false;
req._8 = true;
req.mLoadDataAlignment = 8;
req.mBufferSize = 0;
req.mEntryFactory = nullptr;
req.mAocFileDevice = nullptr;
req._34 = 0;
req.mRequester = "ResourceInfoContainer";
req.mPath = "System/Resource/ResourceSizeTable.product.rsizetable";
req._c = 1;
return sead::DynamicCast<Resource>(mRstbHandle.load(req.mPath, req));
};
const Resource* resource = load_res();
if (!resource)
return false;
const u8* data = resource->getRawData();
if (data[0] == 'R' && data[1] == 'S' && data[2] == 'T' && data[3] == 'B') {
stubbedLogFunction();
const auto num_entries = sead::BitUtil::bitCastPtr<s32>(data, 0x4);
const auto num_string_entries = sead::BitUtil::bitCastPtr<s32>(data, 0x8);
auto* entries_data =
reinterpret_cast<const ResEntry*>(reinterpret_cast<const u8*>(data) + 0xc);
if (num_entries >= 1) {
mEntries = {num_entries, entries_data};
entries_data += num_entries;
}
if (num_string_entries >= 1) {
mStringEntries = {num_string_entries,
reinterpret_cast<const ResStringEntry*>(entries_data)};
// Log each conflict.
for (s32 i = 0; i < num_string_entries; ++i)
stubbedLogFunction();
}
} else {
// Assume that there is no string table.
stubbedLogFunction();
if (resource->getRawSize() != 0) {
const u32 num_entries = resource->getRawSize() / sizeof(ResEntry);
mEntries.setBuffer(num_entries,
reinterpret_cast<const ResEntry*>(resource->getRawData()));
}
}
stubbedLogFunction();
stubbedLogFunction();
stubbedLogFunction();
return true;
}
// NON_MATCHING: missing mStringEntries(string_entry_idx).res_size > 0 check
u32 ResourceInfoContainer::getResourceSize(const sead::SafeString& name) {
const u32 name_hash = sead::HashCRC32::calcStringHash(name.cstr());
const s32 entry_idx = mEntries.binarySearch({name_hash, 0}, ResEntry::compareT);
if (entry_idx >= 1 && mEntries(entry_idx).res_size > 0)
return mEntries(entry_idx).res_size;
const s32 string_entry_idx = mStringEntries.binarySearchC(
[&](const ResStringEntry& entry) { return entry.compare(name); });
if (string_entry_idx >= 1 && mStringEntries(string_entry_idx).res_size > 0)
return mStringEntries(string_entry_idx).res_size;
return 0;
}
namespace {
[[gnu::noinline]] bool stringLessThan(const sead::SafeString& a, const sead::SafeString& b) {
return a < b;
}
} // namespace
[[gnu::noinline]] s32
ResourceInfoContainer::ResStringEntry::compare(const sead::SafeString& name) const {
if (res_name > name)
return 1;
if (stringLessThan(res_name, name))
return -1;
return 0;
}
} // namespace ksys::res
@@ -0,0 +1,48 @@
#pragma once
#include <basis/seadTypes.h>
#include <container/seadBuffer.h>
#include <prim/seadSafeString.h>
#include "KingSystem/Resource/resHandle.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::res {
class ResourceInfoContainer {
public:
ResourceInfoContainer();
virtual ~ResourceInfoContainer();
bool loadResourceSizeTable();
u32 getResourceSize(const sead::SafeString& name);
private:
struct ResEntry {
static s32 compareT(const ResEntry* lhs, const ResEntry* rhs) {
if (*lhs > *rhs)
return 1;
if (*lhs < *rhs)
return -1;
return 0;
}
bool operator<(const ResEntry& other) const { return res_name_hash < other.res_name_hash; }
bool operator>(const ResEntry& other) const { return res_name_hash > other.res_name_hash; }
u32 res_name_hash;
s32 res_size;
};
struct ResStringEntry {
s32 compare(const sead::SafeString& name) const;
char res_name[128];
s32 res_size;
};
Handle mRstbHandle;
sead::Buffer<const ResEntry> mEntries;
sead::Buffer<const ResStringEntry> mStringEntries;
};
KSYS_CHECK_SIZE_NX150(ResourceInfoContainer, 0x78);
} // namespace ksys::res
+5 -1
View File
@@ -1,5 +1,7 @@
#pragma once
#include <framework/seadCalculateTask.h>
#include <hostio/seadHostIONode.h>
#include "KingSystem/Resource/resUnit.h"
namespace sead {
@@ -17,7 +19,7 @@ class TaskThread;
namespace ksys::res {
// FIXME: very, very incomplete.
class ResourceMgrTask {
class ResourceMgrTask : public sead::CalculateTask, public sead::hostio::Node {
public:
static ResourceMgrTask* instance() { return sInstance; }
@@ -46,5 +48,7 @@ public:
private:
static ResourceMgrTask* sInstance;
};
KSYS_CHECK_SIZE_NX150(sead::TaskBase, 0xd0);
KSYS_CHECK_SIZE_NX150(sead::MethodTreeNode, 0x98);
} // namespace ksys::res
+17
View File
@@ -0,0 +1,17 @@
#include "KingSystem/Resource/resSystem.h"
namespace ksys::res {
bool stubbedLogFunction() {
return true;
}
bool returnFalse() {
return false;
}
bool returnFalse2() {
return false;
}
} // namespace ksys::res
+4
View File
@@ -10,4 +10,8 @@ bool stubbedLogFunction();
// TODO: figure out what this is used for. Stubbed log function?
bool returnFalse();
// In release builds, the only thing this function does is return 0.
// TODO: figure out what this is used for. Stubbed log function?
bool returnFalse2();
} // namespace ksys::res
+33
View File
@@ -0,0 +1,33 @@
#include "KingSystem/Resource/resUnitPool.h"
namespace ksys::res {
ResourceUnitPool::ResourceUnitPool() = default;
ResourceUnitPool::~ResourceUnitPool() = default;
bool ResourceUnitPool::init() {
for (s32 i = 0; i < UnitCapacity; ++i)
mRingBuffer.pushBack(&mUnits[i]);
return true;
}
ResourceUnit* ResourceUnitPool::tryAlloc() {
if (mRingBuffer.empty())
return nullptr;
return mRingBuffer.popFront();
}
ResourceUnit* ResourceUnitPool::alloc() {
return mRingBuffer.popFront();
}
void ResourceUnitPool::free(ResourceUnit* unit) {
mRingBuffer.pushBack(unit);
}
void ResourceUnitPool::freeForSync(ResourceUnit* unit) {
free(unit);
}
} // namespace ksys::res
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <container/seadRingBuffer.h>
#include "KingSystem/Resource/resUnit.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::res {
class ResourceUnitPool {
public:
ResourceUnitPool();
virtual ~ResourceUnitPool();
ResourceUnitPool(const ResourceUnitPool&) = delete;
ResourceUnitPool& operator=(const ResourceUnitPool&) = delete;
bool init();
ResourceUnit* tryAlloc();
ResourceUnit* alloc();
void free(ResourceUnit* unit);
void freeForSync(ResourceUnit* unit);
private:
static constexpr s32 UnitCapacity = 9000;
ResourceUnit mUnits[UnitCapacity];
sead::FixedRingBuffer<ResourceUnit*, UnitCapacity> mRingBuffer;
};
KSYS_CHECK_SIZE_NX150(ResourceUnitPool, 0x9c01a0);
} // namespace ksys::res