From 0d1ef1f57f9011fd2bc3354d60fb19db29af7363 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Wed, 25 Jan 2012 16:24:14 +0200 Subject: [PATCH] gbm: Add gbm_surface interface 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 | 30 +++++++++ src/gbm/backends/dri/gbm_driint.h | 15 +++++ src/gbm/main/gbm.c | 107 +++++++++++++++++++++++++++++- src/gbm/main/gbm.h | 18 +++++ src/gbm/main/gbmint.h | 21 +++++- 5 files changed, 186 insertions(+), 5 deletions(-) diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c index 1e02287651c..5398e3dd400 100644 --- a/src/gbm/backends/dri/gbm_dri.c +++ b/src/gbm/backends/dri/gbm_dri.c @@ -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"; diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h index d801a081375..514b5a620c1 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 9459720261f..79ba65051f2 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,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); +} diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h index ecebf11f7b9..6748752d8f1 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,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 diff --git a/src/gbm/main/gbmint.h b/src/gbm/main/gbmint.h index 66c4c41cf8e..53d73f40df6 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, 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); -- 2.30.2