all repos — mgba @ 8047ce11d006ba4a51d055ce78f03807f66e5329

mGBA Game Boy Advance Emulator

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

  1#include "video-glsl.h"
  2
  3#include "gba-io.h"
  4
  5#include <string.h>
  6
  7#define UNIFORM_LOCATION(UNIFORM) (glGetUniformLocation(glslRenderer->program, UNIFORM))
  8
  9static const GLfloat _vertices[4] = {
 10	-1, 0,
 11	1, 0
 12};
 13
 14static const GLchar* _fragmentShader =
 15	"#extension GL_EXT_gpu_shader4 : enable\n"
 16	"varying float x;\n"
 17	"uniform float y;\n"
 18	"uniform sampler2D vram;\n"
 19	"uniform int dispcnt;\n"
 20	"uniform int bg0cnt;\n"
 21	"uniform int bg1cnt;\n"
 22	"uniform int bg2cnt;\n"
 23	"uniform int bg3cnt;\n"
 24	"uniform int bg0hofs;\n"
 25	"uniform int bg0vofs;\n"
 26	"uniform int bg1hofs;\n"
 27	"uniform int bg1vofs;\n"
 28	"uniform int bg2hofs;\n"
 29	"uniform int bg2vofs;\n"
 30	"uniform int bg3hofs;\n"
 31	"uniform int bg3vofs;\n"
 32	"#define VRAM_INDEX(i) (vec2(mod(float(i + 1), 512.0) / 512.0 - 1.0 / 1024.0, (160.0 + floor(float(i) / 512.0)) / 255.0))\n"
 33	"#define DESERIALIZE(vec) int(dot(vec4(63488.0, 1984.0, 62.0, 1.0), vec))\n"
 34
 35	"vec4 backgroundMode0(int bgcnt, int hofs, int vofs) {\n"
 36	"	int charBase = ((bgcnt / 4) & 3) * 8192;\n"
 37	"	int screenBase = ((bgcnt / 256) & 0x1F) * 1024;\n"
 38	"	int size = bgcnt >> 14;\n"
 39	"	int localX = hofs + int(x);\n"
 40	"	int localY = vofs + int(y);\n"
 41	"	int xBase = localX & 0xF8;\n"
 42	"	int yBase = localY & 0xF8;\n"
 43	"	if (size == 1) {\n"
 44	"		xBase += (localX & 0x100) << 5;\n"
 45	"	} else if (size == 2) {\n"
 46	"		yBase += localY & 0x100;\n"
 47	"	} else if (size == 3) {\n"
 48	"		xBase += (localX & 0x100) << 5;\n"
 49	"		yBase += (localY & 0x100) << 1;\n"
 50	"	}\n"
 51	"	screenBase = screenBase + (xBase / 8) + (yBase * 4);\n"
 52	"	int mapData = DESERIALIZE(texture2D(vram, VRAM_INDEX(screenBase)));\n"
 53	"	charBase = charBase + ((mapData & 0x3FF) * 16) + (localX & 0x4) / 4 + (localY & 0x7) * 2;\n"
 54	"	int tileData = DESERIALIZE(texture2D(vram, VRAM_INDEX(charBase)));\n"
 55	"	tileData = ((tileData >> ((localX & 3) * 4)) & 0xF);\n"
 56	"	if (tileData == 0) {\n"
 57	"		return vec4(0, 0, 0, 0);\n"
 58	"   }\n"
 59	"	return texture2D(vram, vec2(float(tileData + (mapData / 4096) * 16) / 512.0, y / 256.0));\n"
 60	"}\n"
 61
 62	"void runPriority(int priority, inout vec4 color) {\n"
 63	"	if (color.a > 0.0) {\n"
 64	"		return;\n"
 65	"	}\n"
 66	"	if ((dispcnt & 0x100) != 0 && (bg0cnt & 0x3) == priority) {\n"
 67	"		color = backgroundMode0(bg0cnt, bg0hofs, bg0vofs);\n"
 68	"	}\n"
 69	"	if (color.a > 0.0) {\n"
 70	"		return;\n"
 71	"	}\n"
 72	"	if ((dispcnt & 0x200) != 0 && (bg1cnt & 0x3) == priority) {\n"
 73	"		color = backgroundMode0(bg1cnt, bg1hofs, bg1vofs);\n"
 74	"	}\n"
 75	"	if (color.a > 0.0) {\n"
 76	"		return;\n"
 77	"	}\n"
 78	"	if ((dispcnt & 0x400) != 0 && (bg2cnt & 0x3) == priority) {\n"
 79	"		color = backgroundMode0(bg2cnt, bg2hofs, bg2vofs);\n"
 80	"	}\n"
 81	"	if (color.a > 0.0) {\n"
 82	"		return;\n"
 83	"	}\n"
 84	"	if ((dispcnt & 0x800) != 0 && (bg3cnt & 0x3) == priority) {\n"
 85	"		color = backgroundMode0(bg3cnt, bg3hofs, bg3vofs);\n"
 86	"	}\n"
 87	"}\n"
 88
 89	"void main() {\n"
 90	"	vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n"
 91	"	runPriority(0, color);\n"
 92	"	runPriority(1, color);\n"
 93	"	runPriority(2, color);\n"
 94	"	runPriority(3, color);\n"
 95	"	if (color.a == 0.0) {\n"
 96	"		color = texture2D(vram, vec2(0.0, y / 256.0));\n"
 97	"	}\n"
 98	"	gl_FragColor = color;\n"
 99	"}\n";
