diff render_sdl.c @ 1696:956c1cce05e2 mame_interp

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Thu, 24 Jan 2019 19:15:59 -0800
parents ba3fb7a3be6b
children 52a47611a273
line wrap: on
line diff
--- a/render_sdl.c	Tue Dec 25 11:12:26 2018 -0800
+++ b/render_sdl.c	Thu Jan 24 19:15:59 2019 -0800
@@ -13,14 +13,19 @@
 #include "genesis.h"
 #include "bindings.h"
 #include "util.h"
+#include "paths.h"
 #include "ppm.h"
 #include "png.h"
 #include "config.h"
 #include "controller_info.h"
 
 #ifndef DISABLE_OPENGL
+#ifdef USE_GLES
+#include <SDL_opengles2.h>
+#else
 #include <GL/glew.h>
 #endif
+#endif
 
 #define MAX_EVENT_POLL_PER_FRAME 2
 
@@ -29,6 +34,7 @@
 static SDL_Renderer *main_renderer;
 static SDL_Renderer **extra_renderers;
 static SDL_Texture  **sdl_textures;
+static window_close_handler *close_handlers;
 static uint8_t num_textures;
 static SDL_Rect      main_clip;
 static SDL_GLContext *main_context;
@@ -40,6 +46,7 @@
 
 static uint32_t last_frame = 0;
 
+static uint8_t output_channels;
 static uint32_t buffer_samples, sample_rate;
 static uint32_t missing_count;
 
@@ -78,23 +85,28 @@
 {
 	int samples = len/(sizeof(int16_t)*2);
 	int16_t *stream = vstream;
-	int16_t *end = stream + 2*samples;
+	int16_t *end = stream + output_channels*samples;
 	int16_t *src = audio->front;
 	uint32_t i = audio->read_start;
 	uint32_t i_end = audio->read_end;
 	int16_t *cur = stream;
+	size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
 	if (audio->num_channels == 1) {
 		while (cur < end && i != i_end)
 		{
-			*(cur++) += src[i];
-			*(cur++) += src[i++];
+			*cur += src[i];
+			cur += first_add;
+			*cur += src[i++];
+			cur += second_add;
 			i &= audio->mask;
 		}
 	} else {
 		while (cur < end && i != i_end)
 		{
-			*(cur++) += src[i++];
-			*(cur++) += src[i++];
+			*cur += src[i++];
+			cur += first_add;
+			*cur += src[i++];
+			cur += second_add;
 			i &= audio->mask;
 		}
 	}
@@ -122,18 +134,23 @@
 	uint32_t i = audio->read_start;
 	uint32_t i_end = audio->read_end;
 	float *cur = stream;
+	size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
 	if (audio->num_channels == 1) {
 		while (cur < end && i != i_end)
 		{
-			*(cur++) += ((float)src[i]) / 0x7FFF;
-			*(cur++) += ((float)src[i++]) / 0x7FFF;
+			*cur += ((float)src[i]) / 0x7FFF;
+			cur += first_add;
+			*cur += ((float)src[i++]) / 0x7FFF;
+			cur += second_add;
 			i &= audio->mask;
 		}
 	} else {
 		while(cur < end && i != i_end)
 		{
-			*(cur++) += ((float)src[i++]) / 0x7FFF;
-			*(cur++) += ((float)src[i++]) / 0x7FFF;
+			*cur += ((float)src[i++]) / 0x7FFF;
+			cur += first_add;
+			*cur += ((float)src[i++]) / 0x7FFF;
+			cur += second_add;
 			i &= audio->mask;
 		}
 	}
@@ -436,7 +453,11 @@
 
 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
 {
+#ifdef USE_GLES
+	return 255 << 24 | b << 16 | g << 8 | r;
+#else
 	return 255 << 24 | r << 16 | g << 8 | b;
+#endif
 }
 
 #ifndef DISABLE_OPENGL
@@ -453,29 +474,49 @@
 
 static const GLushort element_data[] = {0, 1, 2, 3};
 
+static const GLchar shader_prefix[] =
+#ifdef USE_GLES
+	"#version 100\n";
+#else
+	"#version 110\n"
+	"#define lowp\n"
+	"#define mediump\n"
+	"#define highp\n";
+#endif
+
 static GLuint load_shader(char * fname, GLenum shader_type)
 {
 	char const * parts[] = {get_home_dir(), "/.config/blastem/shaders/", fname};
 	char * shader_path = alloc_concat_m(3, parts);
 	FILE * f = fopen(shader_path, "rb");
 	free(shader_path);
-	if (!f) {
-		parts[0] = get_exe_dir();
-		parts[1] = "/shaders/";
-		shader_path = alloc_concat_m(3, parts);
-		f = fopen(shader_path, "rb");
+	GLchar * text;
+	long fsize;
+	if (f) {
+		fsize = file_size(f);
+		text = malloc(fsize);
+		if (fread(text, 1, fsize, f) != fsize) {
+			warning("Error reading from shader file %s\n", fname);
+			free(text);
+			return 0;
+		}
+	} else {
+		shader_path = path_append("shaders", fname);
+		uint32_t fsize32;
+		text = read_bundled_file(shader_path, &fsize32);
 		free(shader_path);
-		if (!f) {
+		if (!text) {
 			warning("Failed to open shader file %s for reading\n", fname);
 			return 0;
 		}
+		fsize = fsize32;
 	}
-	long fsize = file_size(f);
-	GLchar * text = malloc(fsize);
-	if (fread(text, 1, fsize, f) != fsize) {
-		warning("Error reading from shader file %s\n", fname);
-		free(text);
-		return 0;
+	
+	if (strncmp(text, "#version", strlen("#version"))) {
+		GLchar *tmp = text;
+		text = alloc_concat(shader_prefix, tmp);
+		free(tmp);
+		fsize += strlen(shader_prefix);
 	}
 	GLuint ret = glCreateShader(shader_type);
 	glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize);
@@ -498,6 +539,15 @@
 
 static uint32_t texture_buf[512 * 513];
 #ifndef DISABLE_OPENGL
+#ifdef USE_GLES
+#define INTERNAL_FORMAT GL_RGBA
+#define SRC_FORMAT GL_RGBA
+#define RENDER_FORMAT SDL_PIXELFORMAT_ABGR8888
+#else
+#define INTERNAL_FORMAT GL_RGBA8
+#define SRC_FORMAT GL_BGRA
+#define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888
+#endif
 static void gl_setup()
 {
 	tern_val def = {.ptrval = "linear"};
@@ -513,10 +563,10 @@
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 		if (i < 2) {
 			//TODO: Fixme for PAL + invalid display mode
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf);
+			glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 512, 512, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf);
 		} else {
 			uint32_t blank = 255 << 24;
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank);
+			glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank);
 		}
 	}
 	glGenBuffers(2, buffers);
