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.
This commit is contained in:
arbee 2015-10-24 17:47:28 -04:00
parent bd5fca7042
commit 6fb7e0f7d3
5 changed files with 166 additions and 34 deletions

View File

@ -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));
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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,9 +1279,7 @@ 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);
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)
{
@ -1278,6 +1289,10 @@ void a2_video_device::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, co
{
artifact_map_ptr = &m_hires_artifact_map[((vram_row[col + 1] & 0x80) >> 7) * 16];
}
switch (mon_type)
{
case 0:
for (b = 0; b < 7; b++)
{
v = artifact_map_ptr[((w >> (b + 7-1)) & 0x07) | (((b ^ col) & 0x01) << 3)];