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