st/egl: Clean up DRI2 surface.
authorChia-I Wu <olv@lunarg.com>
Fri, 19 Feb 2010 14:12:04 +0000 (22:12 +0800)
committerChia-I Wu <olv@lunarg.com>
Sun, 21 Feb 2010 02:22:07 +0000 (10:22 +0800)
Mainly to move the call to DRI2GetBuffers from dri2_surface_validate to
the new dri2_surface_update_buffers.

src/gallium/state_trackers/egl/x11/native_dri2.c

index 5f2fd41260434a319144449ee091ec7b4316f5d3..dbd1a64992d929b4bf341e9508a8db412d1f3312 100644 (file)
@@ -62,10 +62,15 @@ struct dri2_surface {
    enum pipe_format color_format;
    struct dri2_display *dri2dpy;
 
-   struct pipe_texture *pbuffer_textures[NUM_NATIVE_ATTACHMENTS];
-   boolean have_back, have_fake;
-   int width, height;
    unsigned int sequence_number;
+   int width, height;
+   struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS];
+   uint valid_mask;
+
+   boolean have_back, have_fake;
+
+   struct x11_drawable_buffer *last_xbufs;
+   int last_num_xbufs;
 };
 
 struct dri2_config {
@@ -90,110 +95,24 @@ dri2_config(const struct native_config *nconf)
    return (struct dri2_config *) nconf;
 }
 
-static boolean
-dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
-{
-   struct dri2_surface *dri2surf = dri2_surface(nsurf);
-   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
-
-   /* pbuffer is private */
-   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER)
-      return TRUE;
-
-   /* copy to real front buffer */
-   if (dri2surf->have_fake)
-      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
-            0, 0, dri2surf->width, dri2surf->height,
-            DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
-
-   return TRUE;
-}
-
-static boolean
-dri2_surface_swap_buffers(struct native_surface *nsurf)
-{
-   struct dri2_surface *dri2surf = dri2_surface(nsurf);
-   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
-
-   /* pbuffer is private */
-   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER)
-      return TRUE;
-
-   /* copy to front buffer */
-   if (dri2surf->have_back)
-      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
-            0, 0, dri2surf->width, dri2surf->height,
-            DRI2BufferBackLeft, DRI2BufferFrontLeft);
-
-   /* and update fake front buffer */
-   if (dri2surf->have_fake)
-      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
-            0, 0, dri2surf->width, dri2surf->height,
-            DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
-
-   return TRUE;
-}
-
-static boolean
-dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
-                      unsigned int *seq_num, struct pipe_texture **textures,
-                      int *width, int *height)
+/**
+ * Get the buffers from the server.
+ */
+static void
+dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
 {
    struct dri2_surface *dri2surf = dri2_surface(nsurf);
    struct dri2_display *dri2dpy = dri2surf->dri2dpy;
    unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS];
-   struct pipe_texture templ;
-   struct x11_drawable_buffer *xbufs;
    int num_ins, num_outs, att, i;
-
-   if (attachment_mask) {
-      memset(&templ, 0, sizeof(templ));
-      templ.target = PIPE_TEXTURE_2D;
-      templ.last_level = 0;
-      templ.width0 = dri2surf->width;
-      templ.height0 = dri2surf->height;
-      templ.depth0 = 1;
-      templ.format = dri2surf->color_format;
-      templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
-
-      if (textures)
-         memset(textures, 0, sizeof(*textures) * NUM_NATIVE_ATTACHMENTS);
-   }
-
-   /* create textures for pbuffer */
-   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) {
-      struct pipe_screen *screen = dri2dpy->base.screen;
-
-      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
-         struct pipe_texture *ptex = dri2surf->pbuffer_textures[att];
-
-         /* delay the allocation */
-         if (!native_attachment_mask_test(attachment_mask, att))
-            continue;
-
-         if (!ptex) {
-            ptex = screen->texture_create(screen, &templ);
-            dri2surf->pbuffer_textures[att] = ptex;
-         }
-
-         if (textures)
-            pipe_texture_reference(&textures[att], ptex);
-      }
-
-      if (seq_num)
-         *seq_num = dri2surf->sequence_number;
-      if (width)
-         *width = dri2surf->width;
-      if (height)
-         *height = dri2surf->height;
-
-      return TRUE;
-   }
+   struct x11_drawable_buffer *xbufs;
+   struct pipe_texture templ;
+   uint valid_mask;
 
    /* prepare the attachments */
    num_ins = 0;
    for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
