From a358fbc9f4ba3a7b01f600109fc86aeb2fcf96b8 Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 1 Feb 2026 12:06:37 +0100 Subject: feat(asset_manager): Implement array-based caching - Refactored asset manager to use a static array for caching, improving performance and memory efficiency. - Updated asset_packer to correctly generate ASSET_LAST_ID for array sizing. - Modified asset_manager.h to use a forward declaration for AssetId. - Updated asset_manager.cc to use the conditional include for generated asset headers. - Added a test case in test_assets to verify the array-based cache and ASSET_LAST_ID logic. --- src/util/asset_manager.cc | 70 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-) (limited to 'src/util/asset_manager.cc') diff --git a/src/util/asset_manager.cc b/src/util/asset_manager.cc index 30295b9..3874535 100644 --- a/src/util/asset_manager.cc +++ b/src/util/asset_manager.cc @@ -1,30 +1,82 @@ // This file is part of the 64k demo project. -// It implements the generic asset retrieval logic. -// Uses an array lookup for O(1) access to embedded data. +// It implements the generic asset retrieval logic with runtime caching. #include "util/asset_manager.h" +#if defined(USE_TEST_ASSETS) +#include "generated/test_assets.h" +#else #include "generated/assets.h" +#endif /* defined(USE_TEST_ASSETS) */ + +#include // For potential dynamic allocation for procedural assets +#include // For placement new +#include // For free // These are defined in the generated assets_data.cc +#if defined(USE_TEST_ASSETS) +extern const AssetRecord g_assets[]; +extern const size_t g_assets_count; +#else extern const AssetRecord g_assets[]; extern const size_t g_assets_count; +#endif +// Array-based cache for assets. +// Initialized to all zeros (nullptr data, 0 size, false is_procedural) +// The size is derived from the generated ASSET_LAST_ID enum value. +static AssetRecord g_asset_cache[(size_t)AssetId::ASSET_LAST_ID] = {}; const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) { uint16_t index = (uint16_t)asset_id; + + // Assert that ASSET_LAST_ID is not used for retrieval. + // This ensures the size of the cache is correctly used and not accessed out of bounds. + // If this assert fails, it means assets.txt has an ID larger than expected + // or ASSET_LAST_ID is not correctly generated/updated. + // This is a design decision: ASSET_LAST_ID is purely for sizing and range checking, + // not for a valid asset retrieval itself. + if (index >= (uint16_t)AssetId::ASSET_LAST_ID) { + if (out_size) + *out_size = 0; + return nullptr; // Invalid asset_id + } + + // Check cache first + if (g_asset_cache[index].data != nullptr) { + if (out_size) + *out_size = g_asset_cache[index].size; + return g_asset_cache[index].data; + } + + // Not in cache, retrieve from static data (packed in binary) if (index >= g_assets_count) { if (out_size) *out_size = 0; - return nullptr; + return nullptr; // This asset is not in the static packed data either. } - const AssetRecord& record = g_assets[index]; + // Store static record in cache for future use + g_asset_cache[index] = g_assets[index]; + g_asset_cache[index].is_procedural = false; + if (out_size) - *out_size = record.size; - return record.data; + *out_size = g_asset_cache[index].size; + return g_asset_cache[index].data; } void DropAsset(AssetId asset_id, const uint8_t* asset) { - (void)asset_id; - (void)asset; - // Implementation for lazy decompression will go here + uint16_t index = (uint16_t)asset_id; + if (index >= (uint16_t)AssetId::ASSET_LAST_ID) { + return; // Invalid asset_id + } + + // Only free memory for procedural assets. + if (g_asset_cache[index].is_procedural && g_asset_cache[index].data == asset) { + // In a more complex scenario, we might track ref counts. + // For this demo, we assume a single owner for dynamically allocated assets. + delete[] g_asset_cache[index].data; // Assuming `new uint8_t[]` was used for procedural + g_asset_cache[index].data = nullptr; + g_asset_cache[index].size = 0; + g_asset_cache[index].is_procedural = false; + } + // For static assets, no dynamic memory to free. } -- cgit v1.2.3