src/platform/opengl/gles2.c (view raw)
1/* Copyright (c) 2013-2015 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 "gles2.h"
7
8#include "gba/video.h"
9
10static const char* const _vertexShader =
11 "attribute vec4 position;\n"
12 "varying vec2 texCoord;\n"
13
14 "void main() {\n"
15 " gl_Position = position;\n"
16 " texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.5, -0.5);\n"
17 "}";
18
19static const char* const _nullVertexShader =
20 "attribute vec4 position;\n"
21 "varying vec2 texCoord;\n"
22
23 "void main() {\n"
24 " gl_Position = position;\n"
25 " texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);\n"
26 "}";
27
28static const char* const _fragmentShader =
29 "varying vec2 texCoord;\n"
30 "uniform sampler2D tex;\n"
31 "uniform float gamma;\n"
32 "uniform vec3 scale;\n"
33 "uniform vec3 bias;\n"
34
35 "void main() {\n"
36 " vec4 color = texture2D(tex, texCoord);\n"
37 " color.a = 1.;\n"
38 " color.rgb = scale * pow(color.rgb, vec3(gamma, gamma, gamma)) + bias;\n"
39 " gl_FragColor = color;\n"
40 "}";
41
42static const char* const _nullFragmentShader =
43 "varying vec2 texCoord;\n"
44 "uniform sampler2D tex;\n"
45
46 "void main() {\n"
47 " vec4 color = texture2D(tex, texCoord);\n"
48 " color.a = 1.;\n"
49 " gl_FragColor = color;\n"
50 "}";
51
52static const GLfloat _vertices[] = {
53 -1.f, -1.f,
54 -1.f, 1.f,
55 1.f, 1.f,
56 1.f, -1.f,
57};
58
59
60static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
61 UNUSED(handle);
62 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
63 glGenTextures(1, &context->tex);
64 glBindTexture(GL_TEXTURE_2D, context->tex);
65 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
66 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
67
68#ifdef COLOR_16_BIT
69#ifdef COLOR_5_6_5
70 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
71#else
72 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
73#endif
74#else
75 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
76#endif
77
78 glClearColor(0.f, 0.f, 0.f, 1.f);
79
80 struct GBAGLES2Uniform* uniforms = malloc(sizeof(struct GBAGLES2Uniform) * 3);
81 uniforms[0].name = "gamma";
82 uniforms[0].type = GL_FLOAT;
83 uniforms[0].value.f = 1.0f;
84 uniforms[1].name = "scale";
85 uniforms[1].type = GL_FLOAT_VEC3;
86 uniforms[1].value.fvec3[0] = 1.0f;
87 uniforms[1].value.fvec3[1] = 1.0f;
88 uniforms[1].value.fvec3[2] = 1.0f;
89 uniforms[2].name = "bias";
90 uniforms[2].type = GL_FLOAT_VEC3;
91 uniforms[2].value.fvec3[0] = 0.0f;
92 uniforms[2].value.fvec3[1] = 0.0f;
93 uniforms[2].value.fvec3[2] = 0.0f;
94 GBAGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, uniforms, 3);
95 GBAGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, 0, 0);
96 glDeleteFramebuffers(1, &context->finalShader.fbo);
97 context->finalShader.fbo = 0;
98}
99
100static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
101 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
102 glDeleteTextures(1, &context->tex);
103 GBAGLES2ShaderDeinit(&context->initialShader);
104 GBAGLES2ShaderDeinit(&context->finalShader);
105 free(context->initialShader.uniforms);
106}
107
108static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) {
109 int drawW = w;
110 int drawH = h;
111 if (v->lockAspectRatio) {
112 if (w * 2 > h * 3) {
113 drawW = h * 3 / 2;
114 } else if (w * 2 < h * 3) {
115 drawH = w * 2 / 3;
116 }
117 }
118 glViewport(0, 0, 240, 160);
119 glClearColor(0.f, 0.f, 0.f, 1.f);
120 glClear(GL_COLOR_BUFFER_BIT);
121 glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
122}
123
124static void GBAGLES2ContextClear(struct VideoBackend* v) {
125 UNUSED(v);
126 glClearColor(0.f, 0.f, 0.f, 1.f);
127 glClear(GL_COLOR_BUFFER_BIT);
128}
129
130void _drawShader(struct GBAGLES2Shader* shader) {
131 GLint viewport[4];
132 glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
133 if (shader->blend) {
134 glEnable(GL_BLEND);
135 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
136 } else {
137 glDisable(GL_BLEND);
138 }
139 glGetIntegerv(GL_VIEWPORT, viewport);
140 glViewport(0, 0, shader->width ? shader->width : viewport[2], shader->height ? shader->height : viewport[3]);
141 if (!shader->width || !shader->height) {
142 GLint oldTex;
143 glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
144 glBindTexture(GL_TEXTURE_2D, shader->tex);
145 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width ? shader->width : viewport[2], shader->height ? shader->height : viewport[3], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
146 glBindTexture(GL_TEXTURE_2D, oldTex);
147 }
148
149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
150 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
151 glUseProgram(shader->program);
152 glUniform1i(shader->texLocation, 0);
153 glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
154 glEnableVertexAttribArray(shader->positionLocation);
155 size_t u;
156 for (u = 0; u < shader->nUniforms; ++u) {
157 struct GBAGLES2Uniform* uniform = &shader->uniforms[u];
158 switch (uniform->type) {
159 case GL_FLOAT:
160 glUniform1f(uniform->location, uniform->value.f);
161 break;
162 case GL_INT:
163 glUniform1f(uniform->location, uniform->value.i);
164 break;
165 case GL_UNSIGNED_INT:
166 glUniform1f(uniform->location, uniform->value.ui);
167 break;
168 case GL_FLOAT_VEC2:
169 glUniform2fv(uniform->location, 1, uniform->value.fvec2);
170 break;
171 case GL_FLOAT_VEC3:
172 glUniform3fv(uniform->location, 1, uniform->value.fvec3);
173 break;
174 case GL_FLOAT_VEC4:
175 glUniform4fv(uniform->location, 1, uniform->value.fvec4);
176 break;
177 case GL_INT_VEC2:
178 glUniform2iv(uniform->location, 1, uniform->value.ivec2);
179 break;
180 case GL_INT_VEC3:
181 glUniform3iv(uniform->location, 1, uniform->value.ivec3);
182 break;
183 case GL_INT_VEC4:
184 glUniform4iv(uniform->location, 1, uniform->value.ivec4);
185 break;
186 case GL_UNSIGNED_INT_VEC2:
187 glUniform2uiv(uniform->location, 1, uniform->value.uivec2);
188 break;
189 case GL_UNSIGNED_INT_VEC3:
190 glUniform3uiv(uniform->location, 1, uniform->value.uivec3);
191 break;
192 case GL_UNSIGNED_INT_VEC4:
193 glUniform4uiv(uniform->location, 1, uniform->value.uivec4);
194 break;
195 case GL_FLOAT_MAT2:
196 glUniformMatrix2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x2);
197 break;
198 case GL_FLOAT_MAT2x3:
199 glUniformMatrix2x3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x3);
200 break;
201 case GL_FLOAT_MAT2x4:
202 glUniformMatrix2x4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x4);
203 break;
204 case GL_FLOAT_MAT3x2:
205 glUniformMatrix3x2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x2);
206 break;
207 case GL_FLOAT_MAT3:
208 glUniformMatrix3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x3);
209 break;
210 case GL_FLOAT_MAT3x4:
211 glUniformMatrix3x4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x4);
212 break;
213 case GL_FLOAT_MAT4x2:
214 glUniformMatrix2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x2);
215 break;
216 case GL_FLOAT_MAT4x3:
217 glUniformMatrix2x3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x3);
218 break;
219 case GL_FLOAT_MAT4:
220 glUniformMatrix2x4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x4);
221 break;
222 }
223 }
224 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
225 glBindFramebuffer(GL_FRAMEBUFFER, 0);
226 glBindTexture(GL_TEXTURE_2D, shader->tex);
227 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
228}
229
230void GBAGLES2ContextDrawFrame(struct VideoBackend* v) {
231 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
232 glActiveTexture(GL_TEXTURE0);
233 glBindTexture(GL_TEXTURE_2D, context->tex);
234
235 context->finalShader.filter = v->filter;
236 _drawShader(&context->initialShader);
237 size_t n;
238 for (n = 0; n < context->nShaders; ++n) {
239 _drawShader(&context->shaders[n]);
240 }
241 _drawShader(&context->finalShader);
242 glUseProgram(0);
243}
244
245void GBAGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
246 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
247 glBindTexture(GL_TEXTURE_2D, context->tex);
248 glPixelStorei(GL_UNPACK_ROW_LENGTH, 256);
249#ifdef COLOR_16_BIT
250#ifdef COLOR_5_6_5
251 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
252#else
253 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
254#endif
255#else
256 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
257#endif
258 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
259}
260
261void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
262 context->d.init = GBAGLES2ContextInit;
263 context->d.deinit = GBAGLES2ContextDeinit;
264 context->d.resized = GBAGLES2ContextResized;
265 context->d.swap = 0;
266 context->d.clear = GBAGLES2ContextClear;
267 context->d.postFrame = GBAGLES2ContextPostFrame;
268 context->d.drawFrame = GBAGLES2ContextDrawFrame;
269 context->d.setMessage = 0;
270 context->d.clearMessage = 0;
271 context->shaders = 0;
272 context->nShaders = 0;
273}
274
275void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* vs, const char* fs, int width, int height, struct GBAGLES2Uniform* uniforms, size_t nUniforms) {
276 shader->width = width >= 0 ? width : VIDEO_HORIZONTAL_PIXELS;
277 shader->height = height >= 0 ? height : VIDEO_VERTICAL_PIXELS;
278 shader->filter = false;
279 shader->blend = false;
280 shader->uniforms = uniforms;
281 shader->nUniforms = nUniforms;
282 glGenFramebuffers(1, &shader->fbo);
283 glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
284
285 glGenTextures(1, &shader->tex);
286 glBindTexture(GL_TEXTURE_2D, shader->tex);
287 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
288 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
290 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
291 if (shader->width && shader->height) {
292 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
293 }
294
295 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shader->tex, 0);
296 shader->program = glCreateProgram();
297 shader->vertexShader = glCreateShader(GL_VERTEX_SHADER);
298 shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
299 if (vs) {
300 glShaderSource(shader->vertexShader, 1, (const GLchar**) &vs, 0);
301 } else {
302 glShaderSource(shader->vertexShader, 1, (const GLchar**) &_nullVertexShader, 0);
303 }
304 if (fs) {
305 glShaderSource(shader->fragmentShader, 1, (const GLchar**) &fs, 0);
306 } else {
307 glShaderSource(shader->fragmentShader, 1, (const GLchar**) &_nullFragmentShader, 0);
308 }
309 glAttachShader(shader->program, shader->vertexShader);
310 glAttachShader(shader->program, shader->fragmentShader);
311 char log[1024];
312 glCompileShader(shader->fragmentShader);
313 glGetShaderInfoLog(shader->fragmentShader, 1024, 0, log);
314 printf("%s\n", log);
315 glCompileShader(shader->vertexShader);
316 glGetShaderInfoLog(shader->vertexShader, 1024, 0, log);
317 printf("%s\n", log);
318 glLinkProgram(shader->program);
319 glGetProgramInfoLog(shader->program, 1024, 0, log);
320 printf("%s\n", log);
321
322 shader->texLocation = glGetUniformLocation(shader->program, "tex");
323 shader->positionLocation = glGetAttribLocation(shader->program, "position");
324 size_t i;
325 for (i = 0; i < shader->nUniforms; ++i) {
326 shader->uniforms[i].location = glGetUniformLocation(shader->program, shader->uniforms[i].name);
327 }
328 glBindFramebuffer(GL_FRAMEBUFFER, 0);
329}
330
331void GBAGLES2ShaderDeinit(struct GBAGLES2Shader* shader) {
332 glDeleteTextures(1, &shader->tex);
333 glDeleteShader(shader->fragmentShader);
334 glDeleteProgram(shader->program);
335 glDeleteFramebuffers(1, &shader->fbo);
336}
337
338void GBAGLES2ShaderAttach(struct GBAGLES2Context* context, struct GBAGLES2Shader* shaders, size_t nShaders) {
339 if (context->shaders) {
340 if (context->shaders == shaders && context->nShaders == nShaders) {
341 return;
342 }
343 GBAGLES2ShaderDetach(context);
344 }
345 context->shaders = shaders;
346 context->nShaders = nShaders;
347}
348
349void GBAGLES2ShaderDetach(struct GBAGLES2Context* context) {
350 if (!context->shaders) {
351 return;
352 }
353 context->shaders = 0;
354}