changeset 1891:179a2ac29f27

Wait to reacquire framebuffer so that switching to UI does not require pushing a new frame if it happens in between bottom and top of display
author Michael Pavone <pavone@retrodev.com>
date Wed, 09 Oct 2019 23:06:02 -0700
parents 7bb4081e9e52
children 1afd6e85ec26
files vdp.c
diffstat 1 files changed, 39 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/vdp.c	Wed Oct 09 22:19:04 2019 -0700
+++ b/vdp.c	Wed Oct 09 23:06:02 2019 -0700
@@ -2050,39 +2050,58 @@
 
 static void advance_output_line(vdp_context *context)
 {
+	//This function is kind of gross because of the need to deal with vertical border busting via mode changes
 	uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
-
-	if (context->output_lines == lines_max) {
+	uint32_t output_line = context->vcounter;
+	if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
+		//vcounter increment occurs much later in Mode 4
+		output_line++;
+	} 
+	
+	if (context->output_lines == lines_max || (!context->pushed_frame && output_line == context->inactive_start + context->border_top)) {
+		//we've either filled up a full frame or we're at the bottom of screen in the current defined mode + border crop
 		if (!headless) {
 			render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
-			context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD;
-			context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
+			uint8_t is_even = context->flags2 & FLAG2_EVEN_FIELD;
+			if (context->vcounter <= context->inactive_start && (context->regs[REG_MODE_4] & BIT_INTERLACE)) {
+				is_even = !is_even;
+			}
+			context->cur_buffer = is_even ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD;
+			context->pushed_frame = 1;
+			context->fb = NULL;
 		}
 		vdp_update_per_frame_debug(context);
 		context->h40_lines = 0;
 		context->frame++;
 		context->output_lines = 0;
-	} else if (context->output_lines && context->vcounter < context->inactive_start && context->vcounter > context->output_lines) {	
-		context->output_lines = context->vcounter;
 	}
-	uint32_t output_line = context->vcounter;
-	if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
-		//vcounter increment occurs much later in Mode 4
-		output_line++;
-	} 
-	if (output_line < context->inactive_start + context->border_bot && context->output_lines > 0) {
-		output_line = context->output_lines++;//context->border_top + context->vcounter;
-	} else if (output_line >= 0x200 - context->border_top || (!context->border_top && !output_line)) {
-		if (output_line == 0x200 - context->border_top || (!context->border_top && !output_line)) {
+	
+	if (output_line < context->inactive_start + context->border_bot) {
+		if (context->output_lines) {
+			output_line = context->output_lines++;//context->border_top + context->vcounter;
+		} else if (!output_line && !context->border_top) {
+			//top border is completely cropped so we won't hit the case below
+			output_line = 0;
+			context->output_lines = 1;
+			context->pushed_frame = 0;
+		} else {
+			context->output_lines = output_line + 1;
+		}
+	} else if (output_line >= 0x200 - context->border_top) {
+		if (output_line == 0x200 - context->border_top) {
 			//We're at the top of the display, force context->output_lines to be zero to avoid
 			//potential screen rolling if the mode is changed at an inopportune time
 			context->output_lines = 0;
+			context->pushed_frame = 0;
 		}
 		output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
 	} else {
 		context->output = NULL;
 		return;
 	}
+	if (!context->fb) {
+		context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
+	}
 	output_line += context->top_offset;
 	context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
 #ifdef DEBUG_FB_FILL
@@ -2098,15 +2117,17 @@
 
 void vdp_release_framebuffer(vdp_context *context)
 {
-	render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
-	context->output = context->fb = NULL;
+	if (context->fb) {
+		render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
+		context->output = context->fb = NULL;
+	}
 }
 
 void vdp_reacquire_framebuffer(vdp_context *context)
 {
-	context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
 	uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
 	if (context->output_lines <= lines_max && context->output_lines > 0) {
+		context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
 		context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1 + context->top_offset));
 	} else {
 		context->output = NULL;