xserver: Branch 'server-21.1-branch' - 15 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Feb 6 15:29:23 UTC 2025


 Xi/xichangehierarchy.c                           |   35 ++++++++-
 dix/devices.c                                    |    5 +
 dix/enterleave.c                                 |    2 
 dix/eventconvert.c                               |    4 -
 glamor/glamor_program.c                          |    4 -
 hw/xfree86/common/xf86Configure.c                |    4 -
 hw/xfree86/drivers/modesetting/driver.c          |   81 +++++++++++++++++------
 hw/xfree86/drivers/modesetting/drmmode_display.c |    2 
 hw/xfree86/drivers/modesetting/drmmode_display.h |    2 
 hw/xfree86/drivers/modesetting/present.c         |   24 +++---
 hw/xfree86/fbdevhw/fbdevhw.c                     |    4 -
 os/WaitFor.c                                     |    6 -
 os/access.c                                      |    6 +
 os/connection.c                                  |    2 
 render/picture.c                                 |    3 
 xkb/XKBMAlloc.c                                  |   74 +--------------------
 xkb/xkbUtils.c                                   |   51 ++++++++++----
 17 files changed, 174 insertions(+), 135 deletions(-)

New commits:
commit e183b62e42f49fa297b5667a82199c7e76fc0a81
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Jan 15 09:40:34 2025 +0100

    os/connection: Make sure partial is initialized
    
    Following the change in Xtrans 1.5 that allows for partial connections
    to succeed, we need to make sure partial is properly initialized at
    first, otherwise we rely on an uninitialized variable.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Suggested-by: Twaik Yont <twaikyont at gmail.com>
    Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1783
    (cherry picked from commit 080fb49eff4de7ec3a29214994d1403e4d877f6a)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/os/connection.c b/os/connection.c
index 3fd0b009e..544d05723 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -242,7 +242,7 @@ void
 CreateWellKnownSockets(void)
 {
     int i;
-    int partial;
+    int partial = 0;
 
     /* display is initialized to "0" by main(). It is then set to the display
      * number if specified on the command line. */
commit 6115eb1f65dc5198da01042e70d571d85286c31c
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Jan 10 15:02:54 2025 +0100

    xkb: Always use MAP_LENGTH keymap size
    
    Generating the modifier modmap, the helper function generate_modkeymap()
    would check the entire range up to the MAP_LENGTH.
    
    However, the given keymap might have less keycodes than MAP_LENGTH, in
    which case we would go beyond the size of the modmap, as reported by
    ASAN:
    
    ==ERROR: AddressSanitizer: heap-buffer-overflow
    READ of size 1 at 0x5110001c225b thread T0
        #0 0x5e7369393873 in generate_modkeymap ../dix/inpututils.c:309
        #1 0x5e736930dcce in ProcGetModifierMapping ../dix/devices.c:1794
        #2 0x5e7369336489 in Dispatch ../dix/dispatch.c:550
        #3 0x5e736934407d in dix_main ../dix/main.c:275
        #5 0x7e46d47b2ecb in __libc_start_main
        #6 0x5e73691be324 in _start (xserver/build/hw/xwayland/Xwayland)
    
    Address is located 0 bytes after 219-byte region
    allocated by thread T0 here:
        #0 0x7e46d4cfc542 in realloc
        #1 0x5e73695aa90e in _XkbCopyClientMap ../xkb/xkbUtils.c:1142
        #2 0x5e73695aa90e in XkbCopyKeymap ../xkb/xkbUtils.c:1966
        #3 0x5e73695b1b2f in XkbDeviceApplyKeymap ../xkb/xkbUtils.c:2023
        #4 0x5e73691c6c18 in keyboard_handle_keymap ../hw/xwayland/xwayland-input.c:1194
    
    As MAP_LENGTH is used in various code paths where the max keycode might
    not be easily available, best is to always use MAP_LENGTH to allocate the
    keymaps so that the code never run past the buffer size.
    
    If the max key code is smaller than the MAP_LENGTH limit, fill-in the gap
    with zeros.
    
    That also simplifies the code slightly as we do not constantly need to
    reallocate the keymap to adjust to the max key code size.
    
    Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1780
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    (cherry picked from commit 92bcebfd7e248f695503c0a6e7bee80be4c96834)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/xkb/XKBMAlloc.c b/xkb/XKBMAlloc.c
index 3e380a8ea..7c516dabb 100644
--- a/xkb/XKBMAlloc.c
+++ b/xkb/XKBMAlloc.c
@@ -42,7 +42,6 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
 Status
 XkbAllocClientMap(XkbDescPtr xkb, unsigned which, unsigned nTotalTypes)
 {
-    register int i;
     XkbClientMapPtr map;
 
     if ((xkb == NULL) ||
@@ -104,8 +103,7 @@ XkbAllocClientMap(XkbDescPtr xkb, unsigned which, unsigned nTotalTypes)
             map->syms[0] = NoSymbol;
         }
         if (map->key_sym_map == NULL) {
-            i = xkb->max_key_code + 1;
-            map->key_sym_map = calloc(i, sizeof(XkbSymMapRec));
+            map->key_sym_map = calloc(MAP_LENGTH, sizeof(XkbSymMapRec));
             if (map->key_sym_map == NULL)
                 return BadAlloc;
         }
@@ -116,8 +114,7 @@ XkbAllocClientMap(XkbDescPtr xkb, unsigned which, unsigned nTotalTypes)
             (xkb->max_key_code < xkb->min_key_code))
             return BadMatch;
         if (map->modmap == NULL) {
-            i = xkb->max_key_code + 1;
-            map->modmap = calloc(i, sizeof(unsigned char));
+            map->modmap = calloc(MAP_LENGTH, sizeof(unsigned char));
             if (map->modmap == NULL)
                 return BadAlloc;
         }
@@ -150,8 +147,7 @@ XkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
             (xkb->max_key_code < xkb->min_key_code))
             return BadMatch;
         if (map->explicit == NULL) {
-            i = xkb->max_key_code + 1;
-            map->explicit = calloc(i, sizeof(unsigned char));
+            map->explicit = calloc(MAP_LENGTH, sizeof(unsigned char));
             if (map->explicit == NULL)
                 return BadAlloc;
         }
