all repos — mgba @ da7853bda61525c854b3d275fc6154f7e07fe54d

mGBA Game Boy Advance Emulator

src/egl-main.c (view raw)

  1#include "debugger.h"
  2#include "gba-thread.h"
  3#include "gba.h"
  4#include "renderers/video-glsl.h"
  5#include "sdl-events.h"
  6
  7#include <SDL.h>
  8#include <GLES2/gl2.h>
  9#include <EGL/egl.h>
 10
 11#include <bcm_host.h>
 12
 13#include <fcntl.h>
 14#include <errno.h>
 15#include <signal.h>
 16#include <sys/time.h>
 17#include <unistd.h>
 18
 19struct GBAVideoEGLRenderer {
 20	struct GBAVideoGLSLRenderer d;
 21
 22	EGLDisplay display;
 23	EGLSurface surface;
 24	EGLContext context;
 25};
 26
 27static int _GBAEGLInit(struct GBAVideoEGLRenderer* renderer);
 28static void _GBAEGLDeinit(struct GBAVideoEGLRenderer* renderer);
 29static void _GBAEGLRunloop(struct GBAThread* context, struct GBAVideoEGLRenderer* renderer);
 30
 31int main(int argc, char** argv) {
 32	const char* fname = "test.rom";
 33	if (argc > 1) {
 34		fname = argv[1];
 35	}
 36	int fd = open(fname, O_RDONLY);
 37	if (fd < 0) {
 38		return 1;
 39	}
 40
 41	struct GBAThread context;
 42	struct GBAVideoEGLRenderer renderer;
 43
 44	if (!_GBAEGLInit(&renderer)) {
 45		return 1;
 46	}
 47	GBAVideoGLSLRendererCreate(&renderer.d);
 48
 49	context.fd = fd;
 50	context.renderer = &renderer.d.d;
 51	GBAThreadStart(&context);
 52
 53	_GBAEGLRunloop(&context, &renderer);
 54
 55	GBAThreadJoin(&context);
 56	close(fd);
 57
 58	_GBAEGLDeinit(&renderer);
 59
 60	return 0;
 61}
 62
 63static int _GBAEGLInit(struct GBAVideoEGLRenderer* renderer) {
 64	if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
 65		return 0;
 66	}
 67
 68	GBASDLInitEvents();
 69	bcm_host_init();
 70	renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 71	int major, minor;
 72	if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) {
 73		printf("Failed to initialize EGL");
 74		return 0;
 75	}
 76
 77	if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
 78		printf("Failed to get GLES API");
 79		return 0;
 80	}
 81
 82	const EGLint requestConfig[] = {
 83		EGL_RED_SIZE, 8,
 84		EGL_GREEN_SIZE, 8,
 85		EGL_BLUE_SIZE, 8,
 86		EGL_ALPHA_SIZE, 8,
 87		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
 88		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
 89		EGL_NONE
 90	};
 91
 92	EGLConfig config;
 93	EGLint numConfigs;
 94
 95	if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) {
 96		printf("Failed to choose EGL config\n");
 97		return 0;
 98	}
 99
100	const EGLint contextAttributes[] = {
101		EGL_CONTEXT_CLIENT_VERSION, 2,
102		EGL_NONE
103	};
104
105	renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes);
106
107	DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
108	DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
109
110	VC_RECT_T destRect = {
111		.x = 0,
112		.y = 0,
113		.width = 240,
114		.height = 160
115	};
116
117	VC_RECT_T srcRect = {
118		.x = 0,
119		.y = 0,
120		.width = 240,
121		.height = 160
122	};
123
124	DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, DISPMANX_NO_ROTATE);
125	vc_dispmanx_update_submit_sync(update);
126
127	EGL_DISPMANX_WINDOW_T window = {
128		.element = element,
129		.width = 240,
130		.height = 160
131	};
132
133	renderer->surface = eglCreateWindowSurface(renderer->display, config, &window, 0);
134	return EGL_TRUE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context);
135}
136
137static void _GBAEGLRunloop(struct GBAThread* context, struct GBAVideoEGLRenderer* renderer) {
138	SDL_Event event;
139
140	while (context->started && context->debugger->state != DEBUGGER_EXITING) {
141		GBAVideoGLSLRendererProcessEvents(&renderer->d);
142		pthread_mutex_lock(&renderer->d.mutex);
143		if (renderer->d.d.framesPending) {
144			renderer->d.d.framesPending = 0;
145			pthread_mutex_unlock(&renderer->d.mutex);
146
147			eglSwapBuffers(renderer->display, renderer->surface);
148
149			while (SDL_PollEvent(&event)) {
150				GBASDLHandleEvent(context, &event);
151			}
152			pthread_mutex_lock(&renderer->d.mutex);
153			pthread_cond_broadcast(&renderer->d.downCond);
154		} else {
155			pthread_cond_broadcast(&renderer->d.downCond);
156			pthread_cond_wait(&renderer->d.upCond, &renderer->d.mutex);
157		}
158		pthread_mutex_unlock(&renderer->d.mutex);
159	}
160}
161
162static void _GBAEGLDeinit(struct GBAVideoEGLRenderer* renderer) {
163	eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
164	eglDestroySurface(renderer->display, renderer->surface);
165	eglDestroyContext(renderer->display, renderer->context);
166	eglTerminate(renderer->display);
167
168	GBASDLDeinitEvents();
169	SDL_Quit();
170
171	bcm_host_deinit();
172}