dri3: Stricter SBC wraparound handling
[mesa.git] / src / loader / loader_dri3_helper.c
index 6587281c4ab8c5be507ab4c586eccbbb506b3dcb..f0ff2f07bde72a0f90445a6f55c69ab0b61cf72a 100644 (file)
@@ -370,10 +370,42 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw,
        * checking for wrap.
        */
       if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
-         draw->recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial;
-         if (draw->recv_sbc > draw->send_sbc)
-            draw->recv_sbc -= 0x100000000;
+         uint64_t recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial;
 
+         /* Only assume wraparound if that results in exactly the previous
+          * SBC + 1, otherwise ignore received SBC > sent SBC (those are
+          * probably from a previous loader_dri3_drawable instance) to avoid
+          * calculating bogus target MSC values in loader_dri3_swap_buffers_msc
+          */
+         if (recv_sbc <= draw->send_sbc)
+            draw->recv_sbc = recv_sbc;
+         else if (recv_sbc == (draw->recv_sbc + 0x100000001ULL))
+            draw->recv_sbc = recv_sbc - 0x100000000ULL;
+
+         /* When moving from flip to copy, we assume that we can allocate in
+          * a more optimal way if we don't need to cater for the display
+          * controller.
+          */
+         if (ce->mode == XCB_PRESENT_COMPLETE_MODE_COPY &&
+             draw->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
+            for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
+               if (draw->buffers[b])
+                  draw->buffers[b]->reallocate = true;
+            }
+         }
+
+        /* If the server tells us that our allocation is suboptimal, we
+          * reallocate once.
+          */
+#ifdef HAVE_DRI3_MODIFIERS
+         if (ce->mode == XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY &&
+             draw->last_present_mode != ce->mode) {
+            for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
+               if (draw->buffers[b])
+                  draw->buffers[b]->reallocate = true;
+            }
+         }
+#endif
          draw->last_present_mode = ce->mode;
 
          if (draw->vtable->show_fps)
@@ -396,13 +428,6 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw,
 
          if (buf && buf->pixmap == ie->pixmap)
             buf->busy = 0;
-
-         if (buf && draw->num_back <= b && b < LOADER_DRI3_MAX_BACK &&
-             draw->cur_blit_source != b &&
-             !buf->busy) {
-            dri3_free_render_buffer(draw, buf);
-            draw->buffers[b] = NULL;
-         }
       }
       break;
    }
@@ -535,7 +560,6 @@ dri3_find_back(struct loader_dri3_drawable *draw)
    /* Check whether we need to reuse the current back buffer as new back.
     * In that case, wait until it's not busy anymore.
     */
-   dri3_update_num_back(draw);
    num_to_consider = draw->num_back;
    if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) {
       num_to_consider = 1;
@@ -880,7 +904,10 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
        */
       if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1)
          options |= XCB_PRESENT_OPTION_COPY;
