From 7217010e438d52501ec154050cc0792f30b50161 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 20 Dec 2017 21:09:40 +0100 Subject: tests: kms: Add planes blending test Note that this is kind of Tegra specific right now since it assumes the existence of three planes and that the planes are in the Tegra Z-order, which means the first plane is lowest and the third plane is highest. Signed-off-by: Thierry Reding --- tests/kms/Makefile.am | 5 + tests/kms/kms-planes-blend.c | 342 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 tests/kms/kms-planes-blend.c diff --git a/tests/kms/Makefile.am b/tests/kms/Makefile.am index 6645af7a..beb679b2 100644 --- a/tests/kms/Makefile.am +++ b/tests/kms/Makefile.am @@ -21,14 +21,19 @@ libkms_test_la_LIBADD = \ if HAVE_INSTALL_TESTS bin_PROGRAMS = \ + kms-planes-blend \ kms-steal-crtc \ kms-universal-planes else noinst_PROGRAMS = \ + kms-planes-blend \ kms-steal-crtc \ kms-universal-planes endif +kms_planes_blend_SOURCES = kms-planes-blend.c +kms_planes_blend_LDADD = libkms-test.la $(CAIRO_LIBS) + kms_steal_crtc_SOURCES = kms-steal-crtc.c kms_steal_crtc_LDADD = libkms-test.la ../util/libutil.la $(CAIRO_LIBS) diff --git a/tests/kms/kms-planes-blend.c b/tests/kms/kms-planes-blend.c new file mode 100644 index 00000000..c2cc232d --- /dev/null +++ b/tests/kms/kms-planes-blend.c @@ -0,0 +1,342 @@ +/* + * Copyright © 2017 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include +#include "xf86drm.h" + +#include "util/common.h" +#include "libkms-test.h" + +#define TEST_PER_PLANE_FORMAT 1 + +#ifndef TEST_PER_PLANE_FORMAT +static const uint32_t formats[] = { + //DRM_FORMAT_XRGB8888, + //DRM_FORMAT_RGB565, + //DRM_FORMAT_RGBA8888, + //DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + //DRM_FORMAT_ABGR8888, + //DRM_FORMAT_ARGB1555, + //DRM_FORMAT_BGRA5551, +}; + +static uint32_t choose_format(struct kms_plane *plane) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (kms_plane_supports_format(plane, formats[i])) + return formats[i]; + + return 0; +} +#endif + +struct kms_color { + uint64_t value; + size_t size; +}; + +static int kms_color_set(struct kms_color *color, uint32_t format, + uint16_t red, uint16_t green, uint16_t blue, + uint16_t alpha) +{ + switch (format) { + case DRM_FORMAT_ARGB1555: + color->value = ((alpha >> 15) & 0x1) << 15 | ((red >> 11) & 0x1f) << 10 | ((green >> 11) & 0x1f) << 5 | ((blue >> 11) & 0x1f); + color->size = 2; + return 0; + + case DRM_FORMAT_BGRA5551: + color->value = ((blue >> 11) & 0x1f) << 11 | ((green >> 11) & 0x1f) << 6 | ((red >> 11) & 0x1f) << 1 | ((alpha >> 15) & 0x1); + color->size = 2; + return 0; + + case DRM_FORMAT_RGB565: + color->value = ((red >> 11) & 0x1f) << 11 | + ((green >> 10) & 0x3f) << 5 | + ((blue >> 11) & 0x1f); + color->size = 2; + return 0; + + case DRM_FORMAT_RGBA8888: + color->value = ((red >> 8) & 0xff) << 24 | ((green >> 8) & 0xff) << 16 | + ((blue >> 8) & 0xff) << 8 | ((alpha >> 8) & 0xff); + color->size = 4; + return 0; + + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + color->value = ((alpha >> 8) & 0xff) << 24 | ((red >> 8) & 0xff) << 16 | + ((green >> 8) & 0xff) << 8 | ((blue >> 8) & 0xff); + color->size = 4; + return 0; + + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + color->value = ((alpha >> 8) & 0xff) << 24 | ((blue >> 8) & 0xff) << 16 | + ((green >> 8) & 0xff) << 8 | ((red >> 8) & 0xff); + color->size = 4; + return 0; + } + + return -EINVAL; +} + +static void kms_framebuffer_clear(struct kms_framebuffer *fb, + const struct kms_color *color) +{ + unsigned int i, j; + void *ptr; + int err; + + err = kms_framebuffer_map(fb, &ptr); + if (err < 0) { + fprintf(stderr, "kms_framebuffer_map() failed: %s\n", strerror(-err)); + return; + } + + printf("clearing with %" PRIx64 "\n", color->value); + + for (j = 0; j < fb->height; j++) { + for (i = 0; i < fb->width; i++) { + switch (color->size) { + case 4: + ((uint32_t *)ptr)[j * fb->width + i] = (uint32_t)color->value; + break; + + case 2: + ((uint16_t *)ptr)[j * fb->width + i] = 0xffff;//(uint16_t)color->value; + break; + + default: + break; + } + } + } + + kms_framebuffer_unmap(fb); +} + +int main(int argc, char *argv[]) +{ + static const char opts[] = "chopv"; + static struct option options[] = { + { "help", 0, 0, 'h' }, + { "verbose", 0, 0, 'v' }, + { 0, 0, 0, 0 }, + }; + struct kms_framebuffer *fbs[3]; + struct kms_device *device; + bool verbose = false; + unsigned int size; + unsigned int i; + int opt, idx; + int fd, err; + + while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) { + switch (opt) { + case 'h': + break; + + case 'v': + verbose = true; + break; + + default: + printf("unknown option \"%c\"\n", opt); + return 1; + } + } + + if (optind >= argc) { + fprintf(stderr, "usage: %s [options] DEVICE\n", argv[0]); + return 1; + } + + fd = open(argv[optind], O_RDWR); + if (fd < 0) { + fprintf(stderr, "open() failed: %m\n"); + return 1; + } + + err = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (err < 0) { + fprintf(stderr, "drmSetClientCap() failed: %d\n", err); + return 1; + } + + device = kms_device_open(fd); + if (!device) + return 1; + + if (verbose) { + printf("Screens: %u\n", device->num_screens); + + for (i = 0; i < device->num_screens; i++) { + struct kms_screen *screen = device->screens[i]; + const char *status = "disconnected"; + + if (screen->connected) + status = "connected"; + + printf(" %u: %x\n", i, screen->id); + printf(" Status: %s\n", status); + printf(" Name: %s\n", screen->name); + printf(" Resolution: %ux%u\n", screen->width, + screen->height); + } + + printf("Planes: %u\n", device->num_planes); + + for (i = 0; i < device->num_planes; i++) { + struct kms_plane *plane = device->planes[i]; + const char *type = NULL; + + switch (plane->type) { + case DRM_PLANE_TYPE_OVERLAY: + type = "overlay"; + break; + + case DRM_PLANE_TYPE_PRIMARY: + type = "primary"; + break; + + case DRM_PLANE_TYPE_CURSOR: + type = "cursor"; + break; + } + + printf(" %u: %p\n", i, plane); + printf(" ID: %x\n", plane->id); + printf(" CRTC: %x\n", plane->crtc->id); + printf(" Type: %x (%s)\n", plane->type, type); + } + } + + size = device->screens[0]->height / 2; + + for (i = 0; i < 3; i++) { +#ifndef TEST_PER_PLANE_FORMAT + struct kms_plane *plane = device->planes[i]; +#endif + const struct { + uint32_t format; + uint16_t red; + uint16_t green; + uint16_t blue; + uint16_t alpha; + } colors[3] = { + { DRM_FORMAT_XRGB8888, 0xffff, 0x0000, 0x0000, 0x7fff }, + { DRM_FORMAT_ARGB8888, 0x0000, 0xffff, 0x0000, 0x7fff }, + { DRM_FORMAT_XRGB8888, 0x0000, 0x0000, 0xffff, 0x7fff }, + }; + struct kms_color color; + uint32_t format; + +#ifndef TEST_PER_PLANE_FORMAT + format = choose_format(plane); + if (!format) { + fprintf(stderr, "no matching format found\n"); + return 1; + } +#else + format = colors[i].format; +#endif + + fbs[i] = kms_framebuffer_create(device, size, size, format); + if (!fbs[i]) { + fprintf(stderr, "failed to create framebuffer\n"); + return 1; + } + + kms_color_set(&color, format, colors[i].red, colors[i].green, + colors[i].blue, colors[i].alpha); + kms_framebuffer_clear(fbs[i], &color); + } + + for (i = 0; i < 3; i++) { + struct kms_plane *plane = device->planes[i]; + const struct { + int x; + int y; + } position[3] = { + { -(size / 4), -(size / 4) }, + { (size / 4), -(size / 4) }, + { 0, (size / 4) }, + }; + unsigned int x, y; + + x = ((device->screens[0]->width - size) / 2) + position[i].x; + y = ((device->screens[0]->height - size) / 2) + position[i].y; + + kms_plane_set(plane, fbs[i], x, y); + } + + while (1) { + struct timeval timeout = { 1, 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + + err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout); + if (err < 0) { + fprintf(stderr, "select() failed: %m\n"); + break; + } + + /* timeout */ + if (err == 0) + continue; + + if (FD_ISSET(STDIN_FILENO, &fds)) + break; + } + + for (i = 0; i < 3; i++) + kms_framebuffer_free(fbs[i]); + + kms_device_close(device); + close(fd); + + return 0; +} -- cgit v1.2.3