Merge branch 'port/psp2' into port/crucible

This commit is contained in:
Jeffrey Pfau 2015-08-22 00:52:35 -07:00
commit 015e5962d8
37 changed files with 908 additions and 427 deletions

12
CHANGES
View File

@ -1,3 +1,15 @@
0.4.0: (Future)
Bugfixes:
- Qt: Windows no longer spawn in the top left on first launch
- Qt: Fix install path of XDG desktop file with DESTDIR
- Qt: Fix drag and drop on Windows
- Qt: Reenable double buffering, as disabling it broke some Windows configs
Misc:
- Qt: Window size command line options are now supported
- Qt: Increase usability of key mapper
- GBA Memory: Use a dynamically sized mask for ROM memory
- Qt: Remove useless help icons in dialogs
0.3.0: (2015-08-16) 0.3.0: (2015-08-16)
Features: Features:
- Ability to hide individual background layers, or OBJs - Ability to hide individual background layers, or OBJs

View File

@ -18,6 +18,7 @@ set(BUILD_QT ON CACHE BOOL "Build Qt frontend")
set(BUILD_SDL ON CACHE BOOL "Build SDL frontend") set(BUILD_SDL ON CACHE BOOL "Build SDL frontend")
set(BUILD_LIBRETRO OFF CACHE BOOL "Build libretro core") set(BUILD_LIBRETRO OFF CACHE BOOL "Build libretro core")
set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool") set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool")
set(BUILD_TEST OFF CACHE BOOL "Build testing harness")
set(BUILD_STATIC OFF CACHE BOOL "Build a static library") set(BUILD_STATIC OFF CACHE BOOL "Build a static library")
set(BUILD_SHARED ON CACHE BOOL "Build a shared library") set(BUILD_SHARED ON CACHE BOOL "Build a shared library")
set(BUILD_GL ON CACHE STRING "Build with OpenGL") set(BUILD_GL ON CACHE STRING "Build with OpenGL")
@ -460,8 +461,12 @@ if(WII)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/wii ${CMAKE_BINARY_DIR}) add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/wii ${CMAKE_BINARY_DIR})
endif() endif()
if(PSP2)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2)
endif()
if(BUILD_PERF) if(BUILD_PERF)
set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/perf-main.c) set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
list(APPEND PERF_LIB rt) list(APPEND PERF_LIB rt)
endif() endif()
@ -482,8 +487,10 @@ if(PSP)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp ${CMAKE_BINARY_DIR}/psp) add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp ${CMAKE_BINARY_DIR}/psp)
endif() endif()
if(PSP2) if(BUILD_TEST)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2) add_executable(${BINARY_NAME}-fuzz ${CMAKE_SOURCE_DIR}/src/platform/test/fuzz-main.c)
target_link_libraries(${BINARY_NAME}-fuzz ${BINARY_NAME})
install(TARGETS ${BINARY_NAME}-fuzz DESTINATION bin COMPONENT ${BINARY_NAME}-test)
endif() endif()
# Packaging # Packaging
@ -523,6 +530,7 @@ message(STATUS " Qt: ${BUILD_QT}")
message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}") message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}")
message(STATUS " Libretro core: ${BUILD_LIBRETRO}") message(STATUS " Libretro core: ${BUILD_LIBRETRO}")
message(STATUS " Profiling: ${BUILD_PERF}") message(STATUS " Profiling: ${BUILD_PERF}")
message(STATUS " Test harness: ${BUILD_TEST}")
message(STATUS "Library summary:") message(STATUS "Library summary:")
message(STATUS " Static: ${BUILD_STATIC}") message(STATUS " Static: ${BUILD_STATIC}")
message(STATUS " Shared: ${BUILD_SHARED}") message(STATUS " Shared: ${BUILD_SHARED}")

View File

