mirror of https://github.com/mgba-emu/mgba.git
GB: Start work on video rendering
This commit is contained in:
parent
23ca81708d
commit
3158db06c2
|
@ -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 @@ if(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}")
|
||||
|
|
14
src/gb/gb.c
14
src/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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -64,7 +64,10 @@ void GBVideoDeinit(struct GBVideo* video) {
|
|||
}
|
||||
|
||||
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 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
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)) {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* 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 @@ void GBASDLGLCommonSwap(struct VideoBackend* context) {
|
|||
#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);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#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
|
||||
|
|
|
@ -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 @@ static void _doViewport(int w, int h, struct VideoBackend* 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 @@ bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
|
|||
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 @@ void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -9,17 +9,17 @@
|
|||
|
||||
#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 @@ bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
|
|||
return false;
|
||||
}
|
||||
#else
|
||||
GBASDLGLCommonInit(renderer);
|
||||
mSDLGLCommonInit(renderer);
|
||||
#endif
|
||||
|
||||
renderer->d.outputBuffer = memalign(16, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
|
||||
|
@ -100,12 +100,13 @@ bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
|
|||
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 @@ void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* r
|
|||
}
|
||||
}
|
||||
|
||||
void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) {
|
||||
void mSDLGLES2Deinit(struct mSDLRenderer* renderer) {
|
||||
if (renderer->gl2.d.deinit) {
|
||||
renderer->gl2.d.deinit(&renderer->gl2.d);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,19 @@
|
|||
#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 @@
|
|||
|
||||
#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 @@ int main(int argc, char** argv) {
|
|||
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 @@ int main(int argc, char** argv) {
|
|||
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 @@ int main(int argc, char** argv) {
|
|||
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 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
#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 @@ int main(int argc, char** argv) {
|
|||
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 @@ static bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
|
|||
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)
|
||||
|
|
|
@ -6,7 +6,13 @@
|
|||
#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 @@
|
|||
#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 @@ struct SDLSoftwareRenderer {
|
|||
#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
|
||||
|
|
|
@ -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 @@ bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer) {
|
|||
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 @@ void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
|
|||
}
|
||||
}
|
||||
|
||||
void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer) {
|
||||
void mSDLSWDeinit(struct mSDLRenderer* renderer) {
|
||||
if (renderer->ratio > 1) {
|
||||
free(renderer->d.outputBuffer);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue