diff render_sdl.c @ 1983:a7b753e260a2 mame_interp

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 09 May 2020 23:39:44 -0700
parents 81df9aa2de9b
children 3537514ea206
line wrap: on
line diff
--- a/render_sdl.c	Sun Apr 19 00:59:49 2020 -0700
+++ b/render_sdl.c	Sat May 09 23:39:44 2020 -0700
@@ -50,7 +50,14 @@
 static SDL_cond *audio_ready, *frame_ready;
 static uint8_t quitting = 0;
 
-static uint8_t sync_to_audio, run_on_audio_thread;
+enum {
+	SYNC_AUDIO,
+	SYNC_AUDIO_THREAD,
+	SYNC_VIDEO,
+	SYNC_EXTERNAL
+};
+
+static uint8_t sync_src;
 static uint32_t min_buffered;
 
 uint32_t **frame_buffers;
@@ -64,12 +71,12 @@
 
 uint8_t render_is_audio_sync(void)
 {
-	return sync_to_audio || run_on_audio_thread;
+	return sync_src < SYNC_VIDEO;
 }
 
 uint8_t render_should_release_on_exit(void)
 {
-	return !run_on_audio_thread;
+	return sync_src != SYNC_AUDIO_THREAD;
 }
 
 void render_buffer_consumed(audio_source *src)
@@ -120,7 +127,7 @@
 
 void render_lock_audio()
 {
-	if (sync_to_audio) {
+	if (sync_src == SYNC_AUDIO) {
 		SDL_LockMutex(audio_mutex);
 	} else {
 		SDL_LockAudio();
@@ -129,7 +136,7 @@
 
 void render_unlock_audio()
 {
-	if (sync_to_audio) {
+	if (sync_src == SYNC_AUDIO) {
 		SDL_UnlockMutex(audio_mutex);
 	} else {
 		SDL_UnlockAudio();
@@ -164,34 +171,40 @@
 
 void render_audio_created(audio_source *source)
 {
-	if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
+	if (render_is_audio_sync()) {
 		SDL_PauseAudio(0);
 	}
-	if (current_system) {
-		current_system->request_exit(current_system);
+	if (current_system && sync_src == SYNC_AUDIO_THREAD) {
+		system_request_exit(current_system, 0);
 	}
 }
 
 void render_source_paused(audio_source *src, uint8_t remaining_sources)
 {
-	if (sync_to_audio) {
+	if (sync_src == SYNC_AUDIO) {
 		SDL_CondSignal(audio_ready);
 	}
-	if (!remaining_sources) {
-		SDL_PauseAudio(0);
+	if (!remaining_sources && render_is_audio_sync()) {
+		SDL_PauseAudio(1);
+		if (sync_src == SYNC_AUDIO_THREAD) {
+			SDL_CondSignal(frame_ready);
+		}
 	}
 }
 
 void render_source_resumed(audio_source *src)
 {
-	if (sync_to_audio) {
+	if (render_is_audio_sync()) {
 		SDL_PauseAudio(0);
 	}
+	if (current_system && sync_src == SYNC_AUDIO_THREAD) {
+		system_request_exit(current_system, 0);
+	}
 }
 
 void render_do_audio_ready(audio_source *src)
 {
-	if (run_on_audio_thread) {
+	if (sync_src == SYNC_AUDIO_THREAD) {
 		int16_t *tmp = src->front;
 		src->front = src->back;
 		src->back = tmp;
@@ -199,9 +212,9 @@
 		src->buffer_pos = 0;
 		if (all_sources_ready()) {
 			//we've emulated far enough to fill the current buffer
-			current_system->request_exit(current_system);
+			system_request_exit(current_system, 0);
 		}
-	} else if (sync_to_audio) {
+	} else if (sync_src == SYNC_AUDIO) {
 		SDL_LockMutex(audio_mutex);
 			while (src->front_populated) {
 				SDL_CondWait(src->opaque, audio_mutex);
@@ -253,8 +266,21 @@
 #endif
 }
 
+static uint8_t external_sync;
+void render_set_external_sync(uint8_t ext_sync_on)
+{
+	if (ext_sync_on != external_sync) {
+		external_sync = ext_sync_on;
+		if (windowed_width) {
+			//only do this if render_init has already been called
+			render_config_updated();
+		}
+	}
+}
+
 #ifndef DISABLE_OPENGL
-static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos;
+static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, un_texsize, at_pos;
+static int tex_width, tex_height;
 
 static GLfloat vertex_data_default[] = {
 	-1.0f, -1.0f,
@@ -360,6 +386,15 @@
 	char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval;
 	GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR;
 	glGenTextures(3, textures);
+	def.ptrval = "off";
+	char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", def, TVAL_PTR).ptrval;
+	if (!strcmp(npot_textures, "on")) {
+		tex_width = LINEBUF_SIZE;
+		tex_height = 294; //PAL height with full borders
+	} else {
+		tex_width = tex_height = 512;
+	}
+	printf("Using %dx%d textures\n", tex_width, tex_height);
 	for (int i = 0; i < 3; i++)
 	{
 		glBindTexture(GL_TEXTURE_2D, textures[i]);
@@ -369,7 +404,7 @@
 		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, INTERNAL_FORMAT, 512, 512, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf);
+			glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, tex_width, tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf);
 		} else {
 			uint32_t blank = 255 << 24;
 			glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank);
@@ -398,6 +433,7 @@
 	un_textures[1] = glGetUniformLocation(program, "textures[1]");
 	un_width = glGetUniformLocation(program, "width");
 	un_height = glGetUniformLocation(program, "height");
+	un_texsize = glGetUniformLocation(program, "texsize");
 	at_pos = glGetAttribLocation(program, "pos");
 }
 
@@ -913,7 +949,17 @@
    	}
     debug_message("config says: %d\n", samples);
     desired.samples = samples*2;
-	desired.callback = sync_to_audio ? audio_callback : run_on_audio_thread ? audio_callback_run_on_audio : audio_callback_drc;
+	switch (sync_src)
+	{
+	case SYNC_AUDIO:
+		desired.callback = audio_callback;
+		break;
+	case SYNC_AUDIO_THREAD:
+		desired.callback = audio_callback_run_on_audio;
+		break;
+	default:
+		desired.callback = audio_callback_drc;
+	}
 	desired.userdata = NULL;
 
 	if (SDL_OpenAudio(&desired, &actual) < 0) {
@@ -943,12 +989,31 @@
 	}
 	
 	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");
-	run_on_audio_thread = !strcmp(sync_src, "audio_thread");
+	if (external_sync) {
+		sync_src = SYNC_EXTERNAL;
+	} else {
+		char *sync_src_str = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
+		if (!strcmp(sync_src_str, "audio")) {
+			sync_src = SYNC_AUDIO;
+		} else if (!strcmp(sync_src_str, "audio_thread")) {
+			sync_src = SYNC_AUDIO_THREAD;
+		} else {
+			sync_src = SYNC_VIDEO;
+		}
+	}
+	
+	if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) {
+		frame_mutex = SDL_CreateMutex();
+		free_buffer_mutex = SDL_CreateMutex();
+		frame_ready = SDL_CreateCond();
+		buffer_storage = 4;
+		frame_buffers = calloc(buffer_storage, sizeof(uint32_t*));
+		frame_buffers[0] = texture_buf;
+		num_buffers = 1;
+	}
 	
 	const char *vsync;
-	if (sync_to_audio) {
+	if (sync_src == SYNC_AUDIO) {
 		def.ptrval = "off";
 		vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval;
 	} else {
@@ -1108,16 +1173,6 @@
 	audio_mutex = SDL_CreateMutex();
 	audio_ready = SDL_CreateCond();
 	
-	if (run_on_audio_thread) {
-		frame_mutex = SDL_CreateMutex();
-		free_buffer_mutex = SDL_CreateMutex();
-		frame_ready = SDL_CreateCond();
-		buffer_storage = 4;
-		frame_buffers = calloc(buffer_storage, sizeof(uint32_t*));
-		frame_buffers[0] = texture_buf;
-		num_buffers = 1;
-	}
-	
 	init_audio();
 	
 	uint32_t db_size;
@@ -1136,13 +1191,10 @@
 
 	atexit(render_quit);
 }
-#include<unistd.h>
 static int in_toggle;
 
 void render_config_updated(void)
 {
-	uint8_t old_sync_to_audio = sync_to_audio;
-	
 	free_surfaces();
 #ifndef DISABLE_OPENGL
 	if (render_gl) {
@@ -1336,14 +1388,14 @@
 uint32_t locked_pitch;
 uint32_t *render_get_framebuffer(uint8_t which, int *pitch)
 {
-	if (run_on_audio_thread) {
+	if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
 		*pitch = LINEBUF_SIZE * sizeof(uint32_t);
 		uint32_t *buffer;
 		SDL_LockMutex(free_buffer_mutex);
 			if (num_buffers) {
 				buffer = frame_buffers[--num_buffers];
 			} else {
-				buffer = calloc(512*512, sizeof(uint32_t));
+				buffer = calloc(tex_width*(tex_height + 1), sizeof(uint32_t));
 			}
 		SDL_UnlockMutex(free_buffer_mutex);
 		locked_pixels = buffer;
@@ -1362,14 +1414,14 @@
 			warning("Request for invalid framebuffer number %d\n", which);
 			return NULL;
 		}
-		void *pixels;
-		if (SDL_LockTexture(sdl_textures[which], NULL, &pixels, pitch) < 0) {
+		uint8_t *pixels;
+		if (SDL_LockTexture(sdl_textures[which], NULL, (void **)&pixels, pitch) < 0) {
 			warning("Failed to lock texture: %s\n", SDL_GetError());
 			return NULL;
 		}
 		static uint8_t last;
 		if (which <= FRAMEBUFFER_EVEN) {
-			locked_pixels = pixels;
+			locked_pixels = (uint32_t *)pixels;
 			if (which == FRAMEBUFFER_EVEN) {
 				pixels += *pitch;
 			}
@@ -1379,7 +1431,7 @@
 			}
 			last = which;
 		}
-		return pixels;
+		return (uint32_t *)pixels;
 #ifndef DISABLE_OPENGL
 	}
 #endif
@@ -1408,7 +1460,7 @@
 static void process_framebuffer(uint32_t *buffer, uint8_t which, int width)
 {
 	static uint8_t last;
-	if (!render_is_audio_sync() && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
+	if (sync_src == SYNC_VIDEO && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
 		source_frame++;
 		if (source_frame >= source_hz) {
 			source_frame = 0;
@@ -1464,7 +1516,7 @@
 		}
 	} else {
 #endif
-		//TODO: Support run_on_audio_thread for render API framebuffers
+		//TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers
 		if (which <= FRAMEBUFFER_EVEN && last != which) {
 			uint8_t *cur_dst = (uint8_t *)locked_pixels;
 			uint8_t *cur_saved = (uint8_t *)texture_buf;
@@ -1613,7 +1665,7 @@
 
 void render_framebuffer_updated(uint8_t which, int width)
 {
-	if (run_on_audio_thread) {
+	if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
 		SDL_LockMutex(frame_mutex);
 			while (frame_queue_len == 4) {
 				SDL_CondSignal(frame_ready);
@@ -1651,25 +1703,29 @@
 
 void render_video_loop(void)
 {
-	if (!run_on_audio_thread) {
+	if (sync_src != SYNC_AUDIO_THREAD && sync_src != SYNC_EXTERNAL) {
 		return;
 	}
-	SDL_PauseAudio(0);
 	SDL_LockMutex(frame_mutex);
 		for(;;)
 		{
-			while (!frame_queue_len)
+			while (!frame_queue_len && SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)
 			{
 				SDL_CondWait(frame_ready, frame_mutex);
 			}
-			for (int i = 0; i < frame_queue_len; i++)
+			while (frame_queue_len)
 			{
 				frame f = frame_queue[frame_queue_read++];
 				frame_queue_read &= 0x3;
+				frame_queue_len--;
+				SDL_UnlockMutex(frame_mutex);
 				process_framebuffer(f.buffer, f.which, f.width);
 				release_buffer(f.buffer);
+				SDL_LockMutex(frame_mutex);
 			}
-			frame_queue_len = 0;
+			if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING) {
+				break;
+			}
 		}
 	
 	SDL_UnlockMutex(frame_mutex);
@@ -1699,6 +1755,7 @@
 
 		glUniform1f(un_width, render_emulated_width());
 		glUniform1f(un_height, last_height);
+		glUniform2f(un_texsize, tex_width, tex_height);
 
 		glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
 		glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
@@ -1974,3 +2031,9 @@
 	}
 	return 0xFF;
 }
+
+uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data)
+{
+	*thread = SDL_CreateThread(fun, name, data);
+	return *thread != 0;
+}