Hi Nayan,

+   /* In case of a single gpu we need to get the
+    * handle and pixmap for the texture that is set
+    */
+   if (buffer && scrn->output_texture &&
+       !scrn->is_different_gpu)
+      allocate_new_buffer = true;
+

>So now the normal case i.e. single gpu case have to allocate new buffers and have X extension calls on each frame, which are still very expensive.

>Christian&Michel, any better ways ?

There are only a number of output surfaces taking turns as the mixer render targets, so we probably can use the same pixmap corresponding to each of output surface texture. We don't need to have X call for every frame. just use the right pixmap for right output texture when presentation.

Regards,
Leo




On 11/04/2016 04:00 PM, Leo Liu wrote:


On 11/04/2016 03:54 PM, Leo Liu wrote:


On 11/04/2016 02:45 PM, Nayan Deshmukh wrote:
dri3 allows us to send handle of a texture directly to X
so this patch allows a state tracker to directly send its
texture to X to be used as back buffer and avoids extra
copying

v2: use clip width/height to display a portion of the surface
v3: remove redundant variables, fix wrapping, rename variables
     handle vaapi path

Suggested-by: Leo Liu <leo....@amd.com>
Signed-off-by: Nayan Deshmukh <nayan26deshm...@gmail.com>
---
  src/gallium/auxiliary/vl/vl_winsys.h      |   4 +
src/gallium/auxiliary/vl/vl_winsys_dri3.c | 117 ++++++++++++++++++++++++++----
  2 files changed, 108 insertions(+), 13 deletions(-)

diff --git a/src/gallium/auxiliary/vl/vl_winsys.h b/src/gallium/auxiliary/vl/vl_winsys.h
index 26db9f2..908e9c6 100644
--- a/src/gallium/auxiliary/vl/vl_winsys.h
+++ b/src/gallium/auxiliary/vl/vl_winsys.h
@@ -59,6 +59,10 @@ struct vl_screen
     void *
     (*get_private)(struct vl_screen *vscreen);
  +   void
+ (*set_back_texture_from_output)(struct vl_screen *vscreen, struct pipe_resource *buffer,
+                         uint32_t width, uint32_t height);
+
     struct pipe_screen *pscreen;
     struct pipe_loader_device *dev;
  };
diff --git a/src/gallium/auxiliary/vl/vl_winsys_dri3.c b/src/gallium/auxiliary/vl/vl_winsys_dri3.c
index 2929928..9d0cd5a 100644
--- a/src/gallium/auxiliary/vl/vl_winsys_dri3.c
+++ b/src/gallium/auxiliary/vl/vl_winsys_dri3.c
@@ -31,6 +31,7 @@
  #include <X11/xshmfence.h>
  #include <xcb/dri3.h>
  #include <xcb/present.h>
+#include <xcb/xfixes.h>
    #include "loader.h"
  @@ -57,6 +58,7 @@ struct vl_dri3_buffer
       bool busy;
     uint32_t width, height, pitch;
+   uint32_t clip_width, clip_height;
  };
    struct vl_dri3_screen
@@ -71,6 +73,8 @@ struct vl_dri3_screen
     xcb_special_event_t *special_event;
       struct pipe_context *pipe;
+   struct pipe_resource *output_texture;
+   uint32_t clip_width, clip_height;

Sorry, maybe I haven't explained clear enough on "combine", quick hack on top of this patch, just for your reference.

--- a/src/gallium/auxiliary/vl/vl_winsys_dri3.c
+++ b/src/gallium/auxiliary/vl/vl_winsys_dri3.c
@@ -58,7 +58,6 @@ struct vl_dri3_buffer

    bool busy;
    uint32_t width, height, pitch;
-   uint32_t clip_width, clip_height;
 };

 struct vl_dri3_screen
@@ -241,33 +240,23 @@ dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
    templ.format = PIPE_FORMAT_B8G8R8X8_UNORM;
    templ.target = PIPE_TEXTURE_2D;
    templ.last_level = 0;
