diff --git a/meson.build b/meson.build index d500511..f089ae4 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,7 @@ runtime_lib = library('vyrt', # Project Sources 'src/runtime/aio.h', 'src/runtime/app.h', + 'src/runtime/asset_dependencies.h', 'src/runtime/assets.h', 'src/runtime/buffer_manager.h', 'src/runtime/config.h', @@ -65,6 +66,7 @@ runtime_lib = library('vyrt', 'src/runtime/aio.c', 'src/runtime/app.c', + 'src/runtime/asset_dependencies.c', 'src/runtime/buffer_manager.c', 'src/runtime/config.c', 'src/runtime/error_report.c', diff --git a/src/runtime/aio.c b/src/runtime/aio.c index e48a119..5a8732b 100644 --- a/src/runtime/aio.c +++ b/src/runtime/aio.c @@ -1,5 +1,6 @@ #include "aio.h" #include "threading.h" +#include "config.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -102,7 +103,12 @@ win32CompletionRoutine(DWORD error_code, DWORD num_bytes_transfered, LPOVERLAPPE } #endif -VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations) { +VY_CVAR_I(rt_MaxConcurrentAsyncIO, + "Maximum number of concurrent async. I/O operations. Default: 1024", + 1024); + +vy_result InitAIO(void) { + unsigned int max_concurrent_operations = rt_MaxConcurrentAsyncIO.i; _ringbuffer.guard = vyCreateMutex(); if (!_ringbuffer.guard) { return VY_AIO_OUT_OF_MEMORY; @@ -119,7 +125,7 @@ VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations) { return VY_SUCCESS; } -VY_DLLEXPORT void vyShutdownAIO(void) { +void ShutdownAIO(void) { vyDestroyMutex(_ringbuffer.guard); free(_ringbuffer.storage); _ringbuffer.capacity = 0; @@ -154,7 +160,6 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_hand .InternalHigh = 0, .Offset = (DWORD)(batch->loads[i].offset & MAXDWORD), .OffsetHigh = (DWORD)(batch->loads[i].offset >> 32), - .Pointer = NULL, }; WCHAR wpath[MAX_PATH]; @@ -255,4 +260,21 @@ VY_DLLEXPORT vy_aio_state vyWaitForAIOCompletion(vy_aio_handle handle) { #endif } while (state == VY_AIO_STATE_PENDING); return state; +} + + +VY_DLLEXPORT vy_result vySubmitSingleLoad(vy_file_load load, vy_aio_handle *handle) { + vy_load_batch batch; + batch.loads[0] = load; + batch.num_loads = 1; + return vySubmitLoadBatch(&batch, handle); +} + +VY_DLLEXPORT vy_aio_state vySubmitSingleLoadSync(vy_file_load load) { + vy_aio_handle handle; + if (vySubmitSingleLoad(load, &handle) != VY_SUCCESS) + return VY_AIO_STATE_FAILED; + vy_aio_state state = vyWaitForAIOCompletion(handle); + vyReleaseAIO(handle); + return state; } \ No newline at end of file diff --git a/src/runtime/aio.h b/src/runtime/aio.h index dc7b821..a481d22 100644 --- a/src/runtime/aio.h +++ b/src/runtime/aio.h @@ -47,14 +47,12 @@ typedef enum { VY_AIO_STATE_FAILED, } vy_aio_state; -VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations); - -VY_DLLEXPORT void vyShutdownAIO(void); - VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_handle *handles); VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle); +/* Blocks until the given operation is no longer pending. + * Returns the state that caused the wait to end. The handle is still valid after this function returned. */ VY_DLLEXPORT vy_aio_state vyWaitForAIOCompletion(vy_aio_handle handle); /* Releases the internal storage for the operation. @@ -62,5 +60,10 @@ VY_DLLEXPORT vy_aio_state vyWaitForAIOCompletion(vy_aio_handle handle); */ VY_DLLEXPORT void vyReleaseAIO(vy_aio_handle handle); +VY_DLLEXPORT vy_result vySubmitSingleLoad(vy_file_load load, vy_aio_handle *handle); + +/* Convenience wrapper for a single synchronous file load. + * Returns the state that caused the wait for completion to return. */ +VY_DLLEXPORT vy_aio_state vySubmitSingleLoadSync(vy_file_load load); #endif diff --git a/src/runtime/asset_dependencies.c b/src/runtime/asset_dependencies.c new file mode 100644 index 0000000..58bd341 --- /dev/null +++ b/src/runtime/asset_dependencies.c @@ -0,0 +1,137 @@ +#define VY_DEFINE_DEPENDENCY_FILE_STRUCTURES +#include "asset_dependencies.h" + +#include "aio.h" +#include "buffer_manager.h" + +#include +#include +#include +#include + +typedef struct { + uint32_t begin; + uint32_t count; +} vy_dep_list; + +typedef struct { + vy_uid *uids; + vy_dep_list *lists; + uint32_t capacity; +} vy_dep_map; + +static vy_dep_map _map; +static vy_uid *_list_mem; + +vy_result LoadAssetDependencies(void) { + vy_dependency_file_header header; + vy_file_id fid = vyAddFile("assets/deps.bin"); + + if (vySubmitSingleLoadSync((vy_file_load){.dest = &header, + .num_bytes = sizeof(header), + .offset = 0, + .file = fid}) != VY_AIO_STATE_FINISHED) { + vyReportError("core", "Failed to load deps.bin"); + return VY_UNKNOWN_ERROR; + } + void *buffer = vyAllocBuffer(header.data_size); + if (vySubmitSingleLoadSync((vy_file_load){.dest = buffer, + .num_bytes = header.data_size, + .offset = sizeof(header), + .file = fid}) != VY_AIO_STATE_FINISHED) { + vyReportError("core", "Failed to load deps.bin"); + return VY_UNKNOWN_ERROR; + } + + /* We know the exact number of list entries */ + uint64_t total_list_entries = + (header.data_size - header.num_lists * sizeof(vy_dependency_file_list_header)) / + sizeof(vy_uid); + _list_mem = malloc(total_list_entries * sizeof(vy_uid)); + if (!_list_mem) { + vyReleaseBuffer(buffer, header.data_size); + vyReportError("core", "Failed to allocate dependency list storage."); + return VY_UNKNOWN_ERROR; + } + + _map.capacity = vyNextPowerOfTwo32(header.num_lists); + _map.uids = calloc(_map.capacity, sizeof(vy_uid)); + if (!_map.uids) { + free(_list_mem); + vyReleaseBuffer(buffer, header.data_size); + vyReportError("core", "Failed to allocate dependency list storage."); + return VY_UNKNOWN_ERROR; + } + + _map.lists = calloc(_map.capacity, sizeof(vy_dep_list)); + if (!_map.uids) { + free(_list_mem); + free(_map.uids); + vyReleaseBuffer(buffer, header.data_size); + vyReportError("core", "Failed to allocate dependency list storage."); + return VY_UNKNOWN_ERROR; + } + + uint32_t storage_at = 0; + + vy_dependency_file_list_header *list = buffer; + for (uint32_t i = 0; i < header.num_lists; ++i) { + const vy_uid *entries = (vy_uid *)(list + 1); + + /* Validate the checksum */ + XXH64_hash_t file_hash = XXH64_hashFromCanonical(&list->checksum); + XXH64_hash_t calc_hash = XXH3_64bits(entries, sizeof(vy_uid) * list->num_entries); + if (file_hash != calc_hash) { + vyReportError("core", "Checksum mismatch in list %u", i); + vyReleaseBuffer(buffer, header.data_size); + return VY_UNKNOWN_ERROR; + } + + /* Store the list */ + memcpy(_list_mem + storage_at, entries, sizeof(vy_uid) * list->num_entries); + bool inserted = false; + for (uint32_t j = 0; j < _map.capacity; ++j) { + uint32_t slot = (list->uid + j) % _map.capacity; + if (_map.uids[slot] == VY_INVALID_UID) { + _map.uids[slot] = list->uid; + _map.lists[slot].begin = storage_at; + _map.lists[slot].count = list->num_entries; + inserted = true; + break; + } + } + storage_at += list->num_entries; + assert(inserted); + assert(storage_at <= total_list_entries); + + list = (vy_dependency_file_list_header *)(entries + list->num_entries); + } + + vyReleaseBuffer(buffer, header.data_size); + + return VY_SUCCESS; +} + +void ReleaseAssetDependencies(void) { + free(_list_mem); + free(_map.uids); + free(_map.lists); +} + +VY_DLLEXPORT vy_asset_dependency_list vyGetAssetDependencies(vy_uid asset) { + vy_asset_dependency_list result = { + .dependencies = NULL, + .count = 0, + }; + for (uint32_t i = 0; i < _map.capacity; ++i) { + uint32_t slot = (asset + i) % _map.capacity; + if (_map.uids[slot] == asset) { + result.dependencies = &_list_mem[_map.lists[slot].begin]; + result.count = _map.lists[slot].count; + break; + } else if (_map.uids[slot] == VY_INVALID_UID) { + break; + } + } + return result; +} \ No newline at end of file diff --git a/src/runtime/asset_dependencies.h b/src/runtime/asset_dependencies.h new file mode 100644 index 0000000..71f963e --- /dev/null +++ b/src/runtime/asset_dependencies.h @@ -0,0 +1,33 @@ +#ifndef VY_ASSET_DEPENDENCIES_H +#define VY_ASSET_DEPENDENCIES_H + +#include "assets.h" + +#ifdef VY_DEFINE_DEPENDENCY_FILE_STRUCTURES + +#include "xxhash/xxhash.h" + +#pragma pack(push, 1) +typedef struct { + uint64_t data_size; + uint32_t num_lists; +} vy_dependency_file_header; + +typedef struct { + vy_uid uid; + uint32_t num_entries; + XXH64_canonical_t checksum; +} vy_dependency_file_list_header; + +#pragma pack(pop) + +#endif + +typedef struct { + const vy_uid *dependencies; + uint32_t count; +} vy_asset_dependency_list; + +VY_DLLEXPORT vy_asset_dependency_list vyGetAssetDependencies(vy_uid asset); + +#endif diff --git a/src/runtime/buffer_manager.c b/src/runtime/buffer_manager.c index 21601d1..d769a3c 100644 --- a/src/runtime/buffer_manager.c +++ b/src/runtime/buffer_manager.c @@ -57,7 +57,7 @@ VY_CVAR_SZ(rt_BufferManagerMemory, "Total number of bytes allocated for the buffer manager. Default: 1GB", VY_GB(1)); -VY_DLLEXPORT vy_result vyInitBufferManager(void) { +vy_result InitBufferManager(void) { if ((rt_BufferManagerMemory.sz % NUM_BLOCK_SIZES) != 0) vyLog("BUFFERMGR", "Configured memory amount is not dividable by number of block " @@ -106,7 +106,7 @@ VY_DLLEXPORT vy_result vyInitBufferManager(void) { return VY_SUCCESS; } -VY_DLLEXPORT void vyShutdownBufferManager(void) { +void ShutdownBufferManager(void) { for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) { vyDestroyMutex(_regions[i].guard); free(_regions[i].memory); diff --git a/src/runtime/buffer_manager.h b/src/runtime/buffer_manager.h index cf5e2d1..e978e2d 100644 --- a/src/runtime/buffer_manager.h +++ b/src/runtime/buffer_manager.h @@ -8,10 +8,6 @@ enum { VY_BUFFER_MGR_MUTEX_CREATION_FAILED, }; -VY_DLLEXPORT vy_result vyInitBufferManager(void); - -VY_DLLEXPORT void vyShutdownBufferManager(void); - VY_DLLEXPORT void *vyAllocBuffer(size_t size); VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size); diff --git a/src/runtime/file_tab.c b/src/runtime/file_tab.c index ab3e060..589cf5a 100644 --- a/src/runtime/file_tab.c +++ b/src/runtime/file_tab.c @@ -1,5 +1,6 @@ #include "file_tab.h" #include "threading.h" +#include "config.h" #include @@ -16,7 +17,10 @@ typedef struct { static vy_file_tab _file_tab; -vy_result vyInitFileTab(unsigned int max_files) { +VY_CVAR_I(rt_FileTabCapacity, "Maximum number of filetab entries. Default: 1024", 1024); + +vy_result InitFileTab(void) { + unsigned int max_files = (unsigned int)rt_FileTabCapacity.i; _file_tab.ids = calloc(max_files, sizeof(vy_file_id)); if (!_file_tab.ids) return 1; @@ -33,21 +37,21 @@ vy_result vyInitFileTab(unsigned int max_files) { return VY_SUCCESS; } -void vyShutdownFileTab(void) { +void ShutdownFileTab(void) { free(_file_tab.ids); free(_file_tab.names); free(_file_tab.name_offsets); vyDestroyMutex(_file_tab.mutex); } -vy_file_id vyGetFileId(const char *path) { +VY_DLLEXPORT vy_file_id vyGetFileId(const char *path) { vy_text_span span; span.start = path; span.length = (unsigned int)strlen(path); return vyGetFileIdFromSpan(span); } -vy_file_id vyGetFileIdFromSpan(vy_text_span path) { +VY_DLLEXPORT vy_file_id vyGetFileIdFromSpan(vy_text_span path) { /* Randomly choosen, aka finger smash keyboard */ XXH64_hash_t seed = 15340978; vy_file_id fid = (vy_file_id)XXH3_64bits_withSeed(path.start, path.length, seed); diff --git a/src/runtime/file_tab.h b/src/runtime/file_tab.h index 6f69b15..8bc8a1d 100644 --- a/src/runtime/file_tab.h +++ b/src/runtime/file_tab.h @@ -9,10 +9,6 @@ typedef uint64_t vy_file_id; #define VY_INVALID_FILE_ID 0 -VY_DLLEXPORT vy_result vyInitFileTab(unsigned int max_files); - -VY_DLLEXPORT void vyShutdownFileTab(void); - VY_DLLEXPORT vy_file_id vyGetFileId(const char *path); VY_DLLEXPORT vy_file_id vyGetFileIdFromSpan(vy_text_span path); diff --git a/src/runtime/init.c b/src/runtime/init.c index eccf318..8b170f0 100644 --- a/src/runtime/init.c +++ b/src/runtime/init.c @@ -10,47 +10,69 @@ extern vy_cvar rt_Fullscreen; extern vy_cvar rt_WindowWidth; extern vy_cvar rt_WindowHeight; extern vy_cvar rt_BufferManagerMemory; +extern vy_cvar rt_FileTabCapacity; +extern vy_cvar rt_MaxConcurrentAsyncIO; -void __RegisterRuntimeCVars(void) { +void RegisterRuntimeCVars(void) { vyRegisterCVAR(&rt_Renderer); vyRegisterCVAR(&rt_Fullscreen); vyRegisterCVAR(&rt_WindowWidth); vyRegisterCVAR(&rt_WindowHeight); vyRegisterCVAR(&rt_BufferManagerMemory); + vyRegisterCVAR(&rt_FileTabCapacity); + vyRegisterCVAR(&rt_MaxConcurrentAsyncIO); } -extern void __RTSetMainThreadId(void); +extern void SetMainThreadId(void); + +extern vy_result InitBufferManager(void); +extern void ShutdownBufferManager(void); +extern vy_result InitFileTab(void); +extern void ShutdownFileTab(void); +extern vy_result InitAIO(void); +extern void ShutdownAIO(void); + +extern vy_result LoadUIDTable(void); +extern void ReleaseUIDTable(void); +extern vy_result LoadAssetDependencies(void); +extern void ReleaseAssetDependencies(void); VY_DLLEXPORT vy_result vyInitRuntime(void) { - __RTSetMainThreadId(); - __RegisterRuntimeCVars(); + SetMainThreadId(); + RegisterRuntimeCVars(); vy_result res; - if ((res = vyInitBufferManager()) != VY_SUCCESS) { + if ((res = InitBufferManager()) != VY_SUCCESS) { vyReportError("BUFFERMGR", "Init failed."); return res; } - if ((res = vyInitFileTab(1024)) != VY_SUCCESS) { + if ((res = InitFileTab()) != VY_SUCCESS) { vyReportError("FTAB", "Init failed."); return res; } - if ((res = vyInitAIO(0)) != VY_SUCCESS) { + if ((res = InitAIO()) != VY_SUCCESS) { vyReportError("AIO", "Init failed."); return res; } - if ((res = vyLoadUIDTable()) != VY_SUCCESS) { + if ((res = LoadUIDTable()) != VY_SUCCESS) { vyLog("CORE", "LoadUIDTable returned result: %u", res); } + if ((res = LoadAssetDependencies()) != VY_SUCCESS) { + vyReportError("ASSETDEP", "Init failed."); + return res; + } + return VY_SUCCESS; } VY_DLLEXPORT void vyShutdownRuntime(void) { - vyReleaseUIDTable(); - vyShutdownAIO(); - vyShutdownFileTab(); - vyShutdownBufferManager(); + ReleaseAssetDependencies(); + ReleaseUIDTable(); + ShutdownAIO(); + ShutdownFileTab(); + ShutdownBufferManager(); } \ No newline at end of file diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 2c7baae..f878bb8 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -87,6 +87,21 @@ static VY_INLINE void vySetRelptr(vy_relptr *ptr, void *target) { } } +/* Bitfiddling functions */ + +/* Portable solution, On x64 using clzl is probably faster. */ +static VY_INLINE uint32_t vyNextPowerOfTwo32(uint32_t v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + + /* Runtime init. Initializes basic systems. * You need to call this, even if you build a CLI only app. */ VY_DLLEXPORT vy_result vyInitRuntime(void); diff --git a/src/runtime/threading_thread.c b/src/runtime/threading_thread.c index 582fd93..cee32ee 100644 --- a/src/runtime/threading_thread.c +++ b/src/runtime/threading_thread.c @@ -28,7 +28,7 @@ static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT; static vy_thread_id _main_thread_id; /* Called by the runtime during setup */ -extern void __RTSetMainThreadId(void) { +extern void SetMainThreadId(void) { _main_thread_id = (vy_thread_id)GetCurrentThreadId(); } diff --git a/src/runtime/uidtab.c b/src/runtime/uidtab.c index f5014bf..7bc7325 100644 --- a/src/runtime/uidtab.c +++ b/src/runtime/uidtab.c @@ -17,23 +17,11 @@ typedef struct { static vy_uidtab _tab; -/* Portable solution, On x64 using clzl is probably faster. */ -static uint32_t NextPowerOfTwo(uint32_t v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -VY_DLLEXPORT vy_result vyLoadUIDTable(void) { +vy_result LoadUIDTable(void) { /* We use stdio here, because we cannot load any asset in parallel to this. * This is because the uidtab is what tells us which assets exist. */ - FILE *f = fopen("uidtab.bin", "rb"); + FILE *f = fopen("assets/uidtab.bin", "rb"); if (!f) return VY_LOAD_FAILED; @@ -52,7 +40,7 @@ VY_DLLEXPORT vy_result vyLoadUIDTable(void) { } */ - _tab.slots = NextPowerOfTwo(header.num_entries * 2); + _tab.slots = vyNextPowerOfTwo32(header.num_entries * 2); void *mem = malloc((sizeof(vy_uid) + sizeof(vy_uid_data)) * _tab.slots); if (!mem) { fclose(f); @@ -114,7 +102,7 @@ VY_DLLEXPORT vy_result vyLoadUIDTable(void) { return VY_SUCCESS; } -VY_DLLEXPORT void vyReleaseUIDTable(void) { +void ReleaseUIDTable(void) { free(_tab.uids); _tab.slots = 0; } diff --git a/src/runtime/uidtab.h b/src/runtime/uidtab.h index fb8e5d6..d8ee118 100644 --- a/src/runtime/uidtab.h +++ b/src/runtime/uidtab.h @@ -31,8 +31,6 @@ typedef struct { uint64_t size; } vy_uid_data; -VY_DLLEXPORT vy_result vyLoadUIDTable(void); -VY_DLLEXPORT void vyReleaseUIDTable(void); VY_DLLEXPORT const vy_uid_data *vyGetUIDData(vy_uid uid); #endif \ No newline at end of file diff --git a/src/tools/assetc/assetc.c b/src/tools/assetc/assetc.c index 30a3b5e..7bbdc60 100644 --- a/src/tools/assetc/assetc.c +++ b/src/tools/assetc/assetc.c @@ -102,9 +102,6 @@ int main(int argc, char **argv) { vyInitPackages(); vySetWorkingDirectory(g_assetc_options.root_directory); - /* Explictily reload uidtab, because we changed the working directory here */ - vyLoadUIDTable(); - if (vyLoadAssetMeta() != VY_SUCCESS) { return 1; } @@ -136,6 +133,9 @@ int main(int argc, char **argv) { if (vyWriteUIDTab() != VY_SUCCESS) { return 1; } + if (vySaveAssetDependencies() != VY_SUCCESS) { + return 1; + } vyShutdownRuntime(); diff --git a/src/tools/assetc/dependency_tracking.c b/src/tools/assetc/dependency_tracking.c index 4c925da..5fc7e3d 100644 --- a/src/tools/assetc/dependency_tracking.c +++ b/src/tools/assetc/dependency_tracking.c @@ -1,13 +1,16 @@ #include "dependency_tracking.h" +#define VY_DEFINE_DEPENDENCY_FILE_STRUCTURES #include "runtime/assets.h" #include "runtime/threading.h" +#include "runtime/asset_dependencies.h" #include #include #include #include #include +#include /* Track a list of dependencies per asset. @@ -125,3 +128,101 @@ vy_result vyAddAssetDependency(vy_uid dependent, vy_uid dependency) { res = InsertIntoList(dependency, dependent, 1); return res; } + +vy_result vySaveAssetDependencies(void) { + assert(vyIsMainThread()); + vy_dependency_file_header header = {.num_lists = 0, .data_size = 0}; + + for (size_t i = 0; i < MAP_SIZE; ++i) { + if (_uids[i] != VY_INVALID_UID) { + if (!_lists[i].dependencies) + continue; + header.num_lists += 1; + + /* Determine the list size */ + vy_dep_list_bucket *bucket = &_buckets[_lists[i].dependencies]; + uint32_t total_list_size = bucket->count; + while (bucket->next != END_OF_LIST) { + bucket = &_buckets[bucket->next]; + total_list_size += bucket->count; + } + + header.data_size += total_list_size * sizeof(vy_uid) + sizeof(vy_dependency_file_list_header); + } + } + + FILE *f = fopen("deps.bin", "wb"); + if (!f) { + vyReportError("ASSETC", "Failed to open 'deps.bin' for writing."); + return VY_UNKNOWN_ERROR; + } + + + if (fwrite(&header, sizeof(header), 1, f) != 1) { + vyReportError("ASSETC", "Failed to write to 'deps.bin'."); + fclose(f); + return VY_UNKNOWN_ERROR; + } + + void *buffer = NULL; + size_t buffer_size = 0; + + for (size_t i = 0; i < MAP_SIZE; ++i) { + if (_uids[i] != VY_INVALID_UID) { + if (!_lists[i].dependencies) + continue; + + /* Determine the list size */ + vy_dep_list_bucket *bucket = &_buckets[_lists[i].dependencies]; + uint32_t total_list_size = bucket->count; + while (bucket->next != END_OF_LIST) { + bucket = &_buckets[bucket->next]; + total_list_size += bucket->count; + } + + /* Allocate */ + size_t required_size = + total_list_size * sizeof(vy_uid) + sizeof(vy_dependency_file_list_header); + if (required_size > buffer_size) { + void *t = realloc(buffer, required_size); + if (!t) { + free(buffer); + fclose(f); + return VY_UNKNOWN_ERROR; + } + buffer = t; + buffer_size = required_size; + } + + /* Fill header */ + vy_dependency_file_list_header *list_header = buffer; + vy_uid *list = (vy_uid *)(list_header + 1); + list_header->uid = _uids[i]; + list_header->num_entries = total_list_size; + + /* Copy the list */ + uint32_t at = 0; + bucket = &_buckets[_lists[i].dependencies]; + do { + memcpy(&list[at], bucket->entries, sizeof(vy_uid) * bucket->count); + at += bucket->count; + bucket = &_buckets[bucket->next]; + } while (bucket != &_buckets[END_OF_LIST]); + + XXH64_hash_t hash = XXH3_64bits(list, sizeof(vy_uid) * total_list_size); + XXH64_canonicalFromHash(&list_header->checksum, hash); + + if (fwrite(buffer, required_size, 1, f) != 1) { + vyReportError("ASSETC", "Failed to write to 'deps.bin'."); + fclose(f); + free(buffer); + return VY_UNKNOWN_ERROR; + } + } + } + + fclose(f); + free(buffer); + + return VY_SUCCESS; +} \ No newline at end of file diff --git a/src/tools/assetc/dependency_tracking.h b/src/tools/assetc/dependency_tracking.h index e53e6cc..ace55ca 100644 --- a/src/tools/assetc/dependency_tracking.h +++ b/src/tools/assetc/dependency_tracking.h @@ -9,4 +9,6 @@ vy_result vyInitDependencyTracking(void); vy_result vyAddAssetDependency(vy_uid dependent, vy_uid dependency); +vy_result vySaveAssetDependencies(void); + #endif diff --git a/src/tools/assetc/discovery.c b/src/tools/assetc/discovery.c index afc4a92..d3b234e 100644 --- a/src/tools/assetc/discovery.c +++ b/src/tools/assetc/discovery.c @@ -33,6 +33,10 @@ static vy_result DirectoryHandler(const char *name, vyIterateDirElementType type else if (memcmp(&name[name_len - 4], ".bin", 4) == 0) return VY_SUCCESS; } + if (name[0] == '.') { + return VY_SUCCESS; + } + /* Check if we know that file */ if (data->path_end > 0) { data->path_scratch[data->path_end] = '/';