-      if (native_attachment_mask_test(attachment_mask, att)) {
+      if (native_attachment_mask_test(buffer_mask, att)) {
          unsigned int dri2att;
 
          switch (att) {
@@ -220,27 +139,39 @@ dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
       }
    }
 
-   dri2surf->have_back = FALSE;
-   dri2surf->have_fake = FALSE;
-
-   /* remember old geometry */
-   templ.width0 = dri2surf->width;
-   templ.height0 = dri2surf->height;
-
    xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
                                     &dri2surf->width, &dri2surf->height,
                                     dri2atts, FALSE, num_ins, &num_outs);
-   if (!xbufs)
-      return FALSE;
-
-   if (templ.width0 != dri2surf->width || templ.height0 != dri2surf->height) {
-      /* are there cases where the buffers change and the geometry doesn't? */
-      dri2surf->sequence_number++;
 
-      templ.width0 = dri2surf->width;
-      templ.height0 = dri2surf->height;
+   /* we should be able to do better... */
+   if (xbufs && dri2surf->last_num_xbufs == num_outs &&
+       memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
+      free(xbufs);
+      return;
    }
 
+   /* free the old buffers */
+   for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
+      pipe_texture_reference(&dri2surf->textures[i], NULL);
+   dri2surf->valid_mask = 0x0;
+   dri2surf->sequence_number++;
+
+   dri2surf->have_back = FALSE;
+   dri2surf->have_fake = FALSE;
+
+   if (!xbufs)
+      return;
+
+   memset(&templ, 0, sizeof(templ));
+   templ.target = PIPE_TEXTURE_2D;
+   templ.last_level = 0;
+   templ.width0 = dri2surf->width;
+   templ.height0 = dri2surf->height;
+   templ.depth0 = 1;
+   templ.format = dri2surf->color_format;
+   templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
+
+   valid_mask = 0x0;
    for (i = 0; i < num_outs; i++) {
       struct x11_drawable_buffer *xbuf = &xbufs[i];
       const char *desc;
@@ -266,33 +197,151 @@ dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
          break;
       }
 
-      if (!desc || !native_attachment_mask_test(attachment_mask, natt) ||
-          (textures && textures[natt])) {
+      if (!desc || dri2surf->textures[natt]) {
          if (!desc)
             _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
-         else if (!native_attachment_mask_test(attachment_mask, natt))
-            _eglLog(_EGL_WARNING, "unexpected buffer %d", xbuf->attachment);
          else
             _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
          continue;
       }
 
-      if (textures) {
-         struct pipe_texture *ptex =
-            dri2dpy->api->texture_from_shared_handle(dri2dpy->api,
-                  dri2dpy->base.screen, &templ,
-                  desc, xbuf->pitch, xbuf->name);
-         if (ptex) {
-            /* the caller owns the textures */
-            textures[natt] = ptex;
+      dri2surf->textures[natt] =
+         dri2dpy->api->texture_from_shared_handle(dri2dpy->api,
+               dri2dpy->base.screen, &templ, desc, xbuf->pitch, xbuf->name);
+      if (dri2surf->textures[natt])
+         valid_mask |= 1 << natt;
+   }
+
+   if (dri2surf->last_xbufs)
+      free(dri2surf->last_xbufs);
+   dri2surf->last_xbufs = xbufs;
+   dri2surf->last_num_xbufs = num_outs;
+
+   dri2surf->valid_mask = valid_mask;
+}
+
+/**
+ * Update the buffers of the surface.  This is a slow function due to the
+ * round-trip to the server.
+ */
+static boolean
+dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+
+   /* create textures for pbuffer */
+   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) {
+      struct pipe_screen *screen = dri2dpy->base.screen;
+      struct pipe_texture templ;
+      uint new_valid = 0x0;
+      int att;
+
+      buffer_mask &= ~dri2surf->valid_mask;
+      if (!buffer_mask)
+         return TRUE;
+
+      memset(&templ, 0, sizeof(templ));
+      templ.target = PIPE_TEXTURE_2D;
+      templ.last_level = 0;
+      templ.width0 = dri2surf->width;
+      templ.height0 = dri2surf->height;
+      templ.depth0 = 1;
+      templ.format = dri2surf->color_format;
+      templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
+
+      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
+         if (native_attachment_mask_test(buffer_mask, att)) {
+            assert(!dri2surf->textures[att]);
+
+            dri2surf->textures[att] = screen->texture_create(screen, &templ);
+            if (!dri2surf->textures[att])
+               break;
+
+            new_valid |= 1 << att;
+            if (new_valid == buffer_mask)
+               break;
          }
       }
+      dri2surf->valid_mask |= new_valid;
+      /* no need to update sequence number */
    }
