Merge branch 'master' into qt
jump to
@@ -1,8 +1,8 @@
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 "-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")@@ -24,9 +24,14 @@ 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) + if (NOT ${FEATURE_NAME}) + return() + endif() foreach(REQUIRE ${FEATURE_REQUIRES}) find_package(${REQUIRE} QUIET) pkg_search_module(${REQUIRE} ${REQUIRE})@@ -35,6 +40,13 @@ message(WARNING "Requested module ${REQUIRE} missing for feature ${FEATURE_NAME}. Feature disabled.")
set(${FEATURE_NAME} OFF PARENT_SCOPE) return() endif() + 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()@@ -98,7 +110,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()@@ -110,24 +124,22 @@ 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}) + 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() 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}) + link_directories(${LIBZIP_LIBRARY_DIRS}) list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES}) add_definitions(-DENABLE_LIBZIP) endif()@@ -156,6 +168,7 @@
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
@@ -1,7 +1,7 @@
#ifndef ARM_H #define ARM_H -#include "common.h" +#include "util/common.h" enum { ARM_SP = 13,
@@ -1,20 +1,7 @@
-#ifndef COMMON_H -#define COMMON_H +#ifndef MACROS_H +#define MACROS_H -#include <ctype.h> -#include <fcntl.h> -#include <limits.h> -#include <math.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define UNUSED(V) (void)(V) +#include "util/common.h" #if defined(__PPC__) || defined(__POWERPC__) #define LOAD_32(DEST, ADDR, ARR) { \
@@ -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)
@@ -1,7 +1,7 @@
#ifndef ISA_INLINES_H #define ISA_INLINES_H -#include "common.h" +#include "macros.h" #include "arm.h"
@@ -1,7 +1,7 @@
#ifndef ISA_THUMB_H #define ISA_THUMB_H -#include "common.h" +#include "util/common.h" struct ARMCore;
@@ -72,6 +72,9 @@ { "dis/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" },
{ "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" },@@ -233,16 +236,17 @@
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); } }@@ -579,6 +583,10 @@
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;@@ -593,8 +601,28 @@ break;
} } } - if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) { + if (!name) { 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);
@@ -1,7 +1,7 @@
#ifndef CLI_DEBUGGER_H #define CLI_DEBUGGER_H -#include "common.h" +#include "util/common.h" #include "debugger.h"
@@ -1,7 +1,7 @@
#ifndef DEBUGGER_H #define DEBUGGER_H -#include "common.h" +#include "util/common.h" #include "arm.h"
@@ -1,7 +1,7 @@
#ifndef GDB_STUB_H #define GDB_STUB_H -#include "common.h" +#include "util/common.h" #include "debugger/debugger.h"
@@ -1,7 +1,7 @@
#ifndef MEMORY_DEBUGGER_H #define MEMORY_DEBUGGER_H -#include "common.h" +#include "util/common.h" #include "arm.h"
@@ -77,6 +77,7 @@ next = token - '0';
break; case '0': state = LEX_EXPECT_PREFIX; + next = 0; break; case '$': state = LEX_EXPECT_HEX;@@ -120,6 +121,33 @@ default:
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':@@ -216,8 +244,24 @@ case 'x':
next = 0; state = LEX_EXPECT_HEX; break; - default: - state = LEX_ERROR; + case 'B': + case 'b': + next = 0; + state = LEX_EXPECT_BINARY; + 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; } break;@@ -245,8 +289,10 @@ }
} switch (state) { + case LEX_EXPECT_BINARY: case LEX_EXPECT_DECIMAL: case LEX_EXPECT_HEX: + case LEX_EXPECT_PREFIX: lv->token.type = TOKEN_UINT_TYPE; lv->token.uintValue = next; break;
@@ -1,13 +1,14 @@
#ifndef PARSER_H #define PARSER_H -#include "common.h" +#include "util/common.h" #include "debugger.h" enum LexState { LEX_ERROR = -1, LEX_ROOT = 0, LEX_EXPECT_IDENTIFIER, + LEX_EXPECT_BINARY, LEX_EXPECT_DECIMAL, LEX_EXPECT_HEX, LEX_EXPECT_PREFIX,
@@ -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"
@@ -283,6 +283,11 @@ }
} } +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 @@ uint32_t treeBase = source + 5;
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 @@
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;
@@ -1,7 +1,7 @@
#ifndef GBA_BIOS_H #define GBA_BIOS_H -#include "common.h" +#include "util/common.h" #include "arm.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)
@@ -1,7 +1,7 @@
#ifndef GBA_IO_H #define GBA_IO_H -#include "common.h" +#include "util/common.h" #include "gba.h"
@@ -1,5 +1,7 @@
#include "gba-memory.h" +#include "macros.h" + #include "gba-gpio.h" #include "gba-io.h" #include "gba-serialize.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"
@@ -1,7 +1,7 @@
#ifndef GBA_RR_H #define GBA_RR_H -#include "common.h" +#include "util/common.h" struct GBA; struct VDir;
@@ -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); + } } }
@@ -1,7 +1,7 @@
#ifndef GBA_SAVEDATA_H #define GBA_SAVEDATA_H -#include "common.h" +#include "util/common.h" struct VFile;
@@ -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*);
@@ -103,17 +103,9 @@ }
} 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
@@ -1,7 +1,7 @@
#ifndef GBA_SERIALIZE_H #define GBA_SERIALIZE_H -#include "common.h" +#include "util/common.h" #include "gba.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,
@@ -276,35 +276,12 @@ dirent = threadContext->gameDir->listNext(threadContext->gameDir);
} } - 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 @@ #ifdef USE_PNG
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);
@@ -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"
@@ -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
@@ -554,13 +554,14 @@ if (threadContext) {
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; }
@@ -1,7 +1,7 @@
#ifndef GBA_H #define GBA_H -#include "common.h" +#include "util/common.h" #include "arm.h" #include "debugger/debugger.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[];
@@ -1,7 +1,7 @@
#ifndef VIDEO_GLSL_H #define VIDEO_GLSL_H -#include "common.h" +#include "util/common.h" #include "gba-video.h"
@@ -365,7 +365,7 @@ softwareRenderer->windows[activeWindow].control = win->control;
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; }@@ -1193,6 +1193,9 @@
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 @@ \
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) { \
@@ -1,7 +1,7 @@
#ifndef VIDEO_SOFTWARE_H #define VIDEO_SOFTWARE_H -#include "common.h" +#include "util/common.h" #include "gba-video.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,
@@ -5,6 +5,7 @@
#include <errno.h> #include <fcntl.h> #include <signal.h> +#include <inttypes.h> #include <sys/time.h> #define PERF_OPTIONS "F:NPS:"@@ -96,9 +97,9 @@ rendererName = "none";
} else { rendererName = "software"; } - printf("%s,%i,%lli,%s\n", gameCode, frames, duration, rendererName); + printf("%s,%i,%" PRIu64 ",%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 %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); } return 0;@@ -148,6 +149,7 @@ }
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);
@@ -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()
@@ -1,7 +1,7 @@
#ifndef SDL_AUDIO_H #define SDL_AUDIO_H -#include "common.h" +#include "util/common.h" #include <SDL.h>
@@ -1,7 +1,7 @@
#ifndef SDL_EVENTS_H #define SDL_EVENTS_H -#include "common.h" +#include "util/common.h" #include "gba-thread.h"
@@ -1,7 +1,7 @@
#ifndef CIRCLE_BUFFER_H #define CIRCLE_BUFFER_H -#include "common.h" +#include "util/common.h" struct CircleBuffer { void* data;
@@ -0,0 +1,19 @@
+#ifndef COMMON_H +#define COMMON_H + +#include <ctype.h> +#include <fcntl.h> +#include <limits.h> +#include <math.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define UNUSED(V) (void)(V) + +#endif
@@ -1,8 +1,7 @@
#ifndef CRC32_H #define CRC32_H -#include <stdint.h> -#include <string.h> +#include "util/common.h" struct VFile;
@@ -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);
@@ -1,7 +1,7 @@
#ifndef PATCH_IPS_H #define PATCH_IPS_H -#include "common.h" +#include "util/common.h" struct Patch;
@@ -1,7 +1,7 @@
#ifndef PATCH_UPS_H #define PATCH_UPS_H -#include "common.h" +#include "util/common.h" struct Patch;
@@ -1,7 +1,7 @@
#ifndef PATCH_H #define PATCH_H -#include "common.h" +#include "util/common.h" struct VFile;
@@ -1,7 +1,7 @@
#ifndef PNG_IO_H #define PNG_IO_H -#include "common.h" +#include "util/common.h" #ifdef USE_PNG
@@ -1,7 +1,7 @@
#ifndef SOCKET_H #define SOCKET_H -#include "common.h" +#include "util/common.h" #ifdef __cplusplus #define restrict __restrict__
@@ -1,7 +1,7 @@
#ifndef THREADING_H #define THREADING_H -#include "common.h" +#include "util/common.h" #ifdef USE_PTHREADS #include <pthread.h>
@@ -183,6 +183,34 @@
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) {
@@ -1,7 +1,7 @@
#ifndef VFS_H #define VFS_H -#include "common.h" +#include "util/common.h" enum { MAP_READ = 1,@@ -38,5 +38,7 @@
#ifdef ENABLE_LIBZIP 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
@@ -0,0 +1,123 @@
+#!/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) + env = {} + if 'LD_LIBRARY_PATH' in os.environ: + 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) + proc.wait() + except: + proc.kill() + raise + if proc.returncode < 0: + print('Game crashed!', file=sys.stderr) + 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, renderer='software'): + self.cwd = cwd + self.tests = [] + self.wall = wall + self.game = game + self.renderer = renderer + + 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, renderer=self.renderer)) + if self.game: + self.tests.append(GameClockTest(rom, self.game, renderer=self.renderer)) + + 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=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, renderer=None if args.disable_renderer else 'software') + 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()