summaryrefslogtreecommitdiff
path: root/src/asset-manager.cpp
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-12-22 19:33:26 -0500
committerJonathan Bradley <jcb@pikum.xyz>2023-12-23 11:43:15 -0500
commitb911c5b6c37ab13be6188cf039cd4246414fc7b5 (patch)
treeda4743a719e8134abb35f87f5097541e09c8f581 /src/asset-manager.cpp
parenta3937e7eef97cb0badcd65c390b9dd39d4cfd094 (diff)
first pass background asset loading - buggy
Diffstat (limited to 'src/asset-manager.cpp')
-rw-r--r--src/asset-manager.cpp155
1 files changed, 116 insertions, 39 deletions
diff --git a/src/asset-manager.cpp b/src/asset-manager.cpp
index 753da24..9fda1c1 100644
--- a/src/asset-manager.cpp
+++ b/src/asset-manager.cpp
@@ -1,7 +1,14 @@
#include "asset-manager.hpp"
-const PkeHandleItemIndex_T maxAssetItemsPerBucket = 256;
+#include "thread_pool.hpp"
+
+#include <chrono>
+#include <filesystem>
+#include <fstream>
+#include <future>
+
+const PkeHandleItemIndex_T maxAssetItemsPerBucket = 64;
struct AssetBucket {
Asset assets[maxAssetItemsPerBucket];
@@ -9,65 +16,108 @@ struct AssetBucket {
BucketContainer<AssetBucket, AssetHandle> Asset_BucketContainer{};
+ThreadPoolHandle assetThreadPool = ThreadPoolHandle_MAX;
+
void AM_Init() {
Buckets_Init(Asset_BucketContainer);
+ assetThreadPool = PkeThreads_Init(2, 255);
}
-AssetHandle AM_Register_Inner(const void *src, void *dst, int64_t size, const char *key) {
- bool moved = false;
- AssetHandle assetHandle{Buckets_NewHandle<AssetBucket>(maxAssetItemsPerBucket, Asset_BucketContainer, moved)};
-
- if (src != nullptr) {
- std::memcpy(dst, src, size);
+void AM_Load_Task(Asset &asset) {
+ std::ifstream file(asset.basePath, std::ios::ate | std::ios::binary);
+ if (!file.is_open()) {
+ asset.state = PKE_ASSET_LOADING_STATE_FAILED;
+ return;
}
- Asset *asset = &Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
- asset->ptr = dst;
- asset->size = size;
- int64_t keyLen = std::strlen(key);
- std::memcpy(asset->key, key, keyLen > 16 ? 16 : keyLen);
- return assetHandle;
+ asset.size = std::filesystem::file_size(asset.basePath);
+ asset.ptr = Pke_New(asset.size, 64);
+ file.seekg(0, std::ios::beg);
+ file.read(static_cast<char *>(asset.ptr), asset.size);
+ file.close();
+ asset.state = PKE_ASSET_LOADING_STATE_LOADED;
}
AssetHandle AM_Register(const void *data, int64_t size, std::size_t alignment, const char *key) {
assert(data != nullptr && "Attempt to register invalid asset data");
assert(data != CAFE_BABE(void) && "Attempt to register invalid asset data");
assert(size != 0 && "Attempt to register asset data of size 0");
- void *target = Pke_New(size, alignment);
- return AM_Register_Inner(data, target, size, key);
+ bool moved;
+ AssetHandle assetHandle{Buckets_NewHandle<AssetBucket>(maxAssetItemsPerBucket, Asset_BucketContainer, moved)};
+ Asset &asset = Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
+ new (&asset) Asset{};
+ int64_t keyLen = strlen(key);
+ int64_t keyOffset = (keyLen > 16 ? keyLen - 16 : 0);
+ strncpy(asset.key, key + keyOffset, 16);
+ asset.basePath = nullptr;
+ asset.size = size;
+ asset.ptr = Pke_New(size, alignment);
+ memcpy(asset.ptr, data, size);
+ asset.state = PKE_ASSET_LOADING_STATE_LOADED;
+ return assetHandle;
}
AssetHandle AM_Register(const char *path) {
- std::ifstream file(path, std::ios::ate | std::ios::binary);
- if (!file.is_open()) {
- throw "failed to open file";
- }
- auto fileSize = (int64_t)file.tellg();
- void *target = Pke_New(fileSize, alignof(uint64_t));
-
+ bool moved = false;
+ AssetHandle assetHandle{Buckets_NewHandle<AssetBucket>(maxAssetItemsPerBucket, Asset_BucketContainer, moved)};
+ Asset &asset = Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
+ new (&asset) Asset{};
int64_t pathLen = strlen(path);
- auto assetHandle = AM_Register_Inner(nullptr, target, 0, path + (pathLen > 16 ? pathLen - 16 : 0));
- Asset *asset = &Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
- file.seekg(0);
- file.read(static_cast<char *>(asset->ptr), fileSize);
- file.close();
- asset->size = fileSize;
+ int64_t pathOffset = (pathLen > 16 ? pathLen - 16 : 0);
+ strncpy(asset.key, path + pathOffset, 16);
+ auto *copiedPath = Pke_New<char>(pathLen + 1);
+ copiedPath[pathLen] = '\0';
+ strncpy(copiedPath, path, pathLen);
+ asset.basePath = copiedPath;
+ asset.state = PKE_ASSET_LOADING_STATE_LOADING;
+ std::packaged_task<void()> *task = Pke_New<std::packaged_task<void()>>();
+ new (task) std::packaged_task<void()>( [&asset] {
+ AM_Load_Task(asset);
+ });
+ asset.future = task->get_future();
+ PkeThreads_Enqueue(assetThreadPool, task);
return assetHandle;
}
-void AM_Destroy(AssetHandle assetHandle) {
+void AM_Release(AssetHandle assetHandle) {
assert(assetHandle != AssetHandle_MAX);
- Asset *asset = &Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
- Pke_Delete(asset->ptr, asset->size);
- asset->size = 0;
- asset->ptr = CAFE_BABE(void);
- if (assetHandle.itemIndex == Asset_BucketContainer.pkeHandle.itemIndex) {
- Asset_BucketContainer.pkeHandle.itemIndex -= 1;
- }
+ Asset &asset = Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
+ asset.referenceCount -= 1;
+ assert(asset.referenceCount >= 0 && "asset was unloaded more times than it was retrieved");
}
const Asset *AM_Get(AssetHandle assetHandle) {
- assert(assetHandle != AssetHandle_MAX);
- return &Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
+ auto validationResult = ValidateHandle(assetHandle, Asset_BucketContainer.pkeHandle, maxAssetItemsPerBucket);
+ assert(validationResult == 0);
+ auto &asset = Asset_BucketContainer.buckets[assetHandle.bucketIndex].assets[assetHandle.itemIndex];
+ if (asset.state == PKE_ASSET_LOADING_STATE_LOADED) {
+ asset.referenceCount += 1;
+ return &asset;
+ }
+ if (asset.state == PKE_ASSET_LOADING_STATE_UNLOADED) {
+ if (asset.basePath == nullptr) {
+ return nullptr;
+ }
+ asset.state = PKE_ASSET_LOADING_STATE_LOADING;
+ std::packaged_task<void()> *task = Pke_New<std::packaged_task<void()>>();
+ new (task) std::packaged_task<void()>( [&asset] {
+ AM_Load_Task(asset);
+ });
+ asset.future = task->get_future();
+ PkeThreads_Enqueue(assetThreadPool, task);
+ }
+ if (asset.state == PKE_ASSET_LOADING_STATE_LOADING) {
+ if (asset.future.valid()) {
+ asset.future.wait();
+ } else {
+ char buf[256];
+ buf[255] = '\0';
+ snprintf(buf, 255, "[AM_Get] Attempting to retrieve asset: '%.16s' which had a state of '%hhu', but did not have a valid future and thus cannot wait for completion", asset.key, asset.state);
+ throw buf;
+ }
+ }
+ if (asset.state == PKE_ASSET_LOADING_STATE_LOADED)
+ asset.referenceCount += 1;
+ return &asset;
}
void AM_DebugPrint() {
@@ -82,13 +132,40 @@ void AM_DebugPrint() {
continue;
*/
printf("-Asset: 0x%016lX\n", (b << 32) + i);
- printf("\tkey: %s\n", asset.key);
+ printf("\tkey: %.16s\n", asset.key);
+ if (asset.basePath != nullptr) {
+ printf("\tbasePath: %s\n", asset.basePath);
+ } else {
+ printf("\tbasePath: %p\n", nullptr);
+ }
printf("\tsize: %ld\n", asset.size);
printf("\tptr %p\n", asset.ptr);
+ printf("\tfuture: %i\n", asset.future.valid());
+ printf("\treferenceCount: %i\n", asset.referenceCount);
+ printf("\tAssetLoadingState: %hhu\n", asset.state);
+ }
+ }
+}
+
+void AM_GC() {
+ for (long b = 0; b <= Asset_BucketContainer.pkeHandle.bucketIndex; ++b) {
+ for (long i = 0; i < Asset_BucketContainer.pkeHandle.itemIndex; ++i) {
+ Asset &asset = Asset_BucketContainer.buckets[b].assets[i];
+ if (asset.referenceCount > 0)
+ continue;
+ if (asset.ptr != nullptr && asset.ptr != CAFE_BABE(void)) {
+ Pke_Delete(asset.ptr, asset.size);
+ }
+ asset.size = 0;
+ asset.ptr = CAFE_BABE(void);
+ asset.future = std::future<void>{};
+ asset.state = PKE_ASSET_LOADING_STATE_UNLOADED;
}
}
}
void AM_Teardown() {
+ AM_GC();
Buckets_Destroy(Asset_BucketContainer);
+ PkeThreads_Teardown(assetThreadPool);
}