all repos — mgba @ 3158db06c2c68a5b53a5b0d2ea8fe9375ec74522

mGBA Game Boy Advance Emulator

GB: Start work on video rendering
Jeffrey Pfau jeffrey@endrift.com
Mon, 18 Jan 2016 21:03:50 -0800
commit

3158db06c2c68a5b53a5b0d2ea8fe9375ec74522

parent

23ca81708de270bf1c0aed13a30470e10f287505

M CMakeLists.txtCMakeLists.txt

@@ -13,6 +13,8 @@ set(USE_ZLIB ON CACHE BOOL "Whether or not to enable zlib support")

set(USE_PNG ON CACHE BOOL "Whether or not to enable PNG support") set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support") set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support") +set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core") +set(M_CORE_GB ON CACHE BOOL "Build Game Boy core") set(USE_BLIP ON CACHE BOOL "Whether or not to enable blip_buf support") set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support") set(BUILD_QT ON CACHE BOOL "Build Qt frontend")

@@ -40,17 +42,18 @@ file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c)

file(GLOB GBA_CTX_SRC ${CMAKE_SOURCE_DIR}/src/gba/context/*.c) file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs]) file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/util/gui/*.c ${CMAKE_SOURCE_DIR}/src/gba/gui/*.c) -file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c) +file(GLOB GBA_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c) file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) +file(GLOB GB_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gb/renderers/*.c) file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c) list(APPEND GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c) set(CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c) set(VFS_SRC) source_group("ARM core" FILES ${ARM_SRC}) source_group("LR35902 core" FILES ${LR35902_SRC}) -source_group("GBA board" FILES ${GBA_SRC} ${RENDERER_SRC} ${SIO_SRC}) +source_group("GBA board" FILES ${GBA_SRC} ${GBA_RENDERER_SRC} ${SIO_SRC}) source_group("GBA extra" FILES ${GBA_CHEATS_SRC} ${GBA_CTX_SRC} ${GBA_SV_SRC} ${GBA_RR_SRC}) -source_group("GB board" FILES ${GBA_SRC}) +source_group("GB board" FILES ${GB_SRC}) source_group("Utilities" FILES ${UTIL_SRC}) include_directories(${CMAKE_SOURCE_DIR}/src/arm) include_directories(${CMAKE_SOURCE_DIR}/src)

@@ -494,30 +497,42 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2)

endif() # Binaries -set(CORE_SRC - ${ARM_SRC} - ${LR35902_SRC} - ${GBA_SRC} - ${GB_SRC} - ${GBA_CHEATS_SRC} - ${GBA_CTX_SRC} - ${DEBUGGER_SRC} - ${RENDERER_SRC} +set(CORE_SRC) +if(M_CORE_GB) + add_definitions(-DM_CORE_GB) + list(APPEND CORE_SRC + ${LR35902_SRC} + ${GB_SRC} + ${GB_RENDERER_SRC}) +endif() + +if(M_CORE_GBA) + add_definitions(-DM_CORE_GBA) + list(APPEND CORE_SRC + ${ARM_SRC} + ${GBA_SRC} + ${GBA_CHEATS_SRC} + ${GBA_CTX_SRC} + ${DEBUGGER_SRC} + ${GBA_RENDERER_SRC}) +endif() + +list(APPEND CORE_SRC ${UTIL_SRC} ${CORE_VFS_SRC} ${OS_SRC} ${THIRD_PARTY_SRC}) +set(SRC ${CORE_SRC} ${VFS_SRC}) if(NOT MINIMAL_CORE) - set(SRC - ${CORE_SRC} - ${GBA_RR_SRC} - ${GBA_SV_SRC} - ${SIO_SRC} - ${FEATURE_SRC} - ${VFS_SRC}) -else() - set(SRC ${CORE_SRC} ${VFS_SRC}) + if(M_CORE_GBA) + list(APPEND SRC + ${GBA_RR_SRC} + ${GBA_SV_SRC} + ${SIO_SRC}) + endif() + list(APPEND SRC + ${FEATURE_SRC}) endif() if(NOT SKIP_LIBRARY)

@@ -680,6 +695,9 @@ else()

set(SUMMARY_ZIP OFF) endif() +message(STATUS "Platforms:") +message(STATUS " Game Boy Advance: ${M_CORE_GBA}") +message(STATUS " Game Boy: ${M_CORE_GB}") message(STATUS "Features:") message(STATUS " CLI debugger: ${USE_CLI_DEBUGGER}") message(STATUS " GDB stub: ${USE_GDB_STUB}")
M src/gb/gb.csrc/gb/gb.c

@@ -183,3 +183,17 @@ void GBHitStub(struct LR35902Core* cpu) {

// TODO //printf("Hit stub at address %04X\n", cpu->pc); } + +bool GBIsROM(struct VFile* vf) { + vf->seek(vf, 0x104, SEEK_SET); + uint8_t header[4]; + static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66}; + + if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) { + return false; + } + if (memcmp(header, knownHeader, sizeof(header))) { + return false; + } + return true; +}
A src/gb/renderers/software.c

@@ -0,0 +1,108 @@

+/* Copyright (c) 2013-2016 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 "software.h" + +#include "util/memory.h" + +static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer); +static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer); +static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer); +static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address); +static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); +static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y); +static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer); +static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels); +static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels); + +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 +static const color_t GB_PALETTE[4] = { 0xFFFF, 0x39C7, 0x18C3, 0x0000}; +#else +static const color_t GB_PALETTE[4] = { 0x7FFF, 0x1DE7, 0x0C63, 0x0000}; +#endif +#else +static const color_t GB_PALETTE[4] = { 0xFFFFFF, 0x808080, 0x404040, 0x000000}; +#endif + +void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) { + renderer->d.init = GBVideoSoftwareRendererInit; + renderer->d.reset = GBVideoSoftwareRendererReset; + renderer->d.deinit = GBVideoSoftwareRendererDeinit; + renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister; + renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM; + renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline; + renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame; + renderer->d.getPixels = 0; + renderer->d.putPixels = 0; + + renderer->temporaryBuffer = 0; +} + +static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer) { + GBVideoSoftwareRendererReset(renderer); + + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + + int y; + for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) { + color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y]; + int x; + for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = GB_PALETTE[0]; + } + } +} + +static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + int i; + + // TODO +} + +static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + UNUSED(softwareRenderer); +} + +static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + // TODO +} +static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + // TODO + return value; +} + +static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + + color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y]; + + // TODO + size_t x; +#ifdef COLOR_16_BIT +#if defined(__ARM_NEON) && !defined(__APPLE__) + _to16Bit(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS); +#else + for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = softwareRenderer->row[x]; + } +#endif +#else + memcpy(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS * sizeof(*row)); +#endif +} + +static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + + if (softwareRenderer->temporaryBuffer) { + mappedMemoryFree(softwareRenderer->temporaryBuffer, GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * 4); + softwareRenderer->temporaryBuffer = 0; + } +}
A src/gb/renderers/software.h

@@ -0,0 +1,32 @@

+/* Copyright (c) 2013-2016 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 GB_RENDERER_SOFTWARE_H +#define GB_RENDERER_SOFTWARE_H + +#include "util/common.h" + +#include "gb/video.h" + +#ifdef COLOR_16_BIT +typedef uint16_t color_t; +#else +typedef uint32_t color_t; +#endif + +struct GBVideoSoftwareRenderer { + struct GBVideoRenderer d; + + color_t* outputBuffer; + int outputBufferStride; + + uint32_t row[GB_VIDEO_HORIZONTAL_PIXELS]; + + uint32_t* temporaryBuffer; +}; + +void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*); + +#endif
M src/gb/video.csrc/gb/video.c

@@ -64,7 +64,10 @@ mappedMemoryFree(video->vram, GB_SIZE_VRAM);

} void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) { - // TODO + video->renderer->deinit(video->renderer); + video->renderer = renderer; + renderer->vram = video->vram; + video->renderer->init(video->renderer); } int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {

@@ -79,11 +82,15 @@ }

if (video->nextMode <= 0) { switch (video->mode) { case 0: + if (video->ly < GB_VIDEO_VERTICAL_TOTAL_PIXELS) { + video->renderer->drawScanline(video->renderer, video->ly); + } ++video->ly; video->p->memory.io[REG_LY] = video->ly; if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) { video->ly = 0; ++video->frameCounter; + video->renderer->finishFrame(video->renderer); video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH; video->mode = 1; if (GBRegisterSTATIsVblankIRQ(video->stat)) {
M src/platform/sdl/gl-common.csrc/platform/sdl/gl-common.c

@@ -5,8 +5,8 @@ * 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 "main.h" -void GBASDLGLCommonSwap(struct VideoBackend* context) { - struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user; +void mSDLGLCommonSwap(struct VideoBackend* context) { + struct mSDLRenderer* renderer = (struct mSDLRenderer*) context->user; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SwapWindow(renderer->window); #else

@@ -15,7 +15,7 @@ SDL_GL_SwapBuffers();

#endif } -void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer) { +void mSDLGLCommonInit(struct mSDLRenderer* renderer) { #ifndef COLOR_16_BIT SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
M src/platform/sdl/gl-common.hsrc/platform/sdl/gl-common.h

@@ -7,7 +7,7 @@ #ifndef SDL_GL_COMMON_H

#define SDL_GL_COMMON_H #include "main.h" -void GBASDLGLCommonSwap(struct VideoBackend* context); -void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer); +void mSDLGLCommonSwap(struct VideoBackend* context); +void mSDLGLCommonInit(struct mSDLRenderer* renderer); #endif
M src/platform/sdl/gl-sdl.csrc/platform/sdl/gl-sdl.c

@@ -8,6 +8,9 @@

#include "gl-common.h" #include "gba/supervisor/thread.h" +#ifdef M_CORE_GB +#include "gb/gb.h" +#endif #include "platform/opengl/gl.h" static void _doViewport(int w, int h, struct VideoBackend* v) {

@@ -17,18 +20,25 @@ v->swap(v);

v->clear(v); } -static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer); +#ifdef M_CORE_GBA +static bool mSDLGLInitGBA(struct mSDLRenderer* renderer); +static void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user); +#endif +#ifdef M_CORE_GB +static bool mSDLGLInitGB(struct mSDLRenderer* renderer); +static void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user); +#endif +static void mSDLGLDeinit(struct mSDLRenderer* renderer); -void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLGLInit; - renderer->deinit = GBASDLGLDeinit; - renderer->runloop = GBASDLGLRunloop; +#ifdef M_CORE_GBA +void mSDLGLCreate(struct mSDLRenderer* renderer) { + renderer->init = mSDLGLInitGBA; + renderer->deinit = mSDLGLDeinit; + renderer->runloop = mSDLGLRunloopGBA; } -bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) { - GBASDLGLCommonInit(renderer); +bool mSDLGLInitGBA(struct mSDLRenderer* renderer) { + mSDLGLCommonInit(renderer); renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;

@@ -37,14 +47,15 @@ GBAGLContextCreate(&renderer->gl);

renderer->gl.d.user = renderer; renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl.d.filter = renderer->filter; - renderer->gl.d.swap = GBASDLGLCommonSwap; + renderer->gl.d.swap = mSDLGLCommonSwap; renderer->gl.d.init(&renderer->gl.d, 0); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); return true; } -void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user) { + struct GBAThread* context = user; SDL_Event event; struct VideoBackend* v = &renderer->gl.d;

@@ -69,8 +80,62 @@ v->drawFrame(v);

v->swap(v); } } +#endif -void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) { +#ifdef M_CORE_GB +void mSDLGLCreateGB(struct mSDLRenderer* renderer) { + renderer->init = mSDLGLInitGB; + renderer->deinit = mSDLGLDeinit; + renderer->runloop = mSDLGLRunloopGB; +} + +bool mSDLGLInitGB(struct mSDLRenderer* renderer) { + mSDLGLCommonInit(renderer); + + // TODO: Pass texture size along + renderer->gb.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); + renderer->gb.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; + + GBAGLContextCreate(&renderer->gl); + renderer->gl.d.user = renderer; + renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; + renderer->gl.d.filter = renderer->filter; + renderer->gl.d.swap = mSDLGLCommonSwap; + renderer->gl.d.init(&renderer->gl.d, 0); + + _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); + return true; +} + +void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) { + struct GB* gb = user; + SDL_Event event; + struct VideoBackend* v = &renderer->gl.d; + + while (true) { + int64_t frameCounter = gb->video.frameCounter; + while (gb->video.frameCounter == frameCounter) { + LR35902Tick(gb->cpu); + } + while (SDL_PollEvent(&event)) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + // Event handling can change the size of the screen + if (renderer->player.windowUpdated) { + SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); + _doViewport(renderer->viewportWidth, renderer->viewportHeight, v); + renderer->player.windowUpdated = 0; + } +#endif + } + + v->postFrame(v, renderer->gb.outputBuffer); + v->drawFrame(v); + v->swap(v); + } +} +#endif + +void mSDLGLDeinit(struct mSDLRenderer* renderer) { if (renderer->gl.d.deinit) { renderer->gl.d.deinit(&renderer->gl.d); }
M src/platform/sdl/gles2-sdl.csrc/platform/sdl/gles2-sdl.c

@@ -9,17 +9,17 @@ #include "gl-common.h"

#include <malloc.h> -static bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer); -static void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLGLES2Init(struct SDLSoftwareRenderer* renderer); +static void mSDLGLES2RunloopGBA(struct SDLSoftwareRenderer* renderer, void* user); +static void mSDLGLES2Deinit(struct SDLSoftwareRenderer* renderer); -void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLGLES2Init; - renderer->deinit = GBASDLGLES2Deinit; - renderer->runloop = GBASDLGLES2Runloop; +void mSDLGLES2Create(struct mSDLRenderer* renderer) { + renderer->init = mSDLGLES2Init; + renderer->deinit = mSDLGLES2Deinit; + renderer->runloop = mSDLGLES2RunloopGBA; } -bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) { +bool mSDLGLES2Init(struct SDLSoftwareRenderer* renderer) { #ifdef BUILD_RASPI bcm_host_init(); renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

@@ -90,7 +90,7 @@ if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {

return false; } #else - GBASDLGLCommonInit(renderer); + mSDLGLCommonInit(renderer); #endif renderer->d.outputBuffer = memalign(16, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);

@@ -100,12 +100,13 @@ GBAGLES2ContextCreate(&renderer->gl2);

renderer->gl2.d.user = renderer; renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl2.d.filter = renderer->filter; - renderer->gl2.d.swap = GBASDLGLCommonSwap; + renderer->gl2.d.swap = mSDLGLCommonSwap; renderer->gl2.d.init(&renderer->gl2.d, 0); return true; } -void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) { + struct GBAThread* context = user; SDL_Event event; struct VideoBackend* v = &renderer->gl2.d;

@@ -127,7 +128,7 @@ #endif

} } -void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) { +void mSDLGLES2Deinit(struct mSDLRenderer* renderer) { if (renderer->gl2.d.deinit) { renderer->gl2.d.deinit(&renderer->gl2.d); }
M src/platform/sdl/main.csrc/platform/sdl/main.c

@@ -13,12 +13,19 @@ #ifdef USE_GDB_STUB

#include "debugger/gdb-stub.h" #endif +#ifdef M_CORE_GBA #include "gba/gba.h" #include "gba/context/config.h" #include "gba/supervisor/thread.h" #include "gba/video.h" +#endif +#ifdef M_CORE_GB +#include "gb/gb.h" +#include "gb/video.h" +#endif #include "platform/commandline.h" #include "util/configuration.h" +#include "util/vfs.h" #include <SDL.h>

@@ -28,12 +35,27 @@ #include <sys/time.h>

#define PORT "sdl" -static bool GBASDLInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer); +// TODO: Move somewhere +enum mPlatform { + PLATFORM_NONE = -1, + PLATFORM_GBA, + PLATFORM_GB +}; + +static bool mSDLInit(struct mSDLRenderer* renderer); +static void mSDLDeinit(struct mSDLRenderer* renderer); + +// TODO: Clean up signatures +#ifdef M_CORE_GBA +static int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct GBAConfig* config, struct GBAInputMap* inputMap); +#endif +#ifdef M_CORE_GB +static int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args); +#endif + int main(int argc, char** argv) { - struct SDLSoftwareRenderer renderer; - GBAVideoSoftwareRendererCreate(&renderer.d); + struct mSDLRenderer renderer; struct GBAInputMap inputMap; GBAInputMapInit(&inputMap);

@@ -43,15 +65,14 @@ GBAConfigInit(&config, PORT);

GBAConfigLoad(&config); struct GBAOptions opts = { - .width = VIDEO_HORIZONTAL_PIXELS, - .height = VIDEO_VERTICAL_PIXELS, + .width = 0, + .height = 0, .useBios = true, .rewindEnable = true, .audioBuffers = 512, .videoSync = false, .audioSync = true, }; - GBAConfigLoadDefaults(&config, &opts); struct GBAArguments args; struct GraphicsOpts graphicsOpts;

@@ -75,6 +96,49 @@ GBAConfigDeinit(&config);

return 0; } + enum mPlatform platform = PLATFORM_NONE; + + if (args.fname) { + struct VFile* vf = VFileOpen(args.fname, O_RDONLY); + if (!vf) { + printf("Could not open game. Are you sure the file exists?\n"); + freeArguments(&args); + GBAConfigFreeOpts(&opts); + GBAConfigDeinit(&config); + return 1; + } +#ifdef M_CORE_GBA + else if (GBAIsROM(vf)) { + platform = PLATFORM_GBA; + if (!opts.width) { + opts.width = VIDEO_HORIZONTAL_PIXELS; + } + if (!opts.height) { + opts.height = VIDEO_VERTICAL_PIXELS; + } + } +#endif +#ifdef M_CORE_GB + else if (GBIsROM(vf)) { + platform = PLATFORM_GB; + if (!opts.width) { + opts.width = /*GB_*/VIDEO_HORIZONTAL_PIXELS; + } + if (!opts.height) { + opts.height = /*GB_*/VIDEO_VERTICAL_PIXELS; + } + } +#endif + else { + printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n"); + freeArguments(&args); + GBAConfigFreeOpts(&opts); + GBAConfigDeinit(&config); + return 1; + } + } + + GBAConfigLoadDefaults(&config, &opts); GBAConfigMap(&config, &opts); renderer.viewportWidth = opts.width;

