mirror of https://github.com/mgba-emu/mgba.git
Perf: De-threadify and make compatible with 3DS
This commit is contained in:
parent
9919fffcb7
commit
9f6837da42
|
@ -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 @@ if(NOT MINIMAL_CORE)
|
|||
${SIO_SRC})
|
||||
endif()
|
||||
list(APPEND SRC
|
||||
${FEATURE_SRC})
|
||||
${FEATURE_SRC}
|
||||
${CLI_SRC})
|
||||
endif()
|
||||
|
||||
if(NOT SKIP_LIBRARY)
|
||||
|
@ -622,13 +623,13 @@ if(BUILD_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)
|
||||
|
|
|
@ -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 @@ set_source_files_properties(
|
|||
${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})
|
||||
|
||||
|
@ -93,6 +94,12 @@ add_custom_target(${BINARY_NAME}.cia ALL
|
|||
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
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* 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"
|
||||
|
@ -14,6 +13,10 @@
|
|||
#include "util/string.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
#ifdef _3DS
|
||||
#include <3ds.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
@ -37,17 +40,40 @@ struct PerfOpts {
|
|||
char* savestate;
|
||||
};
|
||||
|
||||
static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet);
|
||||
static void _GBAPerfShutdown(int signal);
|
||||
static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg);
|
||||
static void _loadSavestate(struct mCoreThread* context);
|
||||
#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 _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 @@ int main(int argc, char** argv) {
|
|||
.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 @@ int main(int argc, char** argv) {
|
|||
_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 @@ int main(int argc, char** argv) {
|
|||
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 @@ int main(int argc, char** argv) {
|
|||
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 @@ int main(int argc, char** argv) {
|
|||
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(¤tTime, 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(¤tTime, 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 @@ static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* ar
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue