rtengine/src/runtime/assetbak/asset_dependencies.c
Kevin Trogant 9670844bb2 Move towards using DXC for compiling shaders
This is recommended by the vulkan documentation.
2024-01-25 23:33:29 +01:00

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;
}