S2636 drawing optimisation (nw)

This commit is contained in:
Vas Crabb 2015-12-11 23:03:17 +11:00
parent 5702bef80d
commit e883c98c93

View File

@ -6,12 +6,9 @@
This emulation is pretty low-level. For the most part it models
the kinds of counters and flags you'd use if you were actually
implementing it in programmable logic or on silicon. It even
renders pixels sequentially without multiple passes or needing to
backtrack. This works pretty well, but it probably isn't the most
efficient way to do things. I'm sure there are potential
performance improvements in the drawing and collision detection
code.
implementing it in programmable logic or on silicon. I'm sure
there are potential performance improvements in the drawing and
collision detection code.
At present the entire internal space of 256 bytes can be read and
written. This isn't accurate as some registers are read- or write-
@ -227,8 +224,10 @@ void s2636_device::render_first_line()
void s2636_device::render_next_line()
{
// pre-clear the line for convenience
rectangle const &vis_area = m_screen->visible_area();
UINT16 *const row = &m_bitmap.pix16(m_screen_line);
m_bitmap.plot_box(0, m_screen_line, m_bitmap.width(), 1, 0);
if ((vis_area.min_y > m_screen_line) || (vis_area.max_y < m_screen_line))
{
@ -237,10 +236,6 @@ void s2636_device::render_next_line()
m_registers[REG_VBL_COL_OBJ] |= 0x40;
m_vrst = true;
}
for (int screen_col = 0; screen_col < m_bitmap.width(); screen_col++)
{
row[screen_col] = 0;
}
}
else
{
@ -265,16 +260,8 @@ void s2636_device::render_next_line()
}
// work out what object pixels belong in this line
UINT16 obj_clr[OBJ_COUNT];
int obj_h_cnt[OBJ_COUNT];
int obj_inc[OBJ_COUNT];
UINT8 obj_bits[OBJ_COUNT];
for (int i = 0; i < OBJ_COUNT; i++)
{
obj_clr[i] = object_color(i) | 0x08;
obj_h_cnt[i] = m_registers[OFFS_OBJ[i] + (m_obj_dup[i] ? OFFS_HCB : OFFS_HC)] + m_x_offset;
obj_inc[i] = 1 << (3 - object_scale(i));
// repurpose counter and set flag when we've skipped enough lines
if (!m_obj_cnt[i])
{
@ -284,9 +271,22 @@ void s2636_device::render_next_line()
if (m_obj_disp[i])
{
int const obj_inc = 1 << (3 - object_scale(i));
m_obj_cnt[i] -= obj_inc;
// fetch appropriate line from object
m_obj_cnt[i] -= obj_inc[i];
obj_bits[i] = m_registers[OFFS_OBJ[i] + OBJ_HEIGHT - 1 - (m_obj_cnt[i] >> 3)];
UINT8 const obj_bits = m_registers[OFFS_OBJ[i] + OBJ_HEIGHT - 1 - (m_obj_cnt[i] >> 3)];
UINT16 const obj_clr = object_color(i) | 0x08 | (0x10 << i);
// blit it to the line ignoring intermediate pixels
int const obj_h_cnt = m_registers[OFFS_OBJ[i] + (m_obj_dup[i] ? OFFS_HCB : OFFS_HC)] + m_x_offset;
for (int x = 0, screen_col = vis_area.min_x + (obj_h_cnt * m_divider); (OBJ_WIDTH << 3) > x && (vis_area.max_x >= screen_col); )
{
bool const bit = bool((obj_bits << (x >> 3)) & 0x80);
if (bit && (vis_area.min_x <= screen_col)) row[screen_col] |= obj_clr;
x += obj_inc;
screen_col += m_divider;
}
// if that's the last line of the object, flag completion and prepare for duplicates
if (!m_obj_cnt[i])
@ -301,7 +301,25 @@ void s2636_device::render_next_line()
{
// count down lines to display object
m_obj_cnt[i]--;
obj_bits[i] = 0x00;
}
}
// let's take a look at the score display
UINT16 const bg_clr = m_registers[REG_BG_ENB_CLR] & 0x07;
int const score_row = m_vis_line - m_y_offset - SCORE_START_Y[m_registers[REG_SCORE_FMT] & 0x01];
if ((0 <= score_row) && (SCORE_HEIGHT > score_row))
{
int const (&score_start_x)[SCORE_DIGITS] = SCORE_START_X[(m_registers[REG_SCORE_FMT] >> 1) & 0x01];
for (int i = 0; i < SCORE_DIGITS; i++)
{
UINT16 score_bits = SCORE_FONT[score_digit(i)][score_row >> 2];
int screen_col = vis_area.min_x + ((score_start_x[i] + m_x_offset) * m_divider);
while (score_bits && (vis_area.max_x >= screen_col))
{
if (score_bits & 0x0001) row[screen_col] |= bg_clr | 0x08;
score_bits >>= 1;
screen_col += m_divider;
}
}
}
@ -315,69 +333,17 @@ void s2636_device::render_next_line()
UINT8 const bg_hbar_bits = m_registers[bg_hbar_offs];
bool const bg_hbar_stretch = bool(bg_hbar_bits & (1 << ((((bg_row % 40) >= 20) ? 3 : 0) + (((bg_row % 20) >= 11) ? 2 : ((bg_row % 20) >= 2) ? 1 : 0))));
int const bg_hbar_width = bg_hbar_stretch ? 8 : (0xc0 == (bg_hbar_bits & 0xc0)) ? 4 : (0x40 == (bg_hbar_bits & 0xc0)) ? 2 : 1;
UINT16 const bg_clr = m_registers[REG_BG_ENB_CLR] & 0x07;
UINT16 const scrn_clr = bg_enable ? ((m_registers[REG_BG_ENB_CLR] >> 4) & 0x07) : 0x00;
// let's take a look at the score display
int const (&score_start_x)[SCORE_DIGITS] = SCORE_START_X[(m_registers[REG_SCORE_FMT] >> 1) & 0x01];
int const score_row = m_vis_line - m_y_offset - SCORE_START_Y[m_registers[REG_SCORE_FMT] & 0x01];
bool const score_draw = (0 <= score_row) && (SCORE_HEIGHT > score_row);
UINT16 score_bits[SCORE_DIGITS];
for (int i = 0; i < SCORE_DIGITS; i++)
score_bits[i] = score_draw ? SCORE_FONT[score_digit(i)][score_row >> 2] : 0x0000;
// clear leading horizontal blanking area
m_bitmap.plot_box(0, m_screen_line, m_bitmap.width(), 1, 0);
bool obj_vis[4] = { false, false, false, false };
for (int screen_col = vis_area.min_x, x = 0; vis_area.max_x >= screen_col; x++)
{
// render objects
bool obj[4];
for (int i = 0; i < OBJ_COUNT; i++)
{
if (!obj_h_cnt[i])
{
obj_h_cnt[i] = OBJ_WIDTH << 3;
obj_vis[i] = true;
}
if (obj_vis[i])
{
obj_h_cnt[i] -= obj_inc[i];
obj[i] = bool(obj_bits[i] & (1U << (obj_h_cnt[i] >> 3)));
if (obj[i]) row[screen_col] |= obj_clr[i];
if (!obj_h_cnt[i])
{
obj_h_cnt[i] = -1;
obj_vis[i] = 0;
}
}
else
{
obj_h_cnt[i]--;
obj[i] = false;
}
}
// check object-object collisions
if (obj[0] && obj[1]) m_registers[REG_VBL_COL_OBJ] |= 0x20;
if (obj[0] && obj[2]) m_registers[REG_VBL_COL_OBJ] |= 0x10;
if (obj[0] && obj[3]) m_registers[REG_VBL_COL_OBJ] |= 0x08;
if (obj[1] && obj[2]) m_registers[REG_VBL_COL_OBJ] |= 0x04;
if (obj[1] && obj[3]) m_registers[REG_VBL_COL_OBJ] |= 0x02;
if (obj[2] && obj[3]) m_registers[REG_VBL_COL_OBJ] |= 0x01;
// render scores
if (score_draw)
{
for (int i = 0; i < SCORE_DIGITS; i++)
{
int const score_col = x - m_x_offset - score_start_x[i];
bool const score = bool(score_bits[i] & (1U << score_col));
if ((0 <= score_col) && (SCORE_WIDTH > score_col) && score)
row[screen_col] |= bg_clr | 0x08;
}
}
if ((row[screen_col] & 0x10) && (row[screen_col] & 0x20)) m_registers[REG_VBL_COL_OBJ] |= 0x20;
if ((row[screen_col] & 0x10) && (row[screen_col] & 0x40)) m_registers[REG_VBL_COL_OBJ] |= 0x10;
if ((row[screen_col] & 0x10) && (row[screen_col] & 0x80)) m_registers[REG_VBL_COL_OBJ] |= 0x08;
if ((row[screen_col] & 0x20) && (row[screen_col] & 0x40)) m_registers[REG_VBL_COL_OBJ] |= 0x04;
if ((row[screen_col] & 0x20) && (row[screen_col] & 0x80)) m_registers[REG_VBL_COL_OBJ] |= 0x02;
if ((row[screen_col] & 0x40) && (row[screen_col] & 0x80)) m_registers[REG_VBL_COL_OBJ] |= 0x01;
// work out if the background hits this pixel
int const bg_col = x - m_x_offset - BG_START_X;
@ -385,10 +351,10 @@ void s2636_device::render_next_line()
if (bg_draw && (0 <= bg_col) && (BG_WIDTH > bg_col) && bg && (bg_hbar_width > (bg_col & 0x07)))
{
// do object-background collisions
if (obj[0]) m_registers[REG_COL_BG_CMPL] |= 0x80;
if (obj[1]) m_registers[REG_COL_BG_CMPL] |= 0x40;
if (obj[2]) m_registers[REG_COL_BG_CMPL] |= 0x20;
if (obj[3]) m_registers[REG_COL_BG_CMPL] |= 0x10;
if (row[screen_col] & 0x10) m_registers[REG_COL_BG_CMPL] |= 0x80;
if (row[screen_col] & 0x20) m_registers[REG_COL_BG_CMPL] |= 0x40;
if (row[screen_col] & 0x40) m_registers[REG_COL_BG_CMPL] |= 0x20;
if (row[screen_col] & 0x80) m_registers[REG_COL_BG_CMPL] |= 0x10;
if (!(row[screen_col] & 0x08)) row[screen_col] = bg_clr;
}
else if (!(row[screen_col] & 0x08))
@ -397,10 +363,8 @@ void s2636_device::render_next_line()
row[screen_col] = scrn_clr;
}
// advance the screen column
screen_col++;
// deal with pixel clock divider ratio
// clear collision crud and deal with pixel clock divider ratio
row[screen_col++] &= 0x0f;
for (int i = 1; (i < m_divider) && (vis_area.max_x >= screen_col); i++, screen_col++)
{
row[screen_col] = row[screen_col - 1];