changeset 488:32f053ad9b02 opengl

Basic OpenGL rendering is working
author Mike Pavone <pavone@retrodev.com>
date Sun, 27 Oct 2013 01:29:50 -0700
parents c08a4efeee7f
children e97b80e3bd76
files Makefile blastem.c default.f.glsl default.v.glsl render_sdl.c vdp.c
diffstat 6 files changed, 143 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Sat Oct 26 22:38:47 2013 -0700
+++ b/Makefile	Sun Oct 27 01:29:50 2013 -0700
@@ -1,4 +1,4 @@
-LIBS=sdl gl
+LIBS=sdl glew gl
 LDFLAGS=-lm `pkg-config --libs $(LIBS)`
 ifdef DEBUG
 CFLAGS=-ggdb -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type
--- a/blastem.c	Sat Oct 26 22:38:47 2013 -0700
+++ b/blastem.c	Sun Oct 27 01:29:50 2013 -0700
@@ -62,7 +62,7 @@
 	uint8_t block[SMD_BLOCK_SIZE];
 	filesize -= SMD_HEADER_SIZE;
 	fseek(f, SMD_HEADER_SIZE, SEEK_SET);
-	
+
 	uint16_t * dst = cart;
 	while (filesize > 0) {
 		fread(block, 1, SMD_BLOCK_SIZE, f);
@@ -149,15 +149,15 @@
 				if (next_hint < context->int_cycle) {
 					context->int_cycle = next_hint;
 					context->int_num = 4;
-			
+
 				}
 			}
 		}
 	}
 
 	context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle;