@ -11,6 +11,7 @@
.Nd Game Boy Advance emulator .Nd Game Boy Advance emulator
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm mgba-qt .Nm mgba-qt
.Op Fl 123456f
.Op Fl b Ar biosfile .Op Fl b Ar biosfile
.Op Fl l Ar loglevel .Op Fl l Ar loglevel
.Op Fl p Ar patchfile .Op Fl p Ar patchfile
@ -21,12 +22,26 @@
is a Game Boy Advance emulator. is a Game Boy Advance emulator.
The options are as follows: The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl 1
Scale the window 1\(mu.
.It Fl 2
Scale the window 2\(mu.
.It Fl 3
Scale the window 3\(mu.
.It Fl 4
Scale the window 4\(mu.
.It Fl 5
Scale the window 5\(mu.
.It Fl 6
Scale the window 6\(mu.
.It Fl b Ar biosfile , Fl -bios Ar biosfile .It Fl b Ar biosfile , Fl -bios Ar biosfile
Specify a BIOS file to use during boot. Specify a BIOS file to use during boot.
If this flag is omitted, If this flag is omitted,
.Nm .Nm
will use the BIOS specified in the configuration file, will use the BIOS specified in the configuration file,
or a high\(hylevel emulated BIOS if none is specified. or a high\(hylevel emulated BIOS if none is specified.
.It Fl f
Start the emulator full\(hyscreen.
.It Fl l Ar loglevel .It Fl l Ar loglevel
Log messages during emulation. Log messages during emulation.
.Ar loglevel .Ar loglevel

View File

@ -7,16 +7,12 @@
#include "debugger.h" #include "debugger.h"
#include "util/math.h"
#include <string.h> #include <string.h>
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width); static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width);
static uint32_t _popcount32(unsigned bits) {
bits = bits - ((bits >> 1) & 0x55555555);
bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
#define FIND_DEBUGGER(DEBUGGER, CPU) \ #define FIND_DEBUGGER(DEBUGGER, CPU) \
{ \ { \
DEBUGGER = 0; \ DEBUGGER = 0; \
@ -51,7 +47,7 @@ static uint32_t _popcount32(unsigned bits) {
static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \ static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
struct ARMDebugger* debugger; \ struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \ FIND_DEBUGGER(debugger, cpu); \
uint32_t popcount = _popcount32(mask); \ uint32_t popcount = popcount32(mask); \
int offset = 4; \ int offset = 4; \
int base = address; \ int base = address; \
if (direction & LSM_D) { \ if (direction & LSM_D) { \

View File

@ -17,6 +17,7 @@
#include "util/crc32.h" #include "util/crc32.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/math.h"
#include "util/patch.h" #include "util/patch.h"
#include "util/vfs.h" #include "util/vfs.h"
@ -156,6 +157,7 @@ void GBAReset(struct ARMCore* cpu) {
if (gba->yankedRomSize) { if (gba->yankedRomSize) {
gba->memory.romSize = gba->yankedRomSize; gba->memory.romSize = gba->yankedRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
gba->yankedRomSize = 0; gba->yankedRomSize = 0;
} }
GBAMemoryReset(gba); GBAMemoryReset(gba);
@ -403,6 +405,7 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char
gba->memory.rom = gba->pristineRom; gba->memory.rom = gba->pristineRom;
gba->activeFile = fname; gba->activeFile = fname;
gba->memory.romSize = gba->pristineRomSize; gba->memory.romSize = gba->pristineRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
GBASavedataInit(&gba->memory.savedata, sav); GBASavedataInit(&gba->memory.savedata, sav);
GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
@ -412,6 +415,7 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char
void GBAYankROM(struct GBA* gba) { void GBAYankROM(struct GBA* gba) {
gba->yankedRomSize = gba->memory.romSize; gba->yankedRomSize = gba->memory.romSize;
gba->memory.romSize = 0; gba->memory.romSize = 0;
gba->memory.romMask = 0;
GBARaiseIRQ(gba, IRQ_GAMEPAK); GBARaiseIRQ(gba, IRQ_GAMEPAK);
} }
@ -452,6 +456,7 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
return; return;
} }
gba->memory.romSize = patchedSize; gba->memory.romSize = patchedSize;
gba->memory.romMask = SIZE_CART0 - 1;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
} }

View File

@ -12,11 +12,11 @@
#include "gba/io.h" #include "gba/io.h"
#include "gba/serialize.h" #include "gba/serialize.h"
#include "gba/hle-bios.h" #include "gba/hle-bios.h"
#include "util/math.h"
#include "util/memory.h" #include "util/memory.h"
#define IDLE_LOOP_THRESHOLD 10000 #define IDLE_LOOP_THRESHOLD 10000
static uint32_t _popcount32(unsigned bits);
static void _pristineCow(struct GBA* gba); static void _pristineCow(struct GBA* gba);
static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
@ -50,6 +50,7 @@ void GBAMemoryInit(struct GBA* gba) {
gba->memory.iwram = 0; gba->memory.iwram = 0;
gba->memory.rom = 0; gba->memory.rom = 0;
gba->memory.romSize = 0; gba->memory.romSize = 0;
gba->memory.romMask = 0;
gba->memory.hw.p = gba; gba->memory.hw.p = gba;
int i; int i;
@ -269,7 +270,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
case REGION_CART2: case REGION_CART2:
case REGION_CART2_EX: case REGION_CART2_EX:
cpu->memory.activeRegion = memory->rom; cpu->memory.activeRegion = memory->rom;
cpu->memory.activeMask = SIZE_CART0 - 1; cpu->memory.activeMask = memory->romMask;
if ((address & (SIZE_CART0 - 1)) < memory->romSize) { if ((address & (SIZE_CART0 - 1)) < memory->romSize) {
break; break;
} }
@ -893,6 +894,7 @@ void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* o
_pristineCow(gba); _pristineCow(gba);
if ((address & (SIZE_CART0 - 4)) >= gba->memory.romSize) { if ((address & (SIZE_CART0 - 4)) >= gba->memory.romSize) {
gba->memory.romSize = (address & (SIZE_CART0 - 4)) + 4; gba->memory.romSize = (address & (SIZE_CART0 - 4)) + 4;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
} }
LOAD_32(oldValue, address & (SIZE_CART0 - 4), gba->memory.rom); LOAD_32(oldValue, address & (SIZE_CART0 - 4), gba->memory.rom);
STORE_32(value, address & (SIZE_CART0 - 4), gba->memory.rom); STORE_32(value, address & (SIZE_CART0 - 4), gba->memory.rom);
@ -960,6 +962,7 @@ void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* o
_pristineCow(gba); _pristineCow(gba);
if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) { if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) {
gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2; gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
} }
LOAD_16(oldValue, address & (SIZE_CART0 - 2), gba->memory.rom); LOAD_16(oldValue, address & (SIZE_CART0 - 2), gba->memory.rom);
STORE_16(value, address & (SIZE_CART0 - 2), gba->memory.rom); STORE_16(value, address & (SIZE_CART0 - 2), gba->memory.rom);
@ -1017,6 +1020,7 @@ void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old)
_pristineCow(gba); _pristineCow(gba);
if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) { if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) {
gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2; gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
} }
oldValue = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; oldValue = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)];
((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)] = value; ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)] = value;
@ -1083,7 +1087,7 @@ uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L
int popcount = 0; int popcount = 0;
if (direction & LSM_D) { if (direction & LSM_D) {
offset = -4; offset = -4;
popcount = _popcount32(mask); popcount = popcount32(mask);
address -= (popcount << 2) - 4; address -= (popcount << 2) - 4;
} }
@ -1196,7 +1200,7 @@ uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum
int popcount = 0; int popcount = 0;
if (direction & LSM_D) { if (direction & LSM_D) {
offset = -4; offset = -4;
popcount = _popcount32(mask); popcount = popcount32(mask);
address -= (popcount << 2) - 4; address -= (popcount << 2) - 4;
} }
@ -1588,12 +1592,6 @@ void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedSt
memcpy(memory->iwram, state->iwram, SIZE_WORKING_IRAM); memcpy(memory->iwram, state->iwram, SIZE_WORKING_IRAM);
} }
uint32_t _popcount32(unsigned bits) {
bits = bits - ((bits >> 1) & 0x55555555);
bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
void _pristineCow(struct GBA* gba) { void _pristineCow(struct GBA* gba) {
if (gba->memory.rom != gba->pristineRom) { if (gba->memory.rom != gba->pristineRom) {
return; return;

View File

@ -118,6 +118,7 @@ struct GBAMemory {
struct GBACartridgeHardware hw; struct GBACartridgeHardware hw;
struct GBASavedata savedata; struct GBASavedata savedata;
size_t romSize; size_t romSize;
uint32_t romMask;
uint16_t romID; uint16_t romID;
int fullBios; int fullBios;

View File

@ -18,6 +18,10 @@
#include <strsafe.h> #include <strsafe.h>
#endif #endif
#ifdef PSP2
#include <psp2/io/stat.h>
#endif
#define SECTION_NAME_MAX 128 #define SECTION_NAME_MAX 128
static const char* _lookupValue(const struct GBAConfig* config, const char* key) { static const char* _lookupValue(const struct GBAConfig* config, const char* key) {
@ -135,13 +139,8 @@ bool GBAConfigSavePath(const struct GBAConfig* config, const char* path) {
} }
void GBAConfigMakePortable(const struct GBAConfig* config) { void GBAConfigMakePortable(const struct GBAConfig* config) {
struct VFile* portable; struct VFile* portable = 0;
#ifndef _WIN32 #ifdef _WIN32
char out[PATH_MAX];
getcwd(out, PATH_MAX);
strncat(out, PATH_SEP "portable.ini", PATH_MAX - strlen(out));
portable = VFileOpen(out, O_WRONLY | O_CREAT);
#else
char out[MAX_PATH]; char out[MAX_PATH];
wchar_t wpath[MAX_PATH]; wchar_t wpath[MAX_PATH];
wchar_t wprojectName[MAX_PATH]; wchar_t wprojectName[MAX_PATH];
@ -152,6 +151,13 @@ void GBAConfigMakePortable(const struct GBAConfig* config) {
WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, MAX_PATH, 0, 0); WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, MAX_PATH, 0, 0);
StringCchCatA(out, MAX_PATH, "\\portable.ini"); StringCchCatA(out, MAX_PATH, "\\portable.ini");
portable = VFileOpen(out, O_WRONLY | O_CREAT); portable = VFileOpen(out, O_WRONLY | O_CREAT);
#elif defined(PSP2)
// Already portable
#else
char out[PATH_MAX];
getcwd(out, PATH_MAX);
strncat(out, PATH_SEP "portable.ini", PATH_MAX - strlen(out));
portable = VFileOpen(out, O_WRONLY | O_CREAT);
#endif #endif
if (portable) { if (portable) {
portable->close(portable); portable->close(portable);
@ -161,22 +167,7 @@ void GBAConfigMakePortable(const struct GBAConfig* config) {
void GBAConfigDirectory(char* out, size_t outLength) { void GBAConfigDirectory(char* out, size_t outLength) {
struct VFile* portable; struct VFile* portable;
#ifndef _WIN32 #ifdef _WIN32
getcwd(out, outLength);
strncat(out, PATH_SEP "portable.ini", outLength - strlen(out));
portable = VFileOpen(out, O_RDONLY);
if (portable) {
getcwd(out, outLength);
portable->close(portable);
return;
}
char* home = getenv("HOME");
snprintf(out, outLength, "%s/.config", home);
mkdir(out, 0755);
snprintf(out, outLength, "%s/.config/%s", home, binaryName);
mkdir(out, 0755);
#else
wchar_t wpath[MAX_PATH]; wchar_t wpath[MAX_PATH];
wchar_t wprojectName[MAX_PATH]; wchar_t wprojectName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, projectName, -1, wprojectName, MAX_PATH); MultiByteToWideChar(CP_UTF8, 0, projectName, -1, wprojectName, MAX_PATH);
@ -196,6 +187,25 @@ void GBAConfigDirectory(char* out, size_t outLength) {
CreateDirectoryW(wpath, NULL); CreateDirectoryW(wpath, NULL);
} }
WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, outLength, 0, 0); WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, outLength, 0, 0);
#elif defined(PSP2)
UNUSED(portable);
snprintf(out, outLength, "cache0:/%s", binaryName);
sceIoMkdir(out, 0777);
#else
getcwd(out, outLength);
strncat(out, PATH_SEP "portable.ini", outLength - strlen(out));
portable = VFileOpen(out, O_RDONLY);
if (portable) {
getcwd(out, outLength);
portable->close(portable);
return;
}
char* home = getenv("HOME");
snprintf(out, outLength, "%s/.config", home);
mkdir(out, 0755);
snprintf(out, outLength, "%s/.config/%s", home, binaryName);
mkdir(out, 0755);
#endif #endif
} }

View File

@ -0,0 +1,156 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba/supervisor/context.h"
#include "gba/supervisor/overrides.h"
#include "util/memory.h"
#include "util/vfs.h"
bool GBAContextInit(struct GBAContext* context, const char* port) {
context->gba = anonymousMemoryMap(sizeof(struct GBA));
context->cpu = anonymousMemoryMap(sizeof(struct ARMCore));
context->rom = 0;
context->save = 0;
context->renderer = 0;
if (!context->gba || !context->cpu) {
if (context->gba) {
mappedMemoryFree(context->gba, sizeof(struct GBA));
}
if (context->cpu) {
mappedMemoryFree(context->cpu, sizeof(struct ARMCore));
}
return false;
}
GBAConfigInit(&context->config, port);
if (port) {
GBAConfigLoad(&context->config);
}
GBACreate(context->gba);
ARMSetComponents(context->cpu, &context->gba->d, 0, 0);
ARMInit(context->cpu);
context->gba->sync = 0;
return true;
}
void GBAContextDeinit(struct GBAContext* context) {
if (context->bios) {
context->bios->close(context->bios);
context->bios = 0;
}
if (context->rom) {
context->rom->close(context->rom);
context->rom = 0;
}
if (context->save) {
context->save->close(context->save);
context->save = 0;
}
ARMDeinit(context->cpu);
GBADestroy(context->gba);
mappedMemoryFree(context->gba, 0);
mappedMemoryFree(context->cpu, 0);
GBAConfigDeinit(&context->config);
}
bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autoloadSave) {
context->rom = VFileOpen(path, O_RDONLY);
if (!context->rom) {
return false;
}
if (!GBAIsROM(context->rom)) {
context->rom->close(context->rom);
context->rom = 0;
return false;
}
if (autoloadSave) {
context->save = VDirOptionalOpenFile(0, path, 0, ".sav", O_RDWR | O_CREAT);
}
return true;
}
bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save) {
context->rom = rom;
if (!GBAIsROM(context->rom)) {
context->rom = 0;
return false;
}
context->save = save;
return true;
}
bool GBAContextLoadBIOS(struct GBAContext* context, const char* path) {
context->bios = VFileOpen(path, O_RDONLY);
if (!context->bios) {
return false;
}
if (!GBAIsBIOS(context->bios)) {
context->bios->close(context->bios);
context->bios = 0;
return false;
}
return true;
}
bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios) {
context->bios = bios;
if (!GBAIsBIOS(context->bios)) {
context->bios = 0;
return false;
}
return true;
}
bool GBAContextStart(struct GBAContext* context) {
struct GBAOptions opts = {};
GBAConfigMap(&context->config, &opts);
if (context->renderer) {
GBAVideoAssociateRenderer(&context->gba->video, context->renderer);
}
GBALoadROM(context->gba, context->rom, context->save, 0);
if (opts.useBios && context->bios) {
GBALoadBIOS(context->gba, context->bios);
}
ARMReset(context->cpu);
if (opts.skipBios) {
GBASkipBIOS(context->cpu);
}
struct GBACartridgeOverride override;
const struct GBACartridge* cart = (const struct GBACartridge*) context->gba->memory.rom;
memcpy(override.id, &cart->id, sizeof(override.id));
if (GBAOverrideFind(GBAConfigGetOverrides(&context->config), &override)) {
GBAOverrideApply(context->gba, &override);
}
GBAConfigFreeOpts(&opts);
return true;
}
void GBAContextStop(struct GBAContext* context) {
UNUSED(context);
// TODO?
}
void GBAContextFrame(struct GBAContext* context, uint16_t keys) {
int activeKeys = keys;
context->gba->keySource = &activeKeys;
int frameCounter = context->gba->video.frameCounter;
while (frameCounter == context->gba->video.frameCounter) {
ARMRunLoop(context->cpu);
}
}

View File

@ -0,0 +1,38 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CONTEXT_H
#define CONTEXT_H
#include "util/common.h"
#include "gba/supervisor/config.h"
#include "gba/input.h"
struct GBAContext {
struct GBA* gba;
struct ARMCore* cpu;
struct GBAVideoRenderer* renderer;
struct VFile* rom;
struct VFile* save;
struct VFile* bios;
struct GBAConfig config;
struct GBAOptions opts;
struct GBAInputMap inputMap;
};
bool GBAContextInit(struct GBAContext* context, const char* port);
void GBAContextDeinit(struct GBAContext* context);
bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autoloadSave);
bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save);
bool GBAContextLoadBIOS(struct GBAContext* context, const char* path);
bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios);
bool GBAContextStart(struct GBAContext* context);
void GBAContextStop(struct GBAContext* context);
void GBAContextFrame(struct GBAContext* context, uint16_t keys);
#endif

View File

@ -50,7 +50,7 @@ static const struct option _options[] = {
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg); static bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg);
bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) { bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) {
int ch; int ch;
@ -145,6 +145,7 @@ void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts)
parser->parse = _parseGraphicsArg; parser->parse = _parseGraphicsArg;
parser->extraOptions = GRAPHICS_OPTIONS; parser->extraOptions = GRAPHICS_OPTIONS;
opts->multiplier = 0; opts->multiplier = 0;
opts->fullscreen = false;
} }
bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) { bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
@ -152,6 +153,7 @@ bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int o
struct GraphicsOpts* graphicsOpts = parser->opts; struct GraphicsOpts* graphicsOpts = parser->opts;
switch (option) { switch (option) {
case 'f': case 'f':
graphicsOpts->fullscreen = true;
GBAConfigSetDefaultIntValue(config, "fullscreen", 1); GBAConfigSetDefaultIntValue(config, "fullscreen", 1);
return true; return true;
case '1': case '1':

View File

@ -42,6 +42,7 @@ struct SubParser {
struct GraphicsOpts { struct GraphicsOpts {
int multiplier; int multiplier;
bool fullscreen;
}; };
struct GBAThread; struct GBAThread;

View File

@ -7,12 +7,9 @@
#include "util/common.h" #include "util/common.h"
#include "gba/gba.h"
#include "gba/interface.h"
#include "gba/renderers/video-software.h" #include "gba/renderers/video-software.h"
#include "gba/serialize.h" #include "gba/serialize.h"
#include "gba/supervisor/overrides.h" #include "gba/supervisor/context.h"
#include "gba/video.h"
#include "util/circle-buffer.h" #include "util/circle-buffer.h"
#include "util/vfs.h" #include "util/vfs.h"
@ -37,14 +34,10 @@ static void _setRumble(struct GBARumble* rumble, int enable);
static uint8_t _readLux(struct GBALuminanceSource* lux); static uint8_t _readLux(struct GBALuminanceSource* lux);
static void _updateLux(struct GBALuminanceSource* lux); static void _updateLux(struct GBALuminanceSource* lux);
static struct GBA gba; static struct GBAContext context;
static struct ARMCore cpu;
static struct GBAVideoSoftwareRenderer renderer; static struct GBAVideoSoftwareRenderer renderer;
static struct VFile* rom;
static void* data; static void* data;
static struct VFile* save;
static void* savedata; static void* savedata;
static struct VFile* bios;
static struct GBAAVStream stream; static struct GBAAVStream stream;
static int rumbleLevel; static int rumbleLevel;
static struct CircleBuffer rumbleHistory; static struct CircleBuffer rumbleHistory;
@ -162,53 +155,49 @@ void retro_init(void) {
stream.postAudioBuffer = _postAudioBuffer; stream.postAudioBuffer = _postAudioBuffer;
stream.postVideoFrame = _postVideoFrame; stream.postVideoFrame = _postVideoFrame;
GBACreate(&gba); GBAContextInit(&context, 0);
ARMSetComponents(&cpu, &gba.d, 0, 0); struct GBAOptions opts = {
ARMInit(&cpu); .useBios = true,
gba.logLevel = 0; // TODO: Settings .logLevel = 0,
gba.logHandler = GBARetroLog; .idleOptimization = IDLE_LOOP_REMOVE
gba.stream = &stream; };
gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings GBAConfigLoadDefaults(&context.config, &opts);
context.gba->logHandler = GBARetroLog;
context.gba->stream = &stream;
if (rumbleCallback) { if (rumbleCallback) {
gba.rumble = &rumble; context.gba->rumble = &rumble;
} }
gba.luminanceSource = &lux; context.gba->luminanceSource = &lux;
rom = 0;
const char* sysDir = 0; const char* sysDir = 0;
if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) {
char biosPath[PATH_MAX]; char biosPath[PATH_MAX];
snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin");
bios = VFileOpen(biosPath, O_RDONLY); struct VFile* bios = VFileOpen(biosPath, O_RDONLY);
if (bios) { if (bios) {
GBALoadBIOS(&gba, bios); GBAContextLoadBIOSFromVFile(&context, bios);
} }
} }
GBAVideoSoftwareRendererCreate(&renderer); GBAVideoSoftwareRendererCreate(&renderer);
renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer.outputBufferStride = 256; renderer.outputBufferStride = 256;
GBAVideoAssociateRenderer(&gba.video, &renderer.d); GBAVideoAssociateRenderer(&context.gba->video, &renderer.d);
GBAAudioResizeBuffer(&gba.audio, SAMPLES); GBAAudioResizeBuffer(&context.gba->audio, SAMPLES);
#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF
blip_set_rates(gba.audio.left, GBA_ARM7TDMI_FREQUENCY, 32768); blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 32768);
blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 32768); blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 32768);
#endif #endif
} }
void retro_deinit(void) { void retro_deinit(void) {
if (bios) { GBAContextDeinit(&context);
bios->close(bios);
bios = 0;
}
GBADestroy(&gba);
} }
void retro_run(void) { void retro_run(void) {
int keys; uint16_t keys;
gba.keySource = &keys;
inputPollCallback(); inputPollCallback();
keys = 0; keys = 0;
@ -243,14 +232,11 @@ void retro_run(void) {
} }
} }
int frameCount = gba.video.frameCounter; GBAContextFrame(&context, keys);
while (gba.video.frameCounter == frameCount) {
ARMRunLoop(&cpu);
}
} }
void retro_reset(void) { void retro_reset(void) {
ARMReset(&cpu); ARMReset(context.cpu);
if (rumbleCallback) { if (rumbleCallback) {
CircleBufferClear(&rumbleHistory); CircleBufferClear(&rumbleHistory);
@ -258,6 +244,7 @@ void retro_reset(void) {
} }
bool retro_load_game(const struct retro_game_info* game) { bool retro_load_game(const struct retro_game_info* game) {
struct VFile* rom;
if (game->data) { if (game->data) {
data = malloc(game->size); data = malloc(game->size);
memcpy(data, game->data, game->size); memcpy(data, game->data, game->size);
@ -270,26 +257,23 @@ bool retro_load_game(const struct retro_game_info* game) {
return false; return false;
} }
if (!GBAIsROM(rom)) { if (!GBAIsROM(rom)) {
rom->close(rom);
free(data);
return false; return false;
} }
savedata = malloc(SIZE_CART_FLASH1M); savedata = malloc(SIZE_CART_FLASH1M);
save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M);
GBALoadROM(&gba, rom, save, game->path); GBAContextLoadROMFromVFile(&context, rom, save);
GBAOverrideApplyDefaults(&gba); GBAContextStart(&context);
ARMReset(&cpu);
return true; return true;
} }
void retro_unload_game(void) { void retro_unload_game(void) {
rom->close(rom); GBAContextStop(&context);
rom = 0;
free(data); free(data);
data = 0; data = 0;
save->close(save);
save = 0;
free(savedata); free(savedata);
savedata = 0; savedata = 0;
CircleBufferDeinit(&rumbleHistory); CircleBufferDeinit(&rumbleHistory);
@ -303,7 +287,7 @@ bool retro_serialize(void* data, size_t size) {
if (size != retro_serialize_size()) { if (size != retro_serialize_size()) {
return false; return false;
} }
GBASerialize(&gba, data); GBASerialize(context.gba, data);
return true; return true;
} }
@ -311,7 +295,7 @@ bool retro_unserialize(const void* data, size_t size) {
if (size != retro_serialize_size()) { if (size != retro_serialize_size()) {
return false; return false;
} }
GBADeserialize(&gba, data); GBADeserialize(context.gba, data);
return true; return true;
} }
@ -353,7 +337,7 @@ size_t retro_get_memory_size(unsigned id) {
if (id != RETRO_MEMORY_SAVE_RAM) { if (id != RETRO_MEMORY_SAVE_RAM) {
return 0; return 0;
} }
switch (gba.memory.savedata.type) { switch (context.gba->memory.savedata.type) {
case SAVEDATA_AUTODETECT: case SAVEDATA_AUTODETECT:
case SAVEDATA_FLASH1M: case SAVEDATA_FLASH1M:
return SIZE_CART_FLASH1M; return SIZE_CART_FLASH1M;

View File

@ -72,7 +72,9 @@ int main() {
if (!selectFile(&params, "cache0:", path, sizeof(path), "gba")) { if (!selectFile(&params, "cache0:", path, sizeof(path), "gba")) {
break; break;
} }
GBAPSP2LoadROM(path); if (!GBAPSP2LoadROM(path)) {
continue;
}
GBAPSP2Runloop(); GBAPSP2Runloop();
GBAPSP2UnloadROM(); GBAPSP2UnloadROM();
} }

View File

@ -8,8 +8,7 @@
#include "gba/gba.h" #include "gba/gba.h"
#include "gba/input.h" #include "gba/input.h"
#include "gba/audio.h" #include "gba/audio.h"
#include "gba/supervisor/overrides.h" #include "gba/supervisor/context.h"
#include "gba/video.h"
#include "gba/renderers/video-software.h" #include "gba/renderers/video-software.h"
#include "util/circle-buffer.h" #include "util/circle-buffer.h"
@ -27,13 +26,8 @@
#include <vita2d.h> #include <vita2d.h>
static char gameName[13]; static struct GBAContext context;
static struct GBA* gba;
static struct ARMCore* cpu;
static struct VFile* rom;
static struct VFile* save;
static struct GBAVideoSoftwareRenderer renderer; static struct GBAVideoSoftwareRenderer renderer;
static struct GBAInputMap inputMap;
static vita2d_texture* tex; static vita2d_texture* tex;
static Thread audioThread; static Thread audioThread;
@ -81,172 +75,130 @@ static THREAD_ENTRY _audioThread(void* context) {
} }
void GBAPSP2Setup() { void GBAPSP2Setup() {
GBAInputMapInit(&inputMap); GBAContextInit(&context, 0);
_mapVitaKey(&inputMap, PSP2_CTRL_CROSS, GBA_KEY_A); struct GBAOptions opts = {
_mapVitaKey(&inputMap, PSP2_CTRL_CIRCLE, GBA_KEY_B); .useBios = true,
_mapVitaKey(&inputMap, PSP2_CTRL_START, GBA_KEY_START); .logLevel = 0,
_mapVitaKey(&inputMap, PSP2_CTRL_SELECT, GBA_KEY_SELECT); .idleOptimization = IDLE_LOOP_DETECT
_mapVitaKey(&inputMap, PSP2_CTRL_UP, GBA_KEY_UP); };
_mapVitaKey(&inputMap, PSP2_CTRL_DOWN, GBA_KEY_DOWN); GBAConfigLoadDefaults(&context.config, &opts);
_mapVitaKey(&inputMap, PSP2_CTRL_LEFT, GBA_KEY_LEFT); _mapVitaKey(&context.inputMap, PSP2_CTRL_CROSS, GBA_KEY_A);
_mapVitaKey(&inputMap, PSP2_CTRL_RIGHT, GBA_KEY_RIGHT); _mapVitaKey(&context.inputMap, PSP2_CTRL_CIRCLE, GBA_KEY_B);
_mapVitaKey(&inputMap, PSP2_CTRL_LTRIGGER, GBA_KEY_L); _mapVitaKey(&context.inputMap, PSP2_CTRL_START, GBA_KEY_START);
_mapVitaKey(&inputMap, PSP2_CTRL_RTRIGGER, GBA_KEY_R); _mapVitaKey(&context.inputMap, PSP2_CTRL_SELECT, GBA_KEY_SELECT);
_mapVitaKey(&context.inputMap, PSP2_CTRL_UP, GBA_KEY_UP);
_mapVitaKey(&context.inputMap, PSP2_CTRL_DOWN, GBA_KEY_DOWN);
_mapVitaKey(&context.inputMap, PSP2_CTRL_LEFT, GBA_KEY_LEFT);
_mapVitaKey(&context.inputMap, PSP2_CTRL_RIGHT, GBA_KEY_RIGHT);
_mapVitaKey(&context.inputMap, PSP2_CTRL_LTRIGGER, GBA_KEY_L);
_mapVitaKey(&context.inputMap, PSP2_CTRL_RTRIGGER, GBA_KEY_R);
struct GBAAxis desc = { GBA_KEY_DOWN, GBA_KEY_UP, 192, 64 }; struct GBAAxis desc = { GBA_KEY_DOWN, GBA_KEY_UP, 192, 64 };
GBAInputBindAxis(&inputMap, PSP2_INPUT, 0, &desc); GBAInputBindAxis(&context.inputMap, PSP2_INPUT, 0, &desc);
desc = (struct GBAAxis) { GBA_KEY_RIGHT, GBA_KEY_LEFT, 192, 64 }; desc = (struct GBAAxis) { GBA_KEY_RIGHT, GBA_KEY_LEFT, 192, 64 };
GBAInputBindAxis(&inputMap, PSP2_INPUT, 1, &desc); GBAInputBindAxis(&context.inputMap, PSP2_INPUT, 1, &desc);
tex = vita2d_create_empty_texture_format(256, 256, SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); tex = vita2d_create_empty_texture_format(256, 256, SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR);
GBAVideoSoftwareRendererCreate(&renderer);
renderer.outputBuffer = vita2d_texture_get_datap(tex); renderer.outputBuffer = vita2d_texture_get_datap(tex);
renderer.outputBufferStride = 256; renderer.outputBufferStride = 256;
GBAVideoAssociateRenderer(&context.gba->video, &renderer.d);
printf("%s starting", projectName);
} }
void GBAPSP2LoadROM(const char* path) { bool GBAPSP2LoadROM(const char* path) {
GBAVideoSoftwareRendererCreate(&renderer); if (!GBAContextLoadROM(&context, path, true)) {
printf("%s failed to load!", path);
gba = anonymousMemoryMap(sizeof(struct GBA)); return false;
cpu = anonymousMemoryMap(sizeof(struct ARMCore)); }
printf("%s loaded, starting...", path);
printf("GBA: %08X", gba); GBAContextStart(&context);
printf("CPU: %08X", cpu); char gameTitle[13];
GBAGetGameTitle(context.gba, gameTitle);
rom = VFileOpenSce(path, PSP2_O_RDONLY, 0666); printf("%s started!", gameTitle);
save = VDirOptionalOpenFile(0, path, 0, ".sav", PSP2_O_RDWR | PSP2_O_CREAT);
printf("ROM: %08X", rom);
printf("Save: %08X", save);
GBACreate(gba);
ARMSetComponents(cpu, &gba->d, 0, 0);
ARMInit(cpu);
printf("%s initialized.", "CPU");
gba->sync = 0;
GBAVideoAssociateRenderer(&gba->video, &renderer.d);
GBALoadROM(gba, rom, save, 0);
GBAOverrideApplyDefaults(gba);
GBAGetGameTitle(gba, gameName);
printf("ROM loaded: %s", gameName);
ARMReset(cpu);
double ratio = GBAAudioCalculateRatio(1, 60, 1); double ratio = GBAAudioCalculateRatio(1, 60, 1);
blip_set_rates(gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio);
blip_set_rates(gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio);
CircleBufferInit(&audioContext.buffer, PSP2_AUDIO_BUFFER_SIZE * sizeof(struct GBAStereoSample)); CircleBufferInit(&audioContext.buffer, PSP2_AUDIO_BUFFER_SIZE * sizeof(struct GBAStereoSample));
MutexInit(&audioContext.mutex); MutexInit(&audioContext.mutex);
ConditionInit(&audioContext.cond); ConditionInit(&audioContext.cond);
audioContext.running = true; audioContext.running = true;
ThreadCreate(&audioThread, _audioThread, &audioContext); ThreadCreate(&audioThread, _audioThread, &audioContext);
return true;
printf("%s all set and ready to roll.", projectName);
} }
void GBAPSP2Runloop(void) { void GBAPSP2Runloop(void) {
int activeKeys = 0; int activeKeys = 0;
gba->keySource = &activeKeys;
bool fsToggle = false; bool fsToggle = false;
int frameCounter = 0;
while (true) { while (true) {
ARMRunLoop(cpu); SceCtrlData pad;
sceCtrlPeekBufferPositive(0, &pad, 1);
if (pad.buttons & PSP2_CTRL_TRIANGLE) {
break;
}
if (pad.buttons & PSP2_CTRL_SQUARE) {
if (!fsToggle) {
fullscreen = !fullscreen;
}
fsToggle = true;
} else {
fsToggle = false;
}
if (frameCounter != gba->video.frameCounter) { activeKeys = GBAInputMapKeyBits(&context.inputMap, PSP2_INPUT, pad.buttons, 0);
SceCtrlData pad; enum GBAKey angles = GBAInputMapAxis(&context.inputMap, PSP2_INPUT, 0, pad.ly);
sceCtrlPeekBufferPositive(0, &pad, 1); if (angles != GBA_KEY_NONE) {
if (pad.buttons & PSP2_CTRL_TRIANGLE) { activeKeys |= 1 << angles;
}
angles = GBAInputMapAxis(&context.inputMap, PSP2_INPUT, 1, pad.lx);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
angles = GBAInputMapAxis(&context.inputMap, PSP2_INPUT, 2, pad.ry);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
angles = GBAInputMapAxis(&context.inputMap, PSP2_INPUT, 3, pad.rx);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
GBAContextFrame(&context, activeKeys);
MutexLock(&audioContext.mutex);
while (blip_samples_avail(context.gba->audio.left) >= PSP2_SAMPLES) {
if (CircleBufferSize(&audioContext.buffer) + PSP2_SAMPLES * sizeof(struct GBAStereoSample) > CircleBufferCapacity(&audioContext.buffer)) {
break; break;
} }
if (pad.buttons & PSP2_CTRL_SQUARE) { struct GBAStereoSample samples[PSP2_SAMPLES];
if (!fsToggle) { blip_read_samples(context.gba->audio.left, &samples[0].left, PSP2_SAMPLES, true);
fullscreen = !fullscreen; blip_read_samples(context.gba->audio.right, &samples[0].right, PSP2_SAMPLES, true);
} int i;
fsToggle = true; for (i = 0; i < PSP2_SAMPLES; ++i) {
} else { CircleBufferWrite16(&audioContext.buffer, samples[i].left);
fsToggle = false; CircleBufferWrite16(&audioContext.buffer, samples[i].right);
} }
activeKeys = GBAInputMapKeyBits(&inputMap, PSP2_INPUT, pad.buttons, 0);
enum GBAKey angles = GBAInputMapAxis(&inputMap, PSP2_INPUT, 0, pad.ly);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
angles = GBAInputMapAxis(&inputMap, PSP2_INPUT, 1, pad.lx);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
angles = GBAInputMapAxis(&inputMap, PSP2_INPUT, 2, pad.ry);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
angles = GBAInputMapAxis(&inputMap, PSP2_INPUT, 3, pad.rx);
if (angles != GBA_KEY_NONE) {
activeKeys |= 1 << angles;
}
MutexLock(&audioContext.mutex);
while (blip_samples_avail(gba->audio.left) >= PSP2_SAMPLES) {
if (CircleBufferSize(&audioContext.buffer) + PSP2_SAMPLES * sizeof(struct GBAStereoSample) > CircleBufferCapacity(&audioContext.buffer)) {
break;
}
struct GBAStereoSample samples[PSP2_SAMPLES];
blip_read_samples(gba->audio.left, &samples[0].left, PSP2_SAMPLES, true);
blip_read_samples(gba->audio.right, &samples[0].right, PSP2_SAMPLES, true);
int i;
for (i = 0; i < PSP2_SAMPLES; ++i) {
CircleBufferWrite16(&audioContext.buffer, samples[i].left);
CircleBufferWrite16(&audioContext.buffer, samples[i].right);
}
}
ConditionWake(&audioContext.cond);
MutexUnlock(&audioContext.mutex);
vita2d_start_drawing();
vita2d_clear_screen();
GBAPSP2Draw();
vita2d_end_drawing();
vita2d_swap_buffers();
frameCounter = gba->video.frameCounter;
} }
ConditionWake(&audioContext.cond);
MutexUnlock(&audioContext.mutex);
vita2d_start_drawing();
vita2d_clear_screen();
GBAPSP2Draw();
vita2d_end_drawing();
vita2d_swap_buffers();
} }
} }
void GBAPSP2UnloadROM(void) { void GBAPSP2UnloadROM(void) {
printf("%s shutting down...", projectName); GBAContextStop(&context);
ARMDeinit(cpu);
GBADestroy(gba);
rom->close(rom);
save->close(save);
MutexLock(&audioContext.mutex);
audioContext.running = false;
ConditionWake(&audioContext.cond);
MutexUnlock(&audioContext.mutex);
ThreadJoin(audioThread);
CircleBufferDeinit(&audioContext.buffer);
MutexDeinit(&audioContext.mutex);
ConditionDeinit(&audioContext.cond);
mappedMemoryFree(gba, 0);
mappedMemoryFree(cpu, 0);
gba = 0;
cpu = 0;
rom = 0;
save = 0;
} }
void GBAPSP2Teardown(void) { void GBAPSP2Teardown(void) {
GBAInputMapDeinit(&inputMap); GBAContextDeinit(&context);
vita2d_free_texture(tex); vita2d_free_texture(tex);
} }

View File

@ -11,7 +11,7 @@
void GBAPSP2Setup(void); void GBAPSP2Setup(void);
void GBAPSP2Teardown(void); void GBAPSP2Teardown(void);
void GBAPSP2LoadROM(const char* path); bool GBAPSP2LoadROM(const char* path);
void GBAPSP2Runloop(void); void GBAPSP2Runloop(void);
void GBAPSP2UnloadROM(void); void GBAPSP2UnloadROM(void);

View File

@ -12,7 +12,7 @@
using namespace QGBA; using namespace QGBA;
AboutScreen::AboutScreen(QWidget* parent) AboutScreen::AboutScreen(QWidget* parent)
: QDialog(parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
{ {
m_ui.setupUi(this); m_ui.setupUi(this);

View File

@ -167,7 +167,7 @@ install(TARGETS ${BINARY_NAME}-qt
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
find_program(DESKTOP_FILE_INSTALL desktop-file-install) find_program(DESKTOP_FILE_INSTALL desktop-file-install)
if(DESKTOP_FILE_INSTALL) if(DESKTOP_FILE_INSTALL)
install(CODE "execute_process(COMMAND ${DESKTOP_FILE_INSTALL} \"${CMAKE_SOURCE_DIR}/res/mgba-qt.desktop\" --dir \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/share/applications/\")") install(CODE "execute_process(COMMAND ${DESKTOP_FILE_INSTALL} \"${CMAKE_SOURCE_DIR}/res/mgba-qt.desktop\" --dir \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/applications/\")")
endif() endif()
endif() endif()
if(UNIX) if(UNIX)

View File

@ -126,8 +126,8 @@ ConfigController::~ConfigController() {
GBAConfigFreeOpts(&m_opts); GBAConfigFreeOpts(&m_opts);
} }
bool ConfigController::parseArguments(GBAArguments* args, int argc, char* argv[]) { bool ConfigController::parseArguments(GBAArguments* args, int argc, char* argv[], SubParser* subparser) {
if (::parseArguments(args, &m_config, argc, argv, 0)) { if (::parseArguments(args, &m_config, argc, argv, subparser)) {
GBAConfigMap(&m_config, &m_opts); GBAConfigMap(&m_config, &m_opts);
return true; return true;
} }

View File

@ -16,6 +16,7 @@
extern "C" { extern "C" {
#include "gba/supervisor/config.h" #include "gba/supervisor/config.h"
#include "util/configuration.h" #include "util/configuration.h"
#include "platform/commandline.h"
} }
class QAction; class QAction;
@ -64,7 +65,7 @@ public:
~ConfigController(); ~ConfigController();
const GBAOptions* options() const { return &m_opts; } const GBAOptions* options() const { return &m_opts; }
bool parseArguments(GBAArguments* args, int argc, char* argv[]); bool parseArguments(GBAArguments* args, int argc, char* argv[], SubParser* subparser = nullptr);
ConfigOption* addOption(const char* key); ConfigOption* addOption(const char* key);
void updateOption(const char* key); void updateOption(const char* key);

View File

@ -22,7 +22,7 @@ Display::Driver Display::s_driver = Display::Driver::QT;
Display* Display::create(QWidget* parent) { Display* Display::create(QWidget* parent) {
#ifdef BUILD_GL #ifdef BUILD_GL
QGLFormat format(QGLFormat(QGL::Rgba | QGL::SingleBuffer)); QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer));
format.setSwapInterval(1); format.setSwapInterval(1);
#endif #endif

View File

@ -50,9 +50,12 @@ GBAApp::GBAApp(int& argc, char* argv[])
} }
GBAArguments args; GBAArguments args;
bool loaded = m_configController.parseArguments(&args, argc, argv); GraphicsOpts graphicsOpts;
SubParser subparser;
initParserForGraphics(&subparser, &graphicsOpts);
bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser);
if (loaded && args.showHelp) { if (loaded && args.showHelp) {
usage(argv[0], 0); usage(argv[0], subparser.usage);
::exit(0); ::exit(0);
return; return;
} }
@ -72,6 +75,14 @@ GBAApp::GBAApp(int& argc, char* argv[])
w->loadConfig(); w->loadConfig();
} }
freeArguments(&args); freeArguments(&args);
if (graphicsOpts.multiplier) {
w->resizeFrame(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier);
}
if (graphicsOpts.fullscreen) {
w->enterFullScreen();
}
w->show(); w->show();
w->controller()->setMultiplayerController(&m_multiplayer); w->controller()->setMultiplayerController(&m_multiplayer);

View File

@ -18,7 +18,7 @@
using namespace QGBA; using namespace QGBA;
GDBWindow::GDBWindow(GDBController* controller, QWidget* parent) GDBWindow::GDBWindow(GDBController* controller, QWidget* parent)
: QDialog(parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_gdbController(controller) , m_gdbController(controller)
{ {
setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint);

View File

@ -7,6 +7,7 @@
#include "GamepadAxisEvent.h" #include "GamepadAxisEvent.h"
#include "GamepadButtonEvent.h" #include "GamepadButtonEvent.h"
#include "ShortcutController.h"
#include <QKeyEvent> #include <QKeyEvent>
@ -20,6 +21,7 @@ KeyEditor::KeyEditor(QWidget* parent)
, m_button(false) , m_button(false)
{ {
setAlignment(Qt::AlignCenter); setAlignment(Qt::AlignCenter);
setFocusPolicy(Qt::ClickFocus);
} }
void KeyEditor::setValue(int key) { void KeyEditor::setValue(int key) {
@ -27,7 +29,11 @@ void KeyEditor::setValue(int key) {
if (m_button) { if (m_button) {
updateButtonText(); updateButtonText();
} else { } else {
setText(QKeySequence(key).toString(QKeySequence::NativeText)); if (key < 0) {
setText(tr("---"));
} else {
setText(QKeySequence(key).toString(QKeySequence::NativeText));
}
} }
emit valueChanged(key); emit valueChanged(key);
} }
@ -71,27 +77,60 @@ QSize KeyEditor::sizeHint() const {
void KeyEditor::keyPressEvent(QKeyEvent* event) { void KeyEditor::keyPressEvent(QKeyEvent* event) {
if (!m_button) { if (!m_button) {
setValue(event->key()); if (m_key < 0) {
m_key = 0;
}
if (ShortcutController::isModifierKey(event->key())) {
switch (event->key()) {
case Qt::Key_Shift:
setValue(m_key | Qt::ShiftModifier);
break;
case Qt::Key_Control:
setValue(m_key | Qt::ControlModifier);
break;
case Qt::Key_Alt:
setValue(m_key | Qt::AltModifier);
break;
case Qt::Key_Meta:
setValue(m_key | Qt::MetaModifier);
break;
default:
setValue(m_key);
}
} else {
setValue(event->key() | (m_key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)));
}
} }
event->accept(); event->accept();
} }
bool KeyEditor::event(QEvent* event) { bool KeyEditor::event(QEvent* event) {
if (!m_button) { if (!m_button) {
return QWidget::event(event); if (event->type() == QEvent::KeyPress) {
} QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (event->type() == GamepadButtonEvent::Down()) { if (keyEvent->key() != Qt::Key_Tab && keyEvent->key() != Qt::Key_Backtab) {
setValueButton(static_cast<GamepadButtonEvent*>(event)->value()); return QWidget::event(event);
event->accept(); }
return true; if (!(keyEvent->modifiers() & ~Qt::ShiftModifier)) {
} keyPressEvent(keyEvent);
if (event->type() == GamepadAxisEvent::Type()) { keyEvent->accept();
GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event); return true;
if (gae->isNew()) { }
setValueAxis(gae->axis(), gae->direction()); }
} else {
if (event->type() == GamepadButtonEvent::Down()) {
setValueButton(static_cast<GamepadButtonEvent*>(event)->value());
event->accept();
return true;
}
if (event->type() == GamepadAxisEvent::Type()) {
GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event);
if (gae->isNew()) {
setValueAxis(gae->axis(), gae->direction());
}
event->accept();
return true;
} }
event->accept();
return true;
} }
return QWidget::event(event); return QWidget::event(event);
} }

View File

@ -15,7 +15,7 @@ extern "C" {
using namespace QGBA; using namespace QGBA;
OverrideView::OverrideView(GameController* controller, ConfigController* config, QWidget* parent) OverrideView::OverrideView(GameController* controller, ConfigController* config, QWidget* parent)
: QDialog(parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller) , m_controller(controller)
, m_config(config) , m_config(config)
{ {

View File

@ -12,7 +12,7 @@
using namespace QGBA; using namespace QGBA;
SensorView::SensorView(GameController* controller, InputController* input, QWidget* parent) SensorView::SensorView(GameController* controller, InputController* input, QWidget* parent)
: QDialog(parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller) , m_controller(controller)
, m_input(input) , m_input(input)
, m_rotation(input->rotationSource()) , m_rotation(input->rotationSource())

View File

@ -13,7 +13,7 @@
using namespace QGBA; using namespace QGBA;
SettingsView::SettingsView(ConfigController* controller, QWidget* parent) SettingsView::SettingsView(ConfigController* controller, QWidget* parent)
: QDialog(parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller) , m_controller(controller)
{ {
m_ui.setupUi(this); m_ui.setupUi(this);

View File

@ -37,7 +37,7 @@ QVariant ShortcutController::data(const QModelIndex& index, int role) const {
case 0: case 0:
return item->visibleName(); return item->visibleName();
case 1: case 1:
return item->shortcut().toString(QKeySequence::NativeText); return QKeySequence(item->shortcut()).toString(QKeySequence::NativeText);
case 2: case 2:
if (item->button() >= 0) { if (item->button() >= 0) {
return item->button(); return item->button();
@ -125,7 +125,7 @@ void ShortcutController::addAction(QMenu* menu, QAction* action, const QString&
} }
void ShortcutController::addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release, void ShortcutController::addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
const QKeySequence& shortcut, const QString& visibleName, const QString& name) { int shortcut, const QString& visibleName, const QString& name) {
ShortcutItem* smenu = m_menuMap[menu]; ShortcutItem* smenu = m_menuMap[menu];
if (!smenu) { if (!smenu) {
return; return;
@ -145,6 +145,11 @@ void ShortcutController::addFunctions(QMenu* menu, std::function<void()> press,
createIndex(smenu->items().count() - 1, 2, item)); createIndex(smenu->items().count() - 1, 2, item));
} }
void ShortcutController::addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
const QKeySequence& shortcut, const QString& visibleName, const QString& name) {
addFunctions(menu, press, release, shortcut[0], visibleName, name);
}
void ShortcutController::addMenu(QMenu* menu, QMenu* parentMenu) { void ShortcutController::addMenu(QMenu* menu, QMenu* parentMenu) {
ShortcutItem* smenu = m_menuMap[parentMenu]; ShortcutItem* smenu = m_menuMap[parentMenu];
if (!smenu) { if (!smenu) {
@ -179,10 +184,10 @@ const ShortcutController::ShortcutItem* ShortcutController::itemAt(const QModelI
return static_cast<const ShortcutItem*>(index.internalPointer()); return static_cast<const ShortcutItem*>(index.internalPointer());
} }
QKeySequence ShortcutController::shortcutAt(const QModelIndex& index) const { int ShortcutController::shortcutAt(const QModelIndex& index) const {
const ShortcutItem* item = itemAt(index); const ShortcutItem* item = itemAt(index);
if (!item) { if (!item) {
return QKeySequence(); return 0;
} }
return item->shortcut(); return item->shortcut();
} }
@ -195,7 +200,7 @@ bool ShortcutController::isMenuAt(const QModelIndex& index) const {
return item->menu(); return item->menu();
} }
void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence& keySequence) { void ShortcutController::updateKey(const QModelIndex& index, int keySequence) {
if (!index.isValid()) { if (!index.isValid()) {
return; return;
} }
@ -204,23 +209,28 @@ void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence&
return; return;
} }
ShortcutItem* item = itemAt(index); ShortcutItem* item = itemAt(index);
if (item->functions().first) { updateKey(item, keySequence);
QKeySequence oldShortcut = item->shortcut();
if (!oldShortcut.isEmpty()) {
m_heldKeys.take(oldShortcut);
}
if (!keySequence.isEmpty()) {
m_heldKeys[keySequence] = item;
}
}
item->setShortcut(keySequence);
if (m_config) { if (m_config) {
m_config->setQtOption(item->name(), keySequence.toString(), KEY_SECTION); m_config->setQtOption(item->name(), QKeySequence(keySequence).toString(), KEY_SECTION);
} }
emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), emit dataChanged(createIndex(index.row(), 0, index.internalPointer()),
createIndex(index.row(), 2, index.internalPointer())); createIndex(index.row(), 2, index.internalPointer()));
} }
void ShortcutController::updateKey(ShortcutItem* item, int keySequence) {
int oldShortcut = item->shortcut();
if (item->functions().first) {
if (oldShortcut > 0) {
m_heldKeys.take(oldShortcut);
}
if (keySequence > 0) {
m_heldKeys[keySequence] = item;
}
}
item->setShortcut(keySequence);
}
void ShortcutController::updateButton(const QModelIndex& index, int button) { void ShortcutController::updateButton(const QModelIndex& index, int button) {
if (!index.isValid()) { if (!index.isValid()) {
return; return;
@ -286,7 +296,7 @@ void ShortcutController::updateAxis(const QModelIndex& index, int axis, GamepadA
} }
void ShortcutController::clearKey(const QModelIndex& index) { void ShortcutController::clearKey(const QModelIndex& index) {
updateKey(index, QKeySequence()); updateKey(index, 0);
} }
void ShortcutController::clearButton(const QModelIndex& index) { void ShortcutController::clearButton(const QModelIndex& index) {
@ -299,22 +309,27 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
if (keyEvent->isAutoRepeat()) { if (keyEvent->isAutoRepeat()) {
return false; return false;
} }
auto item = m_heldKeys.find(keyEventToSequence(keyEvent)); int key = keyEvent->key();
if (item == m_heldKeys.end()) { if (!isModifierKey(key)) {
return false; key |= keyEvent->modifiers();
}
ShortcutItem::Functions pair = item.value()->functions();
if (event->type() == QEvent::KeyPress) {
if (pair.first) {
pair.first();
}
} else { } else {
if (pair.second) { key = toModifierKey(key | keyEvent->modifiers());
pair.second(); }
} auto item = m_heldKeys.find(key);
if (item != m_heldKeys.end()) {
ShortcutItem::Functions pair = item.value()->functions();
if (event->type() == QEvent::KeyPress) {
if (pair.first) {
pair.first();
}
} else {
if (pair.second) {
pair.second();
}
}
event->accept();
return true;
} }
event->accept();
return true;
} }
if (event->type() == GamepadButtonEvent::Down()) { if (event->type() == GamepadButtonEvent::Down()) {
auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value()); auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value());
@ -378,15 +393,11 @@ void ShortcutController::loadShortcuts(ShortcutItem* item) {
} }
QVariant shortcut = m_config->getQtOption(item->name(), KEY_SECTION); QVariant shortcut = m_config->getQtOption(item->name(), KEY_SECTION);
if (!shortcut.isNull()) { if (!shortcut.isNull()) {
QKeySequence keySequence(shortcut.toString()); if (shortcut.toString().endsWith("+")) {
if (item->functions().first) { updateKey(item, toModifierShortcut(shortcut.toString()));
QKeySequence oldShortcut = item->shortcut(); } else {
if (!oldShortcut.isEmpty()) { updateKey(item, QKeySequence(shortcut.toString())[0]);
m_heldKeys.take(oldShortcut);
}
m_heldKeys[keySequence] = item;
} }
item->setShortcut(keySequence);
} }
loadGamepadShortcuts(item); loadGamepadShortcuts(item);
} }
@ -446,26 +457,6 @@ void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
} }
} }
QKeySequence ShortcutController::keyEventToSequence(const QKeyEvent* event) {
QString modifier = QString::null;
if (event->modifiers() & Qt::ShiftModifier) {
modifier += "Shift+";
}
if (event->modifiers() & Qt::ControlModifier) {
modifier += "Ctrl+";
}
if (event->modifiers() & Qt::AltModifier) {
modifier += "Alt+";
}
if (event->modifiers() & Qt::MetaModifier) {
modifier += "Meta+";
}
QString key = QKeySequence(event->key()).toString();
return QKeySequence(modifier + key);
}
void ShortcutController::loadProfile(const QString& profile) { void ShortcutController::loadProfile(const QString& profile) {
m_profileName = profile; m_profileName = profile;
m_profile = InputProfile::findProfile(profile); m_profile = InputProfile::findProfile(profile);
@ -481,9 +472,69 @@ void ShortcutController::onSubitems(ShortcutItem* item, std::function<void(Short
} }
} }
int ShortcutController::toModifierShortcut(const QString& shortcut) {
// Qt doesn't seem to work with raw modifier shortcuts!
QStringList modifiers = shortcut.split('+');
int value = 0;
for (const auto& mod : modifiers) {
if (mod == QLatin1String("Shift")) {
value |= Qt::ShiftModifier;
continue;
}
if (mod == QLatin1String("Ctrl")) {
value |= Qt::ControlModifier;
continue;
}
if (mod == QLatin1String("Alt")) {
value |= Qt::AltModifier;
continue;
}
if (mod == QLatin1String("Meta")) {
value |= Qt::MetaModifier;
continue;
}
}
return value;
}
bool ShortcutController::isModifierKey(int key) {
switch (key) {
case Qt::Key_Shift:
case Qt::Key_Control:
case Qt::Key_Alt:
case Qt::Key_Meta:
return true;
default:
return false;
}
}
int ShortcutController::toModifierKey(int key) {
int modifiers = key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier);
key ^= modifiers;
switch (key) {
case Qt::Key_Shift:
modifiers |= Qt::ShiftModifier;
break;
case Qt::Key_Control:
modifiers |= Qt::ControlModifier;
break;
case Qt::Key_Alt:
modifiers |= Qt::AltModifier;
break;
case Qt::Key_Meta:
modifiers |= Qt::MetaModifier;
break;
default:
break;
}
return modifiers;
}
ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent) ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent)
: m_action(action) : m_action(action)
, m_shortcut(action->shortcut()) , m_shortcut(action->shortcut().isEmpty() ? 0 : action->shortcut()[0])
, m_menu(nullptr) , m_menu(nullptr)
, m_name(name) , m_name(name)
, m_button(-1) , m_button(-1)
@ -496,7 +547,7 @@ ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& n
.remove("..."); .remove("...");
} }
ShortcutController::ShortcutItem::ShortcutItem(ShortcutController::ShortcutItem::Functions functions, const QKeySequence& shortcut, const QString& visibleName, const QString& name, ShortcutItem* parent) ShortcutController::ShortcutItem::ShortcutItem(ShortcutController::ShortcutItem::Functions functions, int shortcut, const QString& visibleName, const QString& name, ShortcutItem* parent)
: m_action(nullptr) : m_action(nullptr)
, m_shortcut(shortcut) , m_shortcut(shortcut)
, m_functions(functions) , m_functions(functions)
@ -512,6 +563,7 @@ ShortcutController::ShortcutItem::ShortcutItem(ShortcutController::ShortcutItem:
ShortcutController::ShortcutItem::ShortcutItem(QMenu* menu, ShortcutItem* parent) ShortcutController::ShortcutItem::ShortcutItem(QMenu* menu, ShortcutItem* parent)
: m_action(nullptr) : m_action(nullptr)
, m_shortcut(0)
, m_menu(menu) , m_menu(menu)
, m_button(-1) , m_button(-1)
, m_axis(-1) , m_axis(-1)
@ -530,7 +582,7 @@ void ShortcutController::ShortcutItem::addAction(QAction* action, const QString&
} }
void ShortcutController::ShortcutItem::addFunctions(ShortcutController::ShortcutItem::Functions functions, void ShortcutController::ShortcutItem::addFunctions(ShortcutController::ShortcutItem::Functions functions,
const QKeySequence& shortcut, const QString& visibleName, int shortcut, const QString& visibleName,
const QString& name) { const QString& name) {
m_items.append(ShortcutItem(functions, shortcut, visibleName, name, this)); m_items.append(ShortcutItem(functions, shortcut, visibleName, name, this));
} }
@ -539,10 +591,10 @@ void ShortcutController::ShortcutItem::addSubmenu(QMenu* menu) {
m_items.append(ShortcutItem(menu, this)); m_items.append(ShortcutItem(menu, this));
} }
void ShortcutController::ShortcutItem::setShortcut(const QKeySequence& shortcut) { void ShortcutController::ShortcutItem::setShortcut(int shortcut) {
m_shortcut = shortcut; m_shortcut = shortcut;
if (m_action) { if (m_action) {
m_action->setShortcut(shortcut); m_action->setShortcut(QKeySequence(shortcut));
} }
} }

