gbm: Add gbm_surface interface
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Wed, 25 Jan 2012 14:24:14 +0000 (16:24 +0200)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 29 Mar 2012 02:14:34 +0000 (22:14 -0400)
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
src/gbm/backends/dri/gbm_driint.h
src/gbm/main/gbm.c
src/gbm/main/gbm.h
src/gbm/main/gbmint.h

index 1e02287651cdc75b5c1e0e7acb643881558b38b1..5398e3dd400887cb90ee5ab1effc8420a5607ea0 100644 (file)
@@ -387,6 +387,34 @@ 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, uint32_t flags)
+{
+   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;
+   surf->base.flags = flags;
+
+   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 void
 dri_destroy(struct gbm_device *gbm)
 {
@@ -414,6 +442,8 @@ 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.type = GBM_DRM_DRIVER_TYPE_DRI;
    dri->base.base.name = "drm";
index d801a081375245097be72402ed1309db9a00fb61..514b5a620c1e9e379d110f1e67d51aa55a468f57 100644 (file)
@@ -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);
 
index 9459720261f7219af16f442bcad66f23a0576795..79ba65051f221465a0aec966336ddc631a630925 100644 (file)
@@ -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,105 @@ 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, uint32_t flags)
+{
+   return gbm->surface_create(gbm, width, height, format, flags);
+}
+
+/**
+ * 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);
+}
index ecebf11f7b9f40842e257c6f829063e8336646c4..6748752d8f1d99cdc34499447bc47a17e871af6e 100644 (file)
@@ -44,6 +44,7 @@ extern "C" {
 
 struct gbm_device;
 struct gbm_bo;
+struct gbm_surface;
 
 /**
  * \mainpage The Generic Buffer Manager
@@ -247,6 +248,23 @@ 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, uint32_t flags);
+
+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
index 66c4c41cf8e8d043d7bee6973ad9dbdcf62df6cd..53d73f40df61e61f8002fe330ab6ebac6c26cc2f 100644 (file)
@@ -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, uint32_t flags);
+   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,14 @@ struct gbm_bo {
    union gbm_bo_handle  handle;
 };
 
+struct gbm_surface {
+   struct gbm_device *gbm;
+   uint32_t width;
+   uint32_t height;
+   uint32_t format;
+   uint32_t flags;
+};
+
 struct gbm_backend {
    const char *backend_name;
    struct gbm_device *(*create_device)(int fd);