atomic: add atomic test application
authorInki Dae <inki.dae@samsung.com>
Thu, 8 Dec 2016 08:00:00 +0000 (17:00 +0900)
committerInki Dae <inki.dae@samsung.com>
Mon, 16 Jan 2017 03:30:50 +0000 (12:30 +0900)
This patch is from below chromium git repository,
     https://chromium.googlesource.com/chromiumos/platform/drm-tests

This adds just a simple atomic KMS test application.
I modified set_sp_plane_pset function to set each properties correctly.
Original code managed correct return value as error case so fixed it.

Change-Id: Iaad9fb62c63e01a35f42c803b42be2b0dcbe1a81
Signed-off-by: Inki Dae <inki.dae@samsung.com>
configure.ac
tests/Makefile.am
tests/atomictest/Makefile.am [new file with mode: 0644]
tests/atomictest/Makefile.sources [new file with mode: 0644]
tests/atomictest/atomictest.c [new file with mode: 0644]
tests/atomictest/bo.c [new file with mode: 0644]
tests/atomictest/bo.h [new file with mode: 0644]
tests/atomictest/dev.c [new file with mode: 0644]
tests/atomictest/dev.h [new file with mode: 0644]
tests/atomictest/modeset.c [new file with mode: 0644]
tests/atomictest/modeset.h [new file with mode: 0644]

index 708c562..4e2c3a0 100644 (file)
@@ -553,6 +553,7 @@ AC_CONFIG_FILES([
        tests/nouveau/Makefile
        tests/etnaviv/Makefile
        tests/util/Makefile
+       tests/atomictest/Makefile
        man/Makefile
        libdrm.pc])
 AC_OUTPUT
index 4a499e4..138dec7 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = util kms modeprint proptest modetest vbltest
+SUBDIRS = util kms modeprint proptest modetest vbltest atomictest
 
 if HAVE_LIBKMS
 SUBDIRS += kmstest
