Add a resource namespace file format
This commit is contained in:
parent
0b6e855cef
commit
870f238410
@ -389,7 +389,6 @@ rt_loaded_asset LoadAsset(rt_file_id file) {
|
|||||||
size_t file_size = rtGetFileSize(path);
|
size_t file_size = rtGetFileSize(path);
|
||||||
|
|
||||||
void *buffer = rtAllocBuffer(file_size);
|
void *buffer = rtAllocBuffer(file_size);
|
||||||
rtLog("AC", "Buffer ptr %llx", (uintptr_t)buffer);
|
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
rtLog("AC", "Failed to allocate buffer for loading %s.", path);
|
rtLog("AC", "Failed to allocate buffer for loading %s.", path);
|
||||||
return (rt_loaded_asset){.buffer = NULL, .size = 0};
|
return (rt_loaded_asset){.buffer = NULL, .size = 0};
|
||||||
|
@ -156,7 +156,6 @@ RT_DLLEXPORT void *rtAllocBuffer(size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rtUnlockMutex(_guard);
|
rtUnlockMutex(_guard);
|
||||||
rtLog("BUFFERMGR", "Result ptr %llx", (uintptr_t)result);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ RT_CVAR_I(rt_MaxCachedResources,
|
|||||||
RT_CVAR_I(rt_ResourceNamespaceSize,
|
RT_CVAR_I(rt_ResourceNamespaceSize,
|
||||||
"The maximum number of resources that can exist. Default: 1.048.576",
|
"The maximum number of resources that can exist. Default: 1.048.576",
|
||||||
1048576);
|
1048576);
|
||||||
|
RT_CVAR_I(rt_DisableResourceNamespaceLoad,
|
||||||
|
"Disables the load of the saved resource namespace. Default: 0 (off)",
|
||||||
|
0);
|
||||||
|
|
||||||
#define RT_TOMBSTONE_ID 1
|
#define RT_TOMBSTONE_ID 1
|
||||||
|
|
||||||
@ -72,6 +75,18 @@ typedef struct {
|
|||||||
rt_rwlock lock;
|
rt_rwlock lock;
|
||||||
} rt_resource_namespace;
|
} rt_resource_namespace;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
rt_hash64 checksum;
|
||||||
|
uint32_t num_entries;
|
||||||
|
} rt_namespace_file_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rt_resource_id id;
|
||||||
|
rt_resource_ref ref;
|
||||||
|
} rt_namespace_file_entry;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
/* ~~~ Utilities ~~~ */
|
/* ~~~ Utilities ~~~ */
|
||||||
|
|
||||||
static size_t GetResourceDataSize(const rt_resource *resource) {
|
static size_t GetResourceDataSize(const rt_resource *resource) {
|
||||||
@ -107,25 +122,6 @@ static void CopyResourceData(const rt_resource *resource, void *dest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static rt_resource_ref *GetResourceRefPtr(rt_resource_id id) {
|
|
||||||
rt_resource_ref *ref = NULL;
|
|
||||||
rtLockRead(&_namespace.lock);
|
|
||||||
size_t ns_size = (size_t)rt_ResourceNamespaceSize.i;
|
|
||||||
for (size_t j = 0; j < ns_size; ++j) {
|
|
||||||
size_t at = (id + j) % ns_size;
|
|
||||||
if (_namespace.ids[at] == RT_INVALID_RESOURCE_ID) {
|
|
||||||
break;
|
|
||||||
} else if (_namespace.ids[at] == id) {
|
|
||||||
ref = &_namespace.refs[at];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rtUnlockRead(&_namespace.lock);
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Fills the passed write struct with the necessary information to save the resource to a file */
|
/* Fills the passed write struct with the necessary information to save the resource to a file */
|
||||||
static bool PrepareResourceFlushToFile(rt_resource_id id,
|
static bool PrepareResourceFlushToFile(rt_resource_id id,
|
||||||
const rt_resource *resource,
|
const rt_resource *resource,
|
||||||
@ -441,6 +437,79 @@ static void ShutdownNamespace(void) {
|
|||||||
memset(&_namespace, 0, sizeof(_namespace));
|
memset(&_namespace, 0, sizeof(_namespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LoadNamespace(void) {
|
||||||
|
char path[260];
|
||||||
|
rtSPrint(path, RT_ARRAY_COUNT(path), "%s/namespace.bin", rt_ResourceDirectory.s);
|
||||||
|
rt_file_id fid = rtAddFile(path);
|
||||||
|
size_t file_size = rtGetFileSize(path);
|
||||||
|
if (file_size == 0) {
|
||||||
|
rtLog("RESMGR", "Unable to determine size of %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||||
|
if (!temp.arena) {
|
||||||
|
rtLog("RESMGR", "Unable to get temporary arena for loading the namespace.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void *dest = rtArenaPush(temp.arena, file_size);
|
||||||
|
if (!dest) {
|
||||||
|
rtReturnTemporaryArena(temp);
|
||||||
|
rtLog("RESMGR", "Unable to allocate temporary space for loading the namespace.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_aio_state state = rtSubmitSingleLoadSync(
|
||||||
|
(rt_file_load){.file = fid, .num_bytes = file_size, .offset = 0, .dest = dest});
|
||||||
|
if (state == RT_AIO_STATE_FINISHED) {
|
||||||
|
const rt_namespace_file_header *header = dest;
|
||||||
|
const rt_namespace_file_entry *entries = (const rt_namespace_file_entry *)(header + 1);
|
||||||
|
|
||||||
|
if ((header->num_entries * sizeof(rt_namespace_file_entry)) <=
|
||||||
|
(file_size - sizeof(*header))) {
|
||||||
|
rt_hash64 entries_hash =
|
||||||
|
rtHashBytes(entries, sizeof(rt_namespace_file_entry) * header->num_entries);
|
||||||
|
if (entries_hash == header->checksum) {
|
||||||
|
size_t ns_size = (size_t)rt_ResourceNamespaceSize.i;
|
||||||
|
for (uint32_t i = 0; i < header->num_entries; ++i) {
|
||||||
|
bool inserted = false;
|
||||||
|
for (size_t j = 0; j < ns_size; ++j) {
|
||||||
|
size_t at = (entries[i].id + j) % ns_size;
|
||||||
|
if (_namespace.ids[at] == RT_INVALID_RESOURCE_ID) {
|
||||||
|
inserted = true;
|
||||||
|
_namespace.ids[at] = entries[i].id;
|
||||||
|
_namespace.refs[at] = entries[i].ref;
|
||||||
|
break;
|
||||||
|
} else if (_namespace.ids[at] == entries[i].id) {
|
||||||
|
rtReportError(
|
||||||
|
"RESMGR",
|
||||||
|
"Resource ID (%llx) collision detected in namespace file %s",
|
||||||
|
entries[i].id,
|
||||||
|
path);
|
||||||
|
rtReturnTemporaryArena(temp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inserted) {
|
||||||
|
rtReportError("RESMGR",
|
||||||
|
"Failed to insert namespace entry %llx",
|
||||||
|
entries[i].id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rtLog("RESMGR", "Checksum mismatch in %s", path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rtLog("RESMGR", "Number of entries in %s is inconsistent with the file size.", path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rtLog("RESMGR", "Failed to load %s.", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtReturnTemporaryArena(temp);
|
||||||
|
}
|
||||||
|
|
||||||
static rt_resource_ref GetResourceRef(rt_resource_id id) {
|
static rt_resource_ref GetResourceRef(rt_resource_id id) {
|
||||||
rt_resource_ref ref = {.file = RT_INVALID_FILE_ID};
|
rt_resource_ref ref = {.file = RT_INVALID_FILE_ID};
|
||||||
rtLockRead(&_namespace.lock);
|
rtLockRead(&_namespace.lock);
|
||||||
@ -472,6 +541,9 @@ rt_result InitResourceManager(void) {
|
|||||||
ShutdownResourceCache();
|
ShutdownResourceCache();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
if (!rt_DisableResourceNamespaceLoad.i) {
|
||||||
|
LoadNamespace();
|
||||||
|
}
|
||||||
return RT_SUCCESS;
|
return RT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,7 +808,7 @@ RT_DLLEXPORT rt_result rtCreateResources(uint32_t count,
|
|||||||
"Resource ID collision occured with resource %s.\nID: %llx",
|
"Resource ID collision occured with resource %s.\nID: %llx",
|
||||||
names[i],
|
names[i],
|
||||||
id);
|
id);
|
||||||
result = RT_INVALID_FILE_ID;
|
result = RT_INVALID_VALUE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,3 +930,61 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour
|
|||||||
rtLog("RESMGR", " unknown data at: %llx", (uintptr_t)resource->data);
|
rtLog("RESMGR", " unknown data at: %llx", (uintptr_t)resource->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RT_DLLEXPORT void rtSaveResourceNamespace(void) {
|
||||||
|
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||||
|
rtLockRead(&_namespace.lock);
|
||||||
|
uint32_t entry_count = 0;
|
||||||
|
for (size_t i = 0; i < (size_t)rt_ResourceNamespaceSize.i; ++i) {
|
||||||
|
if (_namespace.ids[i] != RT_INVALID_RESOURCE_ID)
|
||||||
|
++entry_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t buffer_size =
|
||||||
|
sizeof(rt_namespace_file_header) + entry_count * sizeof(rt_namespace_file_entry);
|
||||||
|
void *buffer = rtArenaPush(temp.arena, buffer_size);
|
||||||
|
if (!buffer) {
|
||||||
|
rtReportError(
|
||||||
|
"RESMGR",
|
||||||
|
"Failed to allocate temporary buffer (%zu bytes) for writing the namespace file");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_namespace_file_header *header = buffer;
|
||||||
|
rt_namespace_file_entry *entries = (rt_namespace_file_entry *)(header + 1);
|
||||||
|
size_t at = 0;
|
||||||
|
for (size_t i = 0; i < (size_t)rt_ResourceNamespaceSize.i; ++i) {
|
||||||
|
if (_namespace.ids[i] != RT_INVALID_RESOURCE_ID) {
|
||||||
|
entries[at].id = _namespace.ids[i];
|
||||||
|
entries[at].ref = _namespace.refs[i];
|
||||||
|
++at;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RT_ASSERT(at == entry_count, "");
|
||||||
|
header->num_entries = entry_count;
|
||||||
|
header->checksum = rtHashBytes(entries, entry_count * sizeof(rt_namespace_file_entry));
|
||||||
|
|
||||||
|
char path[260];
|
||||||
|
rtSPrint(path, RT_ARRAY_COUNT(path), "%s/namespace.bin", rt_ResourceDirectory.s);
|
||||||
|
|
||||||
|
rt_write_batch write = {.num_writes = 1};
|
||||||
|
write.writes[0] = (rt_file_write){
|
||||||
|
.file = rtAddFile(path),
|
||||||
|
.buffer = buffer,
|
||||||
|
.num_bytes = buffer_size,
|
||||||
|
.offset = 0,
|
||||||
|
};
|
||||||
|
rt_aio_handle handle;
|
||||||
|
if (rtSubmitWriteBatch(&write, &handle) != RT_SUCCESS) {
|
||||||
|
rtReportError("RESMGR", "Failed to submit the write for %s", path);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rt_aio_state state = rtWaitForAIOCompletion(handle);
|
||||||
|
rtReleaseAIO(handle);
|
||||||
|
if (state != RT_AIO_STATE_FINISHED)
|
||||||
|
rtReportError("RESMGR", "Write to %s failed: %u", path, state);
|
||||||
|
|
||||||
|
out:
|
||||||
|
rtUnlockRead(&_namespace.lock);
|
||||||
|
rtReturnTemporaryArena(temp);
|
||||||
|
}
|
@ -77,6 +77,8 @@ RT_DLLEXPORT size_t rtGetResourceSize(rt_resource_id id);
|
|||||||
/* Logs information about a resource. Useful for debugging */
|
/* Logs information about a resource. Useful for debugging */
|
||||||
RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resource);
|
RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resource);
|
||||||
|
|
||||||
|
RT_DLLEXPORT void rtSaveResourceNamespace(void);
|
||||||
|
|
||||||
/* Registers resources with the resource manager, making them available to the system.
|
/* Registers resources with the resource manager, making them available to the system.
|
||||||
*
|
*
|
||||||
* The runtime will create a standalone file for each resource in the resource directory.
|
* The runtime will create a standalone file for each resource in the resource directory.
|
||||||
|
Loading…
Reference in New Issue
Block a user