atirage: Fix hardware cursor update.

Switching from Watch to Arrow cursor at vertical position zero (top of the screen) would sometimes cut off the top half of the Arrow cursor. The following changes fix this:

Use the new cursor_dirty flag to signal when the cursor should be updated. This reduces the number of cursor updates and doesn't depend on registers being accessed in a specific order.

Set the cursor_dirty flag for any change that should cause the hardware cursor to be updated:
- CUR_CLR0, CUR_CLR1: Cursor color changes. We don't check if the colors actually changed (all cursors are usually black and white). Rather, writes to these registers usually means the cursor bytes have changed or will change.
- CUR_OFFSET: Offset to cursor bytes.
- CUR_VERT_OFF: First vertical line of cursor to draw.
Other changes that don't require the cursor to be updated:
- CUR_HORZ_OFF: Horizontal offset of cursor position. The cursor is unchanged - just need to adjust the drawing position.
- CUR_HORZ_VERT_POSN: The cursor is unchanged - only the drawing position is changed.
The only thing that could change the cursor that we don't check is a change to the cursor bytes.
This commit is contained in:
joevt 2024-03-20 07:32:28 -07:00 committed by dingusdev
parent 3797fdbf1b
commit 288e088f8a
1 changed files with 22 additions and 4 deletions

View File

@ -404,11 +404,29 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
break;
case ATI_CUR_CLR0:
case ATI_CUR_CLR1:
this->setup_hw_cursor();
// fallthrough
new_value = value;
this->cursor_dirty = true;
draw_fb = true;
WRITE_VALUE_AND_LOG(ATICURSOR);
return;
case ATI_CUR_OFFSET:
case ATI_CUR_HORZ_VERT_POSN:
new_value = value;
if (old_value != new_value)
this->cursor_dirty = true;
draw_fb = true;
WRITE_VALUE_AND_LOG(ATICURSOR);
return;
case ATI_CUR_HORZ_VERT_OFF:
new_value = value;
if (
extract_bits<uint32_t>(new_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size) !=
extract_bits<uint32_t>(old_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size)
)
this->cursor_dirty = true;
draw_fb = true;
WRITE_VALUE_AND_LOG(ATICURSOR);
return;
case ATI_CUR_HORZ_VERT_POSN:
new_value = value;
draw_fb = true;
break;
@ -472,7 +490,7 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) {
new_value = value;
if (bit_changed(old_value, new_value, ATI_GEN_CUR_ENABLE)) {
if (bit_set(new_value, ATI_GEN_CUR_ENABLE))
this->setup_hw_cursor();
this->cursor_on = true;
else
this->cursor_on = false;
draw_fb = true;