all repos — mgba @ 16608a408cd3f9df010aeef11fb7240e86f1faec

mGBA Game Boy Advance Emulator

src/platform/sdl/sw-main.c (view raw)

  1#ifdef USE_CLI_DEBUGGER
  2#include "debugger/cli-debugger.h"
  3#endif
  4
  5#ifdef USE_GDB_STUB
  6#include "debugger/gdb-stub.h"
  7#endif
  8
  9#include "gba-thread.h"
 10#include "gba.h"
 11#include "renderers/video-software.h"
 12#include "sdl-audio.h"
 13#include "sdl-events.h"
 14
 15#include <SDL.h>
 16
 17#include <errno.h>
 18#include <signal.h>
 19#include <sys/time.h>
 20
 21struct SoftwareRenderer {
 22	struct GBAVideoSoftwareRenderer d;
 23	struct GBASDLAudio audio;
 24	struct GBASDLEvents events;
 25};
 26
 27static int _GBASDLInit(struct SoftwareRenderer* renderer);
 28static void _GBASDLDeinit(struct SoftwareRenderer* renderer);
 29static void _GBASDLRunloop(struct GBAThread* context, struct SoftwareRenderer* renderer);
 30static void _GBASDLStart(struct GBAThread* context);
 31static void _GBASDLClean(struct GBAThread* context);
 32
 33int main(int argc, char** argv) {
 34	struct SoftwareRenderer renderer;
 35	GBAVideoSoftwareRendererCreate(&renderer.d);
 36
 37	struct StartupOptions opts;
 38	if (!parseCommandArgs(&opts, argc, argv, GRAPHICS_OPTIONS)) {
 39		usage(argv[0], GRAPHICS_USAGE);
 40		return 1;
 41	}
 42
 43	if (!_GBASDLInit(&renderer)) {
 44		return 1;
 45	}
 46
 47	struct GBAThread context = {
 48		.renderer = &renderer.d.d,
 49		.startCallback = _GBASDLStart,
 50		.cleanCallback = _GBASDLClean,
 51		.sync.videoFrameWait = 0,
 52		.sync.audioWait = 1,
 53		.userData = &renderer
 54	};
 55
 56	context.debugger = createDebugger(&opts);
 57
 58	GBAMapOptionsToContext(&opts, &context);
 59
 60	SDL_Surface* surface = SDL_GetVideoSurface();
 61	SDL_LockSurface(surface);
 62	renderer.d.outputBuffer = surface->pixels;
 63#ifdef COLOR_16_BIT
 64	renderer.d.outputBufferStride = surface->pitch / 2;
 65#else
 66	renderer.d.outputBufferStride = surface->pitch / 4;
 67#endif
 68
 69	GBAThreadStart(&context);
 70
 71	_GBASDLRunloop(&context, &renderer);
 72
 73	SDL_UnlockSurface(surface);
 74	GBAThreadJoin(&context);
 75	close(opts.fd);
 76	if (opts.biosFd >= 0) {
 77		close(opts.biosFd);
 78	}
 79	free(context.debugger);
 80
 81	_GBASDLDeinit(&renderer);
 82
 83	return 0;
 84}
 85
 86static int _GBASDLInit(struct SoftwareRenderer* renderer) {
 87	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
 88		return 0;
 89	}
 90
 91	GBASDLInitEvents(&renderer->events);
 92	GBASDLInitAudio(&renderer->audio);
 93
 94#ifdef COLOR_16_BIT
 95	SDL_SetVideoMode(240, 160, 16, SDL_DOUBLEBUF | SDL_HWSURFACE);
 96#else
 97	SDL_SetVideoMode(240, 160, 32, SDL_DOUBLEBUF | SDL_HWSURFACE);
 98#endif
 99
100	return 1;
101}
102
103static void _GBASDLRunloop(struct GBAThread* context, struct SoftwareRenderer* renderer) {
104	SDL_Event event;
105	SDL_Surface* surface = SDL_GetVideoSurface();
106
107	while (context->state < THREAD_EXITING) {
108		if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
109			SDL_UnlockSurface(surface);
110			SDL_Flip(surface);
111			SDL_LockSurface(surface);
112		}
113		GBASyncWaitFrameEnd(&context->sync);
114
115		while (SDL_PollEvent(&event)) {
116			GBASDLHandleEvent(context, &renderer->events, &event);
117		}
118	}
119}
120
121static void _GBASDLDeinit(struct SoftwareRenderer* renderer) {
122	GBASDLDeinitEvents(&renderer->events);
123	GBASDLDeinitAudio(&renderer->audio);
124	SDL_Quit();
125}
126
127static void _GBASDLStart(struct GBAThread* threadContext) {
128	struct SoftwareRenderer* renderer = threadContext->userData;
129	renderer->audio.audio = &threadContext->gba->audio;
130}
131
132static void _GBASDLClean(struct GBAThread* threadContext) {
133	struct SoftwareRenderer* renderer = threadContext->userData;
134	renderer->audio.audio = 0;
135}