[Mesa-dev] [PATCH 1/3] gbm: Add gbm_surface interface

Kristian Høgsberg krh at bitplanet.net
Tue Mar 27 12:08:27 PDT 2012


From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira at intel.com>

The idea here is to be able to create an egl window surface from a
gbm_surface.  This avoids the need for the surfaceless extension and
lets the EGL platform handle buffer allocation, while keeping the user
in charge of somehow presenting the buffers (using kms page flipping,
for example).

gbm_surface_lock_front_buffer() locks a surface's front buffer and
returns a gbm bo representing it.  This bo should later be returned
to the gbm surface using gbm_surface_release_buffer().
---
 src/gbm/backends/dri/gbm_dri.c    |   49 +++++++++++++++++
 src/gbm/backends/dri/gbm_driint.h |   15 +++++
 src/gbm/main/gbm.c                |  106 +++++++++++++++++++++++++++++++++++-
 src/gbm/main/gbm.h                |   17 ++++++
 src/gbm/main/gbmint.h             |   20 ++++++-
 5 files changed, 202 insertions(+), 5 deletions(-)

diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index 1e02287..305938b 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -387,6 +387,49 @@ gbm_dri_bo_create(struct gbm_device *gbm,
    return &bo->base.base;
 }
 
+static struct gbm_surface *
+gbm_dri_surface_create(struct gbm_device *gbm,
+                       uint32_t width, uint32_t height, uint32_t format)
+{
+   struct gbm_dri_surface *surf;
+
+   surf = calloc(1, sizeof *surf);
+   if (surf == NULL)
+      return NULL;
+
+   surf->base.gbm = gbm;
+   surf->base.width = width;
+   surf->base.height = height;
+   surf->base.format = format;
+
+   return &surf->base;
+}
+
+static void
+gbm_dri_surface_destroy(struct gbm_surface *_surf)
+{
+   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
+
+   free(surf);
+}
+
+static struct gbm_bo *
+gbm_dri_surface_lock_front_buffer(struct gbm_surface *_surf)
+{
+   return NULL;
+}
+
+static void
+gbm_dri_surface_release_buffer(struct gbm_surface *_surf, struct gbm_bo *_bo)
+{
+}
+
+static int
+gbm_dri_surface_has_free_buffers(struct gbm_surface *_surf)
+{
+   return 0;
+}
+
 static void
 dri_destroy(struct gbm_device *gbm)
 {
@@ -414,6 +457,12 @@ dri_device_create(int fd)
    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
    dri->base.base.bo_destroy = gbm_dri_bo_destroy;
    dri->base.base.destroy = dri_destroy;
+   dri->base.base.surface_create = gbm_dri_surface_create;
+   dri->base.base.surface_destroy = gbm_dri_surface_destroy;
+   dri->base.base.surface_lock_front_buffer =
+      gbm_dri_surface_lock_front_buffer;
+   dri->base.base.surface_release_buffer = gbm_dri_surface_release_buffer;
+   dri->base.base.surface_has_free_buffers = gbm_dri_surface_has_free_buffers;
 
    dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
    dri->base.base.name = "drm";
diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h
index d801a08..514b5a6 100644
--- a/src/gbm/backends/dri/gbm_driint.h
+++ b/src/gbm/backends/dri/gbm_driint.h
@@ -61,6 +61,15 @@ struct gbm_dri_bo {
    __DRIimage *image;
 };
 
+struct gbm_dri_surface {
+   struct gbm_surface base;
+
+   __DRIbuffer *(*get_front_buffer)(struct gbm_dri_surface *, void *);
+   void (*release_buffer)(struct gbm_dri_surface *, __DRIbuffer *, void *);
+   int (*has_free_buffers)(void *);
+   void *dri_private;
+};
+
 static inline struct gbm_dri_device *
 gbm_dri_device(struct gbm_device *gbm)
 {
@@ -73,6 +82,12 @@ gbm_dri_bo(struct gbm_bo *bo)
    return (struct gbm_dri_bo *) bo;
 }
 
+static inline struct gbm_dri_surface *
+gbm_dri_surface(struct gbm_surface *surface)
+{
+   return (struct gbm_dri_surface *) surface;
+}
+
 char *
 dri_fd_get_driver_name(int fd);
 
diff --git a/src/gbm/main/gbm.c b/src/gbm/main/gbm.c
index 9459720..23a6656 100644
--- a/src/gbm/main/gbm.c
+++ b/src/gbm/main/gbm.c
@@ -84,8 +84,7 @@ gbm_device_get_backend_name(struct gbm_device *gbm)
  */
 int
 gbm_device_is_format_supported(struct gbm_device *gbm,
-                               enum gbm_bo_format format,
-                               uint32_t usage)
+                               uint32_t format, uint32_t usage)
 {
    return gbm->is_format_supported(gbm, format, usage);
 }