-   if (scrn->output_texture) {
-      buffer->clip_width = (scrn->clip_width) ? scrn->clip_width :
-                           scrn->width;
-      buffer->clip_height = (scrn->clip_height) ? scrn->clip_height :
-                            scrn->height;
-      templ.width0 = scrn->output_texture->width0;
-      templ.height0 = scrn->output_texture->height0;
-   } else {
-       templ.width0 = scrn->width;
-       templ.height0 = scrn->height;
-       buffer->clip_width = scrn->width;
-       buffer->clip_height = scrn->height;
-   }
+   templ.width0 = (scrn->output_texture) ?
+         scrn->output_texture->width0 : scrn->width;
+   templ.height0 = (scrn->output_texture) ?
+         scrn->output_texture->height0 : scrn->height;
    templ.depth0 = 1;
    templ.array_size = 1;

    if (scrn->is_different_gpu) {
       buffer->texture = (scrn->output_texture) ? scrn->output_texture :
- scrn->base.pscreen->resource_create(scrn->base.pscreen,
- &templ);
+ scrn->base.pscreen->resource_create(scrn->base.pscreen, &templ);
       if (!buffer->texture)
          goto unmap_shm;

       templ.bind |= PIPE_BIND_SCANOUT | PIPE_BIND_SHARED |
                     PIPE_BIND_LINEAR;
- buffer->linear_texture = scrn->base.pscreen->resource_create(scrn->base.pscreen,
- &templ);
+      buffer->linear_texture =
+ scrn->base.pscreen->resource_create(scrn->base.pscreen, &templ);
       pixmap_buffer_texture = buffer->linear_texture;

       if (!buffer->linear_texture)
@@ -275,8 +264,7 @@ dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
    } else {
       templ.bind |= PIPE_BIND_SCANOUT | PIPE_BIND_SHARED;
       buffer->texture = (scrn->output_texture) ? scrn->output_texture :
- scrn->base.pscreen->resource_create(scrn->base.pscreen,
- &templ);
+ scrn->base.pscreen->resource_create(scrn->base.pscreen, &templ);
       if (!buffer->texture)
          goto unmap_shm;
       pixmap_buffer_texture = buffer->texture;
@@ -373,15 +361,12 @@ dri3_get_back_buffer(struct vl_dri3_screen *scrn)
vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->cur_back]);
       buffer = new_buffer;
       scrn->back_buffers[scrn->cur_back] = buffer;
-   } else if (scrn->output_texture) {
+   } else if (scrn->output_texture)
       /* In case of different gpu we can reuse the linear
        * texture so we only need to set the external
        * texture for copying
        */
       buffer->texture = scrn->output_texture;
-      buffer->clip_width = scrn->clip_width;
-      buffer->clip_height = scrn->clip_height;
-   }

copy and paste missing part

    xcb_flush(scrn->conn);
