[waffle] [RFC] Add display support to GBM backend

Frank Henigman fjhenigman at chromium.org
Fri Dec 12 12:21:21 PST 2014


On Wed, Nov 19, 2014 at 2:38 PM, Chad Versace <chad.versace at intel.com> wrote:
> Frank sent this patch as a proof-of-concept. It's a draft, and not ready for
> committing. I'm posting to the list just to start discussion.
>
> See [https://github.com/waffle-gl/waffle/issues/18]. I think detailed patch
> discussions like this are easier over email than Github's issue tracker, so
> let's keep the bulk of the discussion in email.
>
> Frank, I haven't examined every detail in this patch. I focused on the
> high-level design.  I'll probably wait to examine the fine details until you
> submit a real patch for upstreaming.
>
>> From: Frank Henigman <fjhenigman at chromium.org>
>> Date: Tue, 21 Oct 2014 22:58:45 -0400
>> Subject: [PATCH] gbm WIP: show gbm buffers on screen
>>
>> Four options based on the value of environment variable MODE:
>> COPY: copy render buffer to scanout buffer and flip to scanout buffer
>> FLIP: scan out directly from render buffer
>> ORIG: do what the code originally did, i.e. nothing
>> unset or empty: don't display, but still lock and release buffer
>>
>> TO DO
>> - make it a compile time option
>> - make it a proper run time option, via config attributes or something,
>>   instead of by env var
>
>
> I prefer to make the display-mode a runtime option via attributes to
> waffle_window. Perhaps we should define a new function:
>
>    struct waffle_window*
>    waffle_window_create_attrs(struct waffle_config *config,
>                               const intptr_t attrib_list[]);
>
>> - leave hooks and graceful fails for (as yet) unsupported drm drivers,
>>   currently only i915 is supported
>
>
> If initially the only supported driver is i915, that's ok with me. We have
> to start somewhere, and I don't like waiting for perfect completeness.
>
>> - address all XXX in code
>> ---
>>  cmake/Modules/WaffleFindDependencies.cmake |   1 +
>>  include/waffle/waffle_gbm.h                |   1 +
>>  src/waffle/CMakeLists.txt                  |   2 +
>>  src/waffle/gbm/wgbm_display.h              |   2 +
>>  src/waffle/gbm/wgbm_platform.c             |   2 +-
>>  src/waffle/gbm/wgbm_window.c               | 394
>> ++++++++++++++++++++++++++++-
>>  src/waffle/gbm/wgbm_window.h               |   3 +
>>  7 files changed, 402 insertions(+), 3 deletions(-)
>>
>> diff --git a/cmake/Modules/WaffleFindDependencies.cmake
>> b/cmake/Modules/WaffleFindDependencies.cmake
>> index 9245772..a35ac8f 100644
>> --- a/cmake/Modules/WaffleFindDependencies.cmake
>> +++ b/cmake/Modules/WaffleFindDependencies.cmake
>> @@ -79,4 +79,5 @@ if(waffle_on_linux)
>>      # waffle_has_gbm
>>      waffle_pkg_config(gbm gbm)
>>      waffle_pkg_config(libudev libudev)
>> +    waffle_pkg_config(libdrm libdrm)
>>  endif()
>> diff --git a/include/waffle/waffle_gbm.h b/include/waffle/waffle_gbm.h
>> index fe45343..c9e4691 100644
>> --- a/include/waffle/waffle_gbm.h
>> +++ b/include/waffle/waffle_gbm.h
>> @@ -41,6 +41,7 @@ struct gbm_surface;
>>   struct waffle_gbm_display {
>>      struct gbm_device *gbm_device;
>> +    struct waffle_drm_display *drm_display;
>>      EGLDisplay egl_display;
>>  };
>>  diff --git a/src/waffle/CMakeLists.txt b/src/waffle/CMakeLists.txt
>> index 0e42192..4866dfb 100644
>> --- a/src/waffle/CMakeLists.txt
>> +++ b/src/waffle/CMakeLists.txt
>> @@ -23,6 +23,7 @@ include_directories(
>>      ${gbm_INCLUDE_DIRS}
>>      ${gl_INCLUDE_DIRS}
>>      ${libudev_INCLUDE_DIRS}
>> +    ${libdrm_INCLUDE_DIRS}
>>      ${wayland-client_INCLUDE_DIRS}
>>      ${wayland-egl_INCLUDE_DIRS}
>>      ${x11-xcb_INCLUDE_DIRS}
>> @@ -58,6 +59,7 @@ if(waffle_on_linux)
>>          list(APPEND waffle_libdeps
>>              ${gbm_LDFLAGS}
>>              ${libudev_LDFLAGS}
>> +            ${libdrm_LDFLAGS}
>>              )
>>      endif()
>>  endif()
>> diff --git a/src/waffle/gbm/wgbm_display.h b/src/waffle/gbm/wgbm_display.h
>> index ba4bb89..59d295a 100644
>> --- a/src/waffle/gbm/wgbm_display.h
>> +++ b/src/waffle/gbm/wgbm_display.h
>> @@ -34,10 +34,12 @@
>>   struct wcore_platform;
>>  struct gbm_device;
>> +struct drm_display;
>>   struct wgbm_display {
>>      struct gbm_device *gbm_device;
>>      struct wegl_display wegl;
>> +    struct drm_display *drm_display;
>>  };
>>   static inline struct wgbm_display*
>> diff --git a/src/waffle/gbm/wgbm_platform.c
>> b/src/waffle/gbm/wgbm_platform.c
>> index 5624660..d556145 100644
>> --- a/src/waffle/gbm/wgbm_platform.c
>> +++ b/src/waffle/gbm/wgbm_platform.c
>> @@ -156,7 +156,7 @@ static const struct wcore_platform_vtbl
>> wgbm_platform_vtbl = {
>>          .create = wgbm_window_create,
>>          .destroy = wgbm_window_destroy,
>>          .show = wgbm_window_show,
>> -        .swap_buffers = wegl_window_swap_buffers,
>> +        .swap_buffers = wgbm_window_swap_buffers,
>>          .get_native = wgbm_window_get_native,
>>      },
>>  };
>> diff --git a/src/waffle/gbm/wgbm_window.c b/src/waffle/gbm/wgbm_window.c
>> index 85378da..2a889f4 100644
>> --- a/src/waffle/gbm/wgbm_window.c
>> +++ b/src/waffle/gbm/wgbm_window.c
>> @@ -25,11 +25,16 @@
>>   #define __GBM__ 1
>>  +#include <errno.h>
>>  #include <stdlib.h>
>>  #include <string.h>
>>   #include <gbm.h>
>>  +#include <xf86drm.h>
>> +#include <xf86drmMode.h>
>> +#include <i915_drm.h>
>> +
>>  #include "waffle_gbm.h"
>>   #include "wcore_error.h"
>> @@ -72,9 +77,13 @@ wgbm_window_create(struct wcore_platform *wc_plat,
>>       gbm_format = wgbm_config_get_gbm_format(&wc_config->attrs);
>>      assert(gbm_format != 0);
>> +    uint32_t flags = GBM_BO_USE_RENDERING;
>> +    //XXX display or window config, not env var
>> +    char *mode = getenv("MODE");
>> +    if (mode && mode[0] == 'F')
>> +        flags |= GBM_BO_USE_SCANOUT;
>>      self->gbm_surface = gbm_surface_create(dpy->gbm_device, width,
>> height,
>> -                                           gbm_format,
>> -                                           GBM_BO_USE_RENDERING);
>> +                                           gbm_format, flags);
>>      if (!self->gbm_surface) {
>>          wcore_errorf(WAFFLE_ERROR_UNKNOWN,
>>                       "gbm_surface_create failed");
>> @@ -100,6 +109,387 @@ wgbm_window_show(struct wcore_window *wc_self)
>>      return true;
>>  }
>>  +// i915
>> +struct drm_display {
>> +    int fd;
>> +    bool setcrtc_done;
>> +    struct buffer *flip_pending;
>> +    struct buffer *on_screen;
>> +
>> +    drmModeConnectorPtr conn;
>> +    drmModeModeInfoPtr mode;
>> +    drmModeCrtcPtr crtc;
>> +
>> +    // not used when scanning out from render buffers
>> +    struct buffer *front;
>> +    struct buffer *back;
>> +    void *tmp;
>> +};
>> +
>> +struct buffer {
>
>
> Let's be more descriptive with this typename. How about "struct wgbm_buffer"
> or
> "struct wgbm_surface"?
>
>> +    struct wgbm_display *dpy;
>> +    struct gbm_surface *surface;
>> +    struct gbm_bo *bo;
>> +    bool has_framebuffer;
>> +    uint32_t framebuffer_id;
>> +};
>> +
>> +static drmModeModeInfoPtr
>> +choose_mode(drmModeConnectorPtr conn)
>> +{
>> +    drmModeModeInfoPtr mode = NULL;
>> +    if (!conn)
>> +        return NULL;
>> +    if (conn->connection != DRM_MODE_CONNECTED)
>> +        return NULL;
>> +    for (int i = 0; i < conn->count_modes; ++i) {
>> +        mode = conn->modes + i;
>> +        if (mode->type & DRM_MODE_TYPE_PREFERRED)
>> +            return mode;
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static int
>> +choose_crtc(int drmfd, unsigned count_crtcs, drmModeConnectorPtr conn)
>> +{
>> +    drmModeEncoderPtr enc = 0;
>> +    for (int i = 0; i < conn->count_encoders; ++i) {
>> +        drmModeFreeEncoder(enc);
>> +        enc = drmModeGetEncoder(drmfd, conn->encoders[i]);
>> +        unsigned b = enc->possible_crtcs;
>> +        drmModeFreeEncoder(enc);
>> +        for (int j = 0; b && j < count_crtcs; b >>= 1, ++j) {
>> +            if (b & 1)
>> +                return j;
>> +        }
>> +    }
>> +    return -1;
>> +}
>> +
>> +static void
>> +drm_mode_init(struct drm_display *drm)
>> +{
>> +    drm->conn = NULL;
>> +    drmModeResPtr mr = drmModeGetResources(drm->fd);
>> +    for (int i = 0; i < mr->count_connectors; ++i) {
>> +        drmModeFreeConnector(drm->conn);
>> +        drm->conn = drmModeGetConnector(drm->fd, mr->connectors[i]);
>> +        drm->mode = choose_mode(drm->conn);
>> +        if (!drm->mode)
>> +            continue;
>> +        int n = choose_crtc(drm->fd, mr->count_crtcs, drm->conn);
>> +        if (n < 0)
>> +            continue;
>> +        drm->crtc = drmModeGetCrtc(drm->fd, mr->crtcs[n]);
>> +        if (drm->crtc)
>> +            return;
>> +    }
>> +    drmModeFreeConnector(drm->conn);
>> +    drm->conn = NULL;
>> +    drm->mode = NULL;
>> +}
>> +
>> +static bool
>> +buffer_add_framebuffer(struct buffer *buffer)
>> +{
>> +    struct drm_display *drm = buffer->dpy->drm_display;
>> +
>> +    if (!buffer->has_framebuffer) {
>> +        buffer->has_framebuffer = -1;
>> +        switch(gbm_bo_get_format(buffer->bo)) {
>> +            case GBM_FORMAT_XRGB8888:
>> +            case GBM_FORMAT_ABGR8888:
>> +                break;
>> +            default:
>> +                wcore_errorf(WAFFLE_ERROR_UNKNOWN, "unexpected gbm
>> format");
>> +                return false;
>> +        }
>> +        if (drmModeAddFB(drm->fd,
>> +                         drm->mode->hdisplay,
>> +                         drm->mode->vdisplay,
>> +                         24, 32,
>> +                         gbm_bo_get_stride(buffer->bo),
>> +                         gbm_bo_get_handle(buffer->bo).u32,
>> +                         &buffer->framebuffer_id)) {
>> +            wcore_errorf(WAFFLE_ERROR_UNKNOWN, "drm add fb failed: %s",
>> +                         strerror(errno));
>> +            return false;
>> +        }
>> +        buffer->has_framebuffer = 1;
>> +    }
>> +    return buffer->has_framebuffer == 1;
>> +}
>> +
>> +static struct drm_display*
>> +drm_display_init(struct wgbm_display *dpy)
>> +{
>> +    //XXX probably want to do this early so we get the screen size, use
>> it for window size, decide on GBM_BO_USE_SCANOUT, fail earlier - but that is
>> a big change, wait until we decide to upstream
>>
> As you note in the comment, this function should get called earlier. I think
> waffle_display_connect() should call it, because waffle_display_connect() is
> where Waffle decides the filepath to the DRI device.
>
> Also, this code is display-related rather than window-related, it should go
> into wgbm_display.c along with wgbm_display_connect().
>
>> +    //XXX free - that will belong in display file, along with earlier
>> init - wait until we decide to upstream
>> +    if (!dpy->drm_display) {
>> +        dpy->drm_display = wcore_calloc(sizeof(*dpy->drm_display));
>> +        if (dpy->drm_display) {
>> +            dpy->drm_display->fd = gbm_device_get_fd(dpy->gbm_device);
>> +            dpy->drm_display->setcrtc_done = false;
>> +            //XXX free drm mode, connector, crtc ...
>> +            drm_mode_init(dpy->drm_display);
>> +        }
>> +    }
>> +    return dpy->drm_display;
>> +}
>> +
>> +// called after page flip
>> +static void
>> +page_flip_handler(int fd,
>> +                  unsigned int sequence,
>> +                  unsigned int tv_sec,
>> +                  unsigned int tv_usec,
>> +                  void *user_data)
>> +{
>> +    struct drm_display *drm = (struct drm_display *) user_data;
>> +    assert(drm->flip_pending);
>> +    if (drm->on_screen && drm->on_screen->surface)
>> +        gbm_surface_release_buffer(drm->on_screen->surface,
>> drm->on_screen->bo);
>> +    drm->on_screen = drm->flip_pending;
>> +    drm->flip_pending = NULL;
>> +}
>> +
>> +// scanout from buffer
>> +static bool
>> +buffer_flip(struct buffer *buffer)
>> +{
>> +    struct drm_display *drm = drm_display_init(buffer->dpy);
>> +    if (!drm || !drm->mode)
>> +        return false;
>> +
>> +    if (gbm_bo_get_width(buffer->bo) < drm->mode->hdisplay ||
>> +        gbm_bo_get_height(buffer->bo) < drm->mode->vdisplay) {
>> +        wcore_errorf(WAFFLE_ERROR_UNKNOWN,
>> +                     "cannot flip buffer smaller than screen");
>
>
>    This error message got me thinking... Maybe waffle_window_create() should
>    interpret (w,h)=(-1,-1) as a fullscreen window.
>
>> +        return false;
>> +    }
>> +
>> +    if (!buffer_add_framebuffer(buffer))
>> +        return false;
>> +
>> +    if (!drm->setcrtc_done) {
>> +        drm->setcrtc_done = true;
>> +        if (drmModeSetCrtc(drm->fd, drm->crtc->crtc_id,
>> buffer->framebuffer_id,
>> +                           0, 0, &drm->conn->connector_id, 1, drm->mode))
>> {
>> +            wcore_errorf(WAFFLE_ERROR_UNKNOWN, "drm setcrtc failed: %s",
>> +                         strerror(errno));
>> +            return false;
>> +        }
>> +    }
>> +
>> +    // if flip is pending, wait for it to complete
>
>
> Right. The default behavior should be to stall on pending page flips. If
> some
> use-case really wants an unthrottled, triple-buffered implementation of
> swapBuffers, then we can add that to Waffle later.
>
>> +    if (drm->flip_pending) {
>> +        drmEventContext event = {
>> +            .version = DRM_EVENT_CONTEXT_VERSION,
>> +            .page_flip_handler = page_flip_handler,
>> +        };
>> +        drmHandleEvent(drm->fd, &event);
>> +    }
>> +
>> +    drm->flip_pending = buffer;
>> +    if (drmModePageFlip(drm->fd, drm->crtc->crtc_id,
>> buffer->framebuffer_id,
>> +                        DRM_MODE_PAGE_FLIP_EVENT, drm)) {
>> +        wcore_errorf(WAFFLE_ERROR_UNKNOWN, "drm page flip failed: %s",
>> +                     strerror(errno));
>> +        return false;
>> +    }
>> +
>> +    return true;
>> +}
>> +
>> +static void
>> +buffer_free_from_gbm_bo(struct gbm_bo *bo, void *ptr)
>> +{
>> +    struct buffer *buffer = (struct buffer *) ptr;
>> +    if (buffer->has_framebuffer)
>> +        drmModeRmFB(buffer->dpy->drm_display->fd,
>> buffer->framebuffer_id);
>> +    free(buffer);
>> +}
>> +
>> +static struct buffer*
>> +buffer_wrap_gbm_bo(struct wgbm_display *dpy, struct gbm_surface *surface,
>> +                    struct gbm_bo *bo)
>> +{
>> +    void *ud = gbm_bo_get_user_data(bo);
>> +    struct buffer *buffer;
>> +    if (ud) {
>> +        buffer = (struct buffer *)ud;
>> +    } else {
>> +        buffer = wcore_calloc(sizeof(*buffer));
>> +        if (buffer) {
>> +            buffer->dpy = dpy;
>> +            buffer->surface = surface;
>> +            buffer->bo = bo;
>> +            buffer->has_framebuffer = false;
>> +            gbm_bo_set_user_data(bo, buffer, buffer_free_from_gbm_bo);
>> +        }
>> +    }
>> +    return buffer;
>> +}
>> +
>> +static struct buffer*
>> +buffer_create_for_scanout(struct wgbm_display *dpy, uint32_t format)
>> +{
>> +    struct drm_display *drm = dpy->drm_display;
>> +    struct gbm_bo *bo = gbm_bo_create(dpy->gbm_device,
>> +                                      drm->mode->hdisplay,
>> +                                      drm->mode->vdisplay,
>> +                                      format,
>> +                                      GBM_BO_USE_SCANOUT);
>> +    if (!bo)
>> +        return NULL;
>> +    return buffer_wrap_gbm_bo(dpy, NULL, bo);
>> +}
>> +
>> +#define MIN(a,b) ((a)<(b)?(a):(b))
>> +
>> +static bool
>> +buffer_copy(struct buffer *dst, struct buffer *src)
>> +{
>> +    struct drm_display *drm = dst->dpy->drm_display;
>> +    struct drm_i915_gem_get_tiling dst_tiling = {
>> +        .handle = gbm_bo_get_handle(dst->bo).u32,
>> +    };
>> +    struct drm_i915_gem_get_tiling src_tiling = {
>> +        .handle = gbm_bo_get_handle(src->bo).u32,
>> +    };
>> +
>> +    if (drmIoctl(drm->fd, DRM_IOCTL_I915_GEM_GET_TILING, &dst_tiling) ||
>> +        drmIoctl(drm->fd, DRM_IOCTL_I915_GEM_GET_TILING, &src_tiling))
>> +        return false;
>> +
>> +    if (dst_tiling.tiling_mode != src_tiling.tiling_mode)
>> +        return false;
>> +
>> +    unsigned rows;
>> +    switch (dst_tiling.tiling_mode) {
>> +        case I915_TILING_NONE:
>> +            rows = 1;
>> +            break;
>> +        case I915_TILING_X:
>> +            rows = 8;
>> +            break;
>> +        default:
>> +            return false;
>> +    }
>> +
>> +    unsigned src_step = gbm_bo_get_stride(src->bo) * rows;
>> +    unsigned dst_step = gbm_bo_get_stride(dst->bo) * rows;
>> +    unsigned copy_size = MIN(src_step, dst_step);
>> +    // round up, not down, or we miss the last partly filled tile
>> +    unsigned num_copy = (MIN(gbm_bo_get_height(src->bo),
>> +                             gbm_bo_get_height(dst->bo)) + rows - 1) /
>> rows;
>> +
>> +
>> +    void *tmp = malloc(copy_size);
>> +    if (!tmp)
>> +        return false;
>> +
>> +    struct drm_i915_gem_pread pread = {
>> +        .handle = gbm_bo_get_handle(src->bo).u32,
>> +        .size = copy_size,
>> +        .offset = 0,
>> +        .data_ptr = (uint64_t) (uintptr_t) tmp,
>> +    };
>> +
>> +    struct drm_i915_gem_pwrite pwrite = {
>> +        .handle = gbm_bo_get_handle(dst->bo).u32,
>> +        .size = copy_size,
>> +        .offset = 0,
>> +        .data_ptr = (uint64_t) (uintptr_t) tmp,
>> +    };
>> +
>> +    // blit on gpu must be faster than this, but seems complicated to do
>> +    bool success = true;
>> +    for (unsigned i = 0; success && i < num_copy; ++i) {
>> +        success = !(drmIoctl(drm->fd, DRM_IOCTL_I915_GEM_PREAD, &pread)
>> ||
>> +                    drmIoctl(drm->fd, DRM_IOCTL_I915_GEM_PWRITE,
>> &pwrite));
>> +        pread.offset += src_step;
>> +        pwrite.offset += dst_step;
>> +    }
>> +    free(tmp);
>> +    return success;
>> +}
>> +
>> +// copy to back buffer and flip buffers
>> +static bool
>> +copy_and_flip(struct buffer *buffer)
>> +{
>> +    struct drm_display *drm = drm_display_init(buffer->dpy);
>> +
>> +    if (!drm || !drm->mode)
>> +        return false;
>> +
>> +    if (!drm->back) {
>> +        uint32_t format = gbm_bo_get_format(buffer->bo);
>> +        //XXX free
>> +        drm->back = buffer_create_for_scanout(buffer->dpy, format);
>> +        drm->front = buffer_create_for_scanout(buffer->dpy, format);
>> +    }
>> +    if (!drm->back || !drm->front) {
>> +        return false;
>> +    }
>> +
>> +    bool ok = buffer_copy(drm->back, buffer) && buffer_flip(drm->back);
>> +    struct buffer *tmp = drm->back;
>> +    drm->back = drm->front;
>> +    drm->front = tmp;
>> +    gbm_surface_release_buffer(buffer->surface, buffer->bo);
>> +    return ok;
>> +}
>> +
>> +
>> +bool
>> +wgbm_window_swap_buffers(struct wcore_window *wc_self)
>> +{
>> +    //XXX detect driver before invoking driver-specific code -
>> gbm_device_get_backend_name() doesn't help, it returns "drm"
>> +
>> +    if (!wegl_window_swap_buffers(wc_self))
>> +        return false;
>> +
>> +    //XXX display or window config, not env var
>> +    // O:original, possibly buggy behavior (no lock/release), F:flip,
>> C:copy
>> +    // otherwise: no display (but still lock/release)
>
>
> Regarding MODE="O", Waffle now does lock/release for
> wgbm_window_swap_buffers.
> Let's make MODE="O" be equivalent to MODE="", which selects the default
> behavior:
> lock/release but don't post to display.
>
> Of course, we need better names than "O", "F", and "C". Assuming that we
> associate these attributes with window and not the display (which might be
> a bad assumption), how do these names sound to you?
>
>    name: WAFFLE_GBM_WINDOW_DISPLAY_MODE
>    values:
>        WAFFLE_GBM_WINDOW_DISPLAY_NONE (default)
>        WAFFLE_GBM_WINDOW_DISPLAY_FLIP
>        WAFFLE_GBM_WINDOW_DISPLAY_COPY
>
> Question: Why do you want COPY mode? Is the purpose to exercise the
> implementation pattern of Chrome's partial display update?

Unless I'm mistaken it's the only way (on i915 at least) to have a
window smaller than full screen.  FLIP will scan out of the same
buffers we render into, and it looks like i915 requires the scan out
buffer to be >= the mode size.  In COPY mode you can have any size
render buffer and it gets copied (and clipped to) the scan out buffer.
Maybe this doesn't need to be a user-settable option.  We could always
copy, and maybe detect the full screen case and then use flipping.
I've assumed double buffering, is that ok?  It looks like waffle
doesn't have a way to request single buffering.

> Question: Do you think these display-mode attributes should be associated
> with
> the waffle_display or waffle_window? I'm leaning towards the window, because
> I see no reason to prevent distinct windows from having distinct
> display-modes.

It's not obvious what should happen if there are multiple FLIP and
COPY windows.  Maybe another reason to leave out this setting.  On the
topic of multiple windows we might someday want to control position,
size, stacking... though I'm in no hurry to implement an entire window
system.
If we do leave out WAFFLE_GBM_WINDOW_DISPLAY_MODE then I guess
waffle_window_show() determines whether or not a window is displayed?

>> +    char *mode = getenv("MODE");
>> +    if (mode && mode[0] == 'O')
>> +        return true;
>> +
>> +    bool ok, release;
>> +    struct wgbm_window *self = wgbm_window(wc_self);
>> +    struct gbm_bo *bo = gbm_surface_lock_front_buffer(self->gbm_surface);
>> +    if (!bo)
>> +        return false;
>> +
>> +    if (mode && (mode[0] == 'F' || mode[0] == 'C')) {
>> +        struct wgbm_display *dpy = wgbm_display(wc_self->display);
>> +        struct buffer *buffer = buffer_wrap_gbm_bo(dpy,
>> self->gbm_surface, bo);
>> +        if (buffer) {
>> +            if (mode[0] == 'F')
>> +                ok = buffer_flip(buffer);
>> +            else
>> +                ok = copy_and_flip(buffer);
>> +            release = !ok;
>> +        } else {
>> +            ok = false;
>> +            release = true;
>> +        }
>> +    } else {
>> +        ok = true;
>> +        release = true;
>> +    }
>> +
>> +    if (release)
>> +        gbm_surface_release_buffer(self->gbm_surface, bo);
>> +
>> +    return ok;
>> +}
>> +
>> +
>>  union waffle_native_window*
>>  wgbm_window_get_native(struct wcore_window *wc_self)
>>  {
>> diff --git a/src/waffle/gbm/wgbm_window.h b/src/waffle/gbm/wgbm_window.h
>> index 7cd752b..0a895db 100644
>> --- a/src/waffle/gbm/wgbm_window.h
>> +++ b/src/waffle/gbm/wgbm_window.h
>> @@ -60,5 +60,8 @@ wgbm_window_destroy(struct wcore_window *wc_self);
>>  bool
>>  wgbm_window_show(struct wcore_window *wc_self);
>>  +bool
>> +wgbm_window_swap_buffers(struct wcore_window *wc_self);
>> +
>>  union waffle_native_window*
>>  wgbm_window_get_native(struct wcore_window *wc_self);
>> --
>> 2.1.2.1.g5433a3e
>>
>


More information about the waffle mailing list