[Mesa-dev] [PATCH 4/4] st/egl: Implement swapbuffer throttling

Thomas Hellstrom thellstrom at vmware.com
Fri Feb 25 06:05:11 PST 2011


When doing copy swapbuffers using drm, throttle on outstanding copy operations.
Introduces a new environment variable, EGL_THROTTLE_FENCES that the
user can use to indicate the desired number of outstanding swapbuffers, or
disable throttling using EGL_THROTTLE_FENCES=0.

This can and perhaps should be extended to the pageflip case as well, since
with some hardware pageflips can be pipelined. In case the pageflip syncs, the
throttle operation will be a no-op anyway.

Update copyright notices.

Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>
---
 .../state_trackers/egl/common/native_helper.c      |  103 +++++++++++++++++++-
 .../state_trackers/egl/common/native_helper.h      |   27 +++++
 src/gallium/state_trackers/egl/drm/modeset.c       |   15 +++-
 3 files changed, 141 insertions(+), 4 deletions(-)

diff --git a/src/gallium/state_trackers/egl/common/native_helper.c b/src/gallium/state_trackers/egl/common/native_helper.c
index 0f00c4d..be6713d 100644
--- a/src/gallium/state_trackers/egl/common/native_helper.c
+++ b/src/gallium/state_trackers/egl/common/native_helper.c
@@ -3,6 +3,7 @@
  * Version:  7.9
  *
  * Copyright (C) 2010 LunarG Inc.
+ * Copyright (C) 2011 VMware Inc. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -24,6 +25,7 @@
  *
  * Authors:
  *    Chia-I Wu <olv at lunarg.com>
+ *    Thomas Hellstrom <thellstrom at vmware.com>
  */
 
 #include "util/u_inlines.h"
@@ -34,6 +36,14 @@
 
 #include "native_helper.h"
 