@@ -186,8 +182,7 @@ XkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
                    ((map->size_acts - map->num_acts) * sizeof(XkbAction)));
         }
         if (map->key_acts == NULL) {
-            i = xkb->max_key_code + 1;
-            map->key_acts = calloc(i, sizeof(unsigned short));
+            map->key_acts = calloc(MAP_LENGTH, sizeof(unsigned short));
             if (map->key_acts == NULL)
                 return BadAlloc;
         }
@@ -198,8 +193,7 @@ XkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
             (xkb->max_key_code < xkb->min_key_code))
             return BadMatch;
         if (map->behaviors == NULL) {
-            i = xkb->max_key_code + 1;
-            map->behaviors = calloc(i, sizeof(XkbBehavior));
+            map->behaviors = calloc(MAP_LENGTH, sizeof(XkbBehavior));
             if (map->behaviors == NULL)
                 return BadAlloc;
         }
@@ -210,8 +204,7 @@ XkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
             (xkb->max_key_code < xkb->min_key_code))
             return BadMatch;
         if (map->vmodmap == NULL) {
-            i = xkb->max_key_code + 1;
-            map->vmodmap = calloc(i, sizeof(unsigned short));
+            map->vmodmap = calloc(MAP_LENGTH, sizeof(unsigned short));
             if (map->vmodmap == NULL)
                 return BadAlloc;
         }
