[PATCH weston 6/7] compositor-drm: Support creating drm_fb backed by dumb buffers
Pekka Paalanen
ppaalanen at gmail.com
Wed Jan 23 01:50:12 PST 2013
On Tue, 22 Jan 2013 18:07:14 +0200
Ander Conselvan de Oliveira <ander.conselvan.de.oliveira at intel.com>
wrote:
> ---
> src/compositor-drm.c | 106 +++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 96 insertions(+), 10 deletions(-)
>
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index 4868db0..7c11af1 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -30,6 +30,7 @@
> #include <unistd.h>
> #include <linux/input.h>
> #include <assert.h>
> +#include <sys/mman.h>
>
> #include <xf86drm.h>
> #include <xf86drmMode.h>
> @@ -116,9 +117,12 @@ struct drm_output;
> struct drm_fb {
> struct gbm_bo *bo;
> struct drm_output *output;
> + int fd;
> uint32_t fb_id;
> int is_client_buffer;
> struct weston_buffer_reference buffer_ref;
> + uint32_t stride, handle, size;
> + void *map;
> };
Just for clarity, the new fields in struct drm_fb are only ever used
for dumb buffers, right?
Regrouping all fields into three by used for both, used only for GBM
buffers, and used only for dumb buffers might be nice. Or maybe even an
anonymous embedded struct.
>
> struct drm_output {
> @@ -213,27 +217,106 @@ drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
> }
>
> static struct drm_fb *
> +drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
> +{
> + struct drm_fb *fb;
> + int ret;
> +
> + struct drm_mode_create_dumb create_arg;
> + struct drm_mode_destroy_dumb destroy_arg;
> + struct drm_mode_map_dumb map_arg;
> +
> + fb = calloc(1, sizeof *fb);
> + if (!fb)
> + return NULL;
> +
> + create_arg.bpp = 32;
> + create_arg.width = width;
> + create_arg.height = height;
> +
> + ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
> + if (ret)
> + goto err_fb;
> +
> + fb->handle = create_arg.handle;
> + fb->stride = create_arg.pitch;
> + fb->size = create_arg.size;
> + fb->fd = ec->drm.fd;
> +
> + ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
> + fb->stride, fb->handle, &fb->fb_id);
> + if (ret)
> + goto err_bo;
> +
> + memset(&map_arg, 0, sizeof(map_arg));
> + map_arg.handle = fb->handle;
> + drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
> +
> + if (ret)
> + goto err_add_fb;
> +
> + fb->map = mmap(0, fb->size, PROT_WRITE,
> + MAP_SHARED, ec->drm.fd, map_arg.offset);
> + if (fb->map == MAP_FAILED)
> + goto err_add_fb;
> +
> + return fb;
> +
> +err_add_fb:
> + drmModeRmFB(ec->drm.fd, fb->fb_id);
> +err_bo:
> + memset(&destroy_arg, 0, sizeof(destroy_arg));
> + destroy_arg.handle = create_arg.handle;
> + drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
> +err_fb:
> + free(fb);
> + return NULL;
> +}
> +
> +static void
> +drm_fb_destroy_dumb(struct drm_fb *fb)
> +{
> + struct drm_mode_destroy_dumb destroy_arg;
> +
> + if (!fb->map)
> + return;
> +
> + if (fb->fb_id)
> + drmModeRmFB(fb->fd, fb->fb_id);
> +
> + munmap(fb->map, fb->size);
> +
> + memset(&destroy_arg, 0, sizeof(destroy_arg));
> + destroy_arg.handle = fb->handle;
> + drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
> +
What about fb->buffer_ref? Is it only for GBM case, where a client
buffer is scanned out directly, and so impossible for dumb buffers?
> + free(fb);
> +}
> +
> +static struct drm_fb *
> drm_fb_get_from_bo(struct gbm_bo *bo,
> struct drm_compositor *compositor, uint32_t format)
> {
> struct drm_fb *fb = gbm_bo_get_user_data(bo);
> - uint32_t width, height, stride, handle;
> + uint32_t width, height;
> uint32_t handles[4], pitches[4], offsets[4];
> int ret;
>
> if (fb)
> return fb;
>
> - fb = malloc(sizeof *fb);
> + fb = calloc(1, sizeof *fb);
> + if (!fb)
> + return NULL;
>
> fb->bo = bo;
> - fb->is_client_buffer = 0;
> - fb->buffer_ref.buffer = NULL;
>
> width = gbm_bo_get_width(bo);
> height = gbm_bo_get_height(bo);
> - stride = gbm_bo_get_stride(bo);
> - handle = gbm_bo_get_handle(bo).u32;
> + fb->stride = gbm_bo_get_stride(bo);
> + fb->handle = gbm_bo_get_handle(bo).u32;
> + fb->size = fb->stride * height;
> + fb->fd = compositor->drm.fd;
>
> if (compositor->min_width > width || width > compositor->max_width ||
> compositor->min_height > height ||
> @@ -245,8 +328,8 @@ drm_fb_get_from_bo(struct gbm_bo *bo,
> ret = -1;
>
> if (format && !compositor->no_addfb2) {
> - handles[0] = handle;
> - pitches[0] = stride;
> + handles[0] = fb->handle;
> + pitches[0] = fb->stride;
> offsets[0] = 0;
>
> ret = drmModeAddFB2(compositor->drm.fd, width, height,
> @@ -261,7 +344,7 @@ drm_fb_get_from_bo(struct gbm_bo *bo,
>
> if (ret)
> ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
> - stride, handle, &fb->fb_id);
> + fb->stride, fb->handle, &fb->fb_id);
>
> if (ret) {
> weston_log("failed to create kms fb: %m\n");
> @@ -293,7 +376,9 @@ drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
> if (!fb)
> return;
>
> - if (fb->bo) {
> + if (fb->map) {
> + drm_fb_destroy_dumb(fb);
> + } else if (fb->bo) {
> if (fb->is_client_buffer)
> gbm_bo_destroy(fb->bo);
> else
> @@ -1035,6 +1120,7 @@ init_drm(struct drm_compositor *ec, struct udev_device *device)
>
> ec->drm.fd = fd;
>
> +
> return 0;
> }
>
Thanks,
pq
More information about the wayland-devel
mailing list