@@ -263,7 +262,7 @@ gbm_bo_destroy(struct gbm_bo *bo)
 GBM_EXPORT struct gbm_bo *
 gbm_bo_create(struct gbm_device *gbm,
               uint32_t width, uint32_t height,
-              enum gbm_bo_format format, uint32_t usage)
+              uint32_t format, uint32_t usage)
 {
    if (width == 0 || height == 0)
       return NULL;
@@ -305,3 +304,104 @@ gbm_bo_create_from_egl_image(struct gbm_device *gbm,
    return gbm->bo_create_from_egl_image(gbm, egl_dpy, egl_image,
                                         width, height, usage);
 }
+
+/**
+ * Allocate a surface object
+ *
+ * \param gbm The gbm device returned from gbm_create_device()
+ * \param width The width for the surface
+ * \param height The height for the surface
+ * \param format The format to use for the surface
+ *
+ * \return A newly allocated surface that should be freed with
+ * gbm_surface_destroy() when no longer needed. If an error occurs
+ * during allocation %NULL will be returned.
+ *
+ * \sa enum gbm_bo_format for the list of formats
+ */
+GBM_EXPORT struct gbm_surface *
+gbm_surface_create(struct gbm_device *gbm,
+                   uint32_t width, uint32_t height, uint32_t format)
+{
+   return gbm->surface_create(gbm, width, height, format);
+}
+
+/**
+ * Destroys the given surface and frees all resources associated with
+ * it.
+ *
+ * All buffers locked with gbm_surface_lock_front_buffer() should be
+ * released prior to calling this function.
+ *
+ * \param surf The surface
+ */
+GBM_EXPORT void
+gbm_surface_destroy(struct gbm_surface *surf)
+{
+   surf->gbm->surface_destroy(surf);
+}
+
+/**
+ * Lock the surface's current front buffer
+ *
+ * Lock rendering to the surface's current front buffer until it is
+ * released with gbm_surface_release_buffer().
+ *
+ * This function must be called exactly once after calling
+ * eglSwapBuffers.  Calling it before any eglSwapBuffer has happened
+ * on the surface or two or more times after eglSwapBuffers is an
+ * error.  A new bo representing the new front buffer is returned.  On
+ * multiple invocations, all the returned bos must be released in
+ * order to release the actual surface buffer.
+ *
+ * \param surf The surface
+ *
+ * \return A newly allocated buffer object that should be released
+ * with gbm_surface_release_buffer() when no longer needed.  This bo
+ * should not be destroyed using gbm_bo_destroy().  If an error occurs
+ * this function returns %NULL.
+ */
+GBM_EXPORT struct gbm_bo *
+gbm_surface_lock_front_buffer(struct gbm_surface *surf)
+{
+   return surf->gbm->surface_lock_front_buffer(surf);
+}
+
+/**
+ * Release a locked buffer obtained with gbm_surface_lock_front_buffer()
+ *
+ * The bo is destroyed after a call to this function and returns the
+ * underlying buffer to the gbm surface.  Releasing a bo will
+ * typically make gbm_surface_has_free_buffer() return 1 and thus
+ * allow rendering the next frame, but not always.
+ *
+ * \param surf The surface
+ * \param bo The buffer object
+ */
+GBM_EXPORT void
+gbm_surface_release_buffer(struct gbm_surface *surf, struct gbm_bo *bo)
+{
+   surf->gbm->surface_release_buffer(surf, bo);
+}
+
+/**
+ * Return whether or not a surface has free (non-locked) buffers
+ *
+ * Before starting a new frame, the surface must have a buffer
+ * available for rendering.  Initially, a gbm surface will have a free
+ * buffer, but after one of more buffers have been locked (\sa
+ * gbm_surface_lock_front_buffer()), the application must check for a
+ * free buffer before rendering.
+ *
+ * If a surface doesn't have a free buffer, the application must
+ * return a buffer to the surface using gbm_surface_release_buffer()
+ * and after that, the application can query for free buffers again.
+ *
+ * \param surf The surface
+ * \return 1 if the surface has free buffers, 0 otherwise
+ */
+GBM_EXPORT int
+gbm_surface_has_free_buffers(struct gbm_surface *surf)
+{
+   return surf->gbm->surface_has_free_buffers(surf);
+}
diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h
index ecebf11..dce2bdf 100644
--- a/src/gbm/main/gbm.h
+++ b/src/gbm/main/gbm.h
@@ -44,6 +44,7 @@ extern "C" {
 
 struct gbm_device;
 struct gbm_bo;
+struct gbm_surface;
 
 /**
  * \mainpage The Generic Buffer Manager
@@ -247,6 +248,22 @@ gbm_bo_get_handle(struct gbm_bo *bo);
 void
 gbm_bo_destroy(struct gbm_bo *bo);
 
+struct gbm_surface *
+gbm_surface_create(struct gbm_device *gbm,
+                   uint32_t width, uint32_t height, uint32_t format);
+
+struct gbm_bo *
+gbm_surface_lock_front_buffer(struct gbm_surface *surface);
+
+void
+gbm_surface_release_buffer(struct gbm_surface *surface, struct gbm_bo *bo);
+
+int
+gbm_surface_has_free_buffers(struct gbm_surface *surface);
+
+void
+gbm_surface_destroy(struct gbm_surface *surface);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gbm/main/gbmint.h b/src/gbm/main/gbmint.h
index 66c4c41..eee7fb6 100644
--- a/src/gbm/main/gbmint.h
+++ b/src/gbm/main/gbmint.h
@@ -59,18 +59,27 @@ struct gbm_device {
 
    void (*destroy)(struct gbm_device *gbm);
    int (*is_format_supported)(struct gbm_device *gbm,
-                              enum gbm_bo_format format,
+                              uint32_t format,
                               uint32_t usage);
 
    struct gbm_bo *(*bo_create)(struct gbm_device *gbm,
                                uint32_t width, uint32_t height,
-                               enum gbm_bo_format format,
+                               uint32_t format,
                                uint32_t usage);
    struct gbm_bo *(*bo_create_from_egl_image)(struct gbm_device *gbm,
                                               void *egl_dpy, void *egl_img,
                                               uint32_t width, uint32_t height,
                                               uint32_t usage);
    void (*bo_destroy)(struct gbm_bo *bo);
+
+   struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
+                                         uint32_t width, uint32_t height,
+                                         uint32_t format);
+   struct gbm_bo *(*surface_lock_front_buffer)(struct gbm_surface *surface);
+   void (*surface_release_buffer)(struct gbm_surface *surface,
+                                  struct gbm_bo *bo);
+   int (*surface_has_free_buffers)(struct gbm_surface *surface);
+   void (*surface_destroy)(struct gbm_surface *surface);
 };
 
 /**
@@ -87,6 +96,13 @@ struct gbm_bo {
    union gbm_bo_handle  handle;
 };
 
+struct gbm_surface {
+   struct gbm_device *gbm;
+   uint32_t width;
+   uint32_t height;
+   uint32_t format;
+};
+
 struct gbm_backend {
    const char *backend_name;
    struct gbm_device *(*create_device)(int fd);
-- 
1.7.9.1



More information about the mesa-dev mailing list