src/platform/sdl/gles2-sdl.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "main.h"
7
8#include "gl-common.h"
9
10#include <mgba/core/core.h>
11#include <mgba/core/thread.h>
12
13#ifndef __APPLE__
14#include <malloc.h>
15#endif
16
17static bool mSDLGLES2Init(struct mSDLRenderer* renderer);
18static void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user);
19static void mSDLGLES2Deinit(struct mSDLRenderer* renderer);
20
21void mSDLGLES2Create(struct mSDLRenderer* renderer) {
22 renderer->init = mSDLGLES2Init;
23 renderer->deinit = mSDLGLES2Deinit;
24 renderer->runloop = mSDLGLES2Runloop;
25}
26
27bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
28#ifdef BUILD_RASPI
29 bcm_host_init();
30 renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
31 int major, minor;
32 if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) {
33 printf("Failed to initialize EGL");
34 return false;
35 }
36
37 if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
38 printf("Failed to get GLES API");
39 return false;
40 }
41
42 const EGLint requestConfig[] = {
43 EGL_RED_SIZE, 5,
44 EGL_GREEN_SIZE, 5,
45 EGL_BLUE_SIZE, 5,
46 EGL_ALPHA_SIZE, 1,
47 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
48 EGL_NONE
49 };
50
51 EGLConfig config;
52 EGLint numConfigs;
53
54 if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) {
55 printf("Failed to choose EGL config\n");
56 return false;
57 }
58
59 const EGLint contextAttributes[] = {
60 EGL_CONTEXT_CLIENT_VERSION, 2,
61 EGL_NONE
62 };
63
64 int dispWidth = 240, dispHeight = 160, adjWidth;
65 renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes);
66 graphics_get_display_size(0, &dispWidth, &dispHeight);
67 adjWidth = dispHeight / 2 * 3;
68
69 DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
70 DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
71
72 VC_RECT_T destRect = {
73 .x = (dispWidth - adjWidth) / 2,
74 .y = 0,
75 .width = adjWidth,
76 .height = dispHeight
77 };
78
79 VC_RECT_T srcRect = {
80 .x = 0,
81 .y = 0,
82 .width = 240 << 16,
83 .height = 160 << 16
84 };
85
86 DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0);
87 vc_dispmanx_update_submit_sync(update);
88
89 renderer->window.element = element;
90 renderer->window.width = dispWidth;
91 renderer->window.height = dispHeight;
92
93 renderer->surface = eglCreateWindowSurface(renderer->display, config, &renderer->window, 0);
94 if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {
95 return false;
96 }
97#else
98 mSDLGLCommonInit(renderer);
99#endif
100
101 size_t size = renderer->width * renderer->height * BYTES_PER_PIXEL;
102#ifndef __APPLE__
103 renderer->outputBuffer = memalign(16, size);
104#else
105 posix_memalign((void**) &renderer->outputBuffer, 16, size);
106#endif
107 memset(renderer->outputBuffer, 0, size);
108 renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width);
109
110 mGLES2ContextCreate(&renderer->gl2);
111 renderer->gl2.d.user = renderer;
112 renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio;
113 renderer->gl2.d.lockIntegerScaling = renderer->lockIntegerScaling;
114 renderer->gl2.d.filter = renderer->filter;
115 renderer->gl2.d.swap = mSDLGLCommonSwap;
116 renderer->gl2.d.init(&renderer->gl2.d, 0);
117 renderer->gl2.d.setDimensions(&renderer->gl2.d, renderer->width, renderer->height);
118
119 mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl2.d);
120 return true;
121}
122
123void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
124 struct mCoreThread* context = user;
125 SDL_Event event;
126 struct VideoBackend* v = &renderer->gl2.d;
127
128 while (mCoreThreadIsActive(context)) {
129 while (SDL_PollEvent(&event)) {
130 mSDLHandleEvent(context, &renderer->player, &event);
131#if SDL_VERSION_ATLEAST(2, 0, 0)
132 // Event handling can change the size of the screen
133 if (renderer->player.windowUpdated) {
134 SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
135 mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, v);
136 renderer->player.windowUpdated = 0;
137 }
138#endif
139 }
140
141 if (mCoreSyncWaitFrameStart(&context->impl->sync)) {
142 v->postFrame(v, renderer->outputBuffer);
143 }
144 mCoreSyncWaitFrameEnd(&context->impl->sync);
145 v->drawFrame(v);
146#ifdef BUILD_RASPI
147 eglSwapBuffers(renderer->display, renderer->surface);
148#else
149 v->swap(v);
150#endif
151 }
152}
153
154void mSDLGLES2Deinit(struct mSDLRenderer* renderer) {
155 if (renderer->gl2.d.deinit) {
156 renderer->gl2.d.deinit(&renderer->gl2.d);
157 }
158#ifdef BUILD_RASPI
159 eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
160 eglDestroySurface(renderer->display, renderer->surface);
161 eglDestroyContext(renderer->display, renderer->context);
162 eglTerminate(renderer->display);
163 bcm_host_deinit();
164#elif SDL_VERSION_ATLEAST(2, 0, 0)
165 SDL_GL_DeleteContext(renderer->glCtx);
166#endif
167 free(renderer->outputBuffer);
168}