From e2f398738a740b30d704978580831e2bd3cd4470 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 27 Nov 2021 20:51:51 +0200 Subject: [PATCH] Interlace LOF change update, scandoubler mode last line blanking --- custom.cpp | 90 ++++++++++++++++++++++++----------------- drawing.cpp | 41 ++++++++----------- include/custom.h | 2 +- od-win32/screenshot.cpp | 2 +- 4 files changed, 70 insertions(+), 65 deletions(-) diff --git a/custom.cpp b/custom.cpp index 9f2da1ea..f1f42fcd 100644 --- a/custom.cpp +++ b/custom.cpp @@ -129,7 +129,7 @@ int vpos, vpos_prev, vposh; static int hpos_hsync_extra; static int vpos_count, vpos_count_diff; int lof_store; // real bit in custom registers -static int lof_current; // what display device thinks +int lof_display; // what display device thinks static bool lof_lastline, lof_prev_lastline; static int lol, lol_prev; static int next_lineno; @@ -635,10 +635,14 @@ STATIC_INLINE int hpos_to_diw(int pos) return ((pos + hpos_hsync_extra) * 2 - DDF_OFFSET) * 4; } -static int doflickerfix(void) +static bool doflickerfix_possible(void) { return currprefs.gfx_vresolution && doublescan < 0 && vpos < MAXVPOS; } +static bool doflickerfix_active(void) +{ + return interlace_seen > 0 && doflickerfix_possible(); +} uae_u32 get_copper_address(int copno) { @@ -851,7 +855,7 @@ static void remember_ctable_for_border(void) // This does not need start line check because only OCS Denise modes use this. static int get_equ_vblank_endline(void) { - return equ_vblank_endline + (equ_vblank_toggle ? (lof_current ? 1 : 0) : 0); + return equ_vblank_endline + (equ_vblank_toggle ? (lof_store ? 1 : 0) : 0); } static int output_res(int res) @@ -927,7 +931,7 @@ static void record_color_change2(int hpos, int regno, uae_u32 value) } // HCENTER blanking - if (hcenter_v2 && vs_state_on && vpos < maxvpos_display_vsync && lof_current) { + if (hcenter_v2 && vs_state_on && vpos < maxvpos_display_vsync && lof_display) { int chpos = pos; if (hcenter_v2_end == 0xffff && hcenter_v2 < chpos && hcenter_v2 >= last_recorded_diw_hpos) { cc = &curr_color_changes[next_color_change]; @@ -1064,7 +1068,7 @@ static void sync_color_changes(int hpos) // erase (color0 or bblank) area between previous end and new start static void hdiw_restart(int diw_last, int diw_current) { - if (diw_last >= diw_current || line_hidden()) { + if (diw_last >= diw_current || line_hidden() || nocustom()) { return; } // update state @@ -3395,6 +3399,12 @@ static void finish_final_fetch(int hpos) clear_bitplane_pipeline(1); if (thisline_decision.plfleft < 0) { + // registers that affect programmed vblank must be checked even if line is blank + if (line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3 + || (line_decisions[next_lineno].bplcon0 & 1) != (thisline_decision.bplcon0 & 1) + || line_decisions[next_lineno].vb != thisline_decision.vb + ) + thisline_changed = 1; return; } @@ -3453,8 +3463,8 @@ static void do_sprite_fetch(int hpos, uae_u8 dat); static void scandoubler_bpl_dma_start(void) { - if (!scandoubled_line && doflickerfix() && interlace_seen > 0) { - int lof = 1 - lof_current; + if (!scandoubled_line && doflickerfix_active()) { + int lof = 1 - lof_display; for (int i = 0; i < MAX_PLANES; i++) { prevbpl[lof][vpos][i] = bplptx[i]; if (!lof && (bplcon0 & 4)) { @@ -3758,11 +3768,6 @@ static void decide_vline(void) { bool forceoff = (vb_start_line == 1 && !harddis_v); - // if scandoubler mode: stop display before possible last non-paired line - if (doflickerfix() && interlace_seen > 0 && vpos + 1 >= maxvpos && lof_current && diwstate == DIW_waiting_stop) { - forceoff = true; - } - /* Take care of the vertical DIW. */ if (vpos == plffirstline && !forceoff) { diwstate = DIW_waiting_stop; @@ -4739,9 +4744,18 @@ static void reset_decisions_hsync_start(void) thisline_decision.vb = vb_start_line > 1 + vblank_extraline ? 0 : 1; } // if programmed vblank - if (!thisline_decision.vb && (beamcon0 & 0x1000) && ecs_agnus) { - thisline_decision.vb |= 2; + if ((beamcon0 & 0x1000) && ecs_agnus) { + if (!thisline_decision.vb) { + thisline_decision.vb |= 2; + } + } + // doublescan last line garbage workaround + if (doflickerfix_active()) { + if (vpos < maxvpos_display_vsync || (!lof_display && vpos >= maxvpos - 1) || (lof_display && vpos >= maxvpos - 1)) { + thisline_decision.vb |= 4; + } } + if (!ecs_denise && vb_end_line) { thisline_decision.vb = 1; } @@ -4780,7 +4794,7 @@ static void reset_decisions_hsync_start(void) delay_cycles2 = delay_cycles; set_delay_lastcycle(); - if (1 && fetchmode >= 2 && !doflickerfix()) { + if (1 && fetchmode >= 2 && !doflickerfix_active()) { // handle bitplane data wrap around bool toshift = false; if ((exthblank || (beamcon0 & 0x0110)) && (thisline_decision.bplres == 0 || currprefs.chipset_hr)) { @@ -4912,7 +4926,7 @@ void compute_vsynctime(void) } if (interlace_seen) { svpos += 0.5; - } else if (lof_current) { + } else if (lof_display) { svpos += 1.0; } if (currprefs.produce_sound > 1) { @@ -5202,7 +5216,7 @@ void compute_framesync(void) if (islace) { vblank_hz = vblank_hz_lace; - } else if (lof_current) { + } else if (lof_store) { vblank_hz = vblank_hz_lof; } else { vblank_hz = vblank_hz_shf; @@ -5526,7 +5540,7 @@ static void init_hz(bool checkvposw) } vblank_hz = (isntsc ? 15734.0 : 15625.0) / vpos_count; vblank_hz_nom = vblank_hz_shf = vblank_hz_lof = vblank_hz_lace = (float)vblank_hz; - maxvpos_nom = vpos_count - (lof_current ? 1 : 0); + maxvpos_nom = vpos_count - (lof_store ? 1 : 0); if ((maxvpos_nom >= 256 && maxvpos_nom <= 313) || (beamcon0 & 0x80)) { maxvpos_display = maxvpos_nom; } else if (maxvpos_nom < 256) { @@ -6698,7 +6712,7 @@ static void BPLCON0_Denise(int hpos, uae_u16 v) { v = BPLCON0_Denise_mask(v); - if (bplcon0d == v || bplcon0d_change) { + if (bplcon0d == v && !bplcon0d_change) { return; } bplcon0d_change = false; @@ -9037,7 +9051,7 @@ static void decide_sprites_fetch(int endhpos) if (hpos >= endhpos) { return; } - if (vb_state || (doflickerfix() && interlace_seen && (next_lineno & 1))) { + if (vb_state || (doflickerfix_active() && (next_lineno & 1))) { last_decide_sprite_hpos = endhpos; return; } @@ -9130,7 +9144,7 @@ static int calculate_lineno(int vp) lineno %= MAXVPOS; } nextline_how = nln_normal; - if (doflickerfix() && interlace_seen > 0) { + if (doflickerfix_active()) { lineno *= 2; } else if (!interlace_seen && doublescan <= 0 && currprefs.gfx_vresolution && currprefs.gfx_pscanlines > 1) { @@ -9144,7 +9158,7 @@ static int calculate_lineno(int vp) } else if ((doublescan <= 0 || interlace_seen > 0) && currprefs.gfx_vresolution && currprefs.gfx_iscanlines) { lineno *= 2; if (interlace_seen) { - if (!lof_current) { + if (!lof_display) { lineno++; nextline_how = currprefs.gfx_iscanlines == 2 ? nln_lower_black_always : nln_lower_black; } else { @@ -9156,7 +9170,7 @@ static int calculate_lineno(int vp) } else if (currprefs.gfx_vresolution && (doublescan <= 0 || interlace_seen > 0)) { lineno *= 2; if (interlace_seen) { - if (!lof_current) { + if (!lof_display) { lineno++; nextline_how = nln_lower; } else { @@ -9185,11 +9199,11 @@ void init_hardware_for_drawing_frame(void) } } prev_next_sprite_entry = next_sprite_entry; + next_sprite_entry = 0; next_lineno = calculate_lineno(vpos); last_color_change = 0; next_color_change = 0; - next_sprite_entry = 0; next_color_entry = 0; remembered_color_entry = -1; @@ -9731,7 +9745,6 @@ static void vsync_handler_post(void) #endif } lof_prev_lastline = lof_lastline; - lof_current = lof_store; if (lof_togglecnt_lace >= LOF_TOGGLES_NEEDED) { interlace_changed = notice_interlace_seen(true); if (interlace_changed) { @@ -9867,7 +9880,7 @@ static void hsync_scandoubler(int hpos) return; } - int lof = lof_store; + int lof = lof_display; next_lineno++; scandoubled_line = 1; last_hdiw = 0 - 1; @@ -9889,7 +9902,6 @@ static void hsync_scandoubler(int hpos) } else { bplpt[i] = bplpt[i] - diff; } - } } } @@ -10242,12 +10254,13 @@ static void hsync_handlerh(bool onvsync) if (!nocustom()) { - finish_decisions(hpos); - - hsync_record_line_state(next_lineno, nextline_how, thisline_changed); - - if (doflickerfix() && interlace_seen > 0) { + if (doflickerfix_active()) { + finish_decisions(hpos); + hsync_record_line_state(next_lineno, nextline_how, thisline_changed); hsync_scandoubler(hpos); + } else { + finish_decisions(hpos); + hsync_record_line_state(next_lineno, nextline_how, thisline_changed); } notice_resolution_seen(GET_RES_AGNUS(bplcon0), interlace_seen != 0); @@ -11230,10 +11243,10 @@ static void hsync_handler_post(bool onvsync) } if (beamcon0 & 0x20) { - if (vpos == 2 && !lof_current) { + if (vpos == 2 && !lof_store) { vs_state_hw = true; } - if (vpos == 3 && lof_current) { + if (vpos == 3 && lof_store) { vs_state_hw = true; } if (vpos == 5) { @@ -11297,7 +11310,7 @@ static void hsync_handler_post(bool onvsync) if (diwstate == DIW_waiting_stop) { record_dma_event(DMA_EVENT_VDIW, REFRESH_FIRST_HPOS, vpos); } - if (lof_current) { + if (lof_store) { record_dma_event(DMA_EVENT_LOF, REFRESH_FIRST_HPOS + 2, vpos); } if (lol) { @@ -11509,6 +11522,7 @@ static void hsync_handler(void) if (vpos == maxvpos_display_vsync) { vsync_display_render(); vsync_display_rendered = false; + lof_display = lof_store; reset_autoscale(); } vsync_line = vs; @@ -11663,7 +11677,7 @@ void custom_reset(bool hardreset, bool keyboardreset) } #endif } - lof_store = lof_current = 0; + lof_store = lof_display = 0; lof_lace = false; setextblank(); } @@ -11864,7 +11878,7 @@ void dumpcustom(void) (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop); console_out_f(_T("BPLCON 0: %04x 1: %04x 2: %04x 3: %04x 4: %04x LOF=%d/%d HDIW=%d VDIW=%d\n"), bplcon0, bplcon1, bplcon2, bplcon3, bplcon4, - lof_current, lof_store, + lof_display, lof_store, hdiwstate == DIW_waiting_start ? 0 : 1, diwstate == DIW_waiting_start ? 0 : 1); if (timeframes) { console_out_f(_T("Average frame time: %.2f ms [frames: %d time: %d]\n"), @@ -12541,7 +12555,7 @@ uae_u8 *restore_custom(uae_u8 *src) dsklen = RW; /* 024 DSKLEN */ RW; /* 026 DSKDAT */ refptr = RW; /* 028 REFPTR */ - i = RW; lof_store = lof_current = (i & 0x8000) ? 1 : 0; lol = (i & 0x0080) ? 1 : 0; /* 02A VPOSW */ + i = RW; lof_store = lof_display = (i & 0x8000) ? 1 : 0; lol = (i & 0x0080) ? 1 : 0; /* 02A VPOSW */ RW; /* 02C VHPOSW */ COPCON(RW); /* 02E COPCON */ RW; /* 030 SERDAT* */ diff --git a/drawing.cpp b/drawing.cpp index 7ea0c12d..ac3e8d7e 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -429,7 +429,7 @@ extern int diwfirstword_total, diwlastword_total; extern int ddffirstword_total, ddflastword_total; extern bool vertical_changed, horizontal_changed; extern int firstword_bplcon1; -extern int lof_store; +extern int lof_display; #define MIN_DISPLAY_W 256 #define MIN_DISPLAY_H 192 @@ -490,7 +490,7 @@ static void get_vblanking_limits(int *vbstrtp, int *vbstopp, bool overscanonly) if (!ecs_denise) { vbstrt--; } - int vbstop = maxvpos + lof_store; + int vbstop = maxvpos + lof_display; if (!ecs_denise && !ecs_agnus) { vbstop++; } else if (ecs_agnus && !ecs_denise) { @@ -772,13 +772,13 @@ int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy, int *prealh) if (interlace_seen) { static int interlace_count; // interlace = only use long frames - if (lof_store && (interlace_count & 1) == 0) + if (lof_display && (interlace_count & 1) == 0) interlace_count++; - if (!lof_store && (interlace_count & 1) != 0) + if (!lof_display && (interlace_count & 1) != 0) interlace_count++; if (interlace_count < 3) return ret; - if (!lof_store) + if (!lof_display) return ret; interlace_count = 0; /* program may have set last visible line as last possible line (CD32 boot screen) */ @@ -1447,7 +1447,7 @@ static void fill_line_border(int lineno) int endpos = visible_left_border + vidinfo->drawbuffer.inwidth; int w = endpos - lastpos; - if (lineno < visible_top_start || lineno < vblank_top_start || lineno >= visible_bottom_stop || lineno >= vblank_bottom_stop) { + if (lineno < visible_top_start || lineno < vblank_top_start || lineno >= visible_bottom_stop || lineno >= vblank_bottom_stop || vb_state >= 4) { int b = hposblank; hposblank = 3; fill_line2(lastpos, w); @@ -3299,8 +3299,11 @@ static void do_color_changes(line_draw_func worker_border, line_draw_func worker } // vblank + programmed vblank / hardwired vblank - if (vb_state == 2 || vbarea) { + if (vb_state == 2 || vb_state >= 4 || vbarea) { + if (vbarea || vb_state >= 4) { + hposblank = 3; + } if (nextpos_in_range > lastpos && lastpos < playfield_end) { int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end; (*worker_border)(lastpos, t, 1); @@ -4772,6 +4775,8 @@ void hsync_record_line_state (int lineno, enum nln_how how, int changed) if (ad->framecnt != 0) return; + //write_log("%d:%d:%d ", lineno, how, lof_display); + state = linestate + lineno; changed |= ad->frame_redraw_necessary != 0 || refresh_indicator_buffer != NULL || ((lineno >= lightpen_y1[0] && lineno < lightpen_y2[0]) || @@ -4794,7 +4799,7 @@ void hsync_record_line_state (int lineno, enum nln_how how, int changed) } break; case nln_lower: - if (lineno > 0 && state[-1] == LINE_UNDECIDED) { + if (state[-1] == LINE_UNDECIDED) { state[-1] = LINE_DECIDED; //LINE_BLACK; } *state = changed ? LINE_DECIDED : LINE_DONE; @@ -4809,34 +4814,20 @@ void hsync_record_line_state (int lineno, enum nln_how how, int changed) case nln_lower_black_always: state[1] = LINE_BLACK; *state = LINE_DECIDED; -// if (lineno == (maxvpos + lof_store) * 2 - 1) -// *state = LINE_BLACK; break; case nln_lower_black: changed |= state[0] != LINE_DONE; - state[1] = LINE_DONE; *state = changed ? LINE_DECIDED : LINE_DONE; -// if (lineno == (maxvpos + lof_store) * 2 - 1) -// *state = LINE_BLACK; + state[1] = LINE_DONE; break; case nln_upper_black_always: *state = LINE_DECIDED; - if (lineno > 0) { - state[-1] = LINE_BLACK; - } - if (!interlace_seen && lineno == (maxvpos + lof_store) * 2 - 2) { - state[1] = LINE_BLACK; - } + state[-1] = LINE_BLACK; break; case nln_upper_black: changed |= state[0] != LINE_DONE; *state = changed ? LINE_DECIDED : LINE_DONE; - if (lineno > 0) { - state[-1] = LINE_DONE; - } - if (!interlace_seen && lineno == (maxvpos + lof_store) * 2 - 2) { - state[1] = LINE_DONE; - } + state[-1] = LINE_DONE; break; } } diff --git a/include/custom.h b/include/custom.h index 9f0a8c26..f6d49a24 100644 --- a/include/custom.h +++ b/include/custom.h @@ -56,7 +56,7 @@ extern unsigned long int hsync_counter, vsync_counter; extern uae_u16 dmacon; extern uae_u16 intena, intreq, intreqr; -extern int vpos, lof_store; +extern int vpos, lof_store, lof_display; extern int n_frames; diff --git a/od-win32/screenshot.cpp b/od-win32/screenshot.cpp index 8df06841..b5c77708 100644 --- a/od-win32/screenshot.cpp +++ b/od-win32/screenshot.cpp @@ -959,7 +959,7 @@ uae_u8 *save_screenshot(int monid, int *len) int w = avidinfo->drawbuffer.inwidth; int h = avidinfo->drawbuffer.inheight; if (!programmedmode) { - h = (maxvpos + lof_store - minfirstline) << currprefs.gfx_vresolution; + h = (maxvpos + lof_display - minfirstline) << currprefs.gfx_vresolution; } if (interlace_seen && currprefs.gfx_vresolution > 0) { h -= 1 << (currprefs.gfx_vresolution - 1); -- 2.47.3