+/**
+ * Number of swap fences and mask
+ */
+
+#define EGL_SWAP_FENCES_MAX 4
+#define EGL_SWAP_FENCES_MASK 3
+#define EGL_SWAP_FENCES_DEFAULT 1
+
 struct resource_surface {
    struct pipe_screen *screen;
    enum pipe_format format;
@@ -42,6 +52,15 @@ struct resource_surface {
    struct pipe_resource *resources[NUM_NATIVE_ATTACHMENTS];
    uint resource_mask;
    uint width, height;
+
+   /**
+    * Swap fences.
+    */
+   struct pipe_fence_handle *swap_fences[EGL_SWAP_FENCES_MAX];
+   unsigned int cur_fences;
+   unsigned int head;
+   unsigned int tail;
+   unsigned int desired_fences;
 };
 
 struct resource_surface *
@@ -49,11 +68,16 @@ resource_surface_create(struct pipe_screen *screen,
                         enum pipe_format format, uint bind)
 {
    struct resource_surface *rsurf = CALLOC_STRUCT(resource_surface);
+   char *swap_fences = getenv("EGL_THROTTLE_FENCES");
 
    if (rsurf) {
       rsurf->screen = screen;
       rsurf->format = format;
       rsurf->bind = bind;
+      rsurf->desired_fences = (swap_fences) ? atoi(swap_fences) :
+	 EGL_SWAP_FENCES_DEFAULT;
+      if (rsurf->desired_fences > EGL_SWAP_FENCES_MAX)
+	 rsurf->desired_fences = EGL_SWAP_FENCES_MAX;
    }
 
    return rsurf;
@@ -256,7 +280,6 @@ resource_surface_copy_swap(struct resource_surface *rsurf,
    u_box_origin_2d(ftex->width0, ftex->height0, &src_box);
    pipe->resource_copy_region(pipe, ftex, 0, 0, 0, 0,
 			      btex, 0, &src_box);
-   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
    ret = TRUE;
 
  out_no_ftex:
@@ -266,3 +289,81 @@ resource_surface_copy_swap(struct resource_surface *rsurf,
 
    return ret;
 }
+
+static struct pipe_fence_handle *
+swap_fences_pop_front(struct resource_surface *rsurf)
+{
+   struct pipe_screen *screen = rsurf->screen;
+   struct pipe_fence_handle *fence = NULL;
+
+   if (rsurf->desired_fences == 0)
+      return NULL;
+
+   if (rsurf->cur_fences >= rsurf->desired_fences) {
+      screen->fence_reference(screen, &fence, rsurf->swap_fences[rsurf->tail]);
+      screen->fence_reference(screen, &rsurf->swap_fences[rsurf->tail++], NULL);
+      rsurf->tail &= EGL_SWAP_FENCES_MASK;
+      --rsurf->cur_fences;
+   }
+   return fence;
+}
+
+static void
+swap_fences_push_back(struct resource_surface *rsurf,
+		      struct pipe_fence_handle *fence)
+{
+   struct pipe_screen *screen = rsurf->screen;
+
+   if (!fence || rsurf->desired_fences == 0)
+      return;
+
+   while(rsurf->cur_fences == rsurf->desired_fences)
+      swap_fences_pop_front(rsurf);
+
+   rsurf->cur_fences++;
+   screen->fence_reference(screen, &rsurf->swap_fences[rsurf->head++],
+			   fence);
+   rsurf->head &= EGL_SWAP_FENCES_MASK;
+}
+
+boolean
+resource_surface_throttle(struct resource_surface *rsurf)
+{
+   struct pipe_screen *screen = rsurf->screen;
+   struct pipe_fence_handle *fence = swap_fences_pop_front(rsurf);
+
+   if (fence) {
+      (void) screen->fence_finish(screen, fence, 0);
+      screen->fence_reference(screen, &fence, NULL);
+      return TRUE;
+   }
+
+   return FALSE;
+}
+
+boolean
+resource_surface_flush(struct resource_surface *rsurf,
+		       struct native_display *ndpy)
+{
+   struct pipe_fence_handle *fence = NULL;
+   struct pipe_screen *screen = rsurf->screen;
+   struct pipe_context *pipe= ndpy_get_copy_context(ndpy);
+
+   if (!pipe)
+      return FALSE;
+
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, &fence);
+   if (fence == NULL)
+      return FALSE;
+
+   swap_fences_push_back(rsurf, fence);
+   screen->fence_reference(screen, &fence, NULL);
+
+   return TRUE;
+}
+
+void
+resource_surface_wait(struct resource_surface *rsurf)
+{
+   while (resource_surface_throttle(rsurf));
+}
diff --git a/src/gallium/state_trackers/egl/common/native_helper.h b/src/gallium/state_trackers/egl/common/native_helper.h
index ad68273..39564a0 100644
--- a/src/gallium/state_trackers/egl/common/native_helper.h
+++ b/src/gallium/state_trackers/egl/common/native_helper.h
@@ -3,6 +3,7 @@
  * Version:  7.9
  *
  * Copyright (C) 2010 LunarG Inc.
+ * Copyright (C) 2011 VMware Inc. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -24,6 +25,7 @@
  *
  * Authors:
  *    Chia-I Wu <olv at lunarg.com>
+ *    Thomas Hellstrom <thellstrom at vmware.com>
  */
 
 #include "native.h"
@@ -75,6 +77,31 @@ resource_surface_present(struct resource_surface *rsurf,
                          enum native_attachment which,
                          void *winsys_drawable_handle);
 
+/**
+ * Perform a gallium copy blit between the back left and front left
+ * surfaces. Needs to be followed by a call to resource_surface_flush.
+ */
 boolean
 resource_surface_copy_swap(struct resource_surface *rsurf,
 			   struct native_display *ndpy);
+
+/**
+ * Throttle on outstanding rendering using the copy context. For example
+ * copy swaps.
+ */
+boolean
+resource_surface_throttle(struct resource_surface *rsurf);
+
+/**
+ * Flush pending rendering using the copy context. This function saves a
+ * marker for upcoming throttles.
+ */
+boolean
+resource_surface_flush(struct resource_surface *rsurf,
+		       struct native_display *ndpy);
+/**
+ * Wait for all rendering using the copy context to be complete. Frees all
+ * throttle markers saved using resource_surface_flush.
+ */
+void
+resource_surface_wait(struct resource_surface *rsurf);
diff --git a/src/gallium/state_trackers/egl/drm/modeset.c b/src/gallium/state_trackers/egl/drm/modeset.c
index 6eaa42f..3fff954 100644
--- a/src/gallium/state_trackers/egl/drm/modeset.c
+++ b/src/gallium/state_trackers/egl/drm/modeset.c
@@ -3,6 +3,7 @@
  * Version:  7.9
  *
  * Copyright (C) 2010 LunarG Inc.
+ * Copyright (C) 2011 VMware Inc. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -24,6 +25,7 @@
  *
  * Authors:
  *    Chia-I Wu <olv at lunarg.com>
+ *    Thomas Hellstrom <thellstrom at vmware.com>
  */
 
 #include "util/u_memory.h"
@@ -136,8 +138,12 @@ drm_surface_copy_swap(struct native_surface *nsurf)
    struct drm_surface *drmsurf = drm_surface(nsurf);
    struct drm_display *drmdpy = drmsurf->drmdpy;
 
-   if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base) ||
-       !drm_surface_flush_frontbuffer(nsurf))
+   (void) resource_surface_throttle(drmsurf->rsurf);
+   if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base))
+      return FALSE;
+
+   (void) resource_surface_flush(drmsurf->rsurf, &drmdpy->base);
+   if (!drm_surface_flush_frontbuffer(nsurf))
       return FALSE;
 
    drmsurf->sequence_number++;
@@ -218,7 +224,9 @@ drm_surface_present(struct native_surface *nsurf,
 static void
 drm_surface_wait(struct native_surface *nsurf)
 {
-   /* no-op */
+   struct drm_surface *drmsurf = drm_surface(nsurf);
+
+   resource_surface_wait(drmsurf->rsurf);
 }
 
 static void
@@ -226,6 +234,7 @@ drm_surface_destroy(struct native_surface *nsurf)
 {
    struct drm_surface *drmsurf = drm_surface(nsurf);
 
+   resource_surface_wait(drmsurf->rsurf);
    if (drmsurf->current_crtc.crtc)
          drmModeFreeCrtc(drmsurf->current_crtc.crtc);
 
-- 
1.6.2.5



More information about the mesa-dev mailing list