@@ -574,7 +624,7 @@
 		char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval;
 		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaling);
 		//TODO: Fixme for invalid display mode
-		sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, LINEBUF_SIZE, 588);
+		sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, RENDER_FORMAT, SDL_TEXTUREACCESS_STREAMING, LINEBUF_SIZE, 588);
 #ifndef DISABLE_OPENGL
 	}
 #endif
@@ -921,6 +971,21 @@
 			}
 #endif
 			break;
+		case SDL_WINDOWEVENT_CLOSE:
+			if (SDL_GetWindowID(main_window) == event->window.windowID) {
+				exit(0);
+			} else {
+				for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++)
+				{
+					if (SDL_GetWindowID(extra_windows[i]) == event->window.windowID) {
+						if (close_handlers[i]) {
+							close_handlers[i](i + FRAMEBUFFER_USER_START);
+						}
+						break;
+					}
+				}
+			}
+			break;
 		}
 		break;
 	case SDL_DROPFILE:
@@ -978,6 +1043,7 @@
 	}
 	buffer_samples = actual.samples;
 	sample_rate = actual.freq;
+	output_channels = actual.channels;
 	printf("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples);
 	if (actual.format == AUDIO_S16SYS) {
 		puts("signed 16-bit int format");
@@ -999,7 +1065,7 @@
 		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 	}
 	
-	tern_val def = {.ptrval = "video"};
+	tern_val def = {.ptrval = "audio"};
 	char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
 	sync_to_audio = !strcmp(sync_src, "audio");
 	
@@ -1050,6 +1116,11 @@
 		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
 		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
 		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+#ifdef USE_GLES
+		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+#endif
 	}
 #endif
 	main_window = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, main_width, main_height, flags);
@@ -1060,13 +1131,19 @@
 	if (gl_enabled)
 	{
 		main_context = SDL_GL_CreateContext(main_window);
+#ifdef USE_GLES
+		int major_version;
+		if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major_version) == 0 && major_version >= 2) {
+#else
 		GLenum res = glewInit();
 		if (res != GLEW_OK) {
 			warning("Initialization of GLEW failed with code %d\n", res);
 		}
 
 		if (res == GLEW_OK && GLEW_VERSION_2_0) {
+#endif
 			render_gl = 1;
+			SDL_GL_MakeCurrent(main_window, main_context);
 			if (!strcmp("tear", vsync)) {
 				if (SDL_GL_SetSwapInterval(-1) < 0) {
 					warning("late tear is not available (%s), using normal vsync\n", SDL_GetError());
@@ -1095,6 +1172,9 @@
 		if (!main_renderer) {
 			fatal_error("unable to create SDL renderer: %s\n", SDL_GetError());
 		}
+		SDL_RendererInfo rinfo;
+		SDL_GetRendererInfo(main_renderer, &rinfo);
+		printf("SDL2 Render Driver: %s\n", rinfo.name);
 		main_clip.x = main_clip.y = 0;
 		main_clip.w = main_width;
 		main_clip.h = main_height;
@@ -1302,7 +1382,7 @@
 	source_frame = 0;
 	source_frame_count = frame_repeat[0];
 	//sync samples with audio thread approximately every 8 lines
-	sync_samples = sync_to_audio ? buffer_samples : 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262));
+	sync_samples = sync_to_audio ? buffer_samples : 8 * sample_rate / (source_hz * (std == VID_PAL ? 313 : 262));
 	max_repeat++;
 	min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999;
 	//min_buffered *= buffer_samples;
@@ -1326,7 +1406,7 @@
 	screenshot_path = path;
 }
 
-uint8_t render_create_window(char *caption, uint32_t width, uint32_t height)
+uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler)
 {
 	uint8_t win_idx = 0xFF;
 	for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++)
@@ -1342,6 +1422,7 @@
 		sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures));
 		extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows));
 		extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers));
+		close_handlers = realloc(close_handlers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*close_handlers));
 		win_idx = num_textures - FRAMEBUFFER_USER_START - 1;
 	}
 	extra_windows[win_idx] = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
@@ -1357,6 +1438,7 @@
 	if (!sdl_textures[texture_idx]) {
 		goto fail_texture;
 	}
+	close_handlers[win_idx] = close_handler;
 	return texture_idx;
 	
 fail_texture:
@@ -1466,7 +1548,7 @@
 	if (render_gl && which <= FRAMEBUFFER_EVEN) {
 		SDL_GL_MakeCurrent(main_window, main_context);
 		glBindTexture(GL_TEXTURE_2D, textures[which]);
-		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]);
+		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]);
 		
 		if (screenshot_file) {
 			//properly supporting interlaced modes here is non-trivial, so only save the odd field for now