From 7b4d4e438ae8a06103892fba1c5e103ec7b3a84c Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 7 Oct 2014 02:54:05 -0700 Subject: [PATCH 01/32] Don't look for a package when we don't need to --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 120aa20c1..419f6362e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,9 @@ include_directories(${CMAKE_SOURCE_DIR}/src) # Function definitions include(FindPkgConfig) function(find_feature FEATURE_NAME FEATURE_REQUIRES) + if (NOT ${FEATURE_NAME}) + return() + endif() foreach(REQUIRE ${FEATURE_REQUIRES}) find_package(${REQUIRE} QUIET) pkg_search_module(${REQUIRE} ${REQUIRE}) From fe9d476a77150ebf23d07abe891754ea963768c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 7 Oct 2014 23:56:29 -0700 Subject: [PATCH 02/32] Stop compile flags from stomping over itself --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 419f6362e..3980894ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.6) project(mGBA) set(BINARY_NAME mgba CACHE INTERNAL "Name of output binaries") -set(CMAKE_C_FLAGS_DEBUG "-g -Wall -Wextra -std=gnu99") -set(CMAKE_C_FLAGS_RELEASE "-O3 -Wall -Wextra -std=gnu99") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall -Wextra -std=gnu99") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall -Wextra -std=gnu99") set(USE_CLI_DEBUGGER ON CACHE BOOL "Whether or not to enable the CLI-mode ARM debugger") set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugger") set(USE_FFMPEG ON CACHE BOOL "Whether or not to enable FFmpeg support") From 53333947552deed0babbdbcaa97e00a103486c61 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 00:30:36 -0700 Subject: [PATCH 03/32] Clean up CMakeFiles after adding find_feature --- CMakeLists.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3980894ec..e58000b74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,8 @@ function(find_feature FEATURE_NAME FEATURE_REQUIRES) set(${FEATURE_NAME} OFF PARENT_SCOPE) return() endif() + set(${REQUIRE}_LIBRARIES ${${REQUIRE}_LIBRARIES} PARENT_SCOPE) + set(${REQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) endforeach() endfunction() @@ -112,24 +114,20 @@ endif() source_group("ARM debugger" FILES ${DEBUGGER_SRC}) if(USE_FFMPEG) - pkg_search_module(LIBAVCODEC libavcodec) - pkg_search_module(LIBAVFORMAT libavcodec;libavformat;libavutil) - pkg_search_module(LIBAVUTIL libavutil) add_definitions(-DUSE_FFMPEG) + include_directories(AFTER ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS}) list(APPEND UTIL_SRC "${CMAKE_SOURCE_DIR}/src/platform/ffmpeg/ffmpeg-encoder.c") list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVUTIL_LIBRARIES}) endif() if(USE_PNG) - find_package(PNG) - find_package(ZLIB) add_definitions(-DUSE_PNG) - include_directories(${PNG_PNG_INCLUDE_DIR}) + include_directories(AFTER ${PNG_INCLUDE_DIRS}) list(APPEND DEPENDENCY_LIB ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) endif() if(USE_LIBZIP) - include_directories(${LIBZIP_INCLUDE_DIRS}) + include_directories(AFTER ${LIBZIP_INCLUDE_DIRS}) list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES}) add_definitions(-DENABLE_LIBZIP) endif() From e65ef28486ec50f795b17b95a29d77262e6586e7 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 00:40:57 -0700 Subject: [PATCH 04/32] Export all relevant pkg-config flags --- CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e58000b74..f307726e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,8 +37,12 @@ function(find_feature FEATURE_NAME FEATURE_REQUIRES) set(${FEATURE_NAME} OFF PARENT_SCOPE) return() endif() - set(${REQUIRE}_LIBRARIES ${${REQUIRE}_LIBRARIES} PARENT_SCOPE) + set(${REQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE) + set(${REQUIRE}_FOUND ${${REQUIRE}_FOUND} PARENT_SCOPE) set(${REQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) + set(${REQUIRE}_LIBRARIES ${${REQUIRE}_LIBRARIES} PARENT_SCOPE) + set(${REQUIRE}_LIBRARY_DIRS ${${REQUIRE}_LIBRARY_DIRS} PARENT_SCOPE) + set(${REQUIRE}_LDFLAGS_OTHER ${${REQUIRE}_LDFLAGS_OTHER} PARENT_SCOPE) endforeach() endfunction() @@ -116,6 +120,7 @@ source_group("ARM debugger" FILES ${DEBUGGER_SRC}) if(USE_FFMPEG) add_definitions(-DUSE_FFMPEG) include_directories(AFTER ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS}) + link_directories(${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS}) list(APPEND UTIL_SRC "${CMAKE_SOURCE_DIR}/src/platform/ffmpeg/ffmpeg-encoder.c") list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVUTIL_LIBRARIES}) endif() @@ -128,6 +133,7 @@ endif() if(USE_LIBZIP) include_directories(AFTER ${LIBZIP_INCLUDE_DIRS}) + link_directories(AFTER ${LIBZIP_LIBRARY_DIRS}) list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES}) add_definitions(-DENABLE_LIBZIP) endif() From ef380f27d5d33548023d242e69ca0ba0a19bf940 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 01:03:35 -0700 Subject: [PATCH 05/32] Fix outputing the right variable names in find_feature --- CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f307726e7..8a6b1c75f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,12 +37,13 @@ function(find_feature FEATURE_NAME FEATURE_REQUIRES) set(${FEATURE_NAME} OFF PARENT_SCOPE) return() endif() - set(${REQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE) - set(${REQUIRE}_FOUND ${${REQUIRE}_FOUND} PARENT_SCOPE) - set(${REQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) - set(${REQUIRE}_LIBRARIES ${${REQUIRE}_LIBRARIES} PARENT_SCOPE) - set(${REQUIRE}_LIBRARY_DIRS ${${REQUIRE}_LIBRARY_DIRS} PARENT_SCOPE) - set(${REQUIRE}_LDFLAGS_OTHER ${${REQUIRE}_LDFLAGS_OTHER} PARENT_SCOPE) + string(TOUPPER ${REQUIRE} UREQUIRE) + set(${UREQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE) + set(${UREQUIRE}_FOUND ${${REQUIRE}_FOUND} PARENT_SCOPE) + set(${UREQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) + set(${UREQUIRE}_LIBRARIES ${${REQUIRE}_LIBRARIES} PARENT_SCOPE) + set(${UREQUIRE}_LIBRARY_DIRS ${${REQUIRE}_LIBRARY_DIRS} PARENT_SCOPE) + set(${UREQUIRE}_LDFLAGS_OTHER ${${REQUIRE}_LDFLAGS_OTHER} PARENT_SCOPE) endforeach() endfunction() From 0b91681b2aaa7c7fe08b06a9fe4a0d303084e45a Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 01:04:03 -0700 Subject: [PATCH 06/32] Remove bad AFTER keyword in link_directories directive --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a6b1c75f..a1cabbfa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,7 +134,7 @@ endif() if(USE_LIBZIP) include_directories(AFTER ${LIBZIP_INCLUDE_DIRS}) - link_directories(AFTER ${LIBZIP_LIBRARY_DIRS}) + link_directories(${LIBZIP_LIBRARY_DIRS}) list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES}) add_definitions(-DENABLE_LIBZIP) endif() From b12f7a136ed7debf909dff89cbb9a27f6551d08f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 01:04:19 -0700 Subject: [PATCH 07/32] Fix printf format string to use unsigned instead of signed --- src/platform/perf-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index 593f521cd..0b201cc2b 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -96,9 +96,9 @@ int main(int argc, char** argv) { } else { rendererName = "software"; } - printf("%s,%i,%lli,%s\n", gameCode, frames, duration, rendererName); + printf("%s,%i,%llu,%s\n", gameCode, frames, duration, rendererName); } else { - printf("%u frames in %lli microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); + printf("%u frames in %llu microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); } return 0; From 0890d21645117106a3a4d394b8dd2ae8288f2716 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 01:16:50 -0700 Subject: [PATCH 08/32] Fix types for some LP64 systems --- src/platform/perf-main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index 0b201cc2b..b7ccdf477 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #define PERF_OPTIONS "F:NPS:" @@ -96,9 +97,9 @@ int main(int argc, char** argv) { } else { rendererName = "software"; } - printf("%s,%i,%llu,%s\n", gameCode, frames, duration, rendererName); + printf("%s,%i,%" PRIu64 ",%s\n", gameCode, frames, duration, rendererName); } else { - printf("%u frames in %llu microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); + printf("%u frames in %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); } return 0; From dda454c9a2f099a0e7e0bd35944bc2a3c6c2cf93 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 03:49:48 -0700 Subject: [PATCH 09/32] Fix libedit in CMakeLists --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1cabbfa1..b78d77e95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,9 @@ if(USE_CLI_DEBUGGER) add_definitions(-DUSE_CLI_DEBUGGER) list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c) list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/parser.c) - set(DEBUGGER_LIB ${EDIT_LIBRARIES}) + include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS}) + link_directories(${LIBEDIT_LIBRARY_DIRS}) + set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES}) else() set(DEBUGGER_LIB "") endif() From c7bb9618a092c849c4c48ff525b8eb5a82959f4f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 04:47:56 -0700 Subject: [PATCH 10/32] Mark project as C --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b78d77e95..453ece250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.6) -project(mGBA) +project(mGBA C) set(BINARY_NAME mgba CACHE INTERNAL "Name of output binaries") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall -Wextra -std=gnu99") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall -Wextra -std=gnu99") From 59f1018dd2e69cfc18d0ca715bb3a6a366401826 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Oct 2014 04:48:23 -0700 Subject: [PATCH 11/32] Speculative fixes for SDL fallback and failing configuring --- src/platform/sdl/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index b21e35bea..e577d14f3 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -14,10 +14,11 @@ endif() if(SDL_VERSION EQUAL "1.2" OR NOT SDL2_FOUND) find_package(SDL 1.2) + set(SDL_VERSION "1.2" PARENT_SCOPE) endif() if (NOT SDL2_FOUND AND NOT SDL_FOUND) - set(BUILD_SDL OFF) + set(BUILD_SDL OFF PARENT_SCOPE) return() endif() From dbd939022cf461336879da1b479ca12623be1cd0 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 00:08:46 -0700 Subject: [PATCH 12/32] Simple profiling script for outputing CSV batches --- CMakeLists.txt | 3 ++ tools/perf.py | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100755 tools/perf.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 453ece250..9902c8903 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,8 @@ include_directories(${CMAKE_SOURCE_DIR}/src/arm) include_directories(${CMAKE_SOURCE_DIR}/src/gba) include_directories(${CMAKE_SOURCE_DIR}/src) +include(GNUInstallDirs) + # Function definitions include(FindPkgConfig) function(find_feature FEATURE_NAME FEATURE_REQUIRES) @@ -160,6 +162,7 @@ if(BUILD_PERF) add_executable(${BINARY_NAME}-perf ${PERF_SRC}) target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB}) install(TARGETS ${BINARY_NAME}-perf DESTINATION bin) + install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}") endif() # Summaries diff --git a/tools/perf.py b/tools/perf.py new file mode 100755 index 000000000..a5c11f260 --- /dev/null +++ b/tools/perf.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +from __future__ import print_function +import argparse +import csv +import os +import signal +import subprocess +import sys +import time + +class PerfTest(object): + EXECUTABLE = 'mgba-perf' + + def __init__(self, rom, renderer='software'): + self.rom = rom + self.renderer = renderer + self.results = None + self.name = 'Perf Test: {}'.format(rom) + + def get_args(self): + return [] + + def wait(self, proc): + pass + + def run(self, cwd): + args = [os.path.join(os.getcwd(), self.EXECUTABLE), '-P'] + args.extend(self.get_args()) + if self.renderer != 'software': + args.append('-N') + args.append(self.rom) + proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True) + try: + self.wait(proc) + proc.wait() + except: + proc.kill() + raise + if proc.returncode < 0: + return + reader = csv.DictReader(proc.stdout) + self.results = next(reader) + +class WallClockTest(PerfTest): + def __init__(self, rom, duration, renderer='software'): + super(WallClockTest, self).__init__(rom, renderer) + self.duration = duration + self.name = 'Wall-Clock Test ({} seconds, {} renderer): {}'.format(duration, renderer, rom) + + def wait(self, proc): + time.sleep(self.duration) + proc.send_signal(signal.SIGINT) + +class GameClockTest(PerfTest): + def __init__(self, rom, frames, renderer='software'): + super(GameClockTest, self).__init__(rom, renderer) + self.frames = frames + self.name = 'Game-Clock Test ({} frames, {} renderer): {}'.format(frames, renderer, rom) + + def get_args(self): + return ['-F', str(self.frames)] + +class Suite(object): + def __init__(self, cwd, wall=None, game=None): + self.cwd = cwd + self.tests = [] + self.wall = wall + self.game = game + + def collect_tests(self): + roms = [] + for f in os.listdir(self.cwd): + if f.endswith('.gba'): + roms.append(f) + roms.sort() + for rom in roms: + self.add_tests(rom) + + def add_tests(self, rom): + if self.wall: + self.tests.append(WallClockTest(rom, self.wall)) + self.tests.append(WallClockTest(rom, self.wall, renderer=None)) + if self.game: + self.tests.append(GameClockTest(rom, self.game)) + self.tests.append(GameClockTest(rom, self.game, renderer=None)) + + def run(self): + results = [] + for test in self.tests: + print('Running test {}'.format(test.name), file=sys.stderr) + try: + test.run(self.cwd) + except KeyboardInterrupt: + print('Interrupted, returning early...', file=sys.stderr) + return results + if test.results: + results.append(test.results) + return results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-w', '--wall-time', type=float, default=120, metavar='TIME', help='wall-clock time') + parser.add_argument('-g', '--game-frames', type=int, default=120*60, metavar='FRAMES', help='game-clock frames') + parser.add_argument('-o', '--out', metavar='FILE', help='output file path') + parser.add_argument('directory', help='directory containing ROM files') + args = parser.parse_args() + + s = Suite(args.directory, wall=args.wall_time, game=args.game_frames) + s.collect_tests() + results = s.run() + fout = sys.stdout + if args.out: + fout = open(args.out, 'w') + writer = csv.DictWriter(fout, results[0].keys()) + writer.writeheader() + writer.writerows(results) + if fout is not sys.stdout: + fout.close() From 562a33d98b8faf2c19b8e3a22118e50604e9c385 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 01:36:08 -0700 Subject: [PATCH 13/32] Inherit LD_LIBRARY_PATH in subprocess --- tools/perf.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/perf.py b/tools/perf.py index a5c11f260..8301201d7 100755 --- a/tools/perf.py +++ b/tools/perf.py @@ -29,7 +29,11 @@ class PerfTest(object): if self.renderer != 'software': args.append('-N') args.append(self.rom) - proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True) + env = {} + if 'LD_LIBRARY_PATH' in os.environ: + env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] + env['DYLD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] # Fake it on OS X + proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True, env=env) try: self.wait(proc) proc.wait() From cc255b794b0456540af5442cf1129d86f19e9324 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 01:53:47 -0700 Subject: [PATCH 14/32] Make path absolute in perf.py --- tools/perf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf.py b/tools/perf.py index 8301201d7..cf7202248 100755 --- a/tools/perf.py +++ b/tools/perf.py @@ -31,8 +31,8 @@ class PerfTest(object): args.append(self.rom) env = {} if 'LD_LIBRARY_PATH' in os.environ: - env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] - env['DYLD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] # Fake it on OS X + env['LD_LIBRARY_PATH'] = os.path.abspath(os.environ['LD_LIBRARY_PATH']) + env['DYLD_LIBRARY_PATH'] = env['LD_LIBRARY_PATH'] # Fake it on OS X proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True, env=env) try: self.wait(proc) From f9e79a1a4280b99e3abf0a83de005fd33211a539 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 02:47:06 -0700 Subject: [PATCH 15/32] Tweak perf settings to run a more abridged version --- tools/perf.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/perf.py b/tools/perf.py index cf7202248..715c243ea 100755 --- a/tools/perf.py +++ b/tools/perf.py @@ -83,9 +83,7 @@ class Suite(object): def add_tests(self, rom): if self.wall: self.tests.append(WallClockTest(rom, self.wall)) - self.tests.append(WallClockTest(rom, self.wall, renderer=None)) if self.game: - self.tests.append(GameClockTest(rom, self.game)) self.tests.append(GameClockTest(rom, self.game, renderer=None)) def run(self): @@ -103,7 +101,7 @@ class Suite(object): if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('-w', '--wall-time', type=float, default=120, metavar='TIME', help='wall-clock time') + parser.add_argument('-w', '--wall-time', type=float, default=60, metavar='TIME', help='wall-clock time') parser.add_argument('-g', '--game-frames', type=int, default=120*60, metavar='FRAMES', help='game-clock frames') parser.add_argument('-o', '--out', metavar='FILE', help='output file path') parser.add_argument('directory', help='directory containing ROM files') From 8ae1a3a3a3d385d416def2e63b356310d63fcf3f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 03:02:35 -0700 Subject: [PATCH 16/32] Use bitfield for BIOS Huffman nodes --- src/gba/gba-bios.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/gba/gba-bios.c b/src/gba/gba-bios.c index f036bbb17..de33845d1 100644 --- a/src/gba/gba-bios.c +++ b/src/gba/gba-bios.c @@ -283,6 +283,11 @@ static void _unLz77(struct GBA* gba, uint32_t source, uint8_t* dest) { } } +DECL_BITFIELD(HuffmanNode, uint8_t); +DECL_BITS(HuffmanNode, Offset, 0, 6); +DECL_BIT(HuffmanNode, RTerm, 6); +DECL_BIT(HuffmanNode, LTerm, 7); + static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) { struct ARMCore* cpu = gba->cpu; source = source & 0xFFFFFFFC; @@ -303,39 +308,32 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) { uint32_t sPointer = source + 5 + treesize; uint32_t* dPointer = dest; uint32_t nPointer = treeBase; - union HuffmanNode { - struct { - unsigned offset : 6; - unsigned rTerm : 1; - unsigned lTerm : 1; - }; - uint8_t packed; - } node; + HuffmanNode node; int bitsRemaining; int readBits; int bitsSeen = 0; - node.packed = cpu->memory.load8(cpu, nPointer, 0); + node = cpu->memory.load8(cpu, nPointer, 0); while (remaining > 0) { uint32_t bitstream = cpu->memory.load32(cpu, sPointer, 0); sPointer += 4; for (bitsRemaining = 32; bitsRemaining > 0; --bitsRemaining, bitstream <<= 1) { - uint32_t next = (nPointer & ~1) + node.offset * 2 + 2; + uint32_t next = (nPointer & ~1) + HuffmanNodeGetOffset(node) * 2 + 2; if (bitstream & 0x80000000) { // Go right - if (node.rTerm) { + if (HuffmanNodeIsRTerm(node)) { readBits = cpu->memory.load8(cpu, next + 1, 0); } else { nPointer = next + 1; - node.packed = cpu->memory.load8(cpu, nPointer, 0); + node = cpu->memory.load8(cpu, nPointer, 0); continue; } } else { // Go left - if (node.lTerm) { + if (HuffmanNodeIsLTerm(node)) { readBits = cpu->memory.load8(cpu, next, 0); } else { nPointer = next; - node.packed = cpu->memory.load8(cpu, nPointer, 0); + node = cpu->memory.load8(cpu, nPointer, 0); continue; } } @@ -343,7 +341,7 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) { block |= (readBits & ((1 << bits) - 1)) << bitsSeen; bitsSeen += bits; nPointer = treeBase; - node.packed = cpu->memory.load8(cpu, nPointer, 0); + node = cpu->memory.load8(cpu, nPointer, 0); if (bitsSeen == 32) { bitsSeen = 0; *dPointer = block; From 747e30c5e1b9ab5d2ff6adbbbb119aff4f802bab Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 03:43:51 -0700 Subject: [PATCH 17/32] Fix perf-main parsing when errno is not cleared --- src/platform/perf-main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index b7ccdf477..846540098 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -149,6 +149,7 @@ static void _GBAPerfShutdown(int signal) { static bool _parsePerfOpts(struct SubParser* parser, int option, const char* arg) { struct PerfOpts* opts = parser->opts; + errno = 0; switch (option) { case 'F': opts->frames = strtoul(arg, 0, 10); From e293134a787c4ab434b9f72e6e6d634e6ce92966 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 9 Oct 2014 23:55:02 -0700 Subject: [PATCH 18/32] Unify optional directory file opening --- src/gba/gba-serialize.c | 14 +++----------- src/gba/gba-thread.c | 27 ++------------------------- src/util/vfs.c | 28 ++++++++++++++++++++++++++++ src/util/vfs.h | 2 ++ 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/gba/gba-serialize.c b/src/gba/gba-serialize.c index 903ed5459..b26fd169e 100644 --- a/src/gba/gba-serialize.c +++ b/src/gba/gba-serialize.c @@ -103,17 +103,9 @@ void GBADeserialize(struct GBA* gba, struct GBASerializedState* state) { } static struct VFile* _getStateVf(struct GBA* gba, struct VDir* dir, int slot, bool write) { - char path[PATH_MAX]; - path[PATH_MAX - 1] = '\0'; - struct VFile* vf; - if (!dir) { - snprintf(path, PATH_MAX - 1, "%s.ss%d", gba->activeFile, slot); - vf = VFileOpen(path, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); - } else { - snprintf(path, PATH_MAX - 1, "savestate.ss%d", slot); - vf = dir->openFile(dir, path, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); - } - return vf; + char suffix[5] = { '\0' }; + snprintf(suffix, sizeof(suffix), ".ss%d", slot); + return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); } #ifdef USE_PNG diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 243b3eb57..4a957c53a 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -276,35 +276,12 @@ bool GBAThreadStart(struct GBAThread* threadContext) { } } - if (threadContext->stateDir) { - threadContext->save = threadContext->stateDir->openFile(threadContext->stateDir, "sram.sav", O_RDWR | O_CREAT); - } if (!threadContext->rom) { return false; } - if (threadContext->fname && !threadContext->save) { - char* savedata = 0; - char* dotPoint = strrchr(threadContext->fname, '.'); - if (dotPoint > strrchr(threadContext->fname, '/') && dotPoint[1] && dotPoint[2] && dotPoint[3]) { - savedata = strdup(threadContext->fname); - dotPoint = strrchr(savedata, '.'); - dotPoint[1] = 's'; - dotPoint[2] = 'a'; - dotPoint[3] = 'v'; - dotPoint[4] = '\0'; - } else if (dotPoint) { - savedata = malloc((dotPoint - threadContext->fname + 5) * sizeof(char)); - strncpy(savedata, threadContext->fname, dotPoint - threadContext->fname + 1); - strcat(savedata, "sav"); - } else { - savedata = malloc(strlen(threadContext->fname + 5) * sizeof(char)); - sprintf(savedata, "%s.sav", threadContext->fname); - } - threadContext->save = VFileOpen(savedata, O_RDWR | O_CREAT); - free(savedata); - } + threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR); MutexInit(&threadContext->stateMutex); ConditionInit(&threadContext->stateCond); @@ -524,7 +501,7 @@ struct GBAThread* GBAThreadGetContext(void) { void GBAThreadTakeScreenshot(struct GBAThread* threadContext) { unsigned stride; void* pixels = 0; - struct VFile* vf = threadContext->stateDir->openFile(threadContext->stateDir, "screenshot.png", O_CREAT | O_WRONLY); + struct VFile* vf = VDirOptionalOpenFile(threadContext->stateDir, threadContext->gba->activeFile, "screenshot", ".png", O_CREAT | O_TRUNC | O_WRONLY); threadContext->gba->video.renderer->getPixels(threadContext->gba->video.renderer, &stride, &pixels); png_structp png = PNGWriteOpen(vf); png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); diff --git a/src/util/vfs.c b/src/util/vfs.c index f536e164b..ac8fe4c34 100644 --- a/src/util/vfs.c +++ b/src/util/vfs.c @@ -183,6 +183,34 @@ struct VDir* VDirOpen(const char* path) { return &vd->d; } +struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) { + char path[PATH_MAX]; + path[PATH_MAX - 1] = '\0'; + struct VFile* vf; + if (!dir) { + if (!realPath) { + return 0; + } + char* dotPoint = strrchr(realPath, '.'); + if (dotPoint - realPath + 1 >= PATH_MAX - 1) { + return 0; + } + if (dotPoint > strrchr(realPath, '/')) { + int len = dotPoint - realPath; + strncpy(path, realPath, len); + path[len] = 0; + strncat(path + len, suffix, PATH_MAX - len - 1); + } else { + snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix); + } + vf = VFileOpen(path, mode); + } else { + snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix); + vf = dir->openFile(dir, path, mode); + } + return vf; +} + bool _vdClose(struct VDir* vd) { struct VDirDE* vdde = (struct VDirDE*) vd; if (closedir(vdde->de) < 0) { diff --git a/src/util/vfs.h b/src/util/vfs.h index 90cac8f19..f3089e0d1 100644 --- a/src/util/vfs.h +++ b/src/util/vfs.h @@ -39,4 +39,6 @@ struct VDir* VDirOpen(const char* path); struct VDir* VDirOpenZip(const char* path, int flags); #endif +struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode); + #endif From fd1128f90a17151fd6e3a673332045cf534a3d21 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 02:28:27 -0700 Subject: [PATCH 19/32] Fix 0 not being recognized as a valid token --- src/debugger/parser.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/debugger/parser.c b/src/debugger/parser.c index 33c7cb7f1..bb31c2a67 100644 --- a/src/debugger/parser.c +++ b/src/debugger/parser.c @@ -77,6 +77,7 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { break; case '0': state = LEX_EXPECT_PREFIX; + next = 0; break; case '$': state = LEX_EXPECT_HEX; @@ -216,8 +217,19 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { next = 0; state = LEX_EXPECT_HEX; break; - default: - state = LEX_ERROR; + case '+': + case '-': + case '*': + case '/': + lv->token.type = TOKEN_UINT_TYPE; + lv->token.uintValue = next; + lv = _lexOperator(lv, token); + state = LEX_ROOT; + break; + case ')': + lv->token.type = TOKEN_UINT_TYPE; + lv->token.uintValue = next; + state = LEX_EXPECT_OPERATOR; break; } break; @@ -247,6 +259,7 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { switch (state) { case LEX_EXPECT_DECIMAL: case LEX_EXPECT_HEX: + case LEX_EXPECT_PREFIX: lv->token.type = TOKEN_UINT_TYPE; lv->token.uintValue = next; break; From 6aee0693ec67d5234ad6426a7f12a7e81dcb5aca Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 02:38:05 -0700 Subject: [PATCH 20/32] Add support for 0b-style literals --- src/debugger/parser.c | 33 +++++++++++++++++++++++++++++++++ src/debugger/parser.h | 1 + 2 files changed, 34 insertions(+) diff --git a/src/debugger/parser.c b/src/debugger/parser.c index bb31c2a67..1eb9379f7 100644 --- a/src/debugger/parser.c +++ b/src/debugger/parser.c @@ -121,6 +121,33 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { break; } break; + case LEX_EXPECT_BINARY: + switch (token) { + case '0': + case '1': + // TODO: handle overflow + next <<= 1; + next += token - '0'; + break; + case '+': + case '-': + case '*': + case '/': + lv->token.type = TOKEN_UINT_TYPE; + lv->token.uintValue = next; + lv = _lexOperator(lv, token); + state = LEX_ROOT; + break; + case ')': + lv->token.type = TOKEN_UINT_TYPE; + lv->token.uintValue = next; + state = LEX_EXPECT_OPERATOR; + break; + default: + state = LEX_ERROR; + break; + } + break; case LEX_EXPECT_DECIMAL: switch (token) { case '0': @@ -217,6 +244,11 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { next = 0; state = LEX_EXPECT_HEX; break; + case 'B': + case 'b': + next = 0; + state = LEX_EXPECT_BINARY; + break; case '+': case '-': case '*': @@ -257,6 +289,7 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { } switch (state) { + case LEX_EXPECT_BINARY: case LEX_EXPECT_DECIMAL: case LEX_EXPECT_HEX: case LEX_EXPECT_PREFIX: diff --git a/src/debugger/parser.h b/src/debugger/parser.h index 78cbfa2fe..b4cf29ed3 100644 --- a/src/debugger/parser.h +++ b/src/debugger/parser.h @@ -8,6 +8,7 @@ enum LexState { LEX_ERROR = -1, LEX_ROOT = 0, LEX_EXPECT_IDENTIFIER, + LEX_EXPECT_BINARY, LEX_EXPECT_DECIMAL, LEX_EXPECT_HEX, LEX_EXPECT_PREFIX, From be82f04618980eccd0e0db656900b1840a4a99f0 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 02:45:57 -0700 Subject: [PATCH 21/32] Print address alongside disassembled instructions --- src/debugger/cli-debugger.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 8a25e61fc..39297628a 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -233,16 +233,17 @@ static void _printHelp(struct CLIDebugger* debugger, struct DebugVector* dv) { static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { char disassembly[48]; struct ARMInstructionInfo info; + printf("%08X: ", address); if (mode == MODE_ARM) { uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0); ARMDecodeARM(instruction, &info); ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); - printf("%08X: %s\n", instruction, disassembly); + printf("%08X\t%s\n", instruction, disassembly); } else { uint16_t instruction = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0); ARMDecodeThumb(instruction, &info); ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); - printf("%04X: %s\n", instruction, disassembly); + printf("%04X\t%s\n", instruction, disassembly); } } From 0b736c9cc8a6eb4028e92447d489e2b0a805cca7 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 02:50:09 -0700 Subject: [PATCH 22/32] Add disassemble alias --- src/debugger/cli-debugger.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 39297628a..f2e6f4c4a 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -72,6 +72,9 @@ static struct { { "disasm", _disassemble, _DVParse, "Disassemble instructions" }, { "disasm/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" }, { "disasm/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" }, + { "disassemble", _disassemble, _DVParse, "Disassemble instructions" }, + { "disassemble/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" }, + { "disassemble/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" }, { "h", _printHelp, _DVStringParse, "Print help" }, { "help", _printHelp, _DVStringParse, "Print help" }, { "i", _printStatus, 0, "Print the current status" }, From ef6e1f9e7493042a90026f0865b9f8574d235387 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 02:56:13 -0700 Subject: [PATCH 23/32] Fix tab-completing past the end of the completions list --- src/debugger/cli-debugger.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index f2e6f4c4a..a7e381e05 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -597,6 +597,9 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) { } } } + if (!name) { + return CC_ERROR; + } if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) { return CC_ERROR; } From ab904f2cfdfb3829af402dbd557e216e035aac84 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 03:22:44 -0700 Subject: [PATCH 24/32] Don't tab complete null --- src/debugger/cli-debugger.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index a7e381e05..e2b06f47f 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -583,6 +583,10 @@ static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason static unsigned char _tabComplete(EditLine* elstate, int ch) { UNUSED(ch); const LineInfo* li = el_line(elstate); + if (!li->buffer[0]) { + return CC_ERROR; + } + const char* commandPtr; int cmd = 0, len = 0; const char* name = 0; From 435edc801789fc454c2ad005fe63f875cc3dc5e9 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 03:27:10 -0700 Subject: [PATCH 25/32] Prefix completion --- src/debugger/cli-debugger.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index e2b06f47f..e1ad3f2ef 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -604,8 +604,25 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) { if (!name) { return CC_ERROR; } - if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) { - return CC_ERROR; + if (_debuggerCommands[cmd + 1].name && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) { + --len; + const char* next = 0; + int i; + for (i = cmd + 1; _debuggerCommands[i].name; ++i) { + if (strncasecmp(name, _debuggerCommands[i].name, len)) { + break; + } + next = _debuggerCommands[i].name; + } + + for (; name[len]; ++len) { + if (name[len] != next[len]) { + break; + } + char out[2] = { name[len], '\0' }; + el_insertstr(elstate, out); + } + return CC_REDISPLAY; } name += len - 1; el_insertstr(elstate, name); From 2a6d106ebde9d8c84053ba7dc01e95781c21d4ec Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 22:52:49 -0700 Subject: [PATCH 26/32] Use command line options for renderer, too --- tools/perf.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/perf.py b/tools/perf.py index 715c243ea..b76ece446 100755 --- a/tools/perf.py +++ b/tools/perf.py @@ -65,11 +65,12 @@ class GameClockTest(PerfTest): return ['-F', str(self.frames)] class Suite(object): - def __init__(self, cwd, wall=None, game=None): + def __init__(self, cwd, wall=None, game=None, renderer='software'): self.cwd = cwd self.tests = [] self.wall = wall self.game = game + self.renderer = renderer def collect_tests(self): roms = [] @@ -82,9 +83,9 @@ class Suite(object): def add_tests(self, rom): if self.wall: - self.tests.append(WallClockTest(rom, self.wall)) + self.tests.append(WallClockTest(rom, self.wall, renderer=self.renderer)) if self.game: - self.tests.append(GameClockTest(rom, self.game, renderer=None)) + self.tests.append(GameClockTest(rom, self.game, renderer=self.renderer)) def run(self): results = [] @@ -101,13 +102,14 @@ class Suite(object): if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('-w', '--wall-time', type=float, default=60, metavar='TIME', help='wall-clock time') - parser.add_argument('-g', '--game-frames', type=int, default=120*60, metavar='FRAMES', help='game-clock frames') + parser.add_argument('-w', '--wall-time', type=float, default=0, metavar='TIME', help='wall-clock time') + parser.add_argument('-g', '--game-frames', type=int, default=0, metavar='FRAMES', help='game-clock frames') + parser.add_argument('-N', '--disable-renderer', action='store_const', const=True, help='disable video rendering') parser.add_argument('-o', '--out', metavar='FILE', help='output file path') parser.add_argument('directory', help='directory containing ROM files') args = parser.parse_args() - s = Suite(args.directory, wall=args.wall_time, game=args.game_frames) + s = Suite(args.directory, wall=args.wall_time, game=args.game_frames, renderer=None if args.disable_renderer else 'software') s.collect_tests() results = s.run() fout = sys.stdout From d87081e6bc583f676d5903f91ae1ce0763acca9f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 10 Oct 2014 22:54:04 -0700 Subject: [PATCH 27/32] Log if a game crashes --- tools/perf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf.py b/tools/perf.py index b76ece446..08f75a5f4 100755 --- a/tools/perf.py +++ b/tools/perf.py @@ -41,6 +41,7 @@ class PerfTest(object): proc.kill() raise if proc.returncode < 0: + print('Game crashed!', file=sys.stderr) return reader = csv.DictReader(proc.stdout) self.results = next(reader) From 2bca4c399bda1e630b23ac6cefc56dfb588774e2 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 11 Oct 2014 15:46:59 -0700 Subject: [PATCH 28/32] Fix assumption that savedata->vf is non-null within flash memory code --- src/gba/gba-savedata.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gba/gba-savedata.c b/src/gba/gba-savedata.c index 4e3e6cf98..e1839c82b 100644 --- a/src/gba/gba-savedata.c +++ b/src/gba/gba-savedata.c @@ -343,7 +343,9 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) { savedata->currentBank = &savedata->data[bank << 16]; if (bank > 0) { savedata->type = SAVEDATA_FLASH1M; - savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M); + if (savedata->vf) { + savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M); + } } } From bbcf161fec2d6bb860fd75fd9b9012457ce8e6c4 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 11 Oct 2014 15:49:45 -0700 Subject: [PATCH 29/32] Fix warning about exceeding bounds of array --- src/gba/renderers/video-software.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 74643853e..88351c387 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -365,7 +365,7 @@ static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, stru softwareRenderer->windows[activeWindow].endX = win->h.end; if (win->h.end >= oldWindow.endX) { // Trim off extra windows we've overwritten - for (++activeWindow; win->h.end >= softwareRenderer->windows[activeWindow].endX && softwareRenderer->nWindows > activeWindow; ++activeWindow) { + for (++activeWindow; softwareRenderer->nWindows > activeWindow + 1 && win->h.end >= softwareRenderer->windows[activeWindow].endX; ++activeWindow) { softwareRenderer->windows[activeWindow] = softwareRenderer->windows[activeWindow + 1]; --softwareRenderer->nWindows; } From 4ecdcf25f53a0ca18fc7bc74640d8b1ee4291799 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 11 Oct 2014 14:41:28 -0700 Subject: [PATCH 30/32] Disable blending in backgrounds when unnecessary --- src/gba/renderers/video-software.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 88351c387..f1b0d3b54 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -1193,6 +1193,9 @@ static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, stru int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA); flags |= FLAG_TARGET_2 * background->target2; + if (renderer->blda == 0x10 && renderer->bldb == 0) { + flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); + } uint32_t screenBase; uint32_t charBase; @@ -1255,6 +1258,9 @@ static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, stru int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \ flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA); \ flags |= FLAG_TARGET_2 * background->target2; \ + if (renderer->blda == 0x10 && renderer->bldb == 0) { \ + flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ + } \ int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \ color_t* palette = renderer->normalPalette; \ if (variant) { \ From 4247db81e43fb35526036b5538111a8dc3eb2606 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 11 Oct 2014 18:18:47 -0700 Subject: [PATCH 31/32] Split out macros from common.h --- src/arm/arm.h | 2 +- src/arm/isa-arm.h | 2 +- src/arm/isa-inlines.h | 2 +- src/arm/isa-thumb.h | 2 +- src/arm/{common.h => macros.h} | 19 +++---------------- src/debugger/cli-debugger.h | 2 +- src/debugger/debugger.h | 2 +- src/debugger/gdb-stub.h | 2 +- src/debugger/memory-debugger.h | 2 +- src/debugger/parser.h | 2 +- src/gba/gba-audio.h | 3 ++- src/gba/gba-bios.h | 2 +- src/gba/gba-gpio.h | 2 +- src/gba/gba-io.h | 2 +- src/gba/gba-memory.c | 2 ++ src/gba/gba-memory.h | 3 ++- src/gba/gba-rr.h | 2 +- src/gba/gba-savedata.h | 2 +- src/gba/gba-sensors.h | 2 +- src/gba/gba-serialize.h | 2 +- src/gba/gba-sio.h | 2 +- src/gba/gba-thread.h | 2 +- src/gba/gba-video.h | 3 ++- src/gba/gba.h | 2 +- src/gba/hle-bios.h | 2 +- src/gba/renderers/video-glsl.h | 2 +- src/gba/renderers/video-software.h | 2 +- src/platform/commandline.h | 2 +- src/platform/sdl/sdl-audio.h | 2 +- src/platform/sdl/sdl-events.h | 2 +- src/util/circle-buffer.h | 2 +- src/util/common.h | 19 +++++++++++++++++++ src/util/crc32.h | 3 +-- src/util/memory.h | 2 +- src/util/patch-ips.h | 2 +- src/util/patch-ups.h | 2 +- src/util/patch.h | 2 +- src/util/png-io.h | 2 +- src/util/socket.h | 2 +- src/util/threading.h | 2 +- src/util/vfs.h | 2 +- 41 files changed, 65 insertions(+), 55 deletions(-) rename src/arm/{common.h => macros.h} (88%) create mode 100644 src/util/common.h diff --git a/src/arm/arm.h b/src/arm/arm.h index b1b4f829d..429a4bb67 100644 --- a/src/arm/arm.h +++ b/src/arm/arm.h @@ -1,7 +1,7 @@ #ifndef ARM_H #define ARM_H -#include "common.h" +#include "util/common.h" enum { ARM_SP = 13, diff --git a/src/arm/isa-arm.h b/src/arm/isa-arm.h index 1d9c6a673..b2107a71e 100644 --- a/src/arm/isa-arm.h +++ b/src/arm/isa-arm.h @@ -1,7 +1,7 @@ #ifndef ISA_ARM_H #define ISA_ARM_H -#include "common.h" +#include "util/common.h" #define ARM_PREFETCH_CYCLES (1 + cpu->memory.activeSeqCycles32) diff --git a/src/arm/isa-inlines.h b/src/arm/isa-inlines.h index c50021c92..1ef92caf8 100644 --- a/src/arm/isa-inlines.h +++ b/src/arm/isa-inlines.h @@ -1,7 +1,7 @@ #ifndef ISA_INLINES_H #define ISA_INLINES_H -#include "common.h" +#include "macros.h" #include "arm.h" diff --git a/src/arm/isa-thumb.h b/src/arm/isa-thumb.h index 715086643..51417dbe6 100644 --- a/src/arm/isa-thumb.h +++ b/src/arm/isa-thumb.h @@ -1,7 +1,7 @@ #ifndef ISA_THUMB_H #define ISA_THUMB_H -#include "common.h" +#include "util/common.h" struct ARMCore; diff --git a/src/arm/common.h b/src/arm/macros.h similarity index 88% rename from src/arm/common.h rename to src/arm/macros.h index 4b6eebd54..a949b9f4f 100644 --- a/src/arm/common.h +++ b/src/arm/macros.h @@ -1,20 +1,7 @@ -#ifndef COMMON_H -#define COMMON_H +#ifndef MACROS_H +#define MACROS_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define UNUSED(V) (void)(V) +#include "util/common.h" #if defined(__PPC__) || defined(__POWERPC__) #define LOAD_32(DEST, ADDR, ARR) { \ diff --git a/src/debugger/cli-debugger.h b/src/debugger/cli-debugger.h index b4b97a3a4..4d115cbb8 100644 --- a/src/debugger/cli-debugger.h +++ b/src/debugger/cli-debugger.h @@ -1,7 +1,7 @@ #ifndef CLI_DEBUGGER_H #define CLI_DEBUGGER_H -#include "common.h" +#include "util/common.h" #include "debugger.h" diff --git a/src/debugger/debugger.h b/src/debugger/debugger.h index e5ccba0c4..0f5576924 100644 --- a/src/debugger/debugger.h +++ b/src/debugger/debugger.h @@ -1,7 +1,7 @@ #ifndef DEBUGGER_H #define DEBUGGER_H -#include "common.h" +#include "util/common.h" #include "arm.h" diff --git a/src/debugger/gdb-stub.h b/src/debugger/gdb-stub.h index 9f80ae196..687b2cf35 100644 --- a/src/debugger/gdb-stub.h +++ b/src/debugger/gdb-stub.h @@ -1,7 +1,7 @@ #ifndef GDB_STUB_H #define GDB_STUB_H -#include "common.h" +#include "util/common.h" #include "debugger/debugger.h" diff --git a/src/debugger/memory-debugger.h b/src/debugger/memory-debugger.h index f23d90765..ea57f73f7 100644 --- a/src/debugger/memory-debugger.h +++ b/src/debugger/memory-debugger.h @@ -1,7 +1,7 @@ #ifndef MEMORY_DEBUGGER_H #define MEMORY_DEBUGGER_H -#include "common.h" +#include "util/common.h" #include "arm.h" diff --git a/src/debugger/parser.h b/src/debugger/parser.h index b4cf29ed3..814c8978f 100644 --- a/src/debugger/parser.h +++ b/src/debugger/parser.h @@ -1,7 +1,7 @@ #ifndef PARSER_H #define PARSER_H -#include "common.h" +#include "util/common.h" #include "debugger.h" enum LexState { diff --git a/src/gba/gba-audio.h b/src/gba/gba-audio.h index c77f736f4..1f1cb8ffd 100644 --- a/src/gba/gba-audio.h +++ b/src/gba/gba-audio.h @@ -1,7 +1,8 @@ #ifndef GBA_AUDIO_H #define GBA_AUDIO_H -#include "common.h" +#include "util/common.h" +#include "macros.h" #include "util/circle-buffer.h" diff --git a/src/gba/gba-bios.h b/src/gba/gba-bios.h index 96f110b34..94f23cf33 100644 --- a/src/gba/gba-bios.h +++ b/src/gba/gba-bios.h @@ -1,7 +1,7 @@ #ifndef GBA_BIOS_H #define GBA_BIOS_H -#include "common.h" +#include "util/common.h" #include "arm.h" diff --git a/src/gba/gba-gpio.h b/src/gba/gba-gpio.h index 01211ba89..b8863c30c 100644 --- a/src/gba/gba-gpio.h +++ b/src/gba/gba-gpio.h @@ -1,7 +1,7 @@ #ifndef GBA_GPIO_H #define GBA_GPIO_H -#include "common.h" +#include "util/common.h" #define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL) diff --git a/src/gba/gba-io.h b/src/gba/gba-io.h index 49ca528da..84a8f533c 100644 --- a/src/gba/gba-io.h +++ b/src/gba/gba-io.h @@ -1,7 +1,7 @@ #ifndef GBA_IO_H #define GBA_IO_H -#include "common.h" +#include "util/common.h" #include "gba.h" diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 828871231..07cd3824c 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -1,5 +1,7 @@ #include "gba-memory.h" +#include "macros.h" + #include "gba-gpio.h" #include "gba-io.h" #include "gba-serialize.h" diff --git a/src/gba/gba-memory.h b/src/gba/gba-memory.h index 1978f42f8..23bd0a41a 100644 --- a/src/gba/gba-memory.h +++ b/src/gba/gba-memory.h @@ -1,9 +1,10 @@ #ifndef GBA_MEMORY_H #define GBA_MEMORY_H -#include "common.h" +#include "util/common.h" #include "arm.h" +#include "macros.h" #include "gba-gpio.h" #include "gba-savedata.h" diff --git a/src/gba/gba-rr.h b/src/gba/gba-rr.h index ad93616d5..ca8239529 100644 --- a/src/gba/gba-rr.h +++ b/src/gba/gba-rr.h @@ -1,7 +1,7 @@ #ifndef GBA_RR_H #define GBA_RR_H -#include "common.h" +#include "util/common.h" struct GBA; struct VDir; diff --git a/src/gba/gba-savedata.h b/src/gba/gba-savedata.h index 08654ca6a..ed4a3cd3c 100644 --- a/src/gba/gba-savedata.h +++ b/src/gba/gba-savedata.h @@ -1,7 +1,7 @@ #ifndef GBA_SAVEDATA_H #define GBA_SAVEDATA_H -#include "common.h" +#include "util/common.h" struct VFile; diff --git a/src/gba/gba-sensors.h b/src/gba/gba-sensors.h index f4119e327..463dd3f00 100644 --- a/src/gba/gba-sensors.h +++ b/src/gba/gba-sensors.h @@ -1,7 +1,7 @@ #ifndef GBA_SENSORS_H #define GBA_SENSORS_H -#include "common.h" +#include "util/common.h" struct GBARotationSource { void (*sample)(struct GBARotationSource*); diff --git a/src/gba/gba-serialize.h b/src/gba/gba-serialize.h index 0f294f5fc..86edf9de5 100644 --- a/src/gba/gba-serialize.h +++ b/src/gba/gba-serialize.h @@ -1,7 +1,7 @@ #ifndef GBA_SERIALIZE_H #define GBA_SERIALIZE_H -#include "common.h" +#include "util/common.h" #include "gba.h" diff --git a/src/gba/gba-sio.h b/src/gba/gba-sio.h index dc4944080..5faae1a74 100644 --- a/src/gba/gba-sio.h +++ b/src/gba/gba-sio.h @@ -1,7 +1,7 @@ #ifndef GBA_SIO_H #define GBA_SIO_H -#include "common.h" +#include "util/common.h" enum GBASIOMode { SIO_NORMAL_8 = 0, diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index b6de84fbd..587e0c3ca 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -1,7 +1,7 @@ #ifndef GBA_THREAD_H #define GBA_THREAD_H -#include "common.h" +#include "util/common.h" #include "gba.h" #include "gba-input.h" diff --git a/src/gba/gba-video.h b/src/gba/gba-video.h index c973f7a05..54c65534d 100644 --- a/src/gba/gba-video.h +++ b/src/gba/gba-video.h @@ -1,9 +1,10 @@ #ifndef GBA_VIDEO_H #define GBA_VIDEO_H -#include "common.h" +#include "util/common.h" #include "gba-memory.h" +#include "macros.h" #ifdef COLOR_16_BIT #define BYTES_PER_PIXEL 2 diff --git a/src/gba/gba.h b/src/gba/gba.h index 4472de179..23eb7f13b 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -1,7 +1,7 @@ #ifndef GBA_H #define GBA_H -#include "common.h" +#include "util/common.h" #include "arm.h" #include "debugger/debugger.h" diff --git a/src/gba/hle-bios.h b/src/gba/hle-bios.h index b27196761..f7b83512d 100644 --- a/src/gba/hle-bios.h +++ b/src/gba/hle-bios.h @@ -1,7 +1,7 @@ #ifndef HLE_BIOS_H #define HLE_BIOS_H -#include "common.h" +#include "util/common.h" extern const uint8_t hleBios[]; diff --git a/src/gba/renderers/video-glsl.h b/src/gba/renderers/video-glsl.h index d29123c0d..beb7b4503 100644 --- a/src/gba/renderers/video-glsl.h +++ b/src/gba/renderers/video-glsl.h @@ -1,7 +1,7 @@ #ifndef VIDEO_GLSL_H #define VIDEO_GLSL_H -#include "common.h" +#include "util/common.h" #include "gba-video.h" diff --git a/src/gba/renderers/video-software.h b/src/gba/renderers/video-software.h index 7aa5cc6db..8acfbc15e 100644 --- a/src/gba/renderers/video-software.h +++ b/src/gba/renderers/video-software.h @@ -1,7 +1,7 @@ #ifndef VIDEO_SOFTWARE_H #define VIDEO_SOFTWARE_H -#include "common.h" +#include "util/common.h" #include "gba-video.h" diff --git a/src/platform/commandline.h b/src/platform/commandline.h index 6eb5a7492..e64d4b4fc 100644 --- a/src/platform/commandline.h +++ b/src/platform/commandline.h @@ -1,7 +1,7 @@ #ifndef COMMAND_LINE_H #define COMMAND_LINE_H -#include "common.h" +#include "util/common.h" enum DebuggerType { DEBUGGER_NONE = 0, diff --git a/src/platform/sdl/sdl-audio.h b/src/platform/sdl/sdl-audio.h index f857d581e..a617d5bf9 100644 --- a/src/platform/sdl/sdl-audio.h +++ b/src/platform/sdl/sdl-audio.h @@ -1,7 +1,7 @@ #ifndef SDL_AUDIO_H #define SDL_AUDIO_H -#include "common.h" +#include "util/common.h" #include diff --git a/src/platform/sdl/sdl-events.h b/src/platform/sdl/sdl-events.h index 05debc576..a4350d25e 100644 --- a/src/platform/sdl/sdl-events.h +++ b/src/platform/sdl/sdl-events.h @@ -1,7 +1,7 @@ #ifndef SDL_EVENTS_H #define SDL_EVENTS_H -#include "common.h" +#include "util/common.h" #include "gba-thread.h" diff --git a/src/util/circle-buffer.h b/src/util/circle-buffer.h index 776f62253..a38274ac7 100644 --- a/src/util/circle-buffer.h +++ b/src/util/circle-buffer.h @@ -1,7 +1,7 @@ #ifndef CIRCLE_BUFFER_H #define CIRCLE_BUFFER_H -#include "common.h" +#include "util/common.h" struct CircleBuffer { void* data; diff --git a/src/util/common.h b/src/util/common.h new file mode 100644 index 000000000..ba8bb138b --- /dev/null +++ b/src/util/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNUSED(V) (void)(V) + +#endif diff --git a/src/util/crc32.h b/src/util/crc32.h index 3e8f2e643..98dc46ec0 100644 --- a/src/util/crc32.h +++ b/src/util/crc32.h @@ -1,8 +1,7 @@ #ifndef CRC32_H #define CRC32_H -#include -#include +#include "util/common.h" struct VFile; diff --git a/src/util/memory.h b/src/util/memory.h index 510049e8f..21cc2dd0f 100644 --- a/src/util/memory.h +++ b/src/util/memory.h @@ -1,7 +1,7 @@ #ifndef MEMORY_H #define MEMORY_H -#include "common.h" +#include "util/common.h" void* anonymousMemoryMap(size_t size); void mappedMemoryFree(void* memory, size_t size); diff --git a/src/util/patch-ips.h b/src/util/patch-ips.h index cf6f4e2f5..fb193eb9a 100644 --- a/src/util/patch-ips.h +++ b/src/util/patch-ips.h @@ -1,7 +1,7 @@ #ifndef PATCH_IPS_H #define PATCH_IPS_H -#include "common.h" +#include "util/common.h" struct Patch; diff --git a/src/util/patch-ups.h b/src/util/patch-ups.h index fbc86c374..c11e4cce4 100644 --- a/src/util/patch-ups.h +++ b/src/util/patch-ups.h @@ -1,7 +1,7 @@ #ifndef PATCH_UPS_H #define PATCH_UPS_H -#include "common.h" +#include "util/common.h" struct Patch; diff --git a/src/util/patch.h b/src/util/patch.h index 43a74f5ac..5471a7df2 100644 --- a/src/util/patch.h +++ b/src/util/patch.h @@ -1,7 +1,7 @@ #ifndef PATCH_H #define PATCH_H -#include "common.h" +#include "util/common.h" struct VFile; diff --git a/src/util/png-io.h b/src/util/png-io.h index 81aca92d7..1a9b12eab 100644 --- a/src/util/png-io.h +++ b/src/util/png-io.h @@ -1,7 +1,7 @@ #ifndef PNG_IO_H #define PNG_IO_H -#include "common.h" +#include "util/common.h" #ifdef USE_PNG diff --git a/src/util/socket.h b/src/util/socket.h index 9146b15a7..a84f9e13d 100644 --- a/src/util/socket.h +++ b/src/util/socket.h @@ -1,7 +1,7 @@ #ifndef SOCKET_H #define SOCKET_H -#include "common.h" +#include "util/common.h" #ifdef __cplusplus #define restrict __restrict__ diff --git a/src/util/threading.h b/src/util/threading.h index 54e09a960..dd2dab0d9 100644 --- a/src/util/threading.h +++ b/src/util/threading.h @@ -1,7 +1,7 @@ #ifndef THREADING_H #define THREADING_H -#include "common.h" +#include "util/common.h" #ifdef USE_PTHREADS #include diff --git a/src/util/vfs.h b/src/util/vfs.h index f3089e0d1..853de9058 100644 --- a/src/util/vfs.h +++ b/src/util/vfs.h @@ -1,7 +1,7 @@ #ifndef VFS_H #define VFS_H -#include "common.h" +#include "util/common.h" enum { MAP_READ = 1, From 24c826e5b109faff843179c3ee41fc8a5f21eb2b Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 12 Oct 2014 19:43:19 -0700 Subject: [PATCH 32/32] Don't log everything to the log handler when that log level is disabled --- src/gba/gba.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gba/gba.c b/src/gba/gba.c index 761181938..745ee5ac9 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -554,16 +554,17 @@ static void _GBAVLog(struct GBA* gba, enum GBALogLevel level, const char* format if (!gba) { gba = threadContext->gba; } - if (threadContext->logHandler) { - threadContext->logHandler(threadContext, level, format, args); - return; - } } if (gba && !(level & gba->logLevel) && level != GBA_LOG_FATAL) { return; } + if (threadContext && threadContext->logHandler) { + threadContext->logHandler(threadContext, level, format, args); + return; + } + vprintf(format, args); printf("\n");