@@ -564,8 +549,8 @@ vl_dri3_flush_frontbuffer(struct pipe_screen *screen,

    rectangle.x = 0;
    rectangle.y = 0;
-   rectangle.width = back->clip_width;
-   rectangle.height = back->clip_height;
+   rectangle.width = scrn->clip_width;
+   rectangle.height = scrn->clip_height;

    region = xcb_generate_id(scrn->conn);
    xcb_xfixes_create_region(scrn->conn, region, 2, &rectangle);
@@ -695,8 +680,8 @@ vl_dri3_screen_set_back_texture_from_output(struct vl_screen *vscreen,
    assert(scrn);

    scrn->output_texture = buffer;
-   scrn->clip_width = width;
-   scrn->clip_height = height;
+   scrn->clip_width = (width) ? width : scrn->width;
+   scrn->clip_height = (height) ? height : scrn->height;
 }


       struct vl_dri3_buffer *back_buffers[BACK_BUFFER_NUM];
     int cur_back;
@@ -105,7 +109,8 @@ dri3_free_back_buffer(struct vl_dri3_screen *scrn,
     xcb_free_pixmap(scrn->conn, buffer->pixmap);
     xcb_sync_destroy_fence(scrn->conn, buffer->sync_fence);
     xshmfence_unmap_shm(buffer->shm_fence);
-   pipe_resource_reference(&buffer->texture, NULL);
+   if (!scrn->output_texture)
+      pipe_resource_reference(&buffer->texture, NULL);
     if (buffer->linear_texture)
pipe_resource_reference(&buffer->linear_texture, NULL);
     FREE(buffer);
@@ -236,13 +241,25 @@ dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
     templ.format = PIPE_FORMAT_B8G8R8X8_UNORM;
     templ.target = PIPE_TEXTURE_2D;
     templ.last_level = 0;
-   templ.width0 = scrn->width;
-   templ.height0 = scrn->height;
+   if (scrn->output_texture) {
+      buffer->clip_width = (scrn->clip_width) ? scrn->clip_width :
+                           scrn->width;
+      buffer->clip_height = (scrn->clip_height) ? scrn->clip_height :
+                            scrn->height;
+      templ.width0 = scrn->output_texture->width0;
+      templ.height0 = scrn->output_texture->height0;
+   } else {
+       templ.width0 = scrn->width;
+       templ.height0 = scrn->height;
+       buffer->clip_width = scrn->width;
+       buffer->clip_height = scrn->height;
+   }
     templ.depth0 = 1;
     templ.array_size = 1;
       if (scrn->is_different_gpu) {
- buffer->texture = scrn->base.pscreen->resource_create(scrn->base.pscreen, + buffer->texture = (scrn->output_texture) ? scrn->output_texture :
+ scrn->base.pscreen->resource_create(scrn->base.pscreen,
&templ);
        if (!buffer->texture)
           goto unmap_shm;
@@ -257,7 +274,8 @@ dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
           goto no_linear_texture;
     } else {
        templ.bind |= PIPE_BIND_SCANOUT | PIPE_BIND_SHARED;
- buffer->texture = scrn->base.pscreen->resource_create(scrn->base.pscreen, + buffer->texture = (scrn->output_texture) ? scrn->output_texture :
+ scrn->base.pscreen->resource_create(scrn->base.pscreen,
&templ);
        if (!buffer->texture)
           goto unmap_shm;
@@ -271,11 +289,14 @@ dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
                                             usage);
     buffer_fd = whandle.handle;
     buffer->pitch = whandle.stride;
+   buffer->width = templ.width0;
+   buffer->height = templ.height0;
+
     xcb_dri3_pixmap_from_buffer(scrn->conn,
(pixmap = xcb_generate_id(scrn->conn)),
                                 scrn->drawable,
                                 0,
- scrn->width, scrn->height, buffer->pitch, + buffer->width, buffer->height, buffer->pitch,
                                 scrn->depth, 32,
                                 buffer_fd);
     xcb_dri3_fence_from_fd(scrn->conn,
@@ -287,8 +308,6 @@ dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
     buffer->pixmap = pixmap;
     buffer->sync_fence = sync_fence;
     buffer->shm_fence = shm_fence;
-   buffer->width = scrn->width;
-   buffer->height = scrn->height;
       xshmfence_trigger(buffer->shm_fence);
  @@ -310,6 +329,7 @@ dri3_get_back_buffer(struct vl_dri3_screen *scrn)
  {
     struct vl_dri3_buffer *buffer;
     struct pipe_resource *texture = NULL;
+   bool allocate_new_buffer = false;
       assert(scrn);
@@ -318,8 +338,28 @@ dri3_get_back_buffer(struct vl_dri3_screen *scrn)
        return NULL;
     buffer = scrn->back_buffers[scrn->cur_back];
  -   if (!buffer || buffer->width != scrn->width ||
-       buffer->height != scrn->height) {
+   /* This is normal case when our buffer is smaller
+    * than the screen this will be same for external
+    * texture
+    */
+   if (scrn->output_texture) {
+      if (!buffer || buffer->width < scrn->width ||
+          buffer->height < scrn->height)
+         allocate_new_buffer = true;
+   } else {
+      if (!buffer || buffer->width != scrn->width ||
+          buffer->height != scrn->height)
+         allocate_new_buffer = true;
+   }
+

Any better ways?

+   /* In case of a single gpu we need to get the
+    * handle and pixmap for the texture that is set
+    */
+   if (buffer && scrn->output_texture &&
+       !scrn->is_different_gpu)
+      allocate_new_buffer = true;
+

So now the normal case i.e. single gpu case have to allocate new buffers and have X extension calls on each frame, which are still very expensive.

Christian&Michel, any better ways ?

Regards,
Leo

+   if (allocate_new_buffer) {
        struct vl_dri3_buffer *new_buffer;
          new_buffer = dri3_alloc_back_buffer(scrn);
@@ -329,9 +369,18 @@ dri3_get_back_buffer(struct vl_dri3_screen *scrn)
        if (buffer)
           dri3_free_back_buffer(scrn, buffer);
  - vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->cur_back]);
+      if (!scrn->output_texture)
+ vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->cur_back]);
        buffer = new_buffer;
        scrn->back_buffers[scrn->cur_back] = buffer;
+   } else if (scrn->output_texture) {
+      /* In case of different gpu we can reuse the linear
+       * texture so we only need to set the external
+       * texture for copying
+       */
+      buffer->texture = scrn->output_texture;
+      buffer->clip_width = scrn->clip_width;
+      buffer->clip_height = scrn->clip_height;
     }
       pipe_resource_reference(&texture, buffer->texture);
@@ -500,6 +549,8 @@ vl_dri3_flush_frontbuffer(struct pipe_screen *screen,
     uint32_t options = XCB_PRESENT_OPTION_NONE;
     struct vl_dri3_buffer *back;
     struct pipe_box src_box;
+   xcb_xfixes_region_t region;
+   xcb_rectangle_t rectangle;
       back = scrn->back_buffers[scrn->cur_back];
     if (!back)
@@ -511,8 +562,16 @@ vl_dri3_flush_frontbuffer(struct pipe_screen *screen,
              return;
     }
  +   rectangle.x = 0;
+   rectangle.y = 0;
+   rectangle.width = back->clip_width;
+   rectangle.height = back->clip_height;
+
+   region = xcb_generate_id(scrn->conn);
+   xcb_xfixes_create_region(scrn->conn, region, 2, &rectangle);
+
     if (scrn->is_different_gpu) {
-      u_box_origin_2d(scrn->width, scrn->height, &src_box);
+      u_box_origin_2d(back->width, back->height, &src_box);
        scrn->pipe->resource_copy_region(scrn->pipe,
back->linear_texture,
                                         0, 0, 0, 0,
@@ -528,7 +587,7 @@ vl_dri3_flush_frontbuffer(struct pipe_screen *screen,
                        scrn->drawable,
                        back->pixmap,
                        (uint32_t)(++scrn->send_sbc),
-                      0, 0, 0, 0,
+                      0, region, 0, 0,
                        None, None,
                        back->sync_fence,
                        options,
@@ -627,6 +686,20 @@ vl_dri3_screen_get_private(struct vl_screen *vscreen)
  }
    static void
+vl_dri3_screen_set_back_texture_from_output(struct vl_screen *vscreen,
+ struct pipe_resource *buffer, + uint32_t width, uint32_t height)
+{
+   struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
+
+   assert(scrn);
+
+   scrn->output_texture = buffer;
+   scrn->clip_width = width;
+   scrn->clip_height = height;
+}
+
+static void
  vl_dri3_screen_destroy(struct vl_screen *vscreen)
  {
     struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
@@ -675,6 +748,9 @@ vl_dri3_screen_create(Display *display, int screen)
     xcb_dri3_open_reply_t *open_reply;
     xcb_get_geometry_cookie_t geom_cookie;
     xcb_get_geometry_reply_t *geom_reply;
+   xcb_xfixes_query_version_cookie_t xfixes_cookie;
+   xcb_xfixes_query_version_reply_t *xfixes_reply;
+   xcb_generic_error_t *error;
     int fd;
       assert(display);
@@ -689,12 +765,26 @@ vl_dri3_screen_create(Display *display, int screen)
       xcb_prefetch_extension_data(scrn->conn , &xcb_dri3_id);
     xcb_prefetch_extension_data(scrn->conn, &xcb_present_id);
+   xcb_prefetch_extension_data (scrn->conn, &xcb_xfixes_id);
     extension = xcb_get_extension_data(scrn->conn, &xcb_dri3_id);
     if (!(extension && extension->present))
        goto free_screen;
     extension = xcb_get_extension_data(scrn->conn, &xcb_present_id);
     if (!(extension && extension->present))
        goto free_screen;
+   extension = xcb_get_extension_data(scrn->conn, &xcb_xfixes_id);
+   if (!(extension && extension->present))
+      goto free_screen;
+
+ xfixes_cookie = xcb_xfixes_query_version(scrn->conn, XCB_XFIXES_MAJOR_VERSION,
+ XCB_XFIXES_MINOR_VERSION);
+ xfixes_reply = xcb_xfixes_query_version_reply(scrn->conn, xfixes_cookie, &error);
+   if (!xfixes_reply || error || xfixes_reply->major_version < 2) {
+      free(error);
+      free(xfixes_reply);
+      goto free_screen;
+   }
+   free(xfixes_reply);
open_cookie = xcb_dri3_open(scrn->conn, RootWindow(display, screen), None);
     open_reply = xcb_dri3_open_reply(scrn->conn, open_cookie, NULL);
@@ -744,6 +834,7 @@ vl_dri3_screen_create(Display *display, int screen)
     scrn->base.set_next_timestamp = vl_dri3_screen_set_next_timestamp;
     scrn->base.get_private = vl_dri3_screen_get_private;
     scrn->base.pscreen->flush_frontbuffer = vl_dri3_flush_frontbuffer;
+ scrn->base.set_back_texture_from_output = vl_dri3_screen_set_back_texture_from_output;
       return &scrn->base;

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev


_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to