+   else {
+      dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
+   }
+
+   return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
+}
+
+static boolean
+dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
 
-   free(xbufs);
+   /* pbuffer is private */
+   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER)
+      return TRUE;
+
+   /* copy to real front buffer */
+   if (dri2surf->have_fake)
+      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+            0, 0, dri2surf->width, dri2surf->height,
+            DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+
+   return TRUE;
+}
+
+static boolean
+dri2_surface_swap_buffers(struct native_surface *nsurf)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+
+   /* pbuffer is private */
+   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER)
+      return TRUE;
+
+   /* copy to front buffer */
+   if (dri2surf->have_back)
+      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+            0, 0, dri2surf->width, dri2surf->height,
+            DRI2BufferBackLeft, DRI2BufferFrontLeft);
+
+   /* and update fake front buffer */
+   if (dri2surf->have_fake)
+      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+            0, 0, dri2surf->width, dri2surf->height,
+            DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+
+   return TRUE;
+}
+
+static boolean
+dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+                      unsigned int *seq_num, struct pipe_texture **textures,
+                      int *width, int *height)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+
+   if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
+      return FALSE;
 
    if (seq_num)
       *seq_num = dri2surf->sequence_number;
+
+   if (textures) {
+      int att;
+      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
+         if (native_attachment_mask_test(attachment_mask, att)) {
+            struct pipe_texture *ptex = dri2surf->textures[att];
+
+            textures[att] = NULL;
+            pipe_texture_reference(&textures[att], ptex);
+         }
+      }
+   }
+
    if (width)
       *width = dri2surf->width;
    if (height)
@@ -320,8 +369,11 @@ dri2_surface_destroy(struct native_surface *nsurf)
    struct dri2_surface *dri2surf = dri2_surface(nsurf);
    int i;
 
+   if (dri2surf->last_xbufs)
+      free(dri2surf->last_xbufs);
+
    for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
-      struct pipe_texture *ptex = dri2surf->pbuffer_textures[i];
+      struct pipe_texture *ptex = dri2surf->textures[i];
       pipe_texture_reference(&ptex, NULL);
    }
 
@@ -345,9 +397,6 @@ dri2_display_create_surface(struct native_display *ndpy,
    if (!dri2surf)
       return NULL;
 
-   if (drawable)
-      x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
-
    dri2surf->dri2dpy = dri2dpy;
    dri2surf->type = type;
    dri2surf->drawable = drawable;
@@ -359,6 +408,9 @@ dri2_display_create_surface(struct native_display *ndpy,
    dri2surf->base.validate = dri2_surface_validate;
    dri2surf->base.wait = dri2_surface_wait;
 
+   if (drawable)
+      x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
+
    return dri2surf;
 }