dri3: Move up fourcc utility function
[mesa.git] / src / loader / loader_dri3_helper.c
index 2207b7543b96c799b13bf04fe49e34b02dcd04be..e3120f5d250bfd93ae7453d00d909dc05af75233 100644 (file)
@@ -59,6 +59,9 @@ static struct loader_dri3_blit_context blit_context = {
 static void
 dri3_flush_present_events(struct loader_dri3_drawable *draw);
 
+static struct loader_dri3_buffer *
+dri3_find_back_alloc(struct loader_dri3_drawable *draw);
+
 /**
  * Do we have blit functionality in the image blit extension?
  *
@@ -269,6 +272,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
    draw->first_init = true;
 
    draw->cur_blit_source = -1;
+   draw->back_format = __DRI_IMAGE_FORMAT_NONE;
 
    if (draw->ext->config)
       draw->ext->config->configQueryi(draw->dri_screen,
@@ -616,7 +620,10 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
       flags |= __DRI2_FLUSH_CONTEXT;
    loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER);
 
-   back = dri3_back_buffer(draw);
+   back = dri3_find_back_alloc(draw);
+   if (!back)
+      return;
+
    y = draw->height - y - height;
 
    if (draw->is_different_gpu) {
@@ -641,7 +648,7 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
    loader_dri3_swapbuffer_barrier(draw);
    dri3_fence_reset(draw->conn, back);
    dri3_copy_area(draw->conn,
-                  dri3_back_buffer(draw)->pixmap,
+                  back->pixmap,
                   draw->drawable,
                   dri3_drawable_gc(draw),
                   x, y, x, y, width, height);
@@ -652,7 +659,7 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
    if (draw->have_fake_front && !draw->is_different_gpu) {
       dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw));
       dri3_copy_area(draw->conn,
-                     dri3_back_buffer(draw)->pixmap,
+                     back->pixmap,
                      dri3_fake_front_buffer(draw)->pixmap,
                      dri3_drawable_gc(draw),
                      x, y, x, y, width, height);
@@ -763,7 +770,8 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
 
    draw->vtable->flush_drawable(draw, flush_flags);
 
-   back = draw->buffers[dri3_find_back(draw)];
+   back = dri3_find_back_alloc(draw);
+
    if (draw->is_different_gpu && back) {
       /* Update the linear buffer before presenting the pixmap */
       (void) loader_dri3_blit_image(draw,
@@ -771,22 +779,29 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
                                     back->image,
                                     0, 0, back->width, back->height,
                                     0, 0, __BLIT_FLAG_FLUSH);
-      /* Update the fake front */
-      if (draw->have_fake_front)
-         (void) loader_dri3_blit_image(draw,
-                                       draw->buffers[LOADER_DRI3_FRONT_ID]->image,
-                                       back->image,
-                                       0, 0, draw->width, draw->height,
-                                       0, 0, __BLIT_FLAG_FLUSH);
    }
 
    /* If we need to preload the new back buffer, remember the source.
     * The force_copy parameter is used by EGL to attempt to preserve
     * the back buffer across a call to this function.
     */
-   if (draw->swap_method == __DRI_ATTRIB_SWAP_COPY || force_copy)
+   if (draw->swap_method != __DRI_ATTRIB_SWAP_UNDEFINED || force_copy)
       draw->cur_blit_source = LOADER_DRI3_BACK_ID(draw->cur_back);
 
+   /* Exchange the back and fake front. Even though the server knows about these
+    * buffers, it has no notion of back and fake front.
+    */
+   if (back && draw->have_fake_front) {
+      struct loader_dri3_buffer *tmp;
+
+      tmp = dri3_fake_front_buffer(draw);
+      draw->buffers[LOADER_DRI3_FRONT_ID] = back;
+      draw->buffers[LOADER_DRI3_BACK_ID(draw->cur_back)] = tmp;
+
+      if (draw->swap_method == __DRI_ATTRIB_SWAP_COPY  || force_copy)
+         draw->cur_blit_source = LOADER_DRI3_FRONT_ID;
+   }
+
    dri3_flush_present_events(draw);
 
    if (back && !draw->is_pixmap) {
@@ -852,21 +867,26 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
                          remainder, 0, NULL);
       ret = (int64_t) draw->send_sbc;
 
-      /* If there's a fake front, then copy the source back buffer
-       * to the fake front to keep it up to date. This needs
-       * to reset the fence and make future users block until
-       * the X server is done copying the bits
+      /* Schedule a server-side back-preserving blit if necessary.
+       * This happens iff all conditions below are satisfied:
+       * a) We have a fake front,
+       * b) We need to preserve the back buffer,
+       * c) We don't have local blit capabilities.
        */
