[Mesa-dev] [PATCH 06/14] vl/dri3: add back buffers support

Axel Davy axel.davy at ens.fr
Wed May 11 18:53:26 UTC 2016


Again another comment for the same patch:

vl_dri3_screen_texture_from_drawable seem to call dri3_get_back_buffer 
in the !is_pixmap case.

If I understand dri3_get_back_buffer will puck an idle buffer of the 
buffer list.
Is it really what is expected ?

Shouldn't vl_dri3_screen_texture_from_drawable return a texture on the 
last back buffer sent instead ?
I don't know what vl_dri3_screen_texture_from_drawable is supposed to 
do, so perhaps I'm wrong.

On 11/05/2016 20:42, Axel Davy wrote:
> Another thing is that I think there is no guarantee the Xserver 
> releases all the pixmaps,
> and that it could keep one infinitely (until window destruction).
>
> Thus if the drawable is changed by the user, but the previous drawable 
> isn't destroyed by the user,
> one buffer can stay busy forever. Change several times of drawable and 
> you get stuck...
>
> I think the loader dri3 code suffers the same issues.
>
> For gallium nine, we use the following code:
> https://github.com/iXit/wine/blob/master/dlls/d3d9-nine/dri3.c#L739
> the code is a bit complicated because of thread safety, but likely you 
> don't need the thread safety part for you.
> Basically the idea is that when only one pixmap hasn't been released, 
> you send it again with the copy flag, which garantees it will get 
> released.
>
> Axel
>
> On 11/05/2016 20:29, Axel Davy wrote:
>> On 11/05/2016 17:06, Leo Liu wrote:
>>> This implements DRI3 PixmapFromBuffer. Create buffer objects, and
>>> associate it to a dma-buf fd, and then pass this fd with a pixmap
>>> ID to X server for creating pixmap object; also add a function
>>> for wait events.
>>>
>>> Signed-off-by: Leo Liu <leo.liu at amd.com>
>>> ---
>>>   src/gallium/auxiliary/vl/vl_winsys_dri3.c | 187 
>>> +++++++++++++++++++++++++++++-
>>>   1 file changed, 185 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/src/gallium/auxiliary/vl/vl_winsys_dri3.c 
>>> b/src/gallium/auxiliary/vl/vl_winsys_dri3.c
>>> index ef80730..e78ca07 100644
>>> --- a/src/gallium/auxiliary/vl/vl_winsys_dri3.c
>>> +++ b/src/gallium/auxiliary/vl/vl_winsys_dri3.c
>>> @@ -28,17 +28,35 @@
>>>   #include <fcntl.h>
>>>     #include <X11/Xlib-xcb.h>
>>> +#include <X11/xshmfence.h>
>>>   #include <xcb/dri3.h>
>>>   #include <xcb/present.h>
>>>     #include "loader.h"
>>>     #include "pipe/p_screen.h"
>>> +#include "pipe/p_state.h"
>>>   #include "pipe-loader/pipe_loader.h"
>>>     #include "util/u_memory.h"
>>> +#include "util/u_inlines.h"
>>> +
>>>   #include "vl/vl_winsys.h"
>>>   +#define BACK_BUFFER_NUM 3
>>> +
>>> +struct vl_dri3_buffer
>>> +{
>>> +   struct pipe_resource *texture;
>>> +
>>> +   uint32_t pixmap;
>>> +   uint32_t sync_fence;
>>> +   struct xshmfence *shm_fence;
>>> +
>>> +   bool busy;
>>> +   uint32_t width, height, pitch;
>>> +};
>>> +
>>>   struct vl_dri3_screen
>>>   {
>>>      struct vl_screen base;
>>> @@ -48,9 +66,23 @@ struct vl_dri3_screen
>>>      uint32_t width, height, depth;
>>>        xcb_special_event_t *special_event;
>>> +
>>> +   struct vl_dri3_buffer *back_buffers[BACK_BUFFER_NUM];
>>> +   int cur_back;
>>>   };
>>>     static void
>>> +dri3_free_back_buffer(struct vl_dri3_screen *scrn,
>>> +                        struct vl_dri3_buffer *buffer)
>>> +{
>>> +   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);
>>> +   FREE(buffer);
>>> +}
>>> +
>>> +static void
>>>   dri3_handle_present_event(struct vl_dri3_screen *scrn,
>>>                             xcb_present_generic_event_t *ge)
>>>   {
>>> @@ -83,6 +115,145 @@ dri3_flush_present_events(struct vl_dri3_screen 
>>> *scrn)
>>>   }
>>>     static bool
>>> +dri3_wait_present_events(struct vl_dri3_screen *scrn)
>>> +{
>>> +   if (scrn->special_event) {
>>> +      xcb_generic_event_t *ev;
>>> +      ev = xcb_wait_for_special_event(scrn->conn, 
>>> scrn->special_event);
>>> +      if (!ev)
>>> +         return false;
>>> +      dri3_handle_present_event(scrn, (xcb_present_generic_event_t 
>>> *)ev);
>>> +      return true;
>>> +   }
>>> +   return false;
>>> +}
>>> +
>>> +static int
>>> +dri3_find_back(struct vl_dri3_screen *scrn)
>>> +{
>>> +   int b;
>>> +
>>> +   for (;;) {
>>> +      for (b = 0; b < BACK_BUFFER_NUM; b++) {
>>> +         int id = (b + scrn->cur_back) % BACK_BUFFER_NUM;
>>> +         struct vl_dri3_buffer *buffer = scrn->back_buffers[id];
>>> +         if (!buffer || !buffer->busy)
>>> +            return id;
>>> +      }
>>> +      xcb_flush(scrn->conn);
>>> +      if (!dri3_wait_present_events(scrn))
>>> +         return -1;
>>> +   }
>>> +}
>>> +
>>> +static struct vl_dri3_buffer *
>>> +dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
>>> +{
>>> +   struct vl_dri3_buffer *buffer;
>>> +   xcb_pixmap_t pixmap;
>>> +   xcb_sync_fence_t sync_fence;
>>> +   struct xshmfence *shm_fence;
>>> +   int buffer_fd, fence_fd;
>>> +   struct pipe_resource templ;
>>> +   struct winsys_handle whandle;
>>> +   unsigned usage;
>>> +
>>> +   buffer = CALLOC_STRUCT(vl_dri3_buffer);
>>> +   if (!buffer)
>>> +      return NULL;
>>> +
>>> +   fence_fd = xshmfence_alloc_shm();
>>> +   if (fence_fd < 0)
>>> +      goto free_buffer;
>>> +
>>> +   shm_fence = xshmfence_map_shm(fence_fd);
>>> +   if (!shm_fence)
>>> +      goto close_fd;
>>> +
>>> +   memset(&templ, 0, sizeof(templ));
>>> +   templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
>>> +                PIPE_BIND_SCANOUT | PIPE_BIND_SHARED;
>>> +   templ.format = PIPE_FORMAT_B8G8R8X8_UNORM;
>>> +   templ.target = PIPE_TEXTURE_2D;
>>> +   templ.last_level = 0;
>>> +   templ.width0 = scrn->width;
>>> +   templ.height0 = scrn->height;
>>> +   templ.depth0 = 1;
>>> +   templ.array_size = 1;
>>> +   buffer->texture = 
>>> scrn->base.pscreen->resource_create(scrn->base.pscreen,
>>> + &templ);
>>> +   if (!buffer->texture)
>>> +      goto unmap_shm;
>>> +
>>> +   memset(&whandle, 0, sizeof(whandle));
>>> +   whandle.type= DRM_API_HANDLE_TYPE_FD;
>>> +   usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ;
>> Here using
>>
>> PIPE_HANDLE_USAGE_EXPLICIT_FLUSH
>>
>>  is wrong. Both vaapi and vdpau don't call flush_resource.
>>
>> Perhaps vaapi and vdpau can get fixed to call it, I don't know which 
>> is best
>> for the target usage of the resources.
>>> + scrn->base.pscreen->resource_get_handle(scrn->base.pscreen,
>>> + buffer->texture, &whandle,
>>> +                                           usage);
>>> +   buffer_fd = whandle.handle;
>>> +   buffer->pitch = whandle.stride;
>>> +   xcb_dri3_pixmap_from_buffer(scrn->conn,
>>> +                               (pixmap = xcb_generate_id(scrn->conn)),
>>> +                               scrn->drawable,
>>> +                               0,
>>> +                               scrn->width, scrn->height, 
>>> buffer->pitch,
>>> +                               scrn->depth, 32,
>>> +                               buffer_fd);
>>> +   xcb_dri3_fence_from_fd(scrn->conn,
>>> +                          pixmap,
>>> +                          (sync_fence = xcb_generate_id(scrn->conn)),
>>> +                          false,
>>> +                          fence_fd);
>>> +
>>> +   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);
>>> +
>>> +   return buffer;
>>> +
>>> +unmap_shm:
>>> +   xshmfence_unmap_shm(shm_fence);
>>> +close_fd:
>>> +   close(fence_fd);
>>> +free_buffer:
>>> +   FREE(buffer);
>>> +   return NULL;
>>> +}
>>> +
>>> +static struct vl_dri3_buffer *
>>> +dri3_get_back_buffer(struct vl_dri3_screen *scrn)
>>> +{
>>> +   struct vl_dri3_buffer *buffer;
>>> +   struct pipe_resource *texture = NULL;
>>> +
>>> +   assert(scrn);
>>> +
>>> +   scrn->cur_back = dri3_find_back(scrn);
>>> +   if (scrn->cur_back < 0)
>>> +      return NULL;
>>> +   buffer = scrn->back_buffers[scrn->cur_back];
>>> +
>>> +   if (!buffer) {
>>> +      buffer = dri3_alloc_back_buffer(scrn);
>>> +      if (!buffer)
>>> +         return NULL;
>>> +
>>> +      scrn->back_buffers[scrn->cur_back] = buffer;
>>> +   }
>>> +
>>> +   pipe_resource_reference(&texture, buffer->texture);
>>> +   xcb_flush(scrn->conn);
>>> +   xshmfence_await(buffer->shm_fence);
>>> +
>>> +   return buffer;
>>> +}
>>> +
>>> +static bool
>>>   dri3_set_drawable(struct vl_dri3_screen *scrn, Drawable drawable)
>>>   {
>>>      xcb_get_geometry_cookie_t geom_cookie;
>>> @@ -147,14 +318,18 @@ static struct pipe_resource *
>>>   vl_dri3_screen_texture_from_drawable(struct vl_screen *vscreen, 
>>> void *drawable)
>>>   {
>>>      struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
>>> +   struct vl_dri3_buffer *buffer;
>>>        assert(scrn);
>>>        if (!dri3_set_drawable(scrn, (Drawable)drawable))
>>>         return NULL;
>>>   -   /* TODO */
>>> -   return NULL;
>>> +   buffer = dri3_get_back_buffer(scrn);
>>> +   if (!buffer)
>>> +      return NULL;
>>> +
>>> +   return buffer->texture;
>>>   }
>>>     static struct u_rect *
>>> @@ -188,11 +363,19 @@ static void
>>>   vl_dri3_screen_destroy(struct vl_screen *vscreen)
>>>   {
>>>      struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
>>> +   int i;
>>>        assert(vscreen);
>>>        dri3_flush_present_events(scrn);
>>>   +   for (i = 0; i < BACK_BUFFER_NUM; ++i) {
>>> +      if (scrn->back_buffers[i]) {
>>> +         dri3_free_back_buffer(scrn, scrn->back_buffers[i]);
>>> +         scrn->back_buffers[i] = NULL;
>>> +      }
>>> +   }
>>> +
>>>      if (scrn->special_event)
>>>         xcb_unregister_for_special_event(scrn->conn, 
>>> scrn->special_event);
>>>      scrn->base.pscreen->destroy(scrn->base.pscreen);
>>
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
>
> _______________________________________________
> 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