View File

@ -9,7 +9,6 @@
#include "GamepadAxisEvent.h" #include "GamepadAxisEvent.h"
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QKeySequence>
#include <functional> #include <functional>
@ -38,13 +37,13 @@ private:
typedef QPair<std::function<void ()>, std::function<void ()>> Functions; typedef QPair<std::function<void ()>, std::function<void ()>> Functions;
ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent = nullptr); ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent = nullptr);
ShortcutItem(Functions functions, const QKeySequence& shortcut, const QString& visibleName, const QString& name, ShortcutItem(Functions functions, int shortcut, const QString& visibleName, const QString& name,
ShortcutItem* parent = nullptr); ShortcutItem* parent = nullptr);
ShortcutItem(QMenu* action, ShortcutItem* parent = nullptr); ShortcutItem(QMenu* action, ShortcutItem* parent = nullptr);
QAction* action() { return m_action; } QAction* action() { return m_action; }
const QAction* action() const { return m_action; } const QAction* action() const { return m_action; }
const QKeySequence& shortcut() const { return m_shortcut; } const int shortcut() const { return m_shortcut; }
Functions functions() const { return m_functions; } Functions functions() const { return m_functions; }
QMenu* menu() { return m_menu; } QMenu* menu() { return m_menu; }
const QMenu* menu() const { return m_menu; } const QMenu* menu() const { return m_menu; }
@ -55,11 +54,11 @@ private:
ShortcutItem* parent() { return m_parent; } ShortcutItem* parent() { return m_parent; }
const ShortcutItem* parent() const { return m_parent; } const ShortcutItem* parent() const { return m_parent; }
void addAction(QAction* action, const QString& name); void addAction(QAction* action, const QString& name);
void addFunctions(Functions functions, const QKeySequence& shortcut, const QString& visibleName, void addFunctions(Functions functions, int shortcut, const QString& visibleName,
const QString& name); const QString& name);
void addSubmenu(QMenu* menu); void addSubmenu(QMenu* menu);
int button() const { return m_button; } int button() const { return m_button; }
void setShortcut(const QKeySequence& sequence); void setShortcut(int sequence);
void setButton(int button) { m_button = button; } void setButton(int button) { m_button = button; }
int axis() const { return m_axis; } int axis() const { return m_axis; }
GamepadAxisEvent::Direction direction() const { return m_direction; } GamepadAxisEvent::Direction direction() const { return m_direction; }
@ -71,7 +70,7 @@ private:
private: private:
QAction* m_action; QAction* m_action;
QKeySequence m_shortcut; int m_shortcut;
QMenu* m_menu; QMenu* m_menu;
Functions m_functions; Functions m_functions;
QString m_name; QString m_name;
@ -99,23 +98,26 @@ public:
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
void addAction(QMenu* menu, QAction* action, const QString& name); void addAction(QMenu* menu, QAction* action, const QString& name);
void addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
int shortcut, const QString& visibleName, const QString& name);
void addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release, void addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
const QKeySequence& shortcut, const QString& visibleName, const QString& name); const QKeySequence& shortcut, const QString& visibleName, const QString& name);
void addMenu(QMenu* menu, QMenu* parent = nullptr); void addMenu(QMenu* menu, QMenu* parent = nullptr);
QAction* getAction(const QString& name); QAction* getAction(const QString& name);
int shortcutAt(const QModelIndex& index) const;
QKeySequence shortcutAt(const QModelIndex& index) const;
bool isMenuAt(const QModelIndex& index) const; bool isMenuAt(const QModelIndex& index) const;
void updateKey(const QModelIndex& index, const QKeySequence& keySequence); void updateKey(const QModelIndex& index, int keySequence);
void updateButton(const QModelIndex& index, int button); void updateButton(const QModelIndex& index, int button);
void updateAxis(const QModelIndex& index, int axis, GamepadAxisEvent::Direction direction); void updateAxis(const QModelIndex& index, int axis, GamepadAxisEvent::Direction direction);
void clearKey(const QModelIndex& index); void clearKey(const QModelIndex& index);
void clearButton(const QModelIndex& index); void clearButton(const QModelIndex& index);
static QKeySequence keyEventToSequence(const QKeyEvent*); static int toModifierShortcut(const QString& shortcut);
static bool isModifierKey(int key);
static int toModifierKey(int key);
public slots: public slots:
void loadProfile(const QString& profile); void loadProfile(const QString& profile);
@ -129,12 +131,13 @@ private:
void loadShortcuts(ShortcutItem*); void loadShortcuts(ShortcutItem*);
void loadGamepadShortcuts(ShortcutItem*); void loadGamepadShortcuts(ShortcutItem*);
void onSubitems(ShortcutItem*, std::function<void(ShortcutItem*)> func); void onSubitems(ShortcutItem*, std::function<void(ShortcutItem*)> func);
void updateKey(ShortcutItem* item, int keySequence);
ShortcutItem m_rootMenu; ShortcutItem m_rootMenu;
QMap<QMenu*, ShortcutItem*> m_menuMap; QMap<QMenu*, ShortcutItem*> m_menuMap;
QMap<int, ShortcutItem*> m_buttons; QMap<int, ShortcutItem*> m_buttons;
QMap<QPair<int, GamepadAxisEvent::Direction>, ShortcutItem*> m_axes; QMap<QPair<int, GamepadAxisEvent::Direction>, ShortcutItem*> m_axes;
QMap<QKeySequence, ShortcutItem*> m_heldKeys; QMap<int, ShortcutItem*> m_heldKeys;
ConfigController* m_config; ConfigController* m_config;
QString m_profileName; QString m_profileName;
const InputProfile* m_profile; const InputProfile* m_profile;

