From 6fb7e0f7d3a04c691d8ca8394f955e6eec44ab8b Mon Sep 17 00:00:00 2001 From: arbee Date: Sat, 24 Oct 2015 17:47:28 -0400 Subject: [PATCH] scanline partial updates checkpoint (nw) This isn't working right yet with my test case, but I'm fairly certain the actual core part is generally correct, just the Apple II video rendering and/or floating-bus reading isn't quite right. --- src/emu/screen.c | 124 +++++++++++++++++++++++++++++++++---- src/emu/screen.h | 1 + src/mame/drivers/apple2.c | 11 +++- src/mame/drivers/apple2e.c | 27 +++++--- src/mame/video/apple2.c | 37 +++++++---- 5 files changed, 166 insertions(+), 34 deletions(-) diff --git a/src/emu/screen.c b/src/emu/screen.c index c3bb09e320a..399c376c856 100644 --- a/src/emu/screen.c +++ b/src/emu/screen.c @@ -63,6 +63,7 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev m_curtexture(0), m_changed(true), m_last_partial_scan(0), + m_partial_scan_hpos(0), m_color(rgb_t(0xff, 0xff, 0xff, 0xff)), m_brightness(0xff), m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds()), @@ -661,21 +662,121 @@ bool screen_device::update_partial(int scanline) void screen_device::update_now() { + // these two checks only apply if we're allowed to skip frames + if (!(m_video_attributes & VIDEO_ALWAYS_UPDATE)) + { + // if skipping this frame, bail + if (machine().video().skip_this_frame()) + { + LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n")); + return; + } + + // skip if this screen is not visible anywhere + if (!machine().render().is_live(*this)) + { + LOG_PARTIAL_UPDATES(("skipped because screen not live\n")); + return; + } + } + int current_vpos = vpos(); int current_hpos = hpos(); + rectangle clip = m_visarea; - // since we can currently update only at the scanline - // level, we are trying to do the right thing by - // updating including the current scanline, only if the - // beam is past the halfway point horizontally. - // If the beam is in the first half of the scanline, - // we only update up to the previous scanline. - // This minimizes the number of pixels that might be drawn - // incorrectly until we support a pixel level granularity - if (current_hpos < (m_width / 2) && current_vpos > 0) - current_vpos = current_vpos - 1; + LOG_PARTIAL_UPDATES(("update_now(): Y=%d, X=%d, last partial %d, partial hpos %d (vis %d %d)\n", current_vpos, current_hpos, m_last_partial_scan, m_partial_scan_hpos, m_visarea.max_x, m_visarea.max_y)); - update_partial(current_vpos); + // start off by doing a partial update up to the line before us, in case that was necessary + if (current_vpos > m_last_partial_scan) + { + // if the line before us was incomplete, we must do it in two pieces + if (m_partial_scan_hpos > 0) + { + INT32 save_scan = m_partial_scan_hpos; + update_partial(current_vpos - 2); + m_partial_scan_hpos = save_scan; + + // now finish the previous partial scanline + int scanline = current_vpos - 1; + if (m_partial_scan_hpos > clip.min_x) + clip.min_x = m_partial_scan_hpos; + if (current_hpos < clip.max_x) + clip.max_x = current_hpos; + if (m_last_partial_scan > clip.min_y) + clip.min_y = m_last_partial_scan; + if (scanline < clip.max_y) + clip.max_y = scanline; + + // if there's something to draw, do it + if ((clip.min_x <= clip.max_x) && (clip.min_y <= clip.max_y)) + { + g_profiler.start(PROFILER_VIDEO); + + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } + + m_partial_updates_this_frame++; + g_profiler.stop(); + m_partial_scan_hpos = 0; + m_last_partial_scan = current_vpos + 1; + } + } + else + { + update_partial(current_vpos - 1); + } + } + + // now draw this partial scanline + clip = m_visarea; + + if (m_partial_scan_hpos > clip.min_x) + clip.min_x = m_partial_scan_hpos; + if (current_hpos < clip.max_x) + clip.max_x = current_hpos; + if (current_vpos > clip.min_y) + clip.min_y = current_vpos; + if (current_vpos < clip.max_y) + clip.max_y = current_vpos; + + // and if there's something to draw, do it + if ((clip.min_x <= clip.max_x) && (clip.min_y <= clip.max_y)) + { + g_profiler.start(PROFILER_VIDEO); + + LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.max_y, clip.min_x, clip.max_x)); + + UINT32 flags = UPDATE_HAS_NOT_CHANGED; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } + + m_partial_updates_this_frame++; + g_profiler.stop(); + + // if we modified the bitmap, we have to commit + m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; + + // remember where we left off + m_partial_scan_hpos = current_hpos; + m_last_partial_scan = current_vpos; + + // if we completed the line, mark it so + if (current_hpos >= m_visarea.max_x) + { + m_partial_scan_hpos = 0; + m_last_partial_scan = current_vpos + 1; + } + } } @@ -687,6 +788,7 @@ void screen_device::update_now() void screen_device::reset_partial_updates() { m_last_partial_scan = 0; + m_partial_scan_hpos = 0; m_partial_updates_this_frame = 0; m_scanline0_timer->adjust(time_until_pos(0)); } diff --git a/src/emu/screen.h b/src/emu/screen.h index f3aab539cce..095142cf7c7 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -285,6 +285,7 @@ private: UINT8 m_curtexture; // current texture index bool m_changed; // has this bitmap changed? INT32 m_last_partial_scan; // scanline of last partial update + INT32 m_partial_scan_hpos; // horizontal pixel last rendered on this partial scanline bitmap_argb32 m_screen_overlay_bitmap; // screen overlay bitmap UINT32 m_unique_id; // unique id for this screen_device rgb_t m_color; // render color diff --git a/src/mame/drivers/apple2.c b/src/mame/drivers/apple2.c index 8cf74588ffc..9ce873d5048 100644 --- a/src/mame/drivers/apple2.c +++ b/src/mame/drivers/apple2.c @@ -324,9 +324,6 @@ TIMER_DEVICE_CALLBACK_MEMBER(napple2_state::apple2_interrupt) { int scanline = param; - if((scanline % 8) == 0) - machine().first_screen()->update_partial(machine().first_screen()->vpos()); - // update the video system's shadow copy of the system config at the end of the frame if (scanline == 192) { @@ -450,31 +447,39 @@ void napple2_state::do_io(address_space &space, int offset) break; case 0x50: // graphics mode + machine().first_screen()->update_now(); m_video->m_graphics = true; break; case 0x51: // text mode + machine().first_screen()->update_now(); m_video->m_graphics = false; break; case 0x52: // no mix + machine().first_screen()->update_now(); m_video->m_mix = false; break; case 0x53: // mixed mode + machine().first_screen()->update_now(); m_video->m_mix = true; break; case 0x54: // set page 1 + machine().first_screen()->update_now(); m_page2 = false; m_video->m_page2 = false; break; case 0x55: // set page 2 + machine().first_screen()->update_now(); m_page2 = true; m_video->m_page2 = true; break; case 0x56: // select lo-res + machine().first_screen()->update_now(); m_video->m_hires = false; break; case 0x57: // select hi-res + machine().first_screen()->update_now(); m_video->m_hires = true; break; case 0x58: // AN0 off diff --git a/src/mame/drivers/apple2e.c b/src/mame/drivers/apple2e.c index e5eb2193aa8..692a22a9e0b 100644 --- a/src/mame/drivers/apple2e.c +++ b/src/mame/drivers/apple2e.c @@ -779,11 +779,6 @@ TIMER_DEVICE_CALLBACK_MEMBER(apple2e_state::apple2_interrupt) { int scanline = param; - if((scanline % 8) == 0) - { - machine().first_screen()->update_partial(machine().first_screen()->vpos()); - } - if (m_isiic) { update_iic_mouse(); @@ -1101,10 +1096,12 @@ void apple2e_state::do_io(address_space &space, int offset, bool is_iic) switch (offset) { case 0x5e: // SETDHIRES + machine().first_screen()->update_now(); m_video->m_dhires = true; break; case 0x5f: // CLRDHIRES + machine().first_screen()->update_now(); m_video->m_dhires = false; break; } @@ -1155,35 +1152,47 @@ void apple2e_state::do_io(address_space &space, int offset, bool is_iic) break; case 0x50: // graphics mode - m_video->m_graphics = true; break; + machine().first_screen()->update_now(); + m_video->m_graphics = true; + break; case 0x51: // text mode - m_video->m_graphics = false; break; + machine().first_screen()->update_now(); + m_video->m_graphics = false; + break; case 0x52: // no mix - m_video->m_mix = false; break; + machine().first_screen()->update_now(); + m_video->m_mix = false; + break; case 0x53: // mixed mode - m_video->m_mix = true; break; + machine().first_screen()->update_now(); + m_video->m_mix = true; + break; case 0x54: // set page 1 + machine().first_screen()->update_now(); m_page2 = false; m_video->m_page2 = false; auxbank_update(); break; case 0x55: // set page 2 + machine().first_screen()->update_now(); m_page2 = true; m_video->m_page2 = true; auxbank_update(); break; case 0x56: // select lo-res + machine().first_screen()->update_now(); m_video->m_hires = false; auxbank_update(); break; case 0x57: // select hi-res + machine().first_screen()->update_now(); m_video->m_hires = true; auxbank_update(); break; diff --git a/src/mame/video/apple2.c b/src/mame/video/apple2.c index 195fed4ce8f..56419e0f46a 100644 --- a/src/mame/video/apple2.c +++ b/src/mame/video/apple2.c @@ -1236,6 +1236,7 @@ void a2_video_device::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, co UINT32 w; UINT16 *artifact_map_ptr; int mon_type = m_sysconfig & 0x03; + int begincol = 0, endcol = 40; /* sanity checks */ if (beginrow < cliprect.min_y) @@ -1245,6 +1246,18 @@ void a2_video_device::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, co if (endrow < beginrow) return; + // we generate 2 pixels per "column" so adjust + if (begincol < (cliprect.min_x/14)) + begincol = (cliprect.min_x/14); + if (endcol > (cliprect.max_x/14)) + endcol = (cliprect.max_x/14); + if (cliprect.max_x > 39*14) + endcol = 40; + if (endcol < begincol) + return; + + //printf("HGR draw: page %c, rows %d-%d cols %d-%d\n", m_page2 ? '2' : '1', beginrow, endrow, begincol, endcol); + vram = &m_ram_ptr[(m_page2 ? 0x4000 : 0x2000)]; vram_row[0] = 0; @@ -1252,7 +1265,7 @@ void a2_video_device::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, co for (row = beginrow; row <= endrow; row++) { - for (col = 0; col < 40; col++) + for (col = begincol; col < endcol; col++) { offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10); vram_row[1+col] = vram[offset]; @@ -1266,18 +1279,20 @@ void a2_video_device::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, co | (((UINT32) vram_row[col+1] & 0x7f) << 7) | (((UINT32) vram_row[col+2] & 0x7f) << 14); + + // verified on h/w: setting dhires w/o 80col emulates a rev. 0 Apple ][ with no orange/blue + if (m_dhires) + { + artifact_map_ptr = m_hires_artifact_map; + } + else + { + artifact_map_ptr = &m_hires_artifact_map[((vram_row[col + 1] & 0x80) >> 7) * 16]; + } + switch (mon_type) { case 0: - // verified on h/w: setting dhires w/o 80col emulates a rev. 0 Apple ][ with no orange/blue - if (m_dhires) - { - artifact_map_ptr = m_hires_artifact_map; - } - else - { - artifact_map_ptr = &m_hires_artifact_map[((vram_row[col + 1] & 0x80) >> 7) * 16]; - } for (b = 0; b < 7; b++) { v = artifact_map_ptr[((w >> (b + 7-1)) & 0x07) | (((b ^ col) & 0x01) << 3)]; @@ -1302,7 +1317,7 @@ void a2_video_device::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, co for (b = 0; b < 7; b++) { v = (w & 1); - w >>= 1; + w >>= 1; *(p++) = v ? GREEN : BLACK; *(p++) = v ? GREEN : BLACK; }