From 24c7b0b568125cef4c8ed8806c820b1648bf2871 Mon Sep 17 00:00:00 2001
From: Yang Zhao <yang@yangman.ca>
Date: Sun, 26 Apr 2009 15:31:29 -0700
Subject: [PATCH] Cursor: refactor RandR cursor code, also fixing bug #13405

- Calls to displayCursor() are eliminated, and the number of register
  writes is reduced in general.

- Curor on all active CRTCs are kept enabled if any CRTC has an active
  cursor to fix bug #13405.

- Eliminate calls to displayCursor() and generally reduce the number of
  register writes.

- Code was added to correctly set cursor dimensions. This is disabled as
  there are apparently no benefits on doing so.
---
 src/rhd_cursor.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++--------
 src/rhd_cursor.h |    2 +
 2 files changed, 82 insertions(+), 14 deletions(-)

diff --git a/src/rhd_cursor.c b/src/rhd_cursor.c
index eb4a948..1b37905 100644
--- a/src/rhd_cursor.c
+++ b/src/rhd_cursor.c
@@ -623,11 +623,19 @@ RHDxf86InitCursor(ScreenPtr pScreen)
 void
 rhdCrtcShowCursor(struct rhdCrtc *Crtc)
 {
-    struct rhdCursor *Cursor = Crtc->Cursor;
+    RHDPtr rhdPtr = RHDPTRI(Crtc);
+    int i;
 
-    lockCursor   (Cursor, TRUE);
-    displayCursor(Crtc,   TRUE);
-    lockCursor   (Cursor, FALSE);
+    Crtc->Cursor->disable = FALSE;
+
+    /* Bug #13405: must enable cursor on all active CRTCs
+     * to avoid corruption */
+    for (i = 0; i < 2; i++) {
+        struct rhdCrtc *Crtc = rhdPtr->Crtc[i];
+        if (Crtc->Active) {
+            enableCursor(Crtc->Cursor, TRUE);
+        }
+    }
 }
 
 /*
@@ -636,11 +644,26 @@ rhdCrtcShowCursor(struct rhdCrtc *Crtc)
 void
 rhdCrtcHideCursor(struct rhdCrtc *Crtc)
 {
+    RHDPtr rhdPtr = RHDPTRI(Crtc);
+    struct rhdCrtc *otherCrtc = rhdPtr->Crtc[(rhdPtr->Crtc[0] == Crtc) ? 1 : 0];
     struct rhdCursor *Cursor = Crtc->Cursor;
 
-    lockCursor  (Cursor, TRUE);
-    enableCursor(Cursor, FALSE);
-    lockCursor  (Cursor, FALSE);
+    Cursor->disable = TRUE;
+
+    lockCursor(Cursor, TRUE);
+
+    /* Only disable cursors if all CRTCs should have their cursors disabled */
+    if (!otherCrtc->Active || otherCrtc->Cursor->disable) {
+        enableCursor(Cursor, FALSE);
+        enableCursor(otherCrtc->Cursor, FALSE);
+    }
+
+    /* Move cursor off-screen so it won't be visible*/
+    RHDRegWrite(Cursor, Cursor->RegOffset + D1CUR_POSITION,
+                (Crtc->X + Crtc->Width) << 16 | (Crtc->Y + Crtc->Height));
+    RHDRegWrite(Cursor, Cursor->RegOffset + D1CUR_HOT_SPOT, 0);
+
+    lockCursor(Cursor, FALSE);
 }
 
 /*
@@ -650,11 +673,24 @@ void
 rhdCrtcSetCursorPosition(struct rhdCrtc *Crtc, int x, int y)
 {
     struct rhdCursor *Cursor = Crtc->Cursor;
-    Cursor->X = x;
-    Cursor->Y = y;
+    int hotx, hoty;
+
+    hotx = 0;
+    hoty = 0;
+
+    /* Hardware doesn't allow negative cursor pos; compensate using hotspot */
+    if (x < 0) {
+        hotx = -x;
+        x = 0;
+    }
+    if (y < 0) {
+        hoty = -y;
+        y = 0;
+    }
 
     lockCursor   (Cursor, TRUE);
-    displayCursor(Crtc,   TRUE);
+    RHDRegWrite(Cursor, Cursor->RegOffset + D1CUR_POSITION, x << 16 | y);
+    RHDRegWrite(Cursor, Cursor->RegOffset + D1CUR_HOT_SPOT, hotx << 16 | hoty);
     lockCursor   (Cursor, FALSE);
 }
 
@@ -677,14 +713,44 @@ void
 rhdCrtcLoadCursorARGB(struct rhdCrtc *Crtc, CARD32 *Image)
 {
     struct rhdCursor *Cursor = Crtc->Cursor;
-
-    Cursor->Width = MAX_CURSOR_WIDTH;
-    Cursor->Height = MAX_CURSOR_HEIGHT;
+    int i, j, width, height;
 
     lockCursor       (Cursor, TRUE);
     uploadCursorImage(Cursor, Image);
     setCursorImage   (Cursor);
-    displayCursor    (Crtc,   Crtc->Active);
+
+#if 0
+    /* Calculate the effective cursor size */
+    width = 0;
+    height = 0;
+    for (i = 0; i < MAX_CURSOR_HEIGHT; i++) {
+        for (j = width; j < MAX_CURSOR_WIDTH; j++) {
+            if (Image[i*MAX_CURSOR_WIDTH+j] & 0xff000000) {
+                width = j+1;
+                height = i+1;
+                break;
+            }
+        }
+        if (i >= height) {
+            for (j = 0; j < width; j++) {
+                if (Image[i*MAX_CURSOR_WIDTH+j] & 0xff000000) {
+                    height = i+1;
+                    continue;
+                }
+            }
+        }
+    }
+    if (width == 0) width = MAX_CURSOR_WIDTH;
+    if (height == 0) height = MAX_CURSOR_WIDTH;
+    Cursor->Width = width;
+    Cursor->Height = height;
+#else
+    /* X server always loads cursors that are the maximum allowed size */
+    Cursor->Width = MAX_CURSOR_WIDTH;
+    Cursor->Height = MAX_CURSOR_HEIGHT;
+#endif
+
+    setCursorSize(Cursor, Cursor->Width, Cursor->Height);
     lockCursor       (Cursor, FALSE);
 }
 
diff --git a/src/rhd_cursor.h b/src/rhd_cursor.h
index a2347d7..793990a 100644
--- a/src/rhd_cursor.h
+++ b/src/rhd_cursor.h
@@ -45,6 +45,8 @@ struct rhdCursor
     int X;
     int Y;
 
+    Bool disable;
+
     Bool Stored;
 
     CARD32  StoreControl;
-- 
1.6.0.6