diff --git a/tests/atomictest/Makefile.am b/tests/atomictest/Makefile.am
new file mode 100644 (file)
index 0000000..afed91d
--- /dev/null
@@ -0,0 +1,24 @@
+include Makefile.sources
+
+AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS))
+
+AM_CFLAGS += \
+       -I$(top_srcdir)/include/drm \
+       -I$(top_srcdir)/tests \
+       -I$(top_srcdir)
+
+if HAVE_INSTALL_TESTS
+bin_PROGRAMS = \
+       atomic_kms_test
+else
+noinst_PROGRAMS = \
+       atomic_kms_test
+endif
+
+atomic_kms_test_SOURCES = $(ATOMICTEST_FILES)
+
+atomic_kms_test_LDADD = \
+       $(top_builddir)/libdrm.la \
+       $(top_builddir)/tests/util/libutil.la \
+       $(CAIRO_LIBS) \
+       -lpthread
diff --git a/tests/atomictest/Makefile.sources b/tests/atomictest/Makefile.sources
new file mode 100644 (file)
index 0000000..fc237be
--- /dev/null
@@ -0,0 +1,11 @@
+ATOMICTEST_FILES := \
+       atomictest.c \
+       bo.c \
+       bo.h \
+       dev.c \
+       dev.h \
+       modeset.c \
+       modeset.h
+
+
+       atomictest.c  atomictest.o  bo.c  bo.h  bo.o  dev.c  dev.h  dev.o  Makefile  Makefile.am  Makefile.in  Makefile.sources  modeset.c  modeset.h  modeset.o
diff --git a/tests/atomictest/atomictest.c b/tests/atomictest/atomictest.c
new file mode 100644 (file)
index 0000000..b7bf730
--- /dev/null
@@ -0,0 +1,146 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+
+#include <xf86drm.h>
+
+#include "dev.h"
+#include "bo.h"
+#include "modeset.h"
+
+static int terminate = 0;
+
+static void sigint_handler(int arg)
+{
+       terminate = 1;
+}
+
+static void
+page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
+               unsigned int tv_usec, void *user_data)
+{
+}
+
+static void incrementor(int *inc, int *val, int increment, int lower, int upper)
+{
+       if(*inc > 0)
+               *inc = *val + increment >= upper ? -1 : 1;
+       else
+               *inc = *val - increment <= lower ? 1 : -1;
+       *val += *inc * increment;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret, i, j, num_test_planes;
+       int x_inc = 1, x = 0, y_inc = 1, y = 0;
+       uint32_t plane_w = 128, plane_h = 128;
+       struct sp_dev *dev;
+       struct sp_plane **plane = NULL;
+       struct sp_crtc *test_crtc;
+       fd_set fds;
+       drmModeAtomicReqPtr pset;
+       drmEventContext event_context = {
+               .version = DRM_EVENT_CONTEXT_VERSION,
+               .page_flip_handler = page_flip_handler,
+       };
+
+       signal(SIGINT, sigint_handler);
+
+       dev = create_sp_dev();
+       if (!dev) {
+               printf("Failed to create sp_dev\n");
+               return -1;
+       }
+
+       ret = initialize_screens(dev);
+       if (ret) {
+               printf("Failed to initialize screens\n");
+               goto out;
+       }
+       test_crtc = &dev->crtcs[0];
+
+       plane = calloc(dev->num_planes, sizeof(*plane));
+       if (!plane) {
+               printf("Failed to allocate plane array\n");
+               goto out;
+       }
+
+       /* Create our planes */
+       num_test_planes = test_crtc->num_planes;
+       for (i = 0; i < num_test_planes; i++) {
+               plane[i] = get_sp_plane(dev, test_crtc);
+               if (!plane[i]) {
+                       printf("no unused planes available\n");
+                       goto out;
+               }
+
+               plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, 32,
+                               plane[i]->format, 0);
+               if (!plane[i]->bo) {
+                       printf("failed to create plane bo\n");
+                       goto out;
+               }
+
+               fill_bo(plane[i]->bo, 0xFF, 0x00, 0x00, 0xFF);
+       }
+
+       pset = drmModeAtomicAlloc();
+       if (!pset) {
+               printf("Failed to allocate the property set\n");
+               goto out;
+       }
+
+       while (!terminate) {
+               FD_ZERO(&fds);
+               FD_SET(dev->fd, &fds);
+
+               incrementor(&x_inc, &x, 5, 0,
+                       test_crtc->crtc->mode.hdisplay - plane_w);
+               incrementor(&y_inc, &y, 5, 0, test_crtc->crtc->mode.vdisplay -
+                                               plane_h * num_test_planes);
+
+               drmModeAtomicSetCursor(pset, 0);
+
+               for (j = 0; j < num_test_planes; j++) {
+                       ret = set_sp_plane_pset(dev, plane[j], pset, test_crtc,
+                                       x, y + j * plane_h);
+                       if (ret < 0) {
+                               printf("failed to move plane %d\n", ret);
+                               goto out;
+                       }
+               }
+
+               ret = drmModeAtomicCommit(dev->fd, pset,
+                               DRM_MODE_PAGE_FLIP_EVENT, NULL);
+               if (ret) {
+                       printf("failed to commit properties ret=%d\n", ret);
+                       goto out;
+               }
+
+               do {
+                       ret = select(dev->fd + 1, &fds, NULL, NULL, NULL);
+               } while (ret == -1 && errno == EINTR);
+
+               if (FD_ISSET(dev->fd, &fds))
+                       drmHandleEvent(dev->fd, &event_context);
+       }
+
+       drmModeAtomicFree(pset);
+
+       for (i = 0; i < num_test_planes; i++)
+               put_sp_plane(plane[i]);
+
+out:
+       destroy_sp_dev(dev);
+       free(plane);
+       return ret;
+}
diff --git a/tests/atomictest/bo.c b/tests/atomictest/bo.c
new file mode 100644 (file)
index 0000000..8f37720
--- /dev/null
@@ -0,0 +1,214 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm_fourcc.h>
+
+#include "libdrm_macros.h"
+
+#include "bo.h"
+#include "dev.h"
+
+void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
+{
+       draw_rect(bo, 0, 0, bo->width, bo->height, a, r, g, b);
+}
+
+static uint8_t clampbyte(float f)
+{
+       if (f >= 255.0) return 255;
+       if (f <= 0.0) return 0;
+       return (uint8_t)f;
+}
+
+void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
+               uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
+{
+       uint32_t i, j, xmax = x + width, ymax = y + height;
+       uint8_t Y = 0, Cb = 0, Cr = 0;
+
+       if (xmax > bo->width)
+               xmax = bo->width;
+       if (ymax > bo->height)
+               ymax = bo->height;
+
+       if (bo->format == DRM_FORMAT_NV12 ||
+           bo->format == DRM_FORMAT_NV21) {
+               Y = clampbyte(16 + 0.2567890625 * r + 0.50412890625 * g * 0.09790625);
+               Cb = clampbyte(128 - 0.14822265625 * r - 0.2909921875 * g + 0.43921484375 * b);
+               Cr = clampbyte(128 + 0.43921484375 * r - 0.3677890625 * g - 0.07142578125 * b);
+       }
+
+       for (i = y; i < ymax; i++) {
+               uint8_t *row = bo->map_addr + i * bo->pitch;
+               uint8_t *uvrow = bo->map_addr + bo->height * bo->pitch + (i >> 1) * bo->pitch;
+
+               for (j = x; j < xmax; j++) {
+                       if (bo->format == DRM_FORMAT_ARGB8888 ||
+                           bo->format == DRM_FORMAT_XRGB8888)
+                       {
+                               uint8_t *pixel = row + j * 4;
+                               pixel[0] = b;
+                               pixel[1] = g;
+                               pixel[2] = r;
+                               pixel[3] = a;
+                       } else if (bo->format == DRM_FORMAT_RGBA8888) {
+                               uint8_t *pixel = row + j * 4;
+                               pixel[0] = r;
+                               pixel[1] = g;
+                               pixel[2] = b;
+                               pixel[3] = a;
+                       } else if (bo->format == DRM_FORMAT_NV12) {
+                               row[j] = Y;
+                               uvrow[(j & ~1u)] = Cb;
+                               uvrow[(j & ~1u) + 1] = Cr;
+                       } else if (bo->format == DRM_FORMAT_NV21) {
+                               row[j] = Y;
+                               uvrow[(j & ~1u)] = Cr;
+                               uvrow[(j & ~1u) + 1] = Cb;
+                       }
+               }
+       }
+}
+
+static int add_fb_sp_bo(struct sp_bo *bo, uint32_t format)
+{
+       int ret;
+       uint32_t handles[4], pitches[4], offsets[4];
+
+       handles[0] = bo->handle;
+       pitches[0] = bo->pitch;
+       offsets[0] = 0;
+       if (bo->format == DRM_FORMAT_NV12 ||
+           bo->format == DRM_FORMAT_NV21) {
+               bo->height = (bo->height / 3) * 2;
+               handles[1] = bo->handle;
+               pitches[1] = bo->pitch;
+               offsets[1] = bo->height * bo->pitch;
+       }
+
+       ret = drmModeAddFB2(bo->dev->fd, bo->width, bo->height,
+                       format, handles, pitches, offsets,
+                       &bo->fb_id, bo->flags);
+       if (ret) {
+               printf("failed to create fb ret=%d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int map_sp_bo(struct sp_bo *bo)
+{
+       int ret;
+       struct drm_mode_map_dumb md;
+
+       if (bo->map_addr)
+               return 0;
+
+       memset(&md, 0, sizeof(md));
+       md.handle = bo->handle;
+       ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &md);
+       if (ret) {
+               printf("failed to map sp_bo ret=%d\n", ret);
+               return ret;
+       }
+
+       bo->map_addr = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                               bo->dev->fd, md.offset);
+       if (bo->map_addr == MAP_FAILED) {
+               printf("failed to map bo ret=%d\n", -errno);
+               return -errno;
+       }
+       return 0;
+}
+
+struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
+               uint32_t depth, uint32_t bpp, uint32_t format, uint32_t flags)
+{
+       int ret;
+       struct drm_mode_create_dumb cd = {};
+       struct sp_bo *bo;
+
+       bo = calloc(1, sizeof(*bo));
+       if (!bo)
+               return NULL;
+
+       cd.height = height;
+       cd.width = width;
+       cd.bpp = bpp;
+       cd.flags = flags;
+
+       ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &cd);
+       if (ret) {
+               printf("failed to create sp_bo %d\n", ret);
+               goto err;
+       }
+
+       bo->dev = dev;
+       bo->width = width;
+       bo->height = height;
+       bo->depth = depth;
+       bo->bpp = bpp;
+       bo->format = format;
+       bo->flags = flags;
+
+       bo->handle = cd.handle;
+       bo->pitch = cd.pitch;
+       bo->size = cd.size;
+
+       ret = add_fb_sp_bo(bo, format);
+       if (ret) {
+               printf("failed to add fb ret=%d\n", ret);
+               goto err;
+       }
+
+       ret = map_sp_bo(bo);
+       if (ret) {
+               printf("failed to map bo ret=%d\n", ret);
+               goto err;
+       }
+
+       return bo;
+
+err:
+       free_sp_bo(bo);
+       return NULL;
+}
+
+void free_sp_bo(struct sp_bo *bo)
+{
+       int ret;
+       struct drm_mode_destroy_dumb dd;
+
+       if (!bo)
+               return;
+
+       if (bo->map_addr)
+               drm_munmap(bo->map_addr, bo->size);
+
+       if (bo->fb_id) {
+               ret = drmModeRmFB(bo->dev->fd, bo->fb_id);
+               if (ret)
+                       printf("Failed to rmfb ret=%d!\n", ret);
+       }
+
+       if (bo->handle) {
+               dd.handle = bo->handle;
+               ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dd);
+               if (ret)
+                       printf("Failed to destroy buffer ret=%d\n", ret);
+       }
+
+       free(bo);
+}
diff --git a/tests/atomictest/bo.h b/tests/atomictest/bo.h
new file mode 100644 (file)
index 0000000..4c5ddf8
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __BO_H_INCLUDED__
+#define __BO_H_INCLUDED__
+
+#include <stdint.h>
+
+struct sp_dev;
+
+struct sp_bo {
+       struct sp_dev *dev;
+
+       uint32_t width;
+       uint32_t height;
+       uint32_t depth;
+       uint32_t bpp;
+       uint32_t format;
+       uint32_t flags;
+
+       uint32_t fb_id;
+       uint32_t handle;
+       void *map_addr;
+       uint32_t pitch;
+       uint32_t size;
+};
+
+struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
+               uint32_t depth, uint32_t bpp, uint32_t format, uint32_t flags);
+
+void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
+void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
+               uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
+
+void free_sp_bo(struct sp_bo *bo);
+
+#endif /* __BO_H_INCLUDED__ */
diff --git a/tests/atomictest/dev.c b/tests/atomictest/dev.c
new file mode 100644 (file)
index 0000000..687a7b8
--- /dev/null
@@ -0,0 +1,311 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <drm.h>
+#include <drm_fourcc.h>
+#include <errno.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "bo.h"
+#include "dev.h"
+#include "modeset.h"
+
+static uint32_t get_prop_id(struct sp_dev *dev,
+                       drmModeObjectPropertiesPtr props, const char *name)
+{
+       drmModePropertyPtr p;
+       uint32_t i, prop_id = 0; /* Property ID should always be > 0 */
+
+       for (i = 0; !prop_id && i < props->count_props; i++) {
+               p = drmModeGetProperty(dev->fd, props->props[i]);
+               if (!strcmp(p->name, name))
+                       prop_id = p->prop_id;
+               drmModeFreeProperty(p);
+       }
+       if (!prop_id)
+               printf("Could not find %s property\n", name);
+       return prop_id;
+}
+
+static int get_supported_format(struct sp_plane *plane, uint32_t *format)
+{
+       uint32_t i;
+
+       for (i = 0; i < plane->plane->count_formats; i++) {
+               if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 ||
+                   plane->plane->formats[i] == DRM_FORMAT_ARGB8888 ||
+                   plane->plane->formats[i] == DRM_FORMAT_RGBA8888) {
+                       *format = plane->plane->formats[i];
+                       return 0;
+               }
+       }
+       printf("No suitable formats found!\n");
+       return -ENOENT;
+}
+
+static struct sp_dev *create_sp_dev_from_name(char *name)
+{
+       struct sp_dev *dev;
+       int ret, fd, i, j;
+       drmModeRes *r = NULL;
+       drmModePlaneRes *pr = NULL;
+       char devPath[PATH_MAX];
+
+       strcpy(devPath, "/dev/dri/");
+       strcat(devPath, name);
+       fd = open(devPath, O_RDWR);
+       if (fd < 0) {
+               printf("failed to open card0\n");
+               return NULL;
+       }
+
+       dev = calloc(1, sizeof(*dev));
+       if (!dev) {
+               printf("failed to allocate dev\n");
+               return NULL;
+       }
+
+       dev->fd = fd;
+
+       ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+       if (ret) {
+               printf("failed to set client cap\n");
+               goto err;
+       }
+
+       r = drmModeGetResources(dev->fd);
+       if (!r) {
+               printf("%s failed to get r\n", devPath);
+               goto err;
+       }
+
+       if (!r->count_crtcs ||
+           !r->count_encoders ||
+           !r->count_connectors) {
+               printf("%s no display resources\n", devPath);
+               goto err;
+       }
+
+       dev->num_connectors = r->count_connectors;
+       dev->connectors = calloc(dev->num_connectors, sizeof(*dev->connectors));
+       if (!dev->connectors) {
+               printf("failed to allocate connectors\n");
+               goto err;
+       }
+       for (i = 0; i < dev->num_connectors; i++) {
+               dev->connectors[i] = drmModeGetConnector(dev->fd,
+                                       r->connectors[i]);
+               if (!dev->connectors[i]) {
+                       printf("failed to get connector %d\n", i);
+                       goto err;
+               }
+       }
+
+       dev->num_encoders = r->count_encoders;
+       dev->encoders = calloc(dev->num_encoders, sizeof(*dev->encoders));
+       if (!dev->encoders) {
+               printf("failed to allocate encoders\n");
+               goto err;
+       }
+       for (i = 0; i < dev->num_encoders; i++) {
+               dev->encoders[i] = drmModeGetEncoder(dev->fd, r->encoders[i]);
+               if (!dev->encoders[i]) {
+                       printf("failed to get encoder %d\n", i);
+                       goto err;
+               }
+       }
+
+       dev->num_crtcs = r->count_crtcs;
+       dev->crtcs = calloc(dev->num_crtcs, sizeof(struct sp_crtc));
+       if (!dev->crtcs) {
+               printf("failed to allocate crtcs\n");
+               goto err;
+       }
+       for (i = 0; i < dev->num_crtcs; i++) {
+               dev->crtcs[i].crtc = drmModeGetCrtc(dev->fd, r->crtcs[i]);
+               if (!dev->crtcs[i].crtc) {
+                       printf("failed to get crtc %d\n", i);
+                       goto err;
+               }
+               dev->crtcs[i].scanout = NULL;
+               dev->crtcs[i].pipe = i;
+               dev->crtcs[i].num_planes = 0;
+       }
+
+       pr = drmModeGetPlaneResources(dev->fd);
+       if (!pr) {
+               printf("failed to get plane resources\n");
+               goto err;
+       }
+       dev->num_planes = pr->count_planes;
+       dev->planes = calloc(dev->num_planes, sizeof(struct sp_plane));
+       for(i = 0; i < dev->num_planes; i++) {
+               drmModeObjectPropertiesPtr props;
+               struct sp_plane *plane = &dev->planes[i];
+
+               plane->dev = dev;
+               plane->plane = drmModeGetPlane(dev->fd, pr->planes[i]);
+               if (!plane->plane) {
+                       printf("failed to get plane %d\n", i);
+                       goto err;
+               }
+               plane->bo = NULL;
+               plane->in_use = 0;
+
+               ret = get_supported_format(plane, &plane->format);
+               if (ret) {
+                       printf("failed to get supported format: %d\n", ret);
+                       goto err;
+               }
+
+               for (j = 0; j < dev->num_crtcs; j++) {
+                       if (plane->plane->possible_crtcs & (1 << j))
+                               dev->crtcs[j].num_planes++;
+               }
+
+               props = drmModeObjectGetProperties(dev->fd, pr->planes[i],
+                               DRM_MODE_OBJECT_PLANE);
+               if (!props) {
+                       printf("failed to get plane properties\n");
+                       goto err;
+               }
+
+               plane->crtc_pid = get_prop_id(dev, props, "CRTC_ID");
+               if (!plane->crtc_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->fb_pid = get_prop_id(dev, props, "FB_ID");
+               if (!plane->fb_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->crtc_x_pid = get_prop_id(dev, props, "CRTC_X");
+               if (!plane->crtc_x_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->crtc_y_pid = get_prop_id(dev, props, "CRTC_Y");
+               if (!plane->crtc_y_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->crtc_w_pid = get_prop_id(dev, props, "CRTC_W");
+               if (!plane->crtc_w_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->crtc_h_pid = get_prop_id(dev, props, "CRTC_H");
+               if (!plane->crtc_h_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->src_x_pid = get_prop_id(dev, props, "SRC_X");
+               if (!plane->src_x_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->src_y_pid = get_prop_id(dev, props, "SRC_Y");
+               if (!plane->src_y_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->src_w_pid = get_prop_id(dev, props, "SRC_W");
+               if (!plane->src_w_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               plane->src_h_pid = get_prop_id(dev, props, "SRC_H");
+               if (!plane->src_h_pid) {
+                       drmModeFreeObjectProperties(props);
+                       goto err;
+               }
+               drmModeFreeObjectProperties(props);
+       }
+
+       if (pr)
+               drmModeFreePlaneResources(pr);
+       if (r)
+               drmModeFreeResources(r);
+
+       return dev;
+err:
+       if (pr)
+               drmModeFreePlaneResources(pr);
+       if (r)
+               drmModeFreeResources(r);
+       destroy_sp_dev(dev);
+       return NULL;
+}
+
+struct sp_dev *create_sp_dev(void)
+{
+       struct dirent de, *pde;
+       struct sp_dev *dev = NULL;
+       DIR *dir = opendir("/dev/dri");
+       int res;
+
+       if (!dir)
+               return NULL;
+
+       while ((res = readdir_r(dir, &de, &pde)) == 0) {
+               if (!pde)
+                       break;
+               if (de.d_type != DT_CHR)
+                       continue;
+               dev = create_sp_dev_from_name(de.d_name);
+               if (dev)
+                       break;
+       }
+       closedir(dir);
+       return dev;
+}
+
+void destroy_sp_dev(struct sp_dev *dev)
+{
+       int i;
+
+       if (dev->planes) {
+               for (i = 0; i< dev->num_planes; i++) {
+                       if (dev->planes[i].in_use)
+                               put_sp_plane(&dev->planes[i]);
+                       if (dev->planes[i].plane)
+                               drmModeFreePlane(dev->planes[i].plane);
+                       if (dev->planes[i].bo)
+                               free_sp_bo(dev->planes[i].bo);
+               }
+               free(dev->planes);
+       }
+       if (dev->crtcs) {
+               for (i = 0; i< dev->num_crtcs; i++) {
+                       if (dev->crtcs[i].crtc)
+                               drmModeFreeCrtc(dev->crtcs[i].crtc);
+                       if (dev->crtcs[i].scanout)
+                               free_sp_bo(dev->crtcs[i].scanout);
+               }
+               free(dev->crtcs);
+       }
+       if (dev->encoders) {
+               for (i = 0; i< dev->num_encoders; i++) {
+                       if (dev->encoders[i])
+                               drmModeFreeEncoder(dev->encoders[i]);
+               }
+               free(dev->encoders);
+       }
+       if (dev->connectors) {
+               for (i = 0; i< dev->num_connectors; i++) {
+                       if (dev->connectors[i])
+                               drmModeFreeConnector(dev->connectors[i]);
+               }
+               free(dev->connectors);
+       }
+
+       close(dev->fd);
+       free(dev);
+}
diff --git a/tests/atomictest/dev.h b/tests/atomictest/dev.h
new file mode 100644 (file)
index 0000000..9e6d923
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __DEV_H_INCLUDED__
+#define __DEV_H_INCLUDED__
+
+#include <stdint.h>
+#include <xf86drmMode.h>
+
+struct sp_bo;
+struct sp_dev;
+
+struct sp_plane {
+       struct sp_dev *dev;
+       drmModePlanePtr plane;
+       struct sp_bo *bo;
+       int in_use;
+       uint32_t format;
+
+       /* Property ID's */
+       uint32_t crtc_pid;
+       uint32_t fb_pid;
+       uint32_t zpos_pid;
+       uint32_t crtc_x_pid;
+       uint32_t crtc_y_pid;
+       uint32_t crtc_w_pid;
+       uint32_t crtc_h_pid;
+       uint32_t src_x_pid;
+       uint32_t src_y_pid;
+       uint32_t src_w_pid;
+       uint32_t src_h_pid;
+};
+
+struct sp_crtc {
+       drmModeCrtcPtr crtc;
+       int pipe;
+       int num_planes;
+       struct sp_bo *scanout;
+};
+
+struct sp_dev {
+       int fd;
+
+       int num_connectors;
+       drmModeConnectorPtr *connectors;
+
+       int num_encoders;
+       drmModeEncoderPtr *encoders;
+
+       int num_crtcs;
+       struct sp_crtc *crtcs;
+
+       int num_planes;
+       struct sp_plane *planes;
+};
+
+struct sp_dev *create_sp_dev(void);
+void destroy_sp_dev(struct sp_dev *dev);
+
+#endif /* __DEV_H_INCLUDED__ */
diff --git a/tests/atomictest/modeset.c b/tests/atomictest/modeset.c
new file mode 100644 (file)
index 0000000..c0580ff
--- /dev/null
@@ -0,0 +1,238 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm_fourcc.h>
+
+#include "modeset.h"
+#include "bo.h"
+#include "dev.h"
+
+int initialize_screens(struct sp_dev *dev)
+{
+       int ret, i, j, k;
+
+       for (i = 0; i < dev->num_connectors; i++) {
+               drmModeConnectorPtr c = dev->connectors[i];
+               drmModeModeInfoPtr m = NULL;
+               drmModeEncoderPtr e = NULL;
+               struct sp_crtc *cr = NULL;
+
+               if (c->connection != DRM_MODE_CONNECTED)
+                       continue;
+
+               if (!c->count_modes) {
+                       printf("connector has no modes, skipping\n");
+                       continue;
+               }
+
+               /* Take the first unless there's a preferred mode */
+               m = &c->modes[0];
+               for (j = 0; j < c->count_modes; j++) {
+                       drmModeModeInfoPtr tmp_m = &c->modes[j];
+
+                       if (!(tmp_m->type & DRM_MODE_TYPE_PREFERRED))
+                               continue;
+
+                       m = tmp_m;
+                       break;
+               }
+
+               for (j = 0; j < dev->num_encoders; j++) {
+                       e = dev->encoders[j];
+                       if (!e)
+                               continue;
+                       for (k = 0; k < c->count_encoders; k++) {
+                               if (e->encoder_id == c->encoders[k])
+                                       break;
+                       }
+                       if (k < c->count_encoders)
+                               break;
+               }
+
+               if (j == dev->num_encoders) {
+                       printf("could not find supported encoder for the connector\n");
+                       continue;
+               }
+
+               for (j = 0; j < dev->num_crtcs; j++) {
+                       cr = &dev->crtcs[j];
+                       if (e->possible_crtcs & (1 << j)) {
+                               e->crtc_id = cr->crtc->crtc_id;
+                               break;
+                       }
+               }
+
+               if (j == dev->num_crtcs) {
+                       printf("could not find crtc for the encoder\n");
+                       continue;
+               }
+
+               if (cr->scanout) {
+                       printf("crtc already in use\n");
+                       continue;
+               }
+
+               /* XXX: Hardcoding the format here... :| */
+               cr->scanout = create_sp_bo(dev, m->hdisplay, m->vdisplay,
+                               24, 32, DRM_FORMAT_XRGB8888, 0);
+               if (!cr->scanout) {
+                       printf("failed to create new scanout bo\n");
+                       continue;
+               }
+
+               fill_bo(cr->scanout, 0xFF, 0xFF, 0xFF, 0x00);
+
+               ret = drmModeSetCrtc(dev->fd, cr->crtc->crtc_id,
+                               cr->scanout->fb_id, 0, 0, &c->connector_id,
+                               1, m);
+               if (ret) {
+                       printf("failed to set crtc mode ret=%d\n", ret);
+                       continue;
+               }
+
+               cr->crtc->mode.hdisplay = m->hdisplay;
+               cr->crtc->mode.vdisplay = m->vdisplay;
+       }
+       return 0;
+}
+
+struct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc)
+{
+       int i;
+
+       for(i = 0; i < dev->num_planes; i++) {
+               struct sp_plane *p = &dev->planes[i];
+
+               if (p->in_use)
+                       continue;
+
+               if (!(p->plane->possible_crtcs & (1 << crtc->pipe)))
+                       continue;
+
+               p->in_use = 1;
+               return p;
+       }
+       return NULL;
+}
+
+void put_sp_plane(struct sp_plane *plane)
+{
+       drmModePlanePtr p;
+
+       /* Get the latest plane information (most notably the crtc_id) */
+       p = drmModeGetPlane(plane->dev->fd, plane->plane->plane_id);
+       if (p)
+               plane->plane = p;
+
+       if (plane->plane->crtc_id)
+               drmModeSetPlane(plane->dev->fd, plane->plane->plane_id,
+                               plane->plane->crtc_id, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0);
+
+       if (plane->bo) {
+               free_sp_bo(plane->bo);
+               plane->bo = NULL;
+       }
+       plane->in_use = 0;
+}
+
+int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane,
+               struct sp_crtc *crtc, int x, int y)
+{
+       int ret;
+       uint32_t w, h;
+
+       w = plane->bo->width;
+       h = plane->bo->height;
+
+       if ((w + x) > crtc->crtc->mode.hdisplay)
+               w = crtc->crtc->mode.hdisplay - x;
+       if ((h + y) > crtc->crtc->mode.vdisplay)
+               h = crtc->crtc->mode.vdisplay - y;
+
+       ret = drmModeSetPlane(dev->fd, plane->plane->plane_id,
+                       crtc->crtc->crtc_id, plane->bo->fb_id, 0, x, y, w, h,
+                       0, 0, w << 16, h << 16);
+       if (ret) {
+               printf("failed to set plane to crtc ret=%d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane,
+               drmModeAtomicReqPtr pset, struct sp_crtc *crtc, int x, int y)
+{
+       int ret;
+       uint32_t w, h;
+
+       w = plane->bo->width;
+       h = plane->bo->height;
+
+       if ((w + x) > crtc->crtc->mode.hdisplay)
+               w = crtc->crtc->mode.hdisplay - x;
+       if ((h + y) > crtc->crtc->mode.vdisplay)
+               h = crtc->crtc->mode.vdisplay - y;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->crtc_pid, crtc->crtc->crtc_id);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->fb_pid, plane->bo->fb_id);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->crtc_x_pid, x);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->crtc_y_pid, y);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->crtc_w_pid, w);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->crtc_h_pid, h);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->src_x_pid, 0);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->src_y_pid, 0);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->src_w_pid, w << 16);
+       if (ret < 0)
+               goto err;
+
+       ret = drmModeAtomicAddProperty(pset, plane->plane->plane_id,
+                       plane->src_h_pid, h << 16);
+       if (ret < 0) {
+               printf("failed to add properties to the set\n");
+               return ret;
+       }
+
+       return ret;
+
+err:
+       printf("failed to add properties to the set\n");
+       return ret;
+}
diff --git a/tests/atomictest/modeset.h b/tests/atomictest/modeset.h
new file mode 100644 (file)
index 0000000..5499959
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __MODESET_H_INCLUDED__
+#define __MODESET_H_INCLUDED__
+
+struct sp_dev;
+struct sp_crtc;
+
+int initialize_screens(struct sp_dev *dev);
+
+
+struct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc);
+void put_sp_plane(struct sp_plane *plane);
+
+int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane,
+               struct sp_crtc *crtc, int x, int y);
+
+int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane,
+               drmModeAtomicReqPtr pset, struct sp_crtc *crtc, int x, int y);
+
+#endif /* __MODESET_H_INCLUDED__ */