-	/*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", 
-		context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), 
+	/*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n",
+		context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7),
 		v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/
 }
 
@@ -217,7 +217,7 @@
 	}
 	psg_run(gen->psg, target);
 	ym_run(gen->ym, target);
-	
+
 	//printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
 }
 
@@ -239,7 +239,7 @@
 		}
 		//printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks);
 		vdp_run_context(v_context, mclks_per_frame);
-		
+
 		if (!headless) {
 			break_on_sync |= wait_render_frame(v_context, frame_limit);
 		}
@@ -532,7 +532,7 @@
 				}
 				if (value & 1) {
 					dputs("bus requesting Z80");
-					
+
 					if(!reset && !busreq) {
 						sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K + Z80_ACK_DELAY*MCLKS_PER_Z80);
 						busack_cycle = (gen->z80->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY;
@@ -556,7 +556,7 @@
 					}
 					//busack_cycle = CYCLE_NEVER;
 					//busack = Z80_REQ_BUSY;
-					
+
 				}
 			} else if (location == 0x1200) {
 				sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K);
@@ -1471,7 +1471,7 @@
 				//Z80 debug commands
 				switch(input_buf[1])
 				{
-				case 'b': 
+				case 'b':
 					param = find_param(input_buf);
 					if (!param) {
 						fputs("zb command requires a parameter\n", stderr);
@@ -1523,7 +1523,7 @@
 const memmap_chunk static_map[] = {
 		{0,        0x400000,  0xFFFFFF, 0, MMAP_READ,                          cart,
 		           NULL,          NULL,         NULL,            NULL},
-		{0xE00000, 0x1000000, 0xFFFF,   0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, 
+		{0xE00000, 0x1000000, 0xFFFF,   0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram,
 		           NULL,          NULL,         NULL,            NULL},
 		{0xC00000, 0xE00000,  0x1FFFFF, 0, 0,                                  NULL,
 		           (read_16_fun)vdp_port_read,  (write_16_fun)vdp_port_write,
@@ -1576,7 +1576,7 @@
 			memmap[0].mask = 0xFFFFFF;
 			memmap[0].flags = MMAP_READ;
 			memmap[0].buffer = cart;
-			
+
 			ram_start &= 0xFFFFFE;
 			ram_end |= 1;
 			memmap[1].start = ram_start;
@@ -1593,7 +1593,7 @@
 				size /= 2;
 			}
 			memmap[1].buffer = gen->save_ram = malloc(size);
-			
+
 			memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0]));
 			num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1;
 		} else {
@@ -1602,7 +1602,7 @@
 			memmap[0].mask = 0xFFFFFF;
 			memmap[0].flags = MMAP_READ;
 			memmap[0].buffer = cart;
-			
+
 			memmap[1].start = 0x200000;
 			memmap[1].end = 0x400000;
 			memmap[1].mask = 0x1FFFFF;
@@ -1622,7 +1622,7 @@
 			memmap[num_chunks].end = 0xA13100;
 			memmap[num_chunks].mask = 0xFF;
 			memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w;
-			memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; 
+			memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b;
 			num_chunks++;
 			ram_end++;
 			size = ram_end-ram_start;
@@ -1651,7 +1651,7 @@
 	init_x86_68k_opts(&opts, memmap, num_chunks);
 	opts.address_log = address_log;
 	init_68k_context(&context, opts.native_code_map, &opts);
-	
+
 	context.video_context = gen->vdp;
 	context.system = gen;
 	//cartridge ROM
@@ -1773,7 +1773,7 @@
 	char * romfname = NULL;
 	FILE *address_log = NULL;
 	char * statefile = NULL;
-	uint8_t fullscreen = 0;
+	uint8_t fullscreen = 0, use_gl = 0;
 	for (int i = 1; i < argc; i++) {
 		if (argv[i][0] == '-') {
 			switch(argv[i][1]) {
@@ -1783,6 +1783,9 @@
 			case 'f':
 				fullscreen = 1;
 				break;
+			case 'g':
+				use_gl = 1;
+				break;
 			case 'l':
 				address_log = fopen("address.log", "w");
 				break;
@@ -1885,21 +1888,21 @@
 		fps = 50;
 	}
 	if (!headless) {
-		render_init(width, height, title, fps, fullscreen, 0);
+		render_init(width, height, title, fps, fullscreen, use_gl);
 	}
 	vdp_context v_context;
 	genesis_context gen;
 	memset(&gen, 0, sizeof(gen));
 	gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL;
-	
+
 	init_vdp_context(&v_context);
-	
+
 	ym2612_context y_context;
 	ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0);
-	
+
 	psg_context p_context;
 	psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer());
-	
+
 	z80_context z_context;
 	x86_z80_options z_opts;
 	init_x86_z80_opts(&z_opts);
@@ -1910,13 +1913,13 @@
 	z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80;
 	z_context.int_cycle = CYCLE_NEVER;
 	z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart;
-	
+
 	gen.z80 = &z_context;
 	gen.vdp = &v_context;
 	gen.ym = &y_context;
 	gen.psg = &p_context;
 	genesis = &gen;
-	
+
 	int fname_size = strlen(romfname);
 	sram_filename = malloc(fname_size+6);
 	memcpy(sram_filename, romfname, fname_size);
@@ -1931,7 +1934,7 @@
 		strcpy(sram_filename + fname_size, ".sram");
 	}
 	set_keybindings();
-	
+
 	init_run_cpu(&gen, debug, address_log, statefile);
 	return 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/default.f.glsl	Sun Oct 27 01:29:50 2013 -0700
@@ -0,0 +1,10 @@
+#version 110
+
+uniform sampler2D textures[2];
+
+varying vec2 texcoord;
+
+void main()
+{
+	gl_FragColor = texture2D(textures[0], texcoord);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/default.v.glsl	Sun Oct 27 01:29:50 2013 -0700
@@ -0,0 +1,10 @@
+#version 110
+
+attribute vec2 pos;
+varying vec2 texcoord;
+
+void main()
+{
+	gl_Position = vec4(pos, 0.0, 1.0);
+	texcoord = pos * vec2(320.0/1024.0, 240.0/-512.0) + vec2(320.0/1024.0, 240.0/512.0);
+}
--- a/render_sdl.c	Sat Oct 26 22:38:47 2013 -0700
+++ b/render_sdl.c	Sun Oct 27 01:29:50 2013 -0700
@@ -10,9 +10,7 @@
 #include "io.h"
 
 #ifndef DISABLE_OPENGL
-#define GL_GLEXT_PROTOTYPES
-#include <GL/gl.h>
-#include <GL/glext.h>
+#include <GL/glew.h>
 #endif
 
 SDL_Surface *screen;
@@ -93,13 +91,13 @@
 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
 {
 	if (render_gl) {
-		return b << 24 | g << 16 | r << 8 | 255;
+		return 255 << 24 | r << 16 | g << 8 | b;
 	} else {
 		return SDL_MapRGB(screen->format, r, g, b);
 	}
 }
 
-GLuint textures[3], buffers[2];
+GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], at_pos;
 
 const GLfloat vertex_data[] = {
 	-1.0f, -1.0f,
@@ -110,6 +108,41 @@
 
 const GLushort element_data[] = {0, 1, 2, 3};
 
+GLuint load_shader(char * fname, GLenum shader_type)
+{
+	FILE * f = fopen(fname, "r");
+	if (!f) {
+		fprintf(stderr, "Failed to open shader file %s for reading\n", fname);
+		return 0;
+	}
+	fseek(f, 0, SEEK_END);
+	long fsize = ftell(f);
+	fseek(f, 0, SEEK_SET);
+	GLchar * text = malloc(fsize);
+	if (fread(text, 1, fsize, f) != fsize) {
+		fprintf(stderr, "Error reading from shader file %s\n", fname);
+		free(text);
+		return 0;
+	}
+	GLuint ret = glCreateShader(shader_type);
+	glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize);
+	free(text);
+	glCompileShader(ret);
+	GLint compile_status, loglen;
+	glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status);
+	if (!compile_status) {
+		fprintf(stderr, "Shader %s failed to compile\n", fname);
+		glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &loglen);
+		text = malloc(loglen);
+		glGetShaderInfoLog(ret, loglen, NULL, text);
+		fputs(text, stderr);
+		free(text);
+		glDeleteShader(ret);
+		return 0;
+	}
+	return ret;
+}
+
 void render_alloc_surfaces(vdp_context * context)
 {
 	if (render_gl) {
@@ -134,8 +167,23 @@
 		glGenBuffers(2, buffers);
 		glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
 		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[0]);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
 		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
+		vshader = load_shader("default.v.glsl", GL_VERTEX_SHADER);
+		fshader = load_shader("default.f.glsl", GL_FRAGMENT_SHADER);
+		program = glCreateProgram();
+		glAttachShader(program, vshader);
+		glAttachShader(program, fshader);
+		glLinkProgram(program);
+		GLint link_status;
+		glGetProgramiv(program, GL_LINK_STATUS, &link_status);
+		if (!link_status) {
+			fputs("Failed to link shader program\n", stderr);
+			exit(1);
+		}
+		un_textures[0] = glGetUniformLocation(program, "textures[0]");
+		un_textures[1] = glGetUniformLocation(program, "textures[1]");
+		at_pos = glGetAttribLocation(program, "pos");
 	} else {
 		context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2);
 		context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel;
@@ -159,6 +207,7 @@
 	atexit(render_close_audio);
 	printf("width: %d, height: %d\n", width, height);
 	uint32_t flags = SDL_ANYFORMAT;
+
 #ifndef DISABLE_OPENGL
 	if (use_gl)
 	{
@@ -188,7 +237,21 @@
 		exit(1);
 	}
 #ifndef DISABLE_OPENGL
-	//TODO: Fallback to plain SDL if OpenGL 2.0 not available
+	//TODO: fallback on standard rendering if OpenGL 2.0 is unavailable or if init fails
+	if (use_gl)
+	{
+		GLenum res = glewInit();
+		if (res != GLEW_OK)
+		{
+			fprintf(stderr, "Initialization of GLEW failed with code %d\n", res);
+			exit(1);
+		}
+		if (!GLEW_VERSION_2_0)
+		{
+			fputs("OpenGL 2.0 is unable, falling back to standard SDL rendering\n", stderr);
+			exit(1);
+		}
+	}
 	render_gl = use_gl;
 #endif
 	SDL_WM_SetCaption(title, title);
@@ -263,6 +326,27 @@
 	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 	glClear(GL_COLOR_BUFFER_BIT);
 
+	glUseProgram(program);
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, textures[0]);
+	glUniform1i(un_textures[0], 0);
+
+	glActiveTexture(GL_TEXTURE1);
+	//TODO: Select appropriate texture based on status of interlace
+	glBindTexture(GL_TEXTURE_2D, textures[1]);
+	glUniform1i(un_textures[1], 1);
+
+	glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+	glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
+	glEnableVertexAttribArray(at_pos);
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
+	glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0);
+
+	glDisableVertexAttribArray(at_pos);
+
+	SDL_GL_SwapBuffers();
+
 }
 
 uint32_t blankbuf[320*240];
--- a/vdp.c	Sat Oct 26 22:38:47 2013 -0700
+++ b/vdp.c	Sun Oct 27 01:29:50 2013 -0700
@@ -50,10 +50,13 @@
 	memset(context, 0, sizeof(*context));
 	context->vdpmem = malloc(VRAM_SIZE);
 	memset(context->vdpmem, 0, VRAM_SIZE);
-	context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8));
+	/*context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8));
 	memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (render_depth() / 8));
 	context->evenbuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8));
 	memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (render_depth() / 8));
+	*/
+	render_alloc_surfaces(context);
+	context->framebuf = context->oddbuf;
 	context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
 	memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
 	context->tmp_buf_a = context->linebuf + LINEBUF_SIZE;