diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2023-12-22 19:33:26 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2023-12-23 11:43:15 -0500 |
| commit | b911c5b6c37ab13be6188cf039cd4246414fc7b5 (patch) | |
| tree | da4743a719e8134abb35f87f5097541e09c8f581 /src/asset-manager.cpp | |
| parent | a3937e7eef97cb0badcd65c390b9dd39d4cfd094 (diff) | |
first pass background asset loading - buggy
Diffstat (limited to 'src/asset-manager.cpp')
| -rw-r--r-- | src/asset-manager.cpp | 155 |
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); } |
