Move cutscene JSON parsing entirely into the async loader phase
File read, yyjson parse, and all item dispatch now happen in assetCutsceneLoaderAsync - none of it touches the main thread now that CUTSCENE items defer their nested asset resolution to start time. The sync phase is now just a state flip, kept only so assetUpdate()'s onLoaded dispatch (which only fires for entries finishing via the sync path) still runs. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -101,8 +101,6 @@ errorret_t assetCutsceneLoaderAsync(assetloading_t *loading) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
assertNull(loading->loading.cutscene.buffer, "Buffer already defined?");
|
||||
|
||||
assetfile_t *file = &loading->loading.cutscene.file;
|
||||
assetLoaderErrorChain(loading,
|
||||
assetFileInit(file, loading->entry->name, NULL, NULL)
|
||||
@@ -125,35 +123,17 @@ errorret_t assetCutsceneLoaderAsync(assetloading_t *loading) {
|
||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
||||
|
||||
loading->loading.cutscene.buffer = buffer;
|
||||
loading->loading.cutscene.size = fileSize;
|
||||
loading->loading.cutscene.state = ASSET_CUTSCENE_LOADING_STATE_PARSE;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_PENDING_SYNC;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetCutsceneLoaderSync(assetloading_t *loading) {
|
||||
assertNotNull(loading, "Loading cannot be NULL");
|
||||
assertTrue(loading->type == ASSET_LOADER_TYPE_CUTSCENE, "Invalid type.");
|
||||
assertIsMainThread("Must be called from the main thread.");
|
||||
|
||||
if(loading->loading.cutscene.state == ASSET_CUTSCENE_LOADING_STATE_INITIAL) {
|
||||
loading->loading.cutscene.state = ASSET_CUTSCENE_LOADING_STATE_READ_FILE;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_PENDING_ASYNC;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Parsing is pure CPU work with no main-thread dependency (every item
|
||||
// type's load callback just parses fields - see cutsceneCutsceneLoad's
|
||||
// doc comment for how CUTSCENE items avoid needing one), so it happens
|
||||
// right here instead of bouncing to the sync phase.
|
||||
assetcutsceneoutput_t *out = &loading->entry->data.cutscene;
|
||||
uint8_t *buffer = loading->loading.cutscene.buffer;
|
||||
assertNotNull(buffer, "Cutscene data should have been loaded by now.");
|
||||
size_t bufferSize = loading->loading.cutscene.size;
|
||||
|
||||
yyjson_doc *doc = yyjson_read(
|
||||
(char *)buffer, bufferSize,
|
||||
(char *)buffer, fileSize,
|
||||
YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS
|
||||
);
|
||||
memoryFree(buffer);
|
||||
loading->loading.cutscene.buffer = NULL;
|
||||
|
||||
if(doc == NULL) {
|
||||
assetLoaderErrorThrow(loading, "Failed to parse cutscene JSON");
|
||||
@@ -210,6 +190,31 @@ errorret_t assetCutsceneLoaderSync(assetloading_t *loading) {
|
||||
out->cutscene.pause = pause;
|
||||
out->cutscene.dataSize = 0;
|
||||
|
||||
loading->loading.cutscene.state = ASSET_CUTSCENE_LOADING_STATE_PARSE;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_PENDING_SYNC;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetCutsceneLoaderSync(assetloading_t *loading) {
|
||||
assertNotNull(loading, "Loading cannot be NULL");
|
||||
assertTrue(loading->type == ASSET_LOADER_TYPE_CUTSCENE, "Invalid type.");
|
||||
assertIsMainThread("Must be called from the main thread.");
|
||||
|
||||
if(loading->loading.cutscene.state == ASSET_CUTSCENE_LOADING_STATE_INITIAL) {
|
||||
loading->loading.cutscene.state = ASSET_CUTSCENE_LOADING_STATE_READ_FILE;
|
||||
loading->entry->state = ASSET_ENTRY_STATE_PENDING_ASYNC;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Everything else already happened in the async phase - see
|
||||
// assetCutsceneLoaderAsync. This flip still has to happen from here
|
||||
// rather than the async phase setting LOADED directly, since
|
||||
// assetUpdate() only fires an entry's onLoaded callback for entries
|
||||
// that finish via this sync path.
|
||||
assertTrue(
|
||||
loading->loading.cutscene.state == ASSET_CUTSCENE_LOADING_STATE_PARSE,
|
||||
"Unexpected cutscene loading state."
|
||||
);
|
||||
loading->entry->state = ASSET_ENTRY_STATE_LOADED;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -30,8 +30,6 @@ typedef enum {
|
||||
typedef struct {
|
||||
assetfile_t file;
|
||||
assetcutsceneloadingstate_t state;
|
||||
uint8_t *buffer;
|
||||
size_t size;
|
||||
} assetcutsceneloaderloading_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -80,8 +78,11 @@ void assetCutsceneFreeParsed(assetcutsceneoutput_t *out);
|
||||
|
||||
/**
|
||||
* Asynchronous loader for cutscene assets. Reads the raw JSONC file bytes
|
||||
* into the loading buffer so the sync phase can parse without blocking the
|
||||
* main thread on I/O.
|
||||
* and, in the same call, parses them into a heap-allocated cutsceneitem_t
|
||||
* array + pool - none of that work touches the main thread (every item
|
||||
* type's load callback is pure parsing now; CUTSCENE items defer their
|
||||
* nested asset resolution to cutsceneCutsceneStart), so doing it all here
|
||||
* keeps a large cutscene from ever blocking a frame.
|
||||
*
|
||||
* @param loading Loading information for the asset being loaded.
|
||||
* @return Error code indicating success or failure of the load operation.
|
||||
@@ -89,8 +90,11 @@ void assetCutsceneFreeParsed(assetcutsceneoutput_t *out);
|
||||
errorret_t assetCutsceneLoaderAsync(assetloading_t *loading);
|
||||
|
||||
/**
|
||||
* Synchronous loader for cutscene assets. Parses the JSONC previously read
|
||||
* by the async phase into a heap-allocated cutsceneitem_t array + pool.
|
||||
* Synchronous loader for cutscene assets. All actual work already
|
||||
* happened in the async phase - this only flips the entry to LOADED,
|
||||
* which must happen through this sync callback (rather than the async
|
||||
* phase setting it directly) so assetUpdate()'s onLoaded dispatch, which
|
||||
* only fires for entries finishing via the sync path, still runs.
|
||||
*
|
||||
* @param loading Loading information for the asset being loaded.
|
||||
* @return Error code indicating success or failure of the load operation.
|
||||
|
||||
Reference in New Issue
Block a user