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().
This commit is contained in:
Ander Conselvan de Oliveira 2012-01-25 16:24:14 +02:00 committed by Kristian Høgsberg
parent 7f16246ace
commit 0d1ef1f57f
5 changed files with 186 additions and 5 deletions

View 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";

View 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);

View 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);
}

View 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

View 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);