-
+#ifdef HAVE_DRI3_MODIFIERS
+      if (draw->multiplanes_available)
+         options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
+#endif
       back->busy = 1;
       back->last_swap = draw->send_sbc;
       xcb_present_pixmap(draw->conn,
@@ -995,6 +1022,7 @@ dri3_cpp_for_format(uint32_t format) {
    case  __DRI_IMAGE_FORMAT_XBGR2101010:
    case  __DRI_IMAGE_FORMAT_ABGR2101010:
    case  __DRI_IMAGE_FORMAT_SARGB8:
+   case  __DRI_IMAGE_FORMAT_SABGR8:
       return 4;
    case  __DRI_IMAGE_FORMAT_NONE:
    default:
@@ -1014,6 +1042,7 @@ image_format_to_fourcc(int format)
    /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
    switch (format) {
    case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
+   case __DRI_IMAGE_FORMAT_SABGR8: return __DRI_IMAGE_FOURCC_SABGR8888;
    case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
    case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
    case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
@@ -1027,6 +1056,7 @@ image_format_to_fourcc(int format)
    return 0;
 }
 
+#ifdef HAVE_DRI3_MODIFIERS
 static bool
 has_supported_modifier(struct loader_dri3_drawable *draw, unsigned int format,
                        uint64_t *modifiers, uint32_t count)
@@ -1061,6 +1091,7 @@ has_supported_modifier(struct loader_dri3_drawable *draw, unsigned int format,
    free(supported_modifiers);
    return found;
 }
+#endif
 
 /** loader_dri3_alloc_render_buffer
  *
@@ -1106,6 +1137,7 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
       goto no_image;
 
    if (!draw->is_different_gpu) {
+#ifdef HAVE_DRI3_MODIFIERS
       if (draw->multiplanes_available &&
           draw->ext->image->base.version >= 15 &&
           draw->ext->image->queryDmaBufModifiers &&
@@ -1169,7 +1201,7 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
                                                                     buffer);
          free(modifiers);
       }
-
+#endif
       if (!buffer->image)
          buffer->image = draw->ext->image->createImage(draw->dri_screen,
                                                        width, height,
@@ -1244,6 +1276,7 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
       buffer->modifier = DRM_FORMAT_MOD_INVALID;
 
    pixmap = xcb_generate_id(draw->conn);
+#ifdef HAVE_DRI3_MODIFIERS
    if (draw->multiplanes_available &&
        buffer->modifier != DRM_FORMAT_MOD_INVALID) {
       xcb_dri3_pixmap_from_buffers(draw->conn,
@@ -1258,7 +1291,9 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
                                    depth, buffer->cpp * 8,
                                    buffer->modifier,
                                    buffer_fds);
-   } else {
+   } else
+#endif
+   {
       xcb_dri3_pixmap_from_buffer(draw->conn,
                                   pixmap,
                                   draw->drawable,
@@ -1447,6 +1482,7 @@ loader_dri3_create_image(xcb_connection_t *c,
    return ret;
 }
 
+#ifdef HAVE_DRI3_MODIFIERS
 __DRIimage *
 loader_dri3_create_image_from_buffers(xcb_connection_t *c,
                                       xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
@@ -1488,6 +1524,7 @@ loader_dri3_create_image_from_buffers(xcb_connection_t *c,
 
    return ret;
 }
+#endif
 
 /** dri3_get_pixmap_buffer
  *
@@ -1541,7 +1578,7 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
                           (sync_fence = xcb_generate_id(draw->conn)),
                           false,
                           fence_fd);
-
+#ifdef HAVE_DRI3_MODIFIERS
    if (draw->multiplanes_available &&
        draw->ext->image->base.version >= 15 &&
        draw->ext->image->createImageFromDmaBufs2) {
@@ -1560,7 +1597,9 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
       width = bps_reply->width;
       height = bps_reply->height;
       free(bps_reply);
-   } else {
+   } else
+#endif
+   {
       xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
       xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
 
@@ -1626,11 +1665,12 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
 
    buffer = draw->buffers[buf_id];
 
-   /* Allocate a new buffer if there isn't an old one, or if that
-    * old one is the wrong size
+   /* Allocate a new buffer if there isn't an old one, if that
+    * old one is the wrong size, or if it's suboptimal
     */
    if (!buffer || buffer->width != draw->width ||
-       buffer->height != draw->height) {
+       buffer->height != draw->height ||
+       buffer->reallocate) {
       struct loader_dri3_buffer *new_buffer;
 
       /* Allocate the new buffers
@@ -1775,6 +1815,7 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable,
 {
    struct loader_dri3_drawable *draw = loaderPrivate;
    struct loader_dri3_buffer   *front, *back;
+   int buf_id;
 
    buffers->image_mask = 0;
    buffers->front = NULL;
@@ -1786,6 +1827,16 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable,
    if (!dri3_update_drawable(driDrawable, draw))
       return false;
 
+   dri3_update_num_back(draw);
+
+   /* Free no longer needed back buffers */
+   for (buf_id = draw->num_back; buf_id < LOADER_DRI3_MAX_BACK; buf_id++) {
+      if (draw->cur_blit_source != buf_id && draw->buffers[buf_id]) {
+         dri3_free_render_buffer(draw, draw->buffers[buf_id]);
+         draw->buffers[buf_id] = NULL;
+      }
+   }
+
    /* pixmaps always have front buffers.
     * Exchange swaps also mandate fake front buffers.
     */