@@ -652,18 +645,9 @@ XkbChangeKeycodeRange(XkbDescPtr xkb,
     if (maxKC > xkb->max_key_code) {
         if (changes)
             changes->map.max_key_code = maxKC;
-        tmp = maxKC - xkb->max_key_code;
+        tmp = MAP_LENGTH - xkb->max_key_code;
         if (xkb->map) {
             if (xkb->map->key_sym_map) {
-                XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
-
-                xkb->map->key_sym_map = reallocarray(xkb->map->key_sym_map,
-                                                     maxKC + 1,
-                                                     sizeof(XkbSymMapRec));
-                if (!xkb->map->key_sym_map) {
-                    free(prev_key_sym_map);
-                    return BadAlloc;
-                }
                 memset((char *) &xkb->map->key_sym_map[xkb->max_key_code], 0,
                        tmp * sizeof(XkbSymMapRec));
                 if (changes) {
@@ -676,15 +660,6 @@ XkbChangeKeycodeRange(XkbDescPtr xkb,
                 }
             }
             if (xkb->map->modmap) {
-                unsigned char *prev_modmap = xkb->map->modmap;
-
-                xkb->map->modmap = reallocarray(xkb->map->modmap,
-                                                maxKC + 1,
-                                                sizeof(unsigned char));
-                if (!xkb->map->modmap) {
-                    free(prev_modmap);
-                    return BadAlloc;
-                }
                 memset((char *) &xkb->map->modmap[xkb->max_key_code], 0, tmp);
                 if (changes) {
                     changes->map.changed = _ExtendRange(changes->map.changed,
@@ -699,15 +674,6 @@ XkbChangeKeycodeRange(XkbDescPtr xkb,
         }
         if (xkb->server) {
             if (xkb->server->behaviors) {
-                XkbBehavior *prev_behaviors = xkb->server->behaviors;
-
-                xkb->server->behaviors = reallocarray(xkb->server->behaviors,
-                                                      maxKC + 1,
-                                                      sizeof(XkbBehavior));
-                if (!xkb->server->behaviors) {
-                    free(prev_behaviors);
-                    return BadAlloc;
-                }
                 memset((char *) &xkb->server->behaviors[xkb->max_key_code], 0,
                        tmp * sizeof(XkbBehavior));
                 if (changes) {
@@ -721,15 +687,6 @@ XkbChangeKeycodeRange(XkbDescPtr xkb,
                 }
             }
             if (xkb->server->key_acts) {
-                unsigned short *prev_key_acts = xkb->server->key_acts;
-
-                xkb->server->key_acts = reallocarray(xkb->server->key_acts,
-                                                     maxKC + 1,
-                                                     sizeof(unsigned short));
-                if (!xkb->server->key_acts) {
-                    free(prev_key_acts);
-                    return BadAlloc;
-                }
                 memset((char *) &xkb->server->key_acts[xkb->max_key_code], 0,
                        tmp * sizeof(unsigned short));
                 if (changes) {
@@ -743,15 +700,6 @@ XkbChangeKeycodeRange(XkbDescPtr xkb,
                 }
             }
             if (xkb->server->vmodmap) {
-                unsigned short *prev_vmodmap = xkb->server->vmodmap;
-
-                xkb->server->vmodmap = reallocarray(xkb->server->vmodmap,
-                                                    maxKC + 1,
-                                                    sizeof(unsigned short));
-                if (!xkb->server->vmodmap) {
-                    free(prev_vmodmap);
-                    return BadAlloc;
-                }
                 memset((char *) &xkb->server->vmodmap[xkb->max_key_code], 0,
                        tmp * sizeof(unsigned short));
                 if (changes) {
@@ -766,14 +714,6 @@ XkbChangeKeycodeRange(XkbDescPtr xkb,
             }
         }
         if ((xkb->names) && (xkb->names->keys)) {
-            XkbKeyNameRec *prev_keys = xkb->names->keys;
-
-            xkb->names->keys = reallocarray(xkb->names->keys,
-                                            maxKC + 1, sizeof(XkbKeyNameRec));
-            if (!xkb->names->keys) {
-                free(prev_keys);
-                return BadAlloc;
-            }
             memset((char *) &xkb->names->keys[xkb->max_key_code], 0,
                    tmp * sizeof(XkbKeyNameRec));
             if (changes) {
diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c
index ab0ad7e7d..3dc342e00 100644
--- a/xkb/xkbUtils.c
+++ b/xkb/xkbUtils.c
@@ -933,6 +933,7 @@ _XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst)
 {
     void *tmp = NULL;
     int i;
+    int gap;
     XkbKeyTypePtr stype = NULL, dtype = NULL;
 
     /* client map */
@@ -962,15 +963,20 @@ _XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst)
         }
         dst->map->num_syms = src->map->num_syms;
         dst->map->size_syms = src->map->size_syms;
+        gap = MAP_LENGTH - (src->max_key_code + 1);
 
         if (src->map->key_sym_map) {
-            if (src->max_key_code != dst->max_key_code) {
+            if (!dst->map->key_sym_map) {
                 tmp = reallocarray(dst->map->key_sym_map,
-                                   src->max_key_code + 1, sizeof(XkbSymMapRec));
+                                   MAP_LENGTH, sizeof(XkbSymMapRec));
                 if (!tmp)
                     return FALSE;
                 dst->map->key_sym_map = tmp;
             }
+            if (gap > 0) {
+                memset((char *) &dst->map->key_sym_map[gap], 0,
+                       gap * sizeof(XkbSymMapRec));
+            }
             memcpy(dst->map->key_sym_map, src->map->key_sym_map,
                    (src->max_key_code + 1) * sizeof(XkbSymMapRec));
         }
@@ -1141,12 +1147,15 @@ _XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst)
         }
 
         if (src->map->modmap) {
-            if (src->max_key_code != dst->max_key_code) {
-                tmp = realloc(dst->map->modmap, src->max_key_code + 1);
+            if (!dst->map->modmap) {
+                tmp = realloc(dst->map->modmap, MAP_LENGTH);
                 if (!tmp)
                     return FALSE;
                 dst->map->modmap = tmp;
             }
+            if (gap > 0) {
+                memset(dst->map->modmap + gap, 0, gap);
+            }
             memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1);
         }
         else {
@@ -1166,6 +1175,7 @@ static Bool
 _XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
 {
     void *tmp = NULL;
+    int gap;
 
     /* server map */
     if (src->server) {
@@ -1176,13 +1186,16 @@ _XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
             dst->server = tmp;
         }
 
+        gap = MAP_LENGTH - (src->max_key_code + 1);
         if (src->server->explicit) {
-            if (src->max_key_code != dst->max_key_code) {
-                tmp = realloc(dst->server->explicit, src->max_key_code + 1);
+            if (!dst->server->explicit) {
+                tmp = realloc(dst->server->explicit, MAP_LENGTH);
                 if (!tmp)
                     return FALSE;
                 dst->server->explicit = tmp;
             }
+            if (gap > 0)
+                memset(dst->server->explicit + gap, 0, gap);
             memcpy(dst->server->explicit, src->server->explicit,
                    src->max_key_code + 1);
         }
@@ -1210,13 +1223,15 @@ _XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
         dst->server->num_acts = src->server->num_acts;
 
         if (src->server->key_acts) {
-            if (src->max_key_code != dst->max_key_code) {
+            if (!dst->server->key_acts) {
                 tmp = reallocarray(dst->server->key_acts,
-                                   src->max_key_code + 1, sizeof(unsigned short));
+                                   MAP_LENGTH, sizeof(unsigned short));
                 if (!tmp)
                     return FALSE;
                 dst->server->key_acts = tmp;
             }
+            if (gap > 0)
+                memset((char *) &dst->server->key_acts[gap], 0, gap * sizeof(unsigned short));
             memcpy(dst->server->key_acts, src->server->key_acts,
                    (src->max_key_code + 1) * sizeof(unsigned short));
         }
@@ -1226,13 +1241,15 @@ _XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
         }
 
         if (src->server->behaviors) {
-            if (src->max_key_code != dst->max_key_code) {
+            if (!dst->server->behaviors) {
                 tmp = reallocarray(dst->server->behaviors,
-                                   src->max_key_code + 1, sizeof(XkbBehavior));
+                                   MAP_LENGTH, sizeof(XkbBehavior));
                 if (!tmp)
                     return FALSE;
                 dst->server->behaviors = tmp;
             }
+            if (gap > 0)
+                memset((char *) &dst->server->behaviors[gap], 0, gap * sizeof(XkbBehavior));
             memcpy(dst->server->behaviors, src->server->behaviors,
                    (src->max_key_code + 1) * sizeof(XkbBehavior));
         }
@@ -1244,13 +1261,15 @@ _XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
         memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods);
 
         if (src->server->vmodmap) {
-            if (src->max_key_code != dst->max_key_code) {
+            if (!dst->server->vmodmap) {
                 tmp = reallocarray(dst->server->vmodmap,
-                                   src->max_key_code + 1, sizeof(unsigned short));
+                                   MAP_LENGTH, sizeof(unsigned short));
                 if (!tmp)
                     return FALSE;
                 dst->server->vmodmap = tmp;
             }
+            if (gap > 0)
+                memset((char *) &dst->server->vmodmap[gap], 0, gap * sizeof(unsigned short));
             memcpy(dst->server->vmodmap, src->server->vmodmap,
                    (src->max_key_code + 1) * sizeof(unsigned short));
         }
@@ -1271,6 +1290,7 @@ static Bool
 _XkbCopyNames(XkbDescPtr src, XkbDescPtr dst)
 {
     void *tmp = NULL;
+    int gap;
 
     /* names */
     if (src->names) {
@@ -1280,14 +1300,17 @@ _XkbCopyNames(XkbDescPtr src, XkbDescPtr dst)
                 return FALSE;
         }
 
+        gap = MAP_LENGTH - (src->max_key_code + 1);
         if (src->names->keys) {
-            if (src->max_key_code != dst->max_key_code) {
-                tmp = reallocarray(dst->names->keys, src->max_key_code + 1,
+            if (!dst->names->keys) {
+                tmp = reallocarray(dst->names->keys, MAP_LENGTH,
                                    sizeof(XkbKeyNameRec));
                 if (!tmp)
                     return FALSE;
                 dst->names->keys = tmp;
             }
+            if (gap > 0)
+                memset((char *) &dst->names->keys[gap], 0, gap * sizeof(XkbKeyNameRec));
             memcpy(dst->names->keys, src->names->keys,
                    (src->max_key_code + 1) * sizeof(XkbKeyNameRec));
         }
commit 309ec5a4a71aa189bcf1eb4263d0d34375051856
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Thu Oct 24 15:51:53 2024 -0700

    modesetting: avoid memory leak when ms_present_check_unflip() returns FALSE
    
    Found by Oracle Parfait 13.3 static analyzer:
       Memory leak [memory-leak]:
          Memory leak of pointer event allocated with calloc(1, 16)
            at line 470 of hw/xfree86/drivers/modesetting/present.c in
            function 'ms_present_unflip'.
              event allocated at line 431 with calloc(1, 16)
              event leaks when ms_present_check_unflip(...) == 0 at line 438
                  and i >= config->num_crtc at line 445
    
    Fixes: 13c7d53df ("modesetting: Implement page flipping support for Present.")
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit bf63d9b34ef3a24427f884f66a387119dd5cdb8c)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index c3266d871..0c9ee2bc6 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -391,22 +391,24 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id)
     PixmapPtr pixmap = screen->GetScreenPixmap(screen);
     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
     int i;
-    struct ms_present_vblank_event *event;
 
     ms_present_set_screen_vrr(scrn, FALSE);
 
-    event = calloc(1, sizeof(struct ms_present_vblank_event));
-    if (!event)
-        return;
+    if (ms_present_check_unflip(NULL, screen->root, pixmap, TRUE, NULL)) {
+        struct ms_present_vblank_event *event;
 
-    event->event_id = event_id;
-    event->unflip = TRUE;
+        event = calloc(1, sizeof(struct ms_present_vblank_event));
+        if (!event)
+            return;
+
+        event->event_id = event_id;
+        event->unflip = TRUE;
 
-    if (ms_present_check_unflip(NULL, screen->root, pixmap, TRUE, NULL) &&
-        ms_do_pageflip(screen, pixmap, event, -1, FALSE,
-                       ms_present_flip_handler, ms_present_flip_abort,
-                       "Present-unflip")) {
-        return;
+        if (ms_do_pageflip(screen, pixmap, event, -1, FALSE,
+                           ms_present_flip_handler, ms_present_flip_abort,
+                           "Present-unflip")) {
+            return;
+        }
     }
 
     for (i = 0; i < config->num_crtc; i++) {
commit fbb636bf6b9f8017cf4f905210d15b86a257dad9
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Sat Oct 12 17:33:24 2024 -0700

    dix: limit checks to MAX_VALUATORS when generating Xi events
    
    Previously, it was looping through sizeof(ev->valuators.mask) * 8
    valuators, where valuators.mask is defined as an array of
    (MAX_VALUATORS + 7) / 8 entries.  Since MAX_VALUATORS is defined as 36,
    this made it actually loop through 40 entries.  The last 4 bits in this
    array should never be set, so we should never access memory outside the
    bounds of the arrays defined to be exactly MAX_VALUATORS in length, but
    we can make the static analyzer happier and not waste time checking bits
    that should never be set.
    
    Found by Oracle Parfait 13.3 static analyzer:
    
       Read outside array bounds [read-outside-array-bounds]:
          In array dereference of ev->valuators.data[i] with index i
          Array size is 36 elements (of 8 bytes each), index >= 0 and index <= 39
            at line 741 of dix/eventconvert.c in function 'eventToDeviceEvent'.
    
       Read outside array bounds [read-outside-array-bounds]:
          In array dereference of ev->valuators.data[i] with index i
          Array size is 36 elements (of 8 bytes each), index >= 0 and index <= 39
            at line 808 of dix/eventconvert.c in function 'eventToRawEvent'.
    
       Read outside array bounds [read-outside-array-bounds]:
          In array dereference of ev->valuators.data_raw[i] with index i
          Array size is 36 elements (of 8 bytes each), index >= 0 and index <= 39
            at line 809 of dix/eventconvert.c in function 'eventToRawEvent'.
    
    Fixes: b2ba77bac ("dix: add EventToXI2 and GetXI2Type.")
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit b65eea43dd18cdf6d389b7f82ee55ae764c3bf31)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 5364d75d6..8e830c59a 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -735,7 +735,7 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
 
     ptr += xde->buttons_len * 4;
     axisval = (FP3232 *) (ptr + xde->valuators_len * 4);
-    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
+    for (i = 0; i < MAX_VALUATORS; i++) {
         if (BitIsOn(ev->valuators.mask, i)) {
             SetBit(ptr, i);
             *axisval = double_to_fp3232(ev->valuators.data[i]);
@@ -802,7 +802,7 @@ eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
     ptr = (char *) &raw[1];
     axisval = (FP3232 *) (ptr + raw->valuators_len * 4);
     axisval_raw = axisval + nvals;
-    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
+    for (i = 0; i < MAX_VALUATORS; i++) {
         if (BitIsOn(ev->valuators.mask, i)) {
             SetBit(ptr, i);
             *axisval = double_to_fp3232(ev->valuators.data[i]);
commit abfd0215946c23c36a4b1c689ea6b8b7d277e991
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Sat Oct 12 17:01:03 2024 -0700

    dix: fix button offset when generating DeviceButtonStateNotify events
    
    Found by Oracle Parfait 13.3 static analyzer:
       Buffer Overflow in STD C function [buffer-overflow-call-stdc]:
          Buffer overflow in call to memcpy. Buffer &bev->buttons[4] of
           size 24 is written at an offset of 28
          Array size is 28 bytes, index is 32
            at line 743 of dix/enterleave.c in function
             'DeliverStateNotifyEvent'.
    
    Fixes: a85f0d6b9 ("Xi: fix use of button->down - bitflags instead of int arrays.")
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit 4b073d65bb5e1f4accb7ed280c8926134582b7ab)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/dix/enterleave.c b/dix/enterleave.c
index 0e571a880..fe39ac1b5 100644
--- a/dix/enterleave.c
+++ b/dix/enterleave.c
@@ -738,7 +738,7 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win)
         (ev - 1)->deviceid |= MORE_EVENTS;
         bev->type = DeviceButtonStateNotify;
         bev->deviceid = dev->id;
-        memcpy((char *) &bev->buttons[4], (char *) &b->down[4],
+        memcpy((char *) &bev->buttons[0], (char *) &b->down[4],
                DOWN_LENGTH - 4);
     }
 
commit 5406ddd003c95e2fcbb0411a7afff4daaa9b59f9
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Sat Oct 12 16:38:55 2024 -0700

    render: avoid NULL pointer dereference if PictureFindVisual returns NULL
    
    Found by Oracle Parfait 13.3:
       Null pointer dereference [null-pointer-deref]:
          Read from null pointer pVisual
            at line 257 of dix/colormap.c in function 'CreateColormap'.
              Null pointer introduced at line 412 of render/picture.c in
               function 'PictureFindVisual'.
              Constant 'NULL' passed into function CreateColormap, argument
               pVisual, from call at line 431 in function
               'PictureInitIndexedFormat'.
              Function PictureFindVisual may return constant 'NULL' at
               line 412, called at line 429.
    
    Fixes: d4a101d4e ("Integration of DAMAGE-XFIXES branch to trunk")
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit 7af077dd2f939b76e7d6ba84250368b6649fb777)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/render/picture.c b/render/picture.c
index 2be4b1954..d08f30a8a 100644
--- a/render/picture.c
+++ b/render/picture.c
@@ -427,6 +427,9 @@ PictureInitIndexedFormat(ScreenPtr pScreen, PictFormatPtr format)
     else {
         VisualPtr pVisual = PictureFindVisual(pScreen, format->index.vid);
 
+        if (pVisual == NULL)
+            return FALSE;
+
         if (CreateColormap(FakeClientID(0), pScreen, pVisual,
                            &format->index.pColormap, AllocNone, 0)
             != Success)
commit cec3e55ec96a660a1884fc99784efb4536e557bb
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Sat Oct 12 16:12:13 2024 -0700

    Xi: avoid NULL pointer dereference if GetXTestDevice returns NULL
    
    The comments in that function say "This only happens if master is a
    slave device. don't do that" but static analysis doesn't respect that.
    
    Found by Oracle Parfait 13.3:
       Null pointer dereference [null-pointer-deref]:
          Read from null pointer XTestptr
            at line 274 of Xi/xichangehierarchy.c in function 'remove_master'.
              Null pointer introduced at line 691 of Xext/xtest.c in function
               'GetXTestDevice'.
              Function GetXTestDevice may return constant 'NULL' at line 691,
               called at line 273 of Xi/xichangehierarchy.c in function
               'remove_master'.
       Null pointer dereference [null-pointer-deref]:
          Read from null pointer XTestkeybd
            at line 279 of Xi/xichangehierarchy.c in function 'remove_master'.
              Null pointer introduced at line 691 of Xext/xtest.c in function
               'GetXTestDevice'.
              Function GetXTestDevice may return constant 'NULL' at line 691,
               called at line 278 of Xi/xichangehierarchy.c in function
               'remove_master'.
    
    Fixes: 0814f511d ("input: store the master device's ID in the devPrivate for XTest devices.")
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit d10589cc09c68ad09bebd3a4155c44d1b8f2614b)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c
index 61b5b2dc3..4268c0f12 100644
--- a/Xi/xichangehierarchy.c
+++ b/Xi/xichangehierarchy.c
@@ -271,11 +271,13 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
         goto unwind;
 
     XTestptr = GetXTestDevice(ptr);
+    BUG_RETURN_VAL(XTestptr == NULL, BadDevice);
     rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
     if (rc != Success)
         goto unwind;
 
     XTestkeybd = GetXTestDevice(keybd);
+    BUG_RETURN_VAL(XTestkeybd == NULL, BadDevice);
     rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
     if (rc != Success)
         goto unwind;
commit 23b3b7199c69d0052830c2b219ba06cb26950f51
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Sat Oct 12 15:55:06 2024 -0700

    xfree86: avoid memory leak on realloc failure
    
    Found by Oracle Parfait 13.3 static analyzer:
       Memory leak [memory-leak]:
          Memory leak of pointer optname allocated with asprintf(&optname,
          "\"%s\"", p->name)
            at line 326 of hw/xfree86/common/xf86Configure.c in function
            'configureDeviceSection'.
              optname allocated at line 309 with asprintf(&optname, "\"%s\"",
              p->name)
    
    Fixes: code inherited from XFree86
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit fa711c486a2c2c958c71d7bd8ac0efe552558717)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/hw/xfree86/common/xf86Configure.c b/hw/xfree86/common/xf86Configure.c
index 4347f6d2f..2b4105f2b 100644
--- a/hw/xfree86/common/xf86Configure.c
+++ b/hw/xfree86/common/xf86Configure.c
@@ -308,8 +308,10 @@ configureDeviceSection(int screennum)
                 len += strlen(opttype);
 
                 ptr->dev_comment = realloc(ptr->dev_comment, len);
-                if (!ptr->dev_comment)
+                if (!ptr->dev_comment) {
+                    free(optname);
                     break;
+                }
                 p_e = ptr->dev_comment + strlen(ptr->dev_comment);
                 sprintf(p_e, "%s%-20s%s%s%s", prefix, optname, middle,
                         opttype, suffix);
commit cbc2c654e4099e4d8a35e625e010fd73e7a75521
Author: Alan Coopersmith <alan.coopersmith at oracle.com>
Date:   Mon Sep 9 16:21:46 2024 -0700

    os: NextDPMSTimeout: mark intentional fallthroughs in switch
    
    The comment at the top of the function tells humans the fallthroughs
    are intentional, but gcc doesn't parse that.
    
    Clears 3 -Wimplicit-fallthrough warnings from gcc 14.1
    
    Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    (cherry picked from commit b306df5a6060beea82b5157c3603593527b220b0)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/os/WaitFor.c b/os/WaitFor.c
index ff1d376e9..d03670f7d 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -418,13 +418,13 @@ NextDPMSTimeout(INT32 timeout)
     switch (DPMSPowerLevel) {
     case DPMSModeOn:
         DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
-
+        /* fallthrough */
     case DPMSModeStandby:
         DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
-
+        /* fallthrough */
     case DPMSModeSuspend:
         DPMS_CHECK_TIMEOUT(DPMSOffTime)
-
+        /* fallthrough */
     default:                   /* DPMSModeOff */
         return 0;
     }
commit e38c23e5b81693a1b23ed91e4ecdead08615ab25
Author: Tj <tj.iam.tj at proton.me>
Date:   Fri Jul 19 19:50:56 2024 +0200

    xfree86: fbdevhw: fix pci detection on recent Linux
    
    Linux kernel v6.9 has changed the symlink to point to the parent device. This
    breaks fbdev_open() detection logic. Change it to use the subsystem symlink
    instead which will remain stable.
    
    Kernel v6.8:
    
    [    14.067] (II) fbdev_open() sysfs_path=/sys/class/graphics/fb0
    [    14.067] (II) fbdev_open() buf=../../devices/platform/vesa-framebuffer.0/graphics/fb0
    
    Kernel v6.9:
    
    [    15.609] (II) fbdev_open() sysfs_path=/sys/class/graphics/fb0
    [    15.609] (II) fbdev_open() buf=../../devices/pci0000:00/0000:00:01.0/vesa-framebuffer.0/graphics/fb0
    
    Originally found in automated Debian ISO QA testing [0] and confirmed in Linux [1].
    
    Tested on kernels v6.9.7 and v6.8.12
    
    [0] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1075713
    [1] https://lore.kernel.org/lkml/lLyvPFC_APGHNfyGNHRpQy5izBikkaTPOpHooZIT3fFAoJPquSI31ZMueA99XTdr8ysir3X7O7IMdc6za-0m79vr_claeparHhoRouVgHOI=@proton.me/
    
    Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1714
    Signed-off-by: Tj <tj.iam.tj at proton.me>
    Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>
    Reviewed-by: Enrico Weigelt, metux IT consult <info at metux.net>
    (cherry picked from commit 728b54528d37ffa27b07c9b181c5ed8d2d359379)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/hw/xfree86/fbdevhw/fbdevhw.c b/hw/xfree86/fbdevhw/fbdevhw.c
index 3d8b92e66..9c30f00cc 100644
--- a/hw/xfree86/fbdevhw/fbdevhw.c
+++ b/hw/xfree86/fbdevhw/fbdevhw.c
@@ -335,9 +335,9 @@ fbdev_open(int scrnIndex, const char *dev, char **namep)
         char *sysfs_path = NULL;
         char *node = strrchr(dev, '/') + 1;
 
-        if (asprintf(&sysfs_path, "/sys/class/graphics/%s", node) < 0 ||
+        if (asprintf(&sysfs_path, "/sys/class/graphics/%s/device/subsystem", node) < 0 ||
             readlink(sysfs_path, buf, sizeof(buf) - 1) < 0 ||
-            strstr(buf, "devices/pci")) {
+            strstr(buf, "bus/pci")) {
             free(sysfs_path);
             close(fd);
             return -1;
commit ac48573a9bc943572621aa4d0254f32fca58f7d4
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Sep 23 09:27:21 2024 +0200

    os: Fix NULL pointer dereference
    
    RemoveHost() can be called from DisableLocalHost() with a NULL client,
    but doesn't actually check whether the given client pointer is valid on
    error and assigns the error value unconditionally, leading to a possible
    NULL pointer dereference and a crash of the Xserver.
    
    To avoid the issue, simply check whether the client pointer is not NULL
    prior to assign the errorValue.
    
    Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1752
    See-also: https://bugzilla.redhat.com/2313799
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    (cherry picked from commit 57a446c0f98693bd2e0263e91213344d870f4e03)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/os/access.c b/os/access.c
index 74facf4e1..bf8e96162 100644
--- a/os/access.c
+++ b/os/access.c
@@ -1425,13 +1425,15 @@ RemoveHost(ClientPtr client, int family, unsigned length,       /* of bytes in p
     case FamilyChaos:
     case FamilyServerInterpreted:
         if ((len = CheckAddr(family, pAddr, length)) < 0) {
-            client->errorValue = length;
+            if (client)
+                client->errorValue = length;
             return BadValue;
         }
         break;
     case FamilyLocal:
     default:
-        client->errorValue = family;
+        if (client)
+            client->errorValue = family;
         return BadValue;
     }
     for (prev = &validhosts;
commit f241e4f884be062f947f5dab35465549b8bffdf8
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Jan 30 11:11:54 2024 +1000

    Xi: when removing a master search for a disabled paired device
    
    If either the master pointer or keyboard was disabled, the respective
    GetMaster() call returns NULL, causing a segfault later accessing the
    deviceid.
    
    Fix this by looking in the off_devices list for any master
    device of the type we're looking for. Master devices lose the pairing
    when disabled (on enabling a keyboard we simply pair with the first
    available unpaired pointer).
    
    And for readability, split the device we get from the protocol request
    into a new "dev" variable instead of re-using ptr.
    
    Fixes #1611
    
    (cherry picked from commit e7c876ab0b0daa546a23d4ef82537fdf8fd88e04)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c
index 535328af6..61b5b2dc3 100644
--- a/Xi/xichangehierarchy.c
+++ b/Xi/xichangehierarchy.c
@@ -46,6 +46,7 @@
 #include "exevents.h"
 #include "exglobals.h"
 #include "geext.h"
+#include "misc.h"
 #include "xace.h"
 #include "xiquerydevice.h"      /* for GetDeviceUse */
 
@@ -215,36 +216,56 @@ disable_clientpointer(DeviceIntPtr dev)
     }
 }
 
+static DeviceIntPtr
+find_disabled_master(int type)
+{
+    DeviceIntPtr dev;
+
+    /* Once a master device is disabled it loses the pairing, so returning the first
+     * match is good enough */
+    for (dev = inputInfo.off_devices; dev; dev = dev->next) {
+        if (dev->type == type)
+            return dev;
+    }
+
+    return NULL;
+}
+
 static int
 remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
 {
-    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
+    DeviceIntPtr dev, ptr, keybd, XTestptr, XTestkeybd;
     int rc = Success;
 
     if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
         return BadValue;
 
-    rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
+    rc = dixLookupDevice(&dev, r->deviceid, client, DixDestroyAccess);
     if (rc != Success)
         goto unwind;
 
-    if (!IsMaster(ptr)) {
+    if (!IsMaster(dev)) {
         client->errorValue = r->deviceid;
         rc = BadDevice;
         goto unwind;
     }
 
     /* XXX: For now, don't allow removal of VCP, VCK */
-    if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
+    if (dev == inputInfo.pointer || dev == inputInfo.keyboard) {
         rc = BadDevice;
         goto unwind;
     }
 
-    ptr = GetMaster(ptr, MASTER_POINTER);
+    if ((ptr = GetMaster(dev, MASTER_POINTER)) == NULL)
+        ptr = find_disabled_master(MASTER_POINTER);
+    BUG_RETURN_VAL(ptr == NULL, BadDevice);
     rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
     if (rc != Success)
         goto unwind;
-    keybd = GetMaster(ptr, MASTER_KEYBOARD);
+
+    if ((keybd = GetMaster(dev, MASTER_KEYBOARD)) == NULL)
+        keybd = find_disabled_master(MASTER_KEYBOARD);
+    BUG_RETURN_VAL(keybd == NULL, BadDevice);
     rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
     if (rc != Success)
         goto unwind;
commit de2e2e8d45eaffd8b961d22ba91d45ed4ffb9ea0
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Jan 30 10:44:58 2024 +1000

    dix: don't push the XKB state to a non-existing master keyboard
    
    If our master keyboard is disabled, GetMaster() returns NULL and
    we segfault in XkbPushLockedStateToSlaves().
    
    Fixes 45fb3a934dc0db51584aba37c2f9d73deff9191d
    Fixes #1611
    
    (cherry picked from commit 9b983fecf999b9f50946973f2379a5ce00491cad)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/dix/devices.c b/dix/devices.c
index a01773236..082f86971 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2686,11 +2686,14 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
         dev->spriteInfo->paired = dev;
     }
     else {
+        DeviceIntPtr keyboard = GetMaster(dev, MASTER_KEYBOARD);
+
         dev->spriteInfo->sprite = master->spriteInfo->sprite;
         dev->spriteInfo->paired = master;
         dev->spriteInfo->spriteOwner = FALSE;
 
-        XkbPushLockedStateToSlaves(GetMaster(dev, MASTER_KEYBOARD), 0, 0);
+        if (keyboard)
+            XkbPushLockedStateToSlaves(keyboard, 0, 0);
         RecalculateMasterButtons(master);
     }
 
commit 743f66d6a29d439aac7b9ef2816009f311d58aec
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Jul 29 11:54:15 2024 +0200

    glamor: Fix possible double-free
    
    If glamor_link_glsl_prog() fails, we may jump to the failed code path
    which frees the variable vs_prog_string and fs_prog_string.
    
    But those variables were already freed just before, so in that case we
    end up freeing the memory twice.
    
    Simply move the free at the end of the success code path so we are sure
    to free the values only once, either in the successful of failed code
    paths.
    
    Fixes: 2906ee5e4 - glamor: Fix leak in glamor_build_program()
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    (cherry picked from commit 34ea020344ef5f2ea8ffce78c7e1abd6436b21ec)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c
index d8ddb4c77..cbdb218cb 100644
--- a/glamor/glamor_program.c
+++ b/glamor/glamor_program.c
@@ -340,8 +340,6 @@ glamor_build_program(ScreenPtr          screen,
 
     vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
     fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
-    free(vs_prog_string);
-    free(fs_prog_string);
     glAttachShader(prog->prog, vs_prog);
     glDeleteShader(vs_prog);
     glAttachShader(prog->prog, fs_prog);
@@ -374,6 +372,8 @@ glamor_build_program(ScreenPtr          screen,
     prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
 
     free(version_string);
+    free(vs_prog_string);
+    free(fs_prog_string);
     free(fs_vars);
     free(vs_vars);
     return TRUE;
commit 3bda7d119a289bc7706123b0544bb6ff792986ad
Author: Patrik Jakobsson <patrik.r.jakobsson at gmail.com>
Date:   Wed Jun 9 20:58:59 2021 +0200

    modesetting: Fix dirty updates for sw rotation
    
    Rotation is broken for all drm drivers not providing hardware rotation
    support. Drivers that give direct access to vram and not needing dirty
    updates still work but only by accident. The problem is caused by
    modesetting not sending the correct fb_id to drmModeDirtyFB() and
    passing the damage rects in the rotated state and not as the crtc
    expects them. This patch takes care of both problems.
    
    Signed-off-by: Patrik Jakobsson <pjakobsson at suse.de>
    (cherry picked from commit db9e9d45e8ba73510f11eb9e534c176102f6623e)
    
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1767>

diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 535f49d1d..fe3315a9c 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -515,9 +515,41 @@ GetRec(ScrnInfoPtr pScrn)
     return TRUE;
 }
 
+static void
+rotate_clip(PixmapPtr pixmap, BoxPtr rect, drmModeClip *clip, Rotation rotation)
+{
+    int w = pixmap->drawable.width;
+    int h = pixmap->drawable.height;
+
+    if (rotation == RR_Rotate_90) {
+	/* Rotate 90 degrees counter clockwise */
+        clip->x1 = rect->y1;
+	clip->x2 = rect->y2;
+	clip->y1 = w - rect->x2;
+	clip->y2 = w - rect->x1;
+    } else if (rotation == RR_Rotate_180) {
+	/* Rotate 180 degrees */
+        clip->x1 = w - rect->x2;
+	clip->x2 = w - rect->x1;
+	clip->y1 = h - rect->y2;
+	clip->y2 = h - rect->y1;
+    } else if (rotation == RR_Rotate_270) {
+	/* Rotate 90 degrees clockwise */
+        clip->x1 = h - rect->y2;
+	clip->x2 = h - rect->y1;
+	clip->y1 = rect->x1;
+	clip->y2 = rect->x2;
+    } else {
+	clip->x1 = rect->x1;
+	clip->x2 = rect->x2;
+	clip->y1 = rect->y1;
+	clip->y2 = rect->y2;
+    }
+}
+
 static int
-dispatch_dirty_region(ScrnInfoPtr scrn,
-                      PixmapPtr pixmap, DamagePtr damage, int fb_id)
+dispatch_dirty_region(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
+		      PixmapPtr pixmap, DamagePtr damage, int fb_id)
 {
     modesettingPtr ms = modesettingPTR(scrn);
     RegionPtr dirty = DamageRegion(damage);
@@ -532,13 +564,9 @@ dispatch_dirty_region(ScrnInfoPtr scrn,
         if (!clip)
             return -ENOMEM;
 
-        /* XXX no need for copy? */
-        for (i = 0; i < num_cliprects; i++, rect++) {
-            clip[i].x1 = rect->x1;
-            clip[i].y1 = rect->y1;
-            clip[i].x2 = rect->x2;
-            clip[i].y2 = rect->y2;
-        }
+        /* Rotate and copy rects into clips */
+        for (i = 0; i < num_cliprects; i++, rect++)
+	    rotate_clip(pixmap, rect, &clip[i], crtc->rotation);
 
         /* TODO query connector property to see if this is needed */
         ret = drmModeDirtyFB(ms->fd, fb_id, clip, num_cliprects);
@@ -561,20 +589,31 @@ static void
 dispatch_dirty(ScreenPtr pScreen)
 {
     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
     modesettingPtr ms = modesettingPTR(scrn);
     PixmapPtr pixmap = pScreen->GetScreenPixmap(pScreen);
-    int fb_id = ms->drmmode.fb_id;
-    int ret;
+    uint32_t fb_id;
+    int ret, c, x, y ;
 
-    ret = dispatch_dirty_region(scrn, pixmap, ms->damage, fb_id);
-    if (ret == -EINVAL || ret == -ENOSYS) {
-        ms->dirty_enabled = FALSE;
-        DamageUnregister(ms->damage);
-        DamageDestroy(ms->damage);
-        ms->damage = NULL;
-        xf86DrvMsg(scrn->scrnIndex, X_INFO,
-                   "Disabling kernel dirty updates, not required.\n");
-        return;
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
+        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+        if (!drmmode_crtc)
+            continue;
+
+	drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y);
+
+        ret = dispatch_dirty_region(scrn, crtc, pixmap, ms->damage, fb_id);
+        if (ret == -EINVAL || ret == -ENOSYS) {
+            ms->dirty_enabled = FALSE;
+            DamageUnregister(ms->damage);
+            DamageDestroy(ms->damage);
+            ms->damage = NULL;
+            xf86DrvMsg(scrn->scrnIndex, X_INFO,
+                       "Disabling kernel dirty updates, not required.\n");
+            return;
+        }
     }
 }
 
@@ -586,7 +625,7 @@ dispatch_dirty_pixmap(ScrnInfoPtr scrn, xf86CrtcPtr crtc, PixmapPtr ppix)
     DamagePtr damage = ppriv->secondary_damage;
     int fb_id = ppriv->fb_id;
 
-    dispatch_dirty_region(scrn, ppix, damage, fb_id);
+    dispatch_dirty_region(scrn, crtc, ppix, damage, fb_id);
 }
 
 static void
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 48dccad73..21c9222e1 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -627,7 +627,7 @@ drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
     return ms->atomic_modeset;
 }
 
-static Bool
+Bool
 drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 29f9b8f7d..2a9a91529 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -311,6 +311,8 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 
 int drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data);
 
+Bool drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y);
+
 void drmmode_set_dpms(ScrnInfoPtr scrn, int PowerManagementMode, int flags);
 void drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled);
 


More information about the xorg-commit mailing list