From 288e088f8a9bf1159844da4e84ab84528df8a930 Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 07:32:28 -0700 Subject: [PATCH] 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. --- devices/video/atirage.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index 6d4b913..800ad35 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -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(new_value, ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size) != + extract_bits(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;