diff --git a/CMakeLists.txt b/CMakeLists.txt index 9508ac193..b0fc3c808 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,16 +20,18 @@ include_directories(${CMAKE_SOURCE_DIR}/src/arm) include_directories(${CMAKE_SOURCE_DIR}/src/gba) include_directories(${CMAKE_SOURCE_DIR}/src) +set(BUILD_PGO CACHE BOOL "Build with profiling-guided optimization") +set(PGO_STAGE_2 CACHE BOOL "Rebuild for profiling-guided optimization after profiles have been generated") set(PGO_DIR "/tmp/gba-pgo/" CACHE PATH "Profiling-guided optimization profiles path") -mark_as_advanced(PGO_DIR) +mark_as_advanced(BUILD_PGO PGO_STAGE_2 PGO_DIR) set(PGO_PRE_FLAGS "-pg -fprofile-generate=${PGO_DIR}") set(PGO_POST_FLAGS "-fprofile-use=${PGO_DIR}") -if(PGO_STAGE EQUAL 1) +if(BUILD_PGO AND NOT PGO_STAGE_2) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${PGO_PRE_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PGO_PRE_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${PGO_PRE_FLAGS}") -elseif(PGO_STAGE EQUAL 2) +elseif(BUILD_PGO AND PGO_STAGE_2) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${PGO_POST_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PGO_POST_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${PGO_POST_FLAGS}") diff --git a/src/gba/gba-rr.c b/src/gba/gba-rr.c index f94a4da8e..3e8cd6b3d 100644 --- a/src/gba/gba-rr.c +++ b/src/gba/gba-rr.c @@ -41,7 +41,7 @@ void GBARRContextDestroy(struct GBA* gba) { gba->rr = 0; } -bool GBARRSetStream(struct GBARRContext* rr, struct VDir* stream) { +bool GBARRInitStream(struct GBARRContext* rr, struct VDir* stream) { if (rr->movieStream && !rr->movieStream->close(rr->movieStream)) { return false; } @@ -54,13 +54,34 @@ bool GBARRSetStream(struct GBARRContext* rr, struct VDir* stream) { rr->metadataFile = rr->streamDir->openFile(rr->streamDir, METADATA_FILENAME, O_CREAT | O_RDWR); if (!_parseMetadata(rr, rr->metadataFile)) { rr->metadataFile->close(rr->metadataFile); - rr->streamDir = 0; rr->metadataFile = 0; + rr->maxStreamId = 1; + } + rr->streamId = 1; + rr->movieStream = 0; + return true; +} + +bool GBARRReinitStream(struct GBARRContext* rr, enum GBARRInitFrom initFrom) { + if (!rr) { return false; } - rr->movieStream = 0; + + if (rr->metadataFile) { + rr->metadataFile->truncate(rr->metadataFile, 0); + } else { + rr->metadataFile = rr->streamDir->openFile(rr->streamDir, METADATA_FILENAME, O_CREAT | O_TRUNC | O_RDWR); + } + _emitMagic(rr, rr->metadataFile); + + rr->initFrom = initFrom; + rr->initFromOffset = rr->metadataFile->seek(rr->metadataFile, 0, SEEK_CUR); + _emitTag(rr, rr->metadataFile, TAG_INIT | initFrom); + rr->streamId = 1; rr->maxStreamId = 1; + rr->maxStreamIdOffset = rr->metadataFile->seek(rr->metadataFile, 0, SEEK_CUR); + _emitTag(rr, rr->metadataFile, 1); return true; } @@ -315,9 +336,20 @@ enum GBARRTag _readTag(struct GBARRContext* rr, struct VFile* vf) { vf->read(vf, &rr->lagFrames, sizeof(rr->lagFrames)); break; + case TAG_INIT_EX_NIHILO: + rr->initFrom = INIT_EX_NIHILO; + break; + case TAG_INIT_FROM_SAVEGAME: + rr->initFrom = INIT_FROM_SAVEGAME; + break; + case TAG_INIT_FROM_SAVESTATE: + rr->initFrom = INIT_FROM_SAVESTATE; + case TAG_INIT_FROM_BOTH: + rr->initFrom = INIT_FROM_BOTH; + break; + // To be spec'd case TAG_RR_COUNT: - case TAG_INIT_TYPE: case TAG_AUTHOR: case TAG_COMMENT: break; @@ -362,9 +394,22 @@ bool _emitTag(struct GBARRContext* rr, struct VFile* vf, uint8_t tag) { } bool _parseMetadata(struct GBARRContext* rr, struct VFile* vf) { + if (!_verifyMagic(rr, vf)) { + return false; + } while (_readTag(rr, vf) != TAG_EOF) { - if (rr->peekedTag == TAG_MAX_STREAM) { + switch (rr->peekedTag) { + case TAG_MAX_STREAM: rr->maxStreamIdOffset = vf->seek(vf, 0, SEEK_CUR); + break; + case TAG_INIT_EX_NIHILO: + case TAG_INIT_FROM_SAVEGAME: + case TAG_INIT_FROM_SAVESTATE: + case TAG_INIT_FROM_BOTH: + rr->initFromOffset = vf->seek(vf, 0, SEEK_CUR); + break; + default: + break; } } rr->maxStreamIdOffset = vf->seek(vf, 0, SEEK_SET); diff --git a/src/gba/gba-rr.h b/src/gba/gba-rr.h index 2817de569..0fe96caff 100644 --- a/src/gba/gba-rr.h +++ b/src/gba/gba-rr.h @@ -7,6 +7,13 @@ struct GBA; struct VDir; struct VFile; +enum GBARRInitFrom { + INIT_EX_NIHILO = 0, + INIT_FROM_SAVEGAME = 1, + INIT_FROM_SAVESTATE = 2, + INIT_FROM_BOTH = 3, +}; + enum GBARRTag { // Playback tags TAG_INVALID = 0x00, @@ -25,7 +32,11 @@ enum GBARRTag { TAG_FRAME_COUNT = 0x20, TAG_LAG_COUNT = 0x21, TAG_RR_COUNT = 0x22, - TAG_INIT_TYPE = 0x23, + TAG_INIT = 0x24, + TAG_INIT_EX_NIHILO = 0x24 | INIT_EX_NIHILO, + TAG_INIT_FROM_SAVEGAME = 0x24 | INIT_FROM_SAVEGAME, + TAG_INIT_FROM_SAVESTATE = 0x24 | INIT_FROM_SAVESTATE, + TAG_INIT_FROM_BOTH = 0x24 | INIT_FROM_BOTH, // User metadata tags TAG_AUTHOR = 0x30, @@ -47,9 +58,13 @@ struct GBARRContext { uint32_t frames; uint32_t lagFrames; uint32_t streamId; + uint32_t maxStreamId; off_t maxStreamIdOffset; + enum GBARRInitFrom initFrom; + off_t initFromOffset; + // Streaming state struct VDir* streamDir; struct VFile* metadataFile; @@ -63,7 +78,8 @@ struct GBARRContext { void GBARRContextCreate(struct GBA*); void GBARRContextDestroy(struct GBA*); -bool GBARRSetStream(struct GBARRContext*, struct VDir*); +bool GBARRInitStream(struct GBARRContext*, struct VDir*); +bool GBARRReinitStream(struct GBARRContext*, enum GBARRInitFrom); bool GBARRLoadStream(struct GBARRContext*, uint32_t streamId); bool GBARRIncrementStream(struct GBARRContext*); bool GBARRSkipSegment(struct GBARRContext*); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 5fbbb88e7..d13e82493 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -127,7 +127,8 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents GBAThreadInterrupt(context); GBARRContextCreate(context->gba); if (!GBARRIsRecording(context->gba->rr)) { - GBARRSetStream(context->gba->rr, context->stateDir); + GBARRInitStream(context->gba->rr, context->stateDir); + GBARRReinitStream(context->gba->rr, INIT_FROM_SAVEGAME); GBARRStopPlaying(context->gba->rr); GBARRStartRecording(context->gba->rr); } @@ -139,7 +140,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents GBAThreadReset(context); GBAThreadInterrupt(context); GBARRContextCreate(context->gba); - GBARRSetStream(context->gba->rr, context->stateDir); + GBARRInitStream(context->gba->rr, context->stateDir); GBARRStopRecording(context->gba->rr); GBARRStartPlaying(context->gba->rr, event->keysym.mod & KMOD_SHIFT); GBAThreadContinue(context);