@@ -93,57 +157,78 @@

renderer.lockAspectRatio = opts.lockAspectRatio; renderer.filter = opts.resampleVideo; + int ret; + + switch (platform) { + case PLATFORM_GBA: + ret = mSDLRunGBA(&renderer, &args, &opts, &config, &inputMap); + break; + case PLATFORM_GB: + ret = mSDLRunGB(&renderer, &args); + break; + default: + ret = 1; + break; + } + + freeArguments(&args); + GBAConfigFreeOpts(&opts); + GBAConfigDeinit(&config); + + return ret; +} + +#ifdef M_CORE_GBA +int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct GBAConfig* config, struct GBAInputMap* inputMap) { + GBAVideoSoftwareRendererCreate(&renderer->d); #ifdef BUILD_GL - GBASDLGLCreate(&renderer); + mSDLGLCreate(renderer); #elif defined(BUILD_GLES2) || defined(USE_EPOXY) - GBASDLGLES2Create(&renderer); + mSDLGLES2Create(renderer); #else - GBASDLSWCreate(&renderer); + mSDLSWCreate(renderer); #endif - if (!GBASDLInit(&renderer)) { - freeArguments(&args); - GBAConfigFreeOpts(&opts); - GBAConfigDeinit(&config); + if (!mSDLInit(renderer)) { return 1; } struct GBAThread context = { - .renderer = &renderer.d.d, - .userData = &renderer + .renderer = &renderer->d.d, + .userData = renderer }; - context.debugger = createDebugger(&args, &context); + context.debugger = createDebugger(args, &context); - GBAMapOptionsToContext(&opts, &context); - GBAMapArgumentsToContext(&args, &context); + GBAMapOptionsToContext(opts, &context); + GBAMapArgumentsToContext(args, &context); bool didFail = false; - renderer.audio.samples = context.audioBuffers; - renderer.audio.sampleRate = 44100; - if (opts.sampleRate) { - renderer.audio.sampleRate = opts.sampleRate; + renderer->audio.samples = context.audioBuffers; + renderer->audio.sampleRate = 44100; + if (opts->sampleRate) { + renderer->audio.sampleRate = opts->sampleRate; } - if (!GBASDLInitAudio(&renderer.audio, &context)) { + if (!GBASDLInitAudio(&renderer->audio, &context)) { didFail = true; } - renderer.player.bindings = &inputMap; - GBASDLInitBindings(&inputMap); - GBASDLInitEvents(&renderer.events); - GBASDLEventsLoadConfig(&renderer.events, GBAConfigGetInput(&config)); - GBASDLAttachPlayer(&renderer.events, &renderer.player); - GBASDLPlayerLoadConfig(&renderer.player, GBAConfigGetInput(&config)); - context.overrides = GBAConfigGetOverrides(&config); + renderer->player.bindings = inputMap; + GBASDLInitBindings(inputMap); + GBASDLInitEvents(&renderer->events); + GBASDLEventsLoadConfig(&renderer->events, GBAConfigGetInput(config)); + GBASDLAttachPlayer(&renderer->events, &renderer->player); + GBASDLPlayerLoadConfig(&renderer->player, GBAConfigGetInput(config)); + context.overrides = GBAConfigGetOverrides(config); if (!didFail) { #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLSetScreensaverSuspendable(&renderer.events, opts.suspendScreensaver); - GBASDLSuspendScreensaver(&renderer.events); + GBASDLSetScreensaverSuspendable(&renderer->events, opts->suspendScreensaver); + GBASDLSuspendScreensaver(&renderer->events); #endif if (GBAThreadStart(&context)) { - renderer.runloop(&context, &renderer); + renderer->runloop(renderer, &context); GBAThreadJoin(&context); } else { didFail = true;