View File

@ -19,10 +19,14 @@ ShortcutView::ShortcutView(QWidget* parent)
, m_input(nullptr) , m_input(nullptr)
{ {
m_ui.setupUi(this); m_ui.setupUi(this);
m_ui.keyEdit->setValueButton(-1); m_ui.keyEdit->setValueKey(0);
m_ui.keySequenceEdit->installEventFilter(this);
connect(m_ui.keySequenceEdit, SIGNAL(keySequenceChanged(const QKeySequence&)), this, SLOT(updateKey(const QKeySequence&))); connect(m_ui.gamepadButton, &QAbstractButton::pressed, [this]() {
m_ui.keyEdit->setValueButton(-1);
});
connect(m_ui.keyboardButton, &QAbstractButton::pressed, [this]() {
m_ui.keyEdit->setValueKey(0);
});
connect(m_ui.keyEdit, SIGNAL(valueChanged(int)), this, SLOT(updateButton(int))); connect(m_ui.keyEdit, SIGNAL(valueChanged(int)), this, SLOT(updateButton(int)));
connect(m_ui.keyEdit, SIGNAL(axisChanged(int, int)), this, SLOT(updateAxis(int, int))); connect(m_ui.keyEdit, SIGNAL(axisChanged(int, int)), this, SLOT(updateAxis(int, int)));
connect(m_ui.shortcutTable, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(load(const QModelIndex&))); connect(m_ui.shortcutTable, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(load(const QModelIndex&)));
@ -42,21 +46,6 @@ void ShortcutView::setInputController(InputController* controller) {
m_input->stealFocus(this); m_input->stealFocus(this);
} }
bool ShortcutView::eventFilter(QObject*, QEvent* event) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() != Qt::Key_Tab && keyEvent->key() != Qt::Key_Backtab) {
return false;
}
if (!(keyEvent->modifiers() & ~Qt::ShiftModifier)) {
m_ui.keySequenceEdit->setKeySequence(ShortcutController::keyEventToSequence(keyEvent));
keyEvent->accept();
return true;
}
}
return false;
}
void ShortcutView::load(const QModelIndex& index) { void ShortcutView::load(const QModelIndex& index) {
if (!m_controller) { if (!m_controller) {
return; return;
@ -64,23 +53,20 @@ void ShortcutView::load(const QModelIndex& index) {
if (m_controller->isMenuAt(index)) { if (m_controller->isMenuAt(index)) {
return; return;
} }
QKeySequence sequence = m_controller->shortcutAt(index); int shortcut = m_controller->shortcutAt(index);
if (index.column() == 1) { if (index.column() == 1) {
m_ui.keyboardButton->click(); m_ui.keyboardButton->click();
} else if (index.column() == 2) { } else if (index.column() == 2) {
m_ui.gamepadButton->click(); m_ui.gamepadButton->click();
} }
bool blockSignals = m_ui.keyEdit->blockSignals(true);
m_ui.keyEdit->setFocus(Qt::MouseFocusReason);
if (m_ui.gamepadButton->isChecked()) { if (m_ui.gamepadButton->isChecked()) {
bool blockSignals = m_ui.keyEdit->blockSignals(true);
m_ui.keyEdit->setFocus();
m_ui.keyEdit->setValueButton(-1); // There are no default bindings m_ui.keyEdit->setValueButton(-1); // There are no default bindings
m_ui.keyEdit->blockSignals(blockSignals);
} else { } else {
bool blockSignals = m_ui.keySequenceEdit->blockSignals(true); m_ui.keyEdit->setValueKey(shortcut);
m_ui.keySequenceEdit->setFocus();
m_ui.keySequenceEdit->setKeySequence(sequence);
m_ui.keySequenceEdit->blockSignals(blockSignals);
} }
m_ui.keyEdit->blockSignals(blockSignals);
} }
void ShortcutView::clear() { void ShortcutView::clear() {
@ -96,22 +82,19 @@ void ShortcutView::clear() {
m_ui.keyEdit->setValueButton(-1); m_ui.keyEdit->setValueButton(-1);
} else { } else {
m_controller->clearKey(index); m_controller->clearKey(index);
m_ui.keySequenceEdit->setKeySequence(QKeySequence()); m_ui.keyEdit->setValueKey(-1);
} }
} }
void ShortcutView::updateKey(const QKeySequence& shortcut) {
if (!m_controller || m_controller->isMenuAt(m_ui.shortcutTable->selectionModel()->currentIndex())) {
return;
}
m_controller->updateKey(m_ui.shortcutTable->selectionModel()->currentIndex(), shortcut);
}
void ShortcutView::updateButton(int button) { void ShortcutView::updateButton(int button) {
if (!m_controller || m_controller->isMenuAt(m_ui.shortcutTable->selectionModel()->currentIndex())) { if (!m_controller || m_controller->isMenuAt(m_ui.shortcutTable->selectionModel()->currentIndex())) {
return; return;
} }
m_controller->updateButton(m_ui.shortcutTable->selectionModel()->currentIndex(), button); if (m_ui.gamepadButton->isChecked()) {
m_controller->updateButton(m_ui.shortcutTable->selectionModel()->currentIndex(), button);
} else {
m_controller->updateKey(m_ui.shortcutTable->selectionModel()->currentIndex(), button);
}
} }
void ShortcutView::updateAxis(int axis, int direction) { void ShortcutView::updateAxis(int axis, int direction) {

View File

@ -27,14 +27,12 @@ public:
void setInputController(InputController* input); void setInputController(InputController* input);
protected: protected:
virtual bool eventFilter(QObject* obj, QEvent* event) override;
virtual bool event(QEvent*) override; virtual bool event(QEvent*) override;
virtual void closeEvent(QCloseEvent*) override; virtual void closeEvent(QCloseEvent*) override;
private slots: private slots:
void load(const QModelIndex&); void load(const QModelIndex&);
void clear(); void clear();
void updateKey(const QKeySequence&);
void updateButton(int button); void updateButton(int button);
void updateAxis(int axis, int direction); void updateAxis(int axis, int direction);

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>425</width> <width>432</width>
<height>443</height> <height>443</height>
</rect> </rect>
</property> </property>
@ -60,16 +60,6 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QKeySequenceEdit" name="keySequenceEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item> <item>
<widget class="QGBA::KeyEditor" name="keyEdit"> <widget class="QGBA::KeyEditor" name="keyEdit">
<property name="sizePolicy"> <property name="sizePolicy">
@ -78,9 +68,6 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="visible">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -95,38 +82,5 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections> <connections/>
<connection>
<sender>keyboardButton</sender>
<signal>toggled(bool)</signal>
<receiver>keySequenceEdit</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>86</x>
<y>374</y>
</hint>
<hint type="destinationlabel">
<x>66</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>gamepadButton</sender>
<signal>toggled(bool)</signal>
<receiver>keyEdit</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>213</x>
<y>374</y>
</hint>
<hint type="destinationlabel">
<x>206</x>
<y>340</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Window.h" #include "Window.h"
#include <QDesktopWidget>
#include <QKeyEvent> #include <QKeyEvent>
#include <QKeySequence> #include <QKeySequence>
#include <QMenuBar> #include <QMenuBar>
@ -88,11 +89,6 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
m_screenWidget->setLockAspectRatio(m_logo.width(), m_logo.height()); m_screenWidget->setLockAspectRatio(m_logo.width(), m_logo.height());
setCentralWidget(m_screenWidget); setCentralWidget(m_screenWidget);
QVariant windowPos = m_config->getQtOption("windowPos");
if (!windowPos.isNull()) {
move(windowPos.toPoint());
}
connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*))); connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*)));
connect(m_controller, SIGNAL(gameStarted(GBAThread*)), &m_inputController, SLOT(suspendScreensaver())); connect(m_controller, SIGNAL(gameStarted(GBAThread*)), &m_inputController, SLOT(suspendScreensaver()));
connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing())); connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing()));
@ -465,6 +461,14 @@ void Window::resizeEvent(QResizeEvent* event) {
void Window::showEvent(QShowEvent* event) { void Window::showEvent(QShowEvent* event) {
resizeFrame(m_screenWidget->sizeHint().width(), m_screenWidget->sizeHint().height()); resizeFrame(m_screenWidget->sizeHint().width(), m_screenWidget->sizeHint().height());
QVariant windowPos = m_config->getQtOption("windowPos");
if (!windowPos.isNull()) {
move(windowPos.toPoint());
} else {
QRect rect = frameGeometry();
rect.moveCenter(QApplication::desktop()->availableGeometry().center());
move(rect.topLeft());
}
} }
void Window::closeEvent(QCloseEvent* event) { void Window::closeEvent(QCloseEvent* event) {
@ -503,7 +507,7 @@ void Window::dropEvent(QDropEvent* event) {
return; return;
} }
event->accept(); event->accept();
m_controller->loadGame(url.path()); m_controller->loadGame(url.toLocalFile());
} }
void Window::mouseDoubleClickEvent(QMouseEvent* event) { void Window::mouseDoubleClickEvent(QMouseEvent* event) {

View File

@ -0,0 +1,174 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba/supervisor/config.h"
#include "gba/supervisor/context.h"
#include "gba/gba.h"
#include "gba/renderers/video-software.h"
#include "gba/serialize.h"
#include "platform/commandline.h"
#include "util/memory.h"
#include "util/string.h"
#include "util/vfs.h"
#include <errno.h>
#include <signal.h>
#define FUZZ_OPTIONS "F:NO:S:V:"
#define FUZZ_USAGE \
"\nAdditional options:\n" \
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
" -N Disable video rendering entirely\n" \
" -O OFFSET Offset to apply savestate overlay\n" \
" -S FILE Load a savestate when starting the test\n" \
" -V FILE Overlay a second savestate over the loaded savestate\n" \
struct FuzzOpts {
bool noVideo;
int frames;
size_t overlayOffset;
char* savestate;
char* ssOverlay;
};
static void _GBAFuzzRunloop(struct GBAContext* context, int frames);
static void _GBAFuzzShutdown(int signal);
static bool _parseFuzzOpts(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg);
static bool _dispatchExiting = false;
int main(int argc, char** argv) {
signal(SIGINT, _GBAFuzzShutdown);
struct FuzzOpts fuzzOpts = { false, 0, 0, 0, 0 };
struct SubParser subparser = {
.usage = FUZZ_USAGE,
.parse = _parseFuzzOpts,
.extraOptions = FUZZ_OPTIONS,
.opts = &fuzzOpts
};
struct GBAContext context;
GBAContextInit(&context, "fuzz");
struct GBAOptions opts = {
.idleOptimization = IDLE_LOOP_DETECT
};
GBAConfigLoadDefaults(&context.config, &opts);
GBAConfigFreeOpts(&opts);
struct GBAArguments args;
bool parsed = parseArguments(&args, &context.config, argc, argv, &subparser);
if (!parsed || args.showHelp) {
usage(argv[0], FUZZ_USAGE);
freeArguments(&args);
GBAContextDeinit(&context);
return !parsed;
}
struct VFile* rom = VFileOpen(args.fname, O_RDONLY);
context.gba->hardCrash = false;
GBAContextLoadROMFromVFile(&context, rom, 0);
struct GBAVideoSoftwareRenderer renderer;
renderer.outputBuffer = 0;
struct VFile* savestate = 0;
struct VFile* savestateOverlay = 0;
size_t overlayOffset;
if (!fuzzOpts.noVideo) {
GBAVideoSoftwareRendererCreate(&renderer);
renderer.outputBuffer = malloc(256 * 256 * 4);
renderer.outputBufferStride = 256;
GBAVideoAssociateRenderer(&context.gba->video, &renderer.d);
}
GBAContextStart(&context);
if (fuzzOpts.savestate) {
savestate = VFileOpen(fuzzOpts.savestate, O_RDONLY);
free(fuzzOpts.savestate);
}
if (fuzzOpts.ssOverlay) {
overlayOffset = fuzzOpts.overlayOffset;
if (overlayOffset < sizeof(struct GBASerializedState)) {
savestateOverlay = VFileOpen(fuzzOpts.ssOverlay, O_RDONLY);
}
free(fuzzOpts.ssOverlay);
}
if (savestate) {
if (!savestateOverlay) {
GBALoadStateNamed(context.gba, savestate);
} else {
struct GBASerializedState* state = GBAAllocateState();
savestate->read(savestate, state, sizeof(*state));
savestateOverlay->read(savestateOverlay, (uint8_t*) state + overlayOffset, sizeof(*state) - overlayOffset);
GBADeserialize(context.gba, state);
GBADeallocateState(state);
savestateOverlay->close(savestateOverlay);
savestateOverlay = 0;
}
savestate->close(savestate);
savestate = 0;
}
blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 0x8000);
blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 0x8000);
_GBAFuzzRunloop(&context, fuzzOpts.frames);
if (savestate) {
savestate->close(savestate);
}
if (savestateOverlay) {
savestateOverlay->close(savestateOverlay);
}
GBAContextStop(&context);
GBAContextDeinit(&context);
freeArguments(&args);
if (renderer.outputBuffer) {
free(renderer.outputBuffer);
}
return 0;
}
static void _GBAFuzzRunloop(struct GBAContext* context, int frames) {
do {
GBAContextFrame(context, 0);
} while (context->gba->video.frameCounter < frames && !_dispatchExiting);
}
static void _GBAFuzzShutdown(int signal) {
UNUSED(signal);
_dispatchExiting = true;
}
static bool _parseFuzzOpts(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) {
UNUSED(config);
struct FuzzOpts* opts = parser->opts;
errno = 0;
switch (option) {
case 'F':
opts->frames = strtoul(arg, 0, 10);
return !errno;
case 'N':
opts->noVideo = true;
return true;
case 'O':
opts->overlayOffset = strtoul(arg, 0, 10);
return !errno;
case 'S':
opts->savestate = strdup(arg);
return true;
case 'V':
opts->ssOverlay = strdup(arg);
return true;
default:
return false;
}
}