100
101static const GLchar* _vertexShader[] = {
102	"varying float x;",
103	"attribute vec2 vert;",
104	"uniform float y;",
105
106	"void main() {",
107	"	x = vert.x * 120.0 + 120.0;",
108	"	gl_Position = vec4(vert.x, 1.0 - (y + 1.0) / 80.0, 0, 1.0);",
109	"}"
110};
111
112static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer);
113static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer);
114static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
115static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
116static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
117static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer);
118
119void GBAVideoGLSLRendererCreate(struct GBAVideoGLSLRenderer* glslRenderer) {
120	glslRenderer->d.init = GBAVideoGLSLRendererInit;
121	glslRenderer->d.deinit = GBAVideoGLSLRendererDeinit;
122	glslRenderer->d.writeVideoRegister = GBAVideoGLSLRendererWriteVideoRegister;
123	glslRenderer->d.writePalette = GBAVideoGLSLRendererWritePalette;
124	glslRenderer->d.drawScanline = GBAVideoGLSLRendererDrawScanline;
125	glslRenderer->d.finishFrame = GBAVideoGLSLRendererFinishFrame;
126
127	glslRenderer->d.turbo = 0;
128	glslRenderer->d.framesPending = 0;
129	glslRenderer->d.frameskip = 0;
130
131	glslRenderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
132	glslRenderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
133	glslRenderer->program = glCreateProgram();
134
135	glShaderSource(glslRenderer->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
136	glShaderSource(glslRenderer->vertexShader, 7, _vertexShader, 0);
137
138	glAttachShader(glslRenderer->program, glslRenderer->vertexShader);
139	glAttachShader(glslRenderer->program, glslRenderer->fragmentShader);
140	char log[1024];
141	glCompileShader(glslRenderer->fragmentShader);
142	glCompileShader(glslRenderer->vertexShader);
143	glGetShaderInfoLog(glslRenderer->fragmentShader, 1024, 0, log);
144	glGetShaderInfoLog(glslRenderer->vertexShader, 1024, 0, log);
145	glLinkProgram(glslRenderer->program);
146
147	glGenTextures(1, &glslRenderer->vramTexture);
148	glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
149	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
150	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
151	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
152	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
153
154	memset(glslRenderer->vram, 0, sizeof (glslRenderer->vram));
155
156	{
157		pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
158		glslRenderer->mutex = mutex;
159		pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
160		glslRenderer->upCond = cond;
161		glslRenderer->downCond = cond;
162	}
163}
164
165void GBAVideoGLSLRendererProcessEvents(struct GBAVideoGLSLRenderer* glslRenderer) {
166	glUseProgram(glslRenderer->program);
167	glUniform1i(UNIFORM_LOCATION("vram"), 0);
168	glUniform1i(UNIFORM_LOCATION("dispcnt"), glslRenderer->io[0][REG_DISPCNT >> 1]);
169	glUniform1i(UNIFORM_LOCATION("bg0cnt"), glslRenderer->io[0][REG_BG0CNT >> 1]);
170	glUniform1i(UNIFORM_LOCATION("bg1cnt"), glslRenderer->io[0][REG_BG1CNT >> 1]);
171	glUniform1i(UNIFORM_LOCATION("bg2cnt"), glslRenderer->io[0][REG_BG2CNT >> 1]);
172	glUniform1i(UNIFORM_LOCATION("bg3cnt"), glslRenderer->io[0][REG_BG3CNT >> 1]);
173	glUniform1i(UNIFORM_LOCATION("bg0hofs"), glslRenderer->io[0][REG_BG0HOFS >> 1]);
174	glUniform1i(UNIFORM_LOCATION("bg0vofs"), glslRenderer->io[0][REG_BG0VOFS >> 1]);
175	glUniform1i(UNIFORM_LOCATION("bg1hofs"), glslRenderer->io[0][REG_BG1HOFS >> 1]);
176	glUniform1i(UNIFORM_LOCATION("bg1vofs"), glslRenderer->io[0][REG_BG1VOFS >> 1]);
177	glUniform1i(UNIFORM_LOCATION("bg2hofs"), glslRenderer->io[0][REG_BG2HOFS >> 1]);
178	glUniform1i(UNIFORM_LOCATION("bg2vofs"), glslRenderer->io[0][REG_BG2VOFS >> 1]);
179	glUniform1i(UNIFORM_LOCATION("bg3hofs"), glslRenderer->io[0][REG_BG3HOFS >> 1]);
180	glUniform1i(UNIFORM_LOCATION("bg3vofs"), glslRenderer->io[0][REG_BG3VOFS >> 1]);
181
182	glEnable(GL_TEXTURE_2D);
183	glActiveTexture(GL_TEXTURE0);
184	glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
185	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, glslRenderer->vram);
186
187	GLuint location = glGetAttribLocation(glslRenderer->program, "vert");
188	glEnableVertexAttribArray(location);
189	glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
190	int y;
191	for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
192		glUniform1f(UNIFORM_LOCATION("y"), y);
193		glDrawArrays(GL_LINES, 0, 2);
194	}
195	glDisableVertexAttribArray(location);
196	glFlush();
197}
198
199static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer) {
200	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
201
202	glslRenderer->state = GLSL_NONE;
203	glslRenderer->y = 0;
204
205	glslRenderer->oldVram = renderer->vram;
206	renderer->vram = &glslRenderer->vram[512 * 160];
207
208	pthread_mutex_init(&glslRenderer->mutex, 0);
209	pthread_cond_init(&glslRenderer->upCond, 0);
210	pthread_cond_init(&glslRenderer->downCond, 0);
211}
212
213static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer) {
214	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
215
216	/*glDeleteShader(glslRenderer->fragmentShader);
217	glDeleteShader(glslRenderer->vertexShader);
218	glDeleteProgram(glslRenderer->program);
219
220	glDeleteTextures(1, &glslRenderer->paletteTexture);*/
221
222	renderer->vram = glslRenderer->oldVram;
223
224	pthread_mutex_lock(&glslRenderer->mutex);
225	pthread_cond_broadcast(&glslRenderer->upCond);
226	pthread_mutex_unlock(&glslRenderer->mutex);
227
228	pthread_mutex_destroy(&glslRenderer->mutex);
229	pthread_cond_destroy(&glslRenderer->upCond);
230	pthread_cond_destroy(&glslRenderer->downCond);
231}
232
233static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
234	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
235	GLshort color = 1;
236	color |= (value & 0x001F) << 11;
237	color |= (value & 0x03E0) << 1;
238	color |= (value & 0x7C00) >> 9;
239	glslRenderer->vram[(address >> 1) + glslRenderer->y * 512] = color;
240}
241
242static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
243	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
244	glslRenderer->io[glslRenderer->y][address >> 1] = value;
245
246	return value;
247}
248
249static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
250	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
251
252	glslRenderer->y = y + 1;
253	if (y + 1 < VIDEO_VERTICAL_PIXELS) {
254		memcpy(&glslRenderer->vram[(y + 1) * 512], &glslRenderer->vram[y * 512], 1024);
255		memcpy(glslRenderer->io[y + 1], glslRenderer->io[y], sizeof(*glslRenderer->io));
256	} else {
257		glslRenderer->y = 0;
258		memcpy(&glslRenderer->vram[0], &glslRenderer->vram[y * 512], 1024);
259		memcpy(glslRenderer->io[0], glslRenderer->io[y], sizeof(*glslRenderer->io));
260	}
261}
262
263static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
264	struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
265
266	pthread_mutex_lock(&glslRenderer->mutex);
267	glslRenderer->state = GLSL_NONE;
268	if (renderer->frameskip > 0) {
269		--renderer->frameskip;
270	} else {
271		renderer->framesPending++;
272		pthread_cond_broadcast(&glslRenderer->upCond);
273		if (!renderer->turbo) {
274			pthread_cond_wait(&glslRenderer->downCond, &glslRenderer->mutex);
275		}
276	}
277	pthread_mutex_unlock(&glslRenderer->mutex);
278}