@@ -151,8 +236,8 @@ printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n");

} #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLResumeScreensaver(&renderer.events); - GBASDLSetScreensaverSuspendable(&renderer.events, false); + GBASDLResumeScreensaver(&renderer->events); + GBASDLSetScreensaverSuspendable(&renderer->events, false); #endif if (GBAThreadHasCrashed(&context)) {

@@ -160,20 +245,53 @@ didFail = true;

printf("The game crashed!\n"); } } - freeArguments(&args); - GBAConfigFreeOpts(&opts); - GBAConfigDeinit(&config); free(context.debugger); GBADirectorySetDeinit(&context.dirs); - GBASDLDetachPlayer(&renderer.events, &renderer.player); - GBAInputMapDeinit(&inputMap); + GBASDLDetachPlayer(&renderer->events, &renderer->player); + GBAInputMapDeinit(inputMap); - GBASDLDeinit(&renderer); + mSDLDeinit(renderer); return didFail; } +#endif -static bool GBASDLInit(struct SDLSoftwareRenderer* renderer) { +#ifdef M_CORE_GB +int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) { + GBVideoSoftwareRendererCreate(&renderer->gb); +#ifdef BUILD_GL + mSDLGLCreateGB(renderer); +#elif defined(BUILD_GLES2) + mSDLGLES2CreateGB(renderer); +#else + mSDLSWCreateGB(renderer); +#endif + + if (!mSDLInit(renderer)) { + return 1; + } + + struct LR35902Core cpu; + struct GB gb; + + GBCreate(&gb); + LR35902SetComponents(&cpu, &gb.d, 0, 0); + LR35902Init(&cpu); + + GBVideoAssociateRenderer(&gb.video, &renderer->gb.d); + struct VFile* vf = VFileOpen(args->fname, O_RDONLY); + GBLoadROM(&gb, vf, 0, args->fname); + + LR35902Reset(&cpu); + renderer->runloop(renderer, &gb); + vf->close(vf); + + mSDLDeinit(renderer); + return 0; +} +#endif + +static bool mSDLInit(struct mSDLRenderer* renderer) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("Could not initialize video: %s\n", SDL_GetError()); return false;

