all repos — mgba @ f6a9467e861ccaaa691ab4c826a65cbeb0add6ad

mGBA Game Boy Advance Emulator

src/gba/renderers/video-glsl.c (view raw)

  1#include "video-glsl.h"
  2
  3#include <string.h>
  4
  5#define UNIFORM_LOCATION(UNIFORM) (glGetUniformLocation(glslRenderer->program, UNIFORM))
  6
  7static const GLfloat _vertices[4] = {
  8	-1, 0,
  9	1, 0
 10};
 11
 12static const GLchar* _fragmentShader[] = {
 13	"uniform float y;",
 14	"uniform sampler2D palette;",
 15
 16	"void main() {",
 17	"	gl_FragColor = texture2D(palette, vec2(0, y / 256.0));",
 18	"}"
 19};
 20
 21static const GLchar* _vertexShader[] = {
 22	"attribute vec2 vert;",
 23	"uniform float y;",
 24
 25	"void main() {",
 26	"	gl_Position = vec4(vert.x, 1.0 - y / 80.0, 0, 1.0);",
 27	"}"
 28};
 29
 30static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer);
 31static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer);
 32static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
 33static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
 34static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
 35static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer);
 36
 37void GBAVideoGLSLRendererCreate(struct GBAVideoGLSLRenderer* glslRenderer) {
 38	glslRenderer->d.init = GBAVideoGLSLRendererInit;
 39	glslRenderer->d.deinit = GBAVideoGLSLRendererDeinit;
 40	glslRenderer->d.writeVideoRegister = GBAVideoGLSLRendererWriteVideoRegister;
 41	glslRenderer->d.writePalette = GBAVideoGLSLRendererWritePalette;
 42	glslRenderer->d.drawScanline = GBAVideoGLSLRendererDrawScanline;
 43	glslRenderer->d.finishFrame = GBAVideoGLSLRendererFinishFrame;
 44
 45	glslRenderer->d.turbo = 0;
 46	glslRenderer->d.framesPending = 0;
 47	glslRenderer->d.frameskip = 0;
 48
 49	glslRenderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 50	glslRenderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
 51	glslRenderer->program = glCreateProgram();
 52
 53	glShaderSource(glslRenderer->fragmentShader, 5, _fragmentShader, 0);
 54	glShaderSource(glslRenderer->vertexShader, 5, _vertexShader, 0);
 55
 56	glAttachShader(glslRenderer->program, glslRenderer->vertexShader);
 57	glAttachShader(glslRenderer->program, glslRenderer->fragmentShader);
 58	char log[1024];
 59	glCompileShader(glslRenderer->fragmentShader);
 60	glCompileShader(glslRenderer->vertexShader);
 61	glGetShaderInfoLog(glslRenderer->fragmentShader, 1024, 0, log);
 62	glGetShaderInfoLog(glslRenderer->vertexShader, 1024, 0, log);
 63	glLinkProgram(glslRenderer->program);
 64
 65	glGenTextures(1, &glslRenderer->vramTexture);
 66	glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
 67	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 68	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 69	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 70	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 71
 72	memset(glslRenderer->vram, 0, sizeof (glslRenderer->vram));
 73
 74	{
 75		pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 76		glslRenderer->mutex = mutex;
 77		pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 78		glslRenderer->upCond = cond;
 79		glslRenderer->downCond = cond;
 80	}
 81}
 82
 83void GBAVideoGLSLRendererProcessEvents(struct GBAVideoGLSLRenderer* glslRenderer) {
 84		glUseProgram(glslRenderer->program);
 85		glUniform1i(UNIFORM_LOCATION("palette"), 0);
 86
 87		glEnable(GL_TEXTURE_2D);
 88		glActiveTexture(GL_TEXTURE0);
 89		glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
 90		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, glslRenderer->vram);
 91
 92		GLuint location = glGetAttribLocation(glslRenderer->program, "vert");
 93		glEnableVertexAttribArray(location);
 94		glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
 95		int y;
 96		for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
 97			glUniform1f(UNIFORM_LOCATION("y"), y);
 98			glDrawArrays(GL_LINES, 0, 2);
 99		}
100		glDisableVertexAttribArray(location);
101		glFlush();
102}
103
104static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer) {
105	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
106
107	glslRenderer->state = GLSL_NONE;
108	glslRenderer->y = 0;
109
110	pthread_mutex_init(&glslRenderer->mutex, 0);
111	pthread_cond_init(&glslRenderer->upCond, 0);
112	pthread_cond_init(&glslRenderer->downCond, 0);
113}
114
115static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer) {
116	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
117
118	/*glDeleteShader(glslRenderer->fragmentShader);
119	glDeleteShader(glslRenderer->vertexShader);
120	glDeleteProgram(glslRenderer->program);
121
122	glDeleteTextures(1, &glslRenderer->paletteTexture);*/
123
124	pthread_mutex_lock(&glslRenderer->mutex);
125	pthread_cond_broadcast(&glslRenderer->upCond);
126	pthread_mutex_unlock(&glslRenderer->mutex);
127
128	pthread_mutex_destroy(&glslRenderer->mutex);
129	pthread_cond_destroy(&glslRenderer->upCond);
130	pthread_cond_destroy(&glslRenderer->downCond);
131}
132
133static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
134	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
135	GLshort color = 0;
136	color |= (value & 0x001F) << 11;
137	color |= (value & 0x03E0) << 1;
138	color |= (value & 0x7C00) >> 9;
139	glslRenderer->vram[(address >> 1) + glslRenderer->y * 512] = color;
140}
141
142static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
143	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
144	(void)(glslRenderer);
145	(void)(address);
146
147	return value;
148}
149
150static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
151	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
152
153	glslRenderer->y = y + 1;
154	if (y + 1 < VIDEO_VERTICAL_PIXELS) {
155		memcpy(&glslRenderer->vram[(y + 1) * 512], &glslRenderer->vram[y * 512], 1024);
156	} else {
157		glslRenderer->y = 0;
158		memcpy(&glslRenderer->vram[0], &glslRenderer->vram[y * 512], 1024);
159	}
160}
161
162static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
163	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
164
165	pthread_mutex_lock(&glslRenderer->mutex);
166	glslRenderer->state = GLSL_NONE;
167	if (renderer->frameskip > 0) {
168		--renderer->frameskip;
169	} else {
170		renderer->framesPending++;
171		pthread_cond_broadcast(&glslRenderer->upCond);
172		if (!renderer->turbo) {
173			pthread_cond_wait(&glslRenderer->downCond, &glslRenderer->mutex);
174		}
175	}
176	pthread_mutex_unlock(&glslRenderer->mutex);
177}