137 lines
4.5 KiB
C
137 lines
4.5 KiB
C
#define RT_DEFINE_DEPENDENCY_FILE_STRUCTURES
|
|
#include "asset_dependencies.h"
|
|
|
|
#include "aio.h"
|
|
#include "buffer_manager.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
typedef struct {
|
|
uint32_t begin;
|
|
uint32_t count;
|
|
} rt_dep_list;
|
|
|
|
typedef struct {
|
|
rt_uid *uids;
|
|
rt_dep_list *lists;
|
|
uint32_t capacity;
|
|
} rt_dep_map;
|
|
|
|
static rt_dep_map _map;
|
|
static rt_uid *_list_mem;
|
|
|
|
rt_result LoadAssetDependencies(void) {
|
|
rt_dependency_file_header header;
|
|
rt_file_id fid = rtAddFile("data/deps.bin");
|
|
|
|
if (rtSubmitSingleLoadSync((rt_file_load){.dest = &header,
|
|
.num_bytes = sizeof(header),
|
|
.offset = 0,
|
|
.file = fid}) != RT_AIO_STATE_FINISHED) {
|
|
rtReportError("core", "Failed to load deps.bin");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
void *buffer = rtAllocBuffer(header.data_size);
|
|
if (rtSubmitSingleLoadSync((rt_file_load){.dest = buffer,
|
|
.num_bytes = header.data_size,
|
|
.offset = sizeof(header),
|
|
.file = fid}) != RT_AIO_STATE_FINISHED) {
|
|
rtReportError("core", "Failed to load deps.bin");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
/* We know the exact number of list entries */
|
|
uint64_t total_list_entries =
|
|
(header.data_size - header.num_lists * sizeof(rt_dependency_file_list_header)) /
|
|
sizeof(rt_uid);
|
|
_list_mem = malloc(total_list_entries * sizeof(rt_uid));
|
|
if (!_list_mem) {
|
|
rtReleaseBuffer(buffer, header.data_size);
|
|
rtReportError("core", "Failed to allocate dependency list storage.");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
_map.capacity = rtNextPowerOfTwo32(header.num_lists);
|
|
_map.uids = calloc(_map.capacity, sizeof(rt_uid));
|
|
if (!_map.uids) {
|
|
free(_list_mem);
|
|
rtReleaseBuffer(buffer, header.data_size);
|
|
rtReportError("core", "Failed to allocate dependency list storage.");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
_map.lists = calloc(_map.capacity, sizeof(rt_dep_list));
|
|
if (!_map.uids) {
|
|
free(_list_mem);
|
|
free(_map.uids);
|
|
rtReleaseBuffer(buffer, header.data_size);
|
|
rtReportError("core", "Failed to allocate dependency list storage.");
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
uint32_t storage_at = 0;
|
|
|
|
rt_dependency_file_list_header *list = buffer;
|
|
for (uint32_t i = 0; i < header.num_lists; ++i) {
|
|
const rt_uid *entries = (rt_uid *)(list + 1);
|
|
|
|
/* Validate the checksum */
|
|
XXH64_hash_t file_hash = XXH64_hashFromCanonical(&list->checksum);
|
|
XXH64_hash_t calc_hash = XXH3_64bits(entries, sizeof(rt_uid) * list->num_entries);
|
|
if (file_hash != calc_hash) {
|
|
rtReportError("core", "Checksum mismatch in list %u", i);
|
|
rtReleaseBuffer(buffer, header.data_size);
|
|
return RT_UNKNOWN_ERROR;
|
|
}
|
|
|
|
/* Store the list */
|
|
memcpy(_list_mem + storage_at, entries, sizeof(rt_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] == RT_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 = (rt_dependency_file_list_header *)(entries + list->num_entries);
|
|
}
|
|
|
|
rtReleaseBuffer(buffer, header.data_size);
|
|
|
|
return RT_SUCCESS;
|
|
}
|
|
|
|
void ReleaseAssetDependencies(void) {
|
|
free(_list_mem);
|
|
free(_map.uids);
|
|
free(_map.lists);
|
|
}
|
|
|
|
RT_DLLEXPORT rt_asset_dependency_list rtGetAssetDependencies(rt_uid asset) {
|
|
rt_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] == RT_INVALID_UID) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
} |