@@ -182,7 +300,7 @@

return renderer->init(renderer); } -static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) { +static void mSDLDeinit(struct mSDLRenderer* renderer) { GBASDLDeinitEvents(&renderer->events); GBASDLDeinitAudio(&renderer->audio); #if SDL_VERSION_ATLEAST(2, 0, 0)
M src/platform/sdl/main.hsrc/platform/sdl/main.h

@@ -6,7 +6,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef SDL_MAIN_H #define SDL_MAIN_H +#ifdef M_CORE_GBA #include "gba/renderers/video-software.h" +#endif + +#ifdef M_CORE_GB +#include "gb/renderers/software.h" +#endif #include "sdl-audio.h" #include "sdl-events.h"

@@ -34,15 +40,22 @@ #ifdef USE_PIXMAN

#include <pixman.h> #endif -struct SDLSoftwareRenderer { - struct GBAVideoSoftwareRenderer d; +struct mSDLRenderer { + union { +#ifdef M_CORE_GBA + struct GBAVideoSoftwareRenderer d; +#endif +#ifdef M_CORE_GB + struct GBVideoSoftwareRenderer gb; +#endif + }; struct GBASDLAudio audio; struct GBASDLEvents events; struct GBASDLPlayer player; - bool (*init)(struct SDLSoftwareRenderer* renderer); - void (*runloop)(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); - void (*deinit)(struct SDLSoftwareRenderer* renderer); + bool (*init)(struct mSDLRenderer* renderer); + void (*runloop)(struct mSDLRenderer* renderer, void* user); + void (*deinit)(struct mSDLRenderer* renderer); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window* window;

@@ -86,13 +99,14 @@ void* base[2];

#endif }; -void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer); +void mSDLSWCreate(struct mSDLRenderer* renderer); #ifdef BUILD_GL -void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer); +void mSDLGLCreate(struct mSDLRenderer* renderer); +void mSDLGLCreateGB(struct mSDLRenderer* renderer); #endif #if defined(BUILD_GLES2) || defined(USE_EPOXY) -void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer); +void mSDLGLES2Create(struct mSDLRenderer* renderer); #endif #endif
M src/platform/sdl/sw-sdl.csrc/platform/sdl/sw-sdl.c

@@ -8,17 +8,17 @@

#include "gba/supervisor/thread.h" #include "util/arm-algo.h" -static bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLSWInit(struct mSDLRenderer* renderer); +static void mSDLSWRunloopGBA(struct mSDLRenderer* renderer, void* user); +static void mSDLSWDeinit(struct mSDLRenderer* renderer); -void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLSWInit; - renderer->deinit = GBASDLSWDeinit; - renderer->runloop = GBASDLSWRunloop; +void mSDLSWCreate(struct mSDLRenderer* renderer) { + renderer->init = mSDLSWInit; + renderer->deinit = mSDLSWDeinit; + renderer->runloop = mSDLSWRunloopGBA; } -bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer) { +bool mSDLSWInit(struct mSDLRenderer* renderer) { #if !SDL_VERSION_ATLEAST(2, 0, 0) #ifdef COLOR_16_BIT SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_DOUBLEBUF | SDL_HWSURFACE);

@@ -82,7 +82,8 @@

return true; } -void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLSWRunloopGBA(struct mSDLRenderer* renderer, void* user) { + struct GBAThread* context = user; SDL_Event event; #if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_Surface* surface = SDL_GetVideoSurface();

@@ -132,7 +133,7 @@ GBASyncWaitFrameEnd(&context->sync);

} } -void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer) { +void mSDLSWDeinit(struct mSDLRenderer* renderer) { if (renderer->ratio > 1) { free(renderer->d.outputBuffer); }