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 * vec4(1.0, 1.0, 1.0, 1.0);\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;"
40 "}";
41
42static const GLfloat _vertices[] = {
43 -1.f, -1.f,
44 -1.f, 1.f,
45 1.f, 1.f,
46 1.f, -1.f,
47};
48
49static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
50 UNUSED(handle);
51 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
52 glGenTextures(1, &context->tex);
53 glBindTexture(GL_TEXTURE_2D, context->tex);
54 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
55 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
56
57#ifdef COLOR_16_BIT
58#ifdef COLOR_5_6_5
59 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
60#else
61 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);
62#endif
63#else
64 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
65#endif
66
67 context->program = glCreateProgram();
68 context->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
69 context->vertexShader = glCreateShader(GL_VERTEX_SHADER);
70 context->nullVertexShader = glCreateShader(GL_VERTEX_SHADER);
71
72 glShaderSource(context->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
73 glShaderSource(context->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
74 glShaderSource(context->nullVertexShader, 1, (const GLchar**) &_nullVertexShader, 0);
75 glAttachShader(context->program, context->vertexShader);
76 glAttachShader(context->program, context->fragmentShader);
77 char log[1024];
78 glCompileShader(context->fragmentShader);
79 glCompileShader(context->vertexShader);
80 glCompileShader(context->nullVertexShader);
81 glGetShaderInfoLog(context->fragmentShader, 1024, 0, log);
82 printf("%s\n", log);
83 glGetShaderInfoLog(context->vertexShader, 1024, 0, log);
84 printf("%s\n", log);
85 glGetShaderInfoLog(context->nullVertexShader, 1024, 0, log);
86 printf("%s\n", log);
87 glLinkProgram(context->program);
88 glGetProgramInfoLog(context->program, 1024, 0, log);
89 printf("%s\n", log);
90 context->texLocation = glGetUniformLocation(context->program, "tex");
91 context->gammaLocation = glGetUniformLocation(context->program, "gamma");
92 context->biasLocation = glGetUniformLocation(context->program, "bias");
93 context->scaleLocation = glGetUniformLocation(context->program, "scale");
94 context->positionLocation = glGetAttribLocation(context->program, "position");
95 glClearColor(0.f, 0.f, 0.f, 1.f);
96}
97
98static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
99 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
100 glDeleteTextures(1, &context->tex);
101 glDeleteShader(context->fragmentShader);
102 glDeleteShader(context->vertexShader);
103 glDeleteShader(context->nullVertexShader);
104 glDeleteProgram(context->program);
105}
106
107static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) {
108 int drawW = w;
109 int drawH = h;
110 if (v->lockAspectRatio) {
111 if (w * 2 > h * 3) {
112 drawW = h * 3 / 2;
113 } else if (w * 2 < h * 3) {
114 drawH = w * 2 / 3;
115 }
116 }
117 glViewport(0, 0, 240, 160);
118 glClearColor(0.f, 0.f, 0.f, 1.f);
119 glClear(GL_COLOR_BUFFER_BIT);
120 glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
121}
122
123static void GBAGLES2ContextClear(struct VideoBackend* v) {
124 UNUSED(v);
125 glClearColor(0.f, 0.f, 0.f, 1.f);
126 glClear(GL_COLOR_BUFFER_BIT);
127}
128
129void GBAGLES2ContextDrawFrame(struct VideoBackend* v) {
130 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
131 glActiveTexture(GL_TEXTURE0);
132 glBindTexture(GL_TEXTURE_2D, context->tex);
133
134 if (context->shader) {
135 GLint viewport[4];
136 if (context->shader->blend) {
137 glEnable(GL_BLEND);
138 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
139 } else {
140 glDisable(GL_BLEND);
141 }
142 glGetIntegerv(GL_VIEWPORT, viewport);
143 glViewport(0, 0, context->shader->width, context->shader->height);
144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, context->shader->filter ? GL_LINEAR : GL_NEAREST);
145 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, context->shader->filter ? GL_LINEAR : GL_NEAREST);
146 glBindFramebuffer(GL_FRAMEBUFFER, context->shader->fbo);
147 glUseProgram(context->shader->program);
148 glUniform1i(context->shader->texLocation, 0);
149 glVertexAttribPointer(context->shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
150 glEnableVertexAttribArray(context->shader->positionLocation);
151 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
152 glBindFramebuffer(GL_FRAMEBUFFER, 0);
153 glBindTexture(GL_TEXTURE_2D, context->shader->tex);
154 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
155 }
156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, v->filter ? GL_LINEAR : GL_NEAREST);
157 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, v->filter ? GL_LINEAR : GL_NEAREST);
158 glUseProgram(context->program);
159 glEnable(GL_BLEND);
160 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
161 glUniform1i(context->texLocation, 0);
162 glUniform1f(context->gammaLocation, context->gamma);
163 glUniform3f(context->biasLocation, context->bias[0], context->bias[1], context->bias[2]);
164 glUniform3f(context->scaleLocation, context->scale[0], context->scale[1], context->scale[2]);
165 glVertexAttribPointer(context->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
166 glEnableVertexAttribArray(context->positionLocation);
167 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
168 glDisable(GL_BLEND);
169 glUseProgram(0);
170}
171
172void GBAGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
173 struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
174 glBindTexture(GL_TEXTURE_2D, context->tex);
175 glPixelStorei(GL_UNPACK_ROW_LENGTH, 256);
176#ifdef COLOR_16_BIT
177#ifdef COLOR_5_6_5
178 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
179#else
180 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);
181#endif
182#else
183 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
184#endif
185 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
186}
187
188void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
189 context->d.init = GBAGLES2ContextInit;
190 context->d.deinit = GBAGLES2ContextDeinit;
191 context->d.resized = GBAGLES2ContextResized;
192 context->d.swap = 0;
193 context->d.clear = GBAGLES2ContextClear;
194 context->d.postFrame = GBAGLES2ContextPostFrame;
195 context->d.drawFrame = GBAGLES2ContextDrawFrame;
196 context->d.setMessage = 0;
197 context->d.clearMessage = 0;
198 context->shader = 0;
199 context->gamma = 1.0f;
200 context->bias[0] = 0.0f;
201 context->bias[1] = 0.0f;
202 context->bias[2] = 0.0f;
203 context->scale[0] = 1.0f;
204 context->scale[1] = 1.0f;
205 context->scale[2] = 1.0f;
206}
207
208void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* src, int width, int height) {
209 shader->width = width > 0 ? width : VIDEO_HORIZONTAL_PIXELS;
210 shader->height = height > 0 ? height : VIDEO_VERTICAL_PIXELS;
211 shader->filter = false;
212 shader->blend = false;
213 glGenFramebuffers(1, &shader->fbo);
214 glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
215
216 glGenTextures(1, &shader->tex);
217 glBindTexture(GL_TEXTURE_2D, shader->tex);
218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
221 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
222 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
223
224 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shader->tex, 0);
225 shader->program = glCreateProgram();
226 shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
227 glShaderSource(shader->fragmentShader, 1, (const GLchar**) &src, 0);
228 glAttachShader(shader->program, shader->fragmentShader);
229 glCompileShader(shader->fragmentShader);
230 char log[1024];
231 glGetShaderInfoLog(shader->fragmentShader, 1024, 0, log);
232 glBindFramebuffer(GL_FRAMEBUFFER, 0);
233}
234
235void GBAGLES2ShaderDeinit(struct GBAGLES2Shader* shader) {
236 glDeleteTextures(1, &shader->tex);
237 glDeleteShader(shader->fragmentShader);
238 glDeleteProgram(shader->program);
239}
240
241void GBAGLES2ShaderAttach(struct GBAGLES2Context* context, struct GBAGLES2Shader* shader) {
242 if (context->shader) {
243 if (context->shader == shader) {
244 return;
245 }
246 GBAGLES2ShaderDetach(context);
247 }
248 context->shader = shader;
249 glAttachShader(shader->program, context->nullVertexShader);
250
251 char log[1024];
252 glLinkProgram(shader->program);
253 glGetProgramInfoLog(shader->program, 1024, 0, log);
254 printf("%s\n", log);
255 shader->texLocation = glGetUniformLocation(shader->program, "tex");
256 shader->positionLocation = glGetAttribLocation(shader->program, "position");
257}
258
259void GBAGLES2ShaderDetach(struct GBAGLES2Context* context) {
260 if (!context->shader) {
261 return;
262 }
263 glDetachShader(context->shader->program, context->nullVertexShader);
264 context->shader = 0;
265}