all repos — mgba @ 8c6a57f7d9bf32a90e4315099f77d35ecb5040ad

mGBA Game Boy Advance Emulator

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}