59
src/util/math.h Normal file
View File

@ -0,0 +1,59 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef UTIL_MATH_H
#define UTIL_MATH_H
#include "util/common.h"
static inline uint32_t popcount32(unsigned bits) {
bits = bits - ((bits >> 1) & 0x55555555);
bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
static inline unsigned clz32(uint32_t bits) {
#if defined(__GNUC__) || __clang__
return __builtin_clz(bits);
#else
static const int table[256] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if (bits & 0xFF000000) {
return table[bits >> 24];
} else if (bits & 0x00FF0000) {
return table[bits >> 16] + 8;
} else if (bits & 0x0000FF00) {
return table[bits >> 8] + 16;
}
return table[bits] + 24;
#endif
}
static inline uint32_t toPow2(uint32_t bits) {
if (!bits) {
return 0;
}
unsigned lz = clz32(bits - 1);
return 1 << (32 - lz);
}
#endif

View File

@ -37,7 +37,30 @@ struct VFile* VFileOpen(const char* path, int flags) {
} }
return VFileFOpen(path, chflags); return VFileFOpen(path, chflags);
#elif defined(PSP) || defined(PSP2) #elif defined(PSP) || defined(PSP2)
return VFileOpenSce(path, flags, 0666); int sceFlags = PSP2_O_RDONLY;
switch (flags & O_ACCMODE) {
case O_WRONLY:
sceFlags = PSP2_O_WRONLY;
break;
case O_RDWR:
sceFlags = PSP2_O_RDWR;
break;
case O_RDONLY:
sceFlags = PSP2_O_RDONLY;
break;
}
if (flags & O_APPEND) {
sceFlags |= PSP2_O_APPEND;
}
if (flags & O_TRUNC) {
sceFlags |= PSP2_O_TRUNC;
}
if (flags & O_CREAT) {
sceFlags |= PSP2_O_CREAT;
}
return VFileOpenSce(path, sceFlags, 0666);
>>>>>>> port/psp2
#else #else
return VFileOpenFD(path, flags); return VFileOpenFD(path, flags);
#endif #endif