-      if (draw->have_fake_front && !draw->is_different_gpu) {
-         dri3_fence_reset(draw->conn, draw->buffers[LOADER_DRI3_FRONT_ID]);
-         dri3_copy_area(draw->conn,
-                        back->pixmap,
-                        draw->buffers[LOADER_DRI3_FRONT_ID]->pixmap,
+      if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1 &&
+          draw->cur_blit_source != LOADER_DRI3_BACK_ID(draw->cur_back)) {
+         struct loader_dri3_buffer *new_back = dri3_back_buffer(draw);
+         struct loader_dri3_buffer *src = draw->buffers[draw->cur_blit_source];
+
+         dri3_fence_reset(draw->conn, new_back);
+         dri3_copy_area(draw->conn, src->pixmap,
+                        new_back->pixmap,
                         dri3_drawable_gc(draw),
-                        0, 0, 0, 0,
-                        draw->width, draw->height);
-         dri3_fence_trigger(draw->conn, draw->buffers[LOADER_DRI3_FRONT_ID]);
+                        0, 0, 0, 0, draw->width, draw->height);
+         dri3_fence_trigger(draw->conn, new_back);
+         new_back->last_swap = src->last_swap;
       }
+
       xcb_flush(draw->conn);
       if (draw->stamp)
          ++(*draw->stamp);
@@ -880,15 +900,12 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
 int
 loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw)
 {
-   int back_id = LOADER_DRI3_BACK_ID(dri3_find_back(draw));
+   struct loader_dri3_buffer *back = dri3_find_back_alloc(draw);
 
-   if (back_id < 0 || !draw->buffers[back_id])
+   if (!back || back->last_swap == 0)
       return 0;
 
-   if (draw->buffers[back_id]->last_swap != 0)
-      return draw->send_sbc - draw->buffers[back_id]->last_swap + 1;
-   else
-      return 0;
+   return draw->send_sbc - back->last_swap + 1;
 }
 
 /** loader_dri3_open
@@ -946,6 +963,27 @@ dri3_cpp_for_format(uint32_t format) {
    }
 }
 
+/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
+ * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
+ * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
+ * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
+ */
+static int
+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_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;
+   case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
+   case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
+   }
+   return 0;
+}
+
 /** loader_dri3_alloc_render_buffer
  *
  * Use the driver createImage function to construct a __DRIimage, then
@@ -1169,27 +1207,6 @@ dri3_update_drawable(__DRIdrawable *driDrawable,
    return true;
 }
 
-/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
- * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
- * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
- * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
- */
-static int
-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_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;
-   case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
-   case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
-   }
-   return 0;
-}
-
 __DRIimage *
 loader_dri3_create_image(xcb_connection_t *c,
                          xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
@@ -1289,7 +1306,6 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
    buffer->own_pixmap = false;
    buffer->width = bp_reply->width;
    buffer->height = bp_reply->height;
-   buffer->buffer_type = buffer_type;
    buffer->shm_fence = shm_fence;
    buffer->sync_fence = sync_fence;
 
@@ -1323,6 +1339,8 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
    int buf_id;
 
    if (buffer_type == loader_dri3_buffer_back) {
+      draw->back_format = format;
+
       buf_id = dri3_find_back(draw);
 
       if (buf_id < 0)
@@ -1399,7 +1417,6 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
          break;
       }
       buffer = new_buffer;
-      buffer->buffer_type = buffer_type;
       draw->buffers[buf_id] = buffer;
    }
    dri3_fence_await(draw->conn, buffer);
@@ -1494,8 +1511,10 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable,
    if (!dri3_update_drawable(driDrawable, draw))
       return false;
 
-   /* pixmaps always have front buffers */
-   if (draw->is_pixmap)
+   /* pixmaps always have front buffers.
+    * Exchange swaps also mandate fake front buffers.
+    */
+   if (draw->is_pixmap || draw->swap_method == __DRI_ATTRIB_SWAP_EXCHANGE)
       buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
 
    if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
@@ -1608,3 +1627,35 @@ loader_dri3_close_screen(__DRIscreen *dri_screen)
    }
    mtx_unlock(&blit_context.mtx);
 }
+
+/**
+ * Find a backbuffer slot - potentially allocating a back buffer
+ *
+ * \param draw[in,out]  Pointer to the drawable for which to find back.
+ * \return Pointer to a new back buffer or NULL if allocation failed or was
+ * not mandated.
+ *
+ * Find a potentially new back buffer, and if it's not been allocated yet and
+ * in addition needs initializing, then try to allocate and initialize it.
+ */
+static struct loader_dri3_buffer *
+dri3_find_back_alloc(struct loader_dri3_drawable *draw)
+{
+   struct loader_dri3_buffer *back;
+   int id;
+
+   id = dri3_find_back(draw);
+   back = (id >= 0) ? draw->buffers[id] : NULL;
+
+   if (back || (id >= 0 && draw->back_format != __DRI_IMAGE_FORMAT_NONE)) {
+      if (dri3_update_drawable(draw->dri_drawable, draw)) {
+         (void) dri3_get_buffer(draw->dri_drawable,
+                                draw->back_format,
+                                loader_dri3_buffer_back,
+                                draw);
+         back = (id >= 0) ? draw->buffers[id] : NULL;
+      }
+   }
+
+   return back;
+}