On Thu, Dec 12, 2013 at 03:36:29PM +0100, Thierry Reding wrote: > This is a simple test module that can be used to allocate, export and > delete DMA-BUF objects. It can be used to test DMA-BUF sharing in > systems that lack a real second driver. > > Signed-off-by: Thierry Reding <treding@xxxxxxxxxx> > --- > drivers/base/Kconfig | 4 + > drivers/base/Makefile | 1 + > drivers/base/dma-buf-test.c | 308 ++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 313 insertions(+) > create mode 100644 drivers/base/dma-buf-test.c And attached is a small test program that I've been using to test this new module. It can be built with: $ gcc -O2 -g -Wall -Werror -I/usr/include/libdrm -o dma-buf-test dma-buf-test.c -ldrm Thierry
/* * Copyright (C) 2013 NVIDIA Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <fcntl.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <linux/ioctl.h> #include <xf86drm.h> #include <xf86drmMode.h> #include <drm_fourcc.h> struct dmabuf_create { __u32 flags; __u32 size; }; #define DMABUF_IOCTL_BASE 'D' #define DMABUF_IOCTL_CREATE _IOWR(DMABUF_IOCTL_BASE, 0, struct dmabuf_create) #define DMABUF_IOCTL_DELETE _IOWR(DMABUF_IOCTL_BASE, 1, int) #define DMABUF_IOCTL_EXPORT _IOWR(DMABUF_IOCTL_BASE, 2, int) #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) static const char default_dmabuf_device[] = "/dev/dmabuf"; static const char default_dri_card[] = "/dev/dri/card0"; struct screen { int fd; unsigned int width; unsigned int height; unsigned int pitch; unsigned int depth; unsigned int bpp; drmModeModeInfo mode; uint32_t fb, old_fb; uint32_t connector; uint32_t format; uint32_t handle; uint32_t crtc; }; static int probe_connector(struct screen *screen, drmModeConnectorPtr connector) { drmModeEncoderPtr encoder; drmModeCrtcPtr crtc; drmModeFBPtr fb; encoder = drmModeGetEncoder(screen->fd, connector->encoder_id); if (!encoder) return -ENODEV; crtc = drmModeGetCrtc(screen->fd, encoder->crtc_id); if (!crtc) { drmModeFreeEncoder(encoder); return -ENODEV; } screen->old_fb = crtc->buffer_id; fb = drmModeGetFB(screen->fd, crtc->buffer_id); if (!fb) { /* TODO: create new framebuffer */ drmModeFreeEncoder(encoder); drmModeFreeCrtc(crtc); return -ENOSYS; } screen->connector = connector->connector_id; screen->old_fb = crtc->buffer_id; screen->crtc = encoder->crtc_id; /* TODO: check crtc->mode_valid */ screen->mode = crtc->mode; screen->width = fb->width; screen->height = fb->height; screen->pitch = fb->pitch; screen->depth = fb->depth; screen->bpp = fb->bpp; drmModeFreeEncoder(encoder); drmModeFreeCrtc(crtc); drmModeFreeFB(fb); return 0; } static int screen_open(struct screen **screenp, int fd) { drmModeConnectorPtr connector; struct screen *screen; bool found = false; drmModeResPtr res; unsigned int i; int err; if (!screenp || fd < 0) return -EINVAL; screen = calloc(1, sizeof(*screen)); if (!screen) return -ENOMEM; screen->format = DRM_FORMAT_XRGB8888; screen->fd = fd; res = drmModeGetResources(fd); if (!res) { free(screen); return -ENOMEM; } for (i = 0; i < res->count_connectors; i++) { connector = drmModeGetConnector(fd, res->connectors[i]); if (!connector) continue; if (connector->connection != DRM_MODE_CONNECTED) { drmModeFreeConnector(connector); continue; } err = probe_connector(screen, connector); if (err < 0) { drmModeFreeConnector(connector); continue; } found = true; break; } drmModeFreeResources(res); if (!found) { free(screen); return -ENODEV; } *screenp = screen; return 0; } int screen_close(struct screen *screen) { struct drm_gem_close args; int err; err = drmModeSetCrtc(screen->fd, screen->crtc, screen->old_fb, 0, 0, &screen->connector, 1, &screen->mode); if (err < 0) { fprintf(stderr, "drmModeSetCrtc() failed: %m\n"); return -errno; } err = drmModeRmFB(screen->fd, screen->fb); if (err < 0) { fprintf(stderr, "drmModeRmFB() failed: %m\n"); return -errno; } memset(&args, 0, sizeof(args)); args.handle = screen->handle; err = ioctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &args); if (err < 0) { fprintf(stderr, "ioctl(DRM_IOCTL_GEM_CLOSE) failed: %m\n"); return -errno; } return 0; } int screen_import(struct screen *screen, int buf) { uint32_t handles[4], pitches[4], offsets[4]; int err; err = drmPrimeFDToHandle(screen->fd, buf, &screen->handle); if (err < 0) { fprintf(stderr, "drmPrimeFDToHandle() failed: %m\n"); return -errno; } printf("DRM handle: %x\n", screen->handle); handles[0] = screen->handle; pitches[0] = screen->pitch; offsets[0] = 0; err = drmModeAddFB2(screen->fd, screen->width, screen->height, screen->format, handles, pitches, offsets, &screen->fb, 0); if (err < 0) { fprintf(stderr, "drmModeAddFB() failed: %m\n"); return -errno; } err = drmModeSetCrtc(screen->fd, screen->crtc, screen->fb, 0, 0, &screen->connector, 1, &screen->mode); if (err < 0) { fprintf(stderr, "drmModeSetCrtc() failed: %m\n"); return -errno; } return 0; } int dmabuf_create(int fd, size_t size, int flags) { struct dmabuf_create args; memset(&args, 0, sizeof(args)); args.flags = flags; args.size = size; return ioctl(fd, DMABUF_IOCTL_CREATE, &args); } int dmabuf_delete(int fd) { return ioctl(fd, DMABUF_IOCTL_DELETE, 0); } int dmabuf_export(int fd, int flags) { return ioctl(fd, DMABUF_IOCTL_EXPORT, flags); } void *dmabuf_mmap(int buf, off_t offset, size_t size) { void *ptr; ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, buf, offset); if (ptr == MAP_FAILED) return NULL; return ptr; } void dmabuf_unmap(int buf, void *ptr, size_t size) { munmap(ptr, size); } static void prepare_buffer(int buf, size_t size, struct screen *screen) { void *ptr; /* TODO: handle other formats */ if (screen->format != DRM_FORMAT_XRGB8888) { fprintf(stderr, "unsupported format: %x\n", screen->format); return; } ptr = dmabuf_mmap(buf, 0, size); if (ptr) { uint32_t colors[2] = { 0x00ff0000, 0x000000ff }; unsigned int sx = 16; unsigned int sy = 16; uint32_t *fb = ptr; unsigned int i, j; for (j = 0; j < screen->height; j++) { unsigned int y = j / sy; for (i = 0; i < screen->width; i++) { unsigned int x = i / sx; *fb++ = colors[(x ^ y) & 1]; } } dmabuf_unmap(buf, ptr, size); } else { fprintf(stderr, "dmabuf_mmap() failed: %m\n"); } } int main(int argc, char *argv[]) { const char *dmabuf, *card; struct timeval timeout; struct screen *screen; int fd, err, buf, drm; size_t size; fd_set fds; if (argc < 2) dmabuf = default_dmabuf_device; else dmabuf = argv[1]; if (argc < 3) card = default_dri_card; else card = argv[2]; fd = open(dmabuf, O_RDWR); if (fd < 0) { fprintf(stderr, "open() failed: %m\n"); return 1; } drm = open(card, O_RDWR); if (drm < 0) { fprintf(stderr, "open() failed: %m\n"); return 1; } err = drmSetMaster(drm); if (err < 0) { fprintf(stderr, "drmSetMaster() failed: %m\n"); return 1; } err = screen_open(&screen, drm); if (err < 0) { fprintf(stderr, "screen_open() failed: %s\n", strerror(-err)); return 1; } size = screen->pitch * screen->height; err = dmabuf_create(fd, size, O_RDWR); if (err < 0) { fprintf(stderr, "dmabuf_create() failed: %m\n"); return 1; } buf = dmabuf_export(fd, 0); if (buf < 0) { fprintf(stderr, "dmabuf_export() failed: %m\n"); return 1; } printf("obtained DMA-BUF: %d\n", buf); prepare_buffer(buf, size, screen); err = screen_import(screen, buf); if (err < 0) { fprintf(stderr, "screen_import() failed: %s\n", strerror(-err)); return 1; } FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = 5; timeout.tv_usec = 0; err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout); if (err < 0) { fprintf(stderr, "select() failed: %m\n"); return 1; } err = screen_close(screen); if (err < 0) { fprintf(stderr, "screen_close() failed: %s\n", strerror(-err)); return 1; } err = dmabuf_delete(fd); if (err < 0) { fprintf(stderr, "dmabuf_delete() failed: %m\n"); return 1; } close(buf); err = drmDropMaster(drm); if (err < 0) { fprintf(stderr, "drmDropMaster() failed: %m\n"); return 1; } close(drm); close(fd); return 0; }
Attachment:
pgpn6hy7Swvgg.pgp
Description: PGP signature
_______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel