all repos — mgba @ e6ea94d2296eae963a48a18d009217a38d92bf9b

mGBA Game Boy Advance Emulator

src/platform/sdl/egl-sdl.c (view raw)

  1#include "main.h"
  2
  3static const char* _vertexShader =
  4	"attribute vec4 position;\n"
  5	"varying vec2 texCoord;\n"
  6
  7	"void main() {\n"
  8	"	gl_Position = position;\n"
  9	"	texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n"
 10	"}";
 11
 12static const char* _fragmentShader =
 13	"varying vec2 texCoord;\n"
 14	"uniform sampler2D tex;\n"
 15
 16	"void main() {\n"
 17	"	vec4 color = texture2D(tex, texCoord);\n"
 18	"	color.a = 1.;\n"
 19	"	gl_FragColor = color;"
 20	"}";
 21
 22static const GLfloat _vertices[] = {
 23	-1.f, -1.f,
 24	-1.f, 1.f,
 25	1.f, 1.f,
 26	1.f, -1.f,
 27};
 28
 29bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
 30	bcm_host_init();
 31	renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 32	int major, minor;
 33	if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) {
 34		printf("Failed to initialize EGL");
 35		return false;
 36	}
 37
 38	if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
 39		printf("Failed to get GLES API");
 40		return false;
 41	}
 42
 43	const EGLint requestConfig[] = {
 44		EGL_RED_SIZE, 5,
 45		EGL_GREEN_SIZE, 5,
 46		EGL_BLUE_SIZE, 5,
 47		EGL_ALPHA_SIZE, 1,
 48		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
 49		EGL_NONE
 50	};
 51
 52	EGLConfig config;
 53	EGLint numConfigs;
 54
 55	if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) {
 56		printf("Failed to choose EGL config\n");
 57		return false;
 58	}
 59
 60	const EGLint contextAttributes[] = {
 61		EGL_CONTEXT_CLIENT_VERSION, 2,
 62		EGL_NONE
 63	};
 64
 65	int dispWidth = 240, dispHeight = 160, adjWidth;
 66	renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes);
 67	graphics_get_display_size(0, &dispWidth, &dispHeight);
 68	adjWidth = dispHeight / 2 * 3;
 69
 70	DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
 71	DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
 72
 73	VC_RECT_T destRect = {
 74		.x = (dispWidth - adjWidth) / 2,
 75		.y = 0,
 76		.width = adjWidth,
 77		.height = dispHeight
 78	};
 79
 80	VC_RECT_T srcRect = {
 81		.x = 0,
 82		.y = 0,
 83		.width = 240 << 16,
 84		.height = 160 << 16
 85	};
 86
 87	DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0);
 88	vc_dispmanx_update_submit_sync(update);
 89
 90	renderer->window.element = element;
 91	renderer->window.width = dispWidth;
 92	renderer->window.height = dispHeight;
 93
 94	renderer->surface = eglCreateWindowSurface(renderer->display, config, &renderer->window, 0);
 95	if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {
 96		return false;
 97	}
 98
 99	renderer->d.outputBuffer = memalign(16, 256 * 256 * 4);
100	renderer->d.outputBufferStride = 256;
101	glGenTextures(1, &renderer->tex);
102	glBindTexture(GL_TEXTURE_2D, renderer->tex);
103	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
104	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
105	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
106	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
107	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
108	renderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
109	renderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
110	renderer->program = glCreateProgram();
111
112	glShaderSource(renderer->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
113	glShaderSource(renderer->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
114	glAttachShader(renderer->program, renderer->vertexShader);
115	glAttachShader(renderer->program, renderer->fragmentShader);
116	char log[1024];
117	glCompileShader(renderer->fragmentShader);
118	glCompileShader(renderer->vertexShader);
119	glGetShaderInfoLog(renderer->fragmentShader, 1024, 0, log);
120	glGetShaderInfoLog(renderer->vertexShader, 1024, 0, log);
121	glLinkProgram(renderer->program);
122	glGetProgramInfoLog(renderer->program, 1024, 0, log);
123	printf("%s\n", log);
124	renderer->texLocation = glGetUniformLocation(renderer->program, "tex");
125	renderer->positionLocation = glGetAttribLocation(renderer->program, "position");
126	glClearColor(1.f, 0.f, 0.f, 1.f);
127}
128
129void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
130	SDL_Event event;
131
132	while (context->state < THREAD_EXITING) {
133		while (SDL_PollEvent(&event)) {
134			GBASDLHandleEvent(context, &renderer->events, &event);
135		}
136
137		if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
138			glViewport(0, 0, 240, 160);
139			glClear(GL_COLOR_BUFFER_BIT);
140			glUseProgram(renderer->program);
141			glUniform1i(renderer->texLocation, 0);
142			glActiveTexture(GL_TEXTURE0);
143			glBindTexture(GL_TEXTURE_2D, renderer->tex);
144			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
145			glVertexAttribPointer(renderer->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
146			glEnableVertexAttribArray(renderer->positionLocation);
147			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
148			glUseProgram(0);
149			eglSwapBuffers(renderer->display, renderer->surface);
150		}
151		GBASyncWaitFrameEnd(&context->sync);
152	}
153}
154
155void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
156	eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
157	eglDestroySurface(renderer->display, renderer->surface);
158	eglDestroyContext(renderer->display, renderer->context);
159	eglTerminate(renderer->display);
160	bcm_host_deinit();
161}