all repos — mgba @ 9f6837da422c9f7b1a83e6ace63b23a2a8f1e393

mGBA Game Boy Advance Emulator

Perf: De-threadify and make compatible with 3DS
Jeffrey Pfau jeffrey@endrift.com
Thu, 25 Feb 2016 23:54:14 -0800
commit

9f6837da422c9f7b1a83e6ace63b23a2a8f1e393

parent

9919fffcb7e6bb23b5a8a77799051cded983c2af

M CMakeLists.txtCMakeLists.txt

@@ -45,7 +45,7 @@ file(GLOB GBA_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c)

file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) file(GLOB GB_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gb/renderers/*.c) file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c) -list(APPEND GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c) +set(CLI_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c) set(CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c) set(VFS_SRC) source_group("ARM core" FILES ${ARM_SRC})

@@ -529,7 +529,8 @@ ${GBA_SV_SRC}

${SIO_SRC}) endif() list(APPEND SRC - ${FEATURE_SRC}) + ${FEATURE_SRC} + ${CLI_SRC}) endif() if(NOT SKIP_LIBRARY)

@@ -622,13 +623,13 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/qt ${CMAKE_BINARY_DIR}/qt)

endif() if(BUILD_PERF) - set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c) + set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c ${CLI_SRC}) if(UNIX AND NOT APPLE) list(APPEND PERF_LIB rt) endif() add_executable(${BINARY_NAME}-perf ${PERF_SRC}) - target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB}) + target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB} ${OS_LIB}) set_target_properties(${BINARY_NAME}-perf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") install(TARGETS ${BINARY_NAME}-perf DESTINATION bin COMPONENT ${BINARY_NAME}-perf) install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf)
M src/platform/3ds/CMakeLists.txtsrc/platform/3ds/CMakeLists.txt

@@ -14,8 +14,9 @@ set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64)

include_directories(${CMAKE_CURRENT_BINARY_DIR}) list(APPEND OS_LIB ctru) -file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c) +file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c ${CMAKE_CURRENT_SOURCE_DIR}/ctru-heap.c) set(OS_SRC ${OS_SRC} PARENT_SCOPE) +set(OS_LIB ${OS_LIB} PARENT_SCOPE) source_group("3DS-specific code" FILES ${OS_SRC}) if(USE_VFS_3DS)

@@ -45,7 +46,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/uishader.c

${CMAKE_CURRENT_BINARY_DIR}/uishader.h ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h PROPERTIES GENERATED ON) -add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c ctru-heap.c) +add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c) set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${OS_LIB})

@@ -92,6 +93,12 @@ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf ${BINARY_NAME}.elf ${BINARY_NAME}.smdh ${BINARY_NAME}.bnr)

add_custom_target(run ${3DSLINK} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx DEPENDS ${BINARY_NAME}.3dsx) + +if(BUILD_PERF) + add_custom_target(${BINARY_NAME}-perf.3dsx ALL + ${3DSXTOOL} ../${BINARY_NAME}-perf ${BINARY_NAME}-perf.3dsx --smdh=${BINARY_NAME}.smdh + DEPENDS ${BINARY_NAME}-perf ${BINARY_NAME}.smdh) +endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cia.rsf.in ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf) install(FILES
M src/platform/3ds/CMakeToolchain.txtsrc/platform/3ds/CMakeToolchain.txt

@@ -25,7 +25,7 @@ set(CMAKE_PROGRAM_PATH ${DEVKITARM}/bin)

set(cross_prefix ${CMAKE_PROGRAM_PATH}/arm-none-eabi-) set(arch_flags "-march=armv6k -mtune=mpcore -mfpu=vfp -mfloat-abi=hard") set(inc_flags "-I${CTRULIB}/include ${arch_flags} -mword-relocations") -set(link_flags "-L${CTRULIB}/lib -lctru -specs=3dsx.specs ${arch_flags}") +set(link_flags "-L${CTRULIB}/lib -specs=3dsx.specs ${arch_flags}") set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name") set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor")
M src/platform/test/perf-main.csrc/platform/test/perf-main.c

@@ -4,7 +4,6 @@ * This Source Code Form is subject to the terms of the Mozilla Public

* License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "core/config.h" -#include "core/thread.h" #include "gba/core.h" #include "gba/gba.h" #include "gba/renderers/video-software.h"

@@ -13,6 +12,10 @@

#include "platform/commandline.h" #include "util/string.h" #include "util/vfs.h" + +#ifdef _3DS +#include <3ds.h> +#endif #include <errno.h> #include <fcntl.h>

@@ -37,17 +40,40 @@ unsigned frames;

char* savestate; }; -static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet); -static void _GBAPerfShutdown(int signal); +#ifdef _3DS +extern bool allocateRomBuffer(void); +FS_Archive sdmcArchive; +#endif + +static void _mPerfRunloop(struct mCore* context, int* frames, bool quiet); +static void _mPerfShutdown(int signal); static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg); -static void _loadSavestate(struct mCoreThread* context); +static void _log(struct mLogger*, int, enum mLogLevel, const char*, va_list); -static struct mCoreThread* _thread; static bool _dispatchExiting = false; static struct VFile* _savestate = 0; int main(int argc, char** argv) { - signal(SIGINT, _GBAPerfShutdown); +#ifdef _3DS + gfxInitDefault(); + osSetSpeedupEnable(true); + consoleInit(GFX_BOTTOM, NULL); + if (!allocateRomBuffer()) { + return 1; + } + sdmcArchive = (FS_Archive) { + ARCHIVE_SDMC, + (FS_Path) { PATH_EMPTY, 1, "" }, + 0 + }; + FSUSER_OpenArchive(&sdmcArchive); +#else + signal(SIGINT, _mPerfShutdown); +#endif + int didFail = 0; + + struct mLogger logger = { .log = _log }; + mLogSetDefaultLogger(&logger); struct PerfOpts perfOpts = { false, false, 0, 0, 0 }; struct mSubParser subparser = {

@@ -57,30 +83,26 @@ .extraOptions = PERF_OPTIONS,

.opts = &perfOpts }; - struct mArguments args; + struct mArguments args = {}; bool parsed = parseArguments(&args, argc, argv, &subparser); if (!parsed || args.showHelp) { usage(argv[0], PERF_USAGE); - freeArguments(&args); - return !parsed; + didFail = !parsed; + goto cleanup; } + if (args.showVersion) { version(argv[0]); - freeArguments(&args); - return 0; + goto cleanup; } void* outputBuffer = malloc(256 * 256 * 4); struct mCore* core = mCoreFind(args.fname); if (!core) { - freeArguments(&args); - return 1; + didFail = 1; + goto cleanup; } - struct mCoreThread context = { - .core = core - }; - _thread = &context; if (!perfOpts.noVideo) { core->setVideoBuffer(core, outputBuffer, 256);

@@ -89,9 +111,6 @@ if (perfOpts.savestate) {

_savestate = VFileOpen(perfOpts.savestate, O_RDONLY); free(perfOpts.savestate); } - if (_savestate) { - context.startCallback = _loadSavestate; - } // TODO: Put back debugger char gameCode[5] = { 0 };

@@ -110,19 +129,14 @@ applyArguments(&args, NULL, &core->config);

mCoreConfigLoadDefaults(&core->config, &opts); mCoreLoadConfig(core); - int didStart = mCoreThreadStart(&context); - - if (!didStart) { - goto cleanup; - } - mCoreThreadInterrupt(&context); - if (mCoreThreadHasCrashed(&context)) { - mCoreThreadJoin(&context); - goto cleanup; + core->reset(core); + if (_savestate) { + core->loadState(core, _savestate, 0); + _savestate->close(_savestate); + _savestate = NULL; } - GBAGetGameCode(core->board, gameCode); - mCoreThreadContinue(&context); + core->getGameCode(core, gameCode); int frames = perfOpts.frames; if (!frames) {

@@ -131,12 +145,12 @@ }

struct timeval tv; gettimeofday(&tv, 0); uint64_t start = 1000000LL * tv.tv_sec + tv.tv_usec; - _GBAPerfRunloop(&context, &frames, perfOpts.csv); + _mPerfRunloop(core, &frames, perfOpts.csv); gettimeofday(&tv, 0); uint64_t end = 1000000LL * tv.tv_sec + tv.tv_usec; uint64_t duration = end - start; - mCoreThreadJoin(&context); + core->deinit(core); float scaledFrames = frames * 1000000.f; if (perfOpts.csv) {

@@ -152,49 +166,46 @@ } else {

printf("%u frames in %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); } -cleanup: - if (_savestate) { - _savestate->close(_savestate); - } mCoreConfigFreeOpts(&opts); - freeArguments(&args); mCoreConfigDeinit(&core->config); free(outputBuffer); - return !didStart || mCoreThreadHasCrashed(&context); + cleanup: + freeArguments(&args); + +#ifdef _3DS + gfxExit(); +#endif + + return didFail; } -static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet) { +static void _mPerfRunloop(struct mCore* core, int* frames, bool quiet) { struct timeval lastEcho; gettimeofday(&lastEcho, 0); int duration = *frames; *frames = 0; int lastFrames = 0; - while (context->state < THREAD_EXITING) { - if (mCoreSyncWaitFrameStart(&context->sync)) { - ++*frames; - ++lastFrames; - if (!quiet) { - struct timeval currentTime; - long timeDiff; - gettimeofday(&currentTime, 0); - timeDiff = currentTime.tv_sec - lastEcho.tv_sec; - timeDiff *= 1000; - timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; - if (timeDiff >= 1000) { - printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); - fflush(stdout); - lastEcho = currentTime; - lastFrames = 0; - } + while (!_dispatchExiting) { + core->runFrame(core); + ++*frames; + ++lastFrames; + if (!quiet) { + struct timeval currentTime; + long timeDiff; + gettimeofday(&currentTime, 0); + timeDiff = currentTime.tv_sec - lastEcho.tv_sec; + timeDiff *= 1000; + timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; + if (timeDiff >= 1000) { + printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); + fflush(stdout); + lastEcho = currentTime; + lastFrames = 0; } } - mCoreSyncWaitFrameEnd(&context->sync); if (duration > 0 && *frames == duration) { - _GBAPerfShutdown(0); - } - if (_dispatchExiting) { - mCoreThreadEnd(context); + break; } } if (!quiet) {

@@ -202,11 +213,9 @@ printf("\033[2K\r");

} } -static void _GBAPerfShutdown(int signal) { +static void _mPerfShutdown(int signal) { UNUSED(signal); - // This will come in ON the GBA thread, so we have to handle it carefully _dispatchExiting = true; - ConditionWake(&_thread->sync.videoFrameAvailableCond); } static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg) {

@@ -233,8 +242,10 @@ return false;

} } -static void _loadSavestate(struct mCoreThread* context) { - context->core->loadState(context->core, _savestate, 0); - _savestate->close(_savestate); - _savestate = 0; +static void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) { + UNUSED(log); + UNUSED(category); + UNUSED(level); + UNUSED(format); + UNUSED(args); }