[Mesa-dev] [PATCH v3] vl/dri3: use external texture as back buffers(v3)

Leo Liu leo.liu at amd.com
Fri Nov 4 20:48:43 UTC 2016


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.liu at amd.com>
>>> Signed-off-by: Nayan Deshmukh <nayan26deshmukh at 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 at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>



More information about the mesa-dev mailing list