/* * Copyright © 2014 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. */ #include <fcntl.h> #include <getopt.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <unistd.h> #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> #endif #include <drm_fourcc.h> #include "xf86drm.h" #include "util/common.h" #include "libkms-test.h" static const uint32_t formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGBA8888, }; 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; } static void prepare_framebuffer(struct kms_framebuffer *fb, bool invert) { const unsigned int block_size = 16; uint32_t colors[2]; unsigned int i, j; uint32_t *buf; void *ptr; int err; switch (fb->format) { case DRM_FORMAT_XRGB8888: printf("using XRGB8888 format\n"); /* XXRRGGBB */ colors[0] = 0xffff0000; colors[1] = 0xff0000ff; break; case DRM_FORMAT_XBGR8888: printf("using XBGR8888 format\n"); /* XXBBGGRR */ colors[0] = 0xff0000ff; colors[1] = 0xffff0000; break; case DRM_FORMAT_RGBA8888: printf("using RGBA8888 format\n"); /* RRGGBBAA */ colors[0] = 0xff0000ff; colors[1] = 0x0000ffff; break; default: colors[0] = 0xffffffff; colors[1] = 0xffffffff; break; } err = kms_framebuffer_map(fb, &ptr); if (err < 0) { fprintf(stderr, "kms_framebuffer_map() failed: %s\n", strerror(-err)); return; } buf = ptr; for (j = 0; j < fb->height; j++) { for (i = 0; i < fb->width; i++) { unsigned int color = (j / block_size) ^ (i / block_size); if (invert) color ^= color; *buf++ = colors[color & 1]; } } kms_framebuffer_unmap(fb); } int main(int argc, char *argv[]) { static const char opts[] = "chopv"; static struct option options[] = { { "cursor", 0, 0, 'c' }, { "help", 0, 0, 'h' }, { "overlay", 0, 0, 'o' }, { "primary", 0, 0, 'p' }, { "verbose", 0, 0, 'v' }, { 0, 0, 0, 0 }, }; struct kms_framebuffer *cursor = NULL; struct kms_framebuffer *root = NULL; struct kms_framebuffer *fb = NULL; struct kms_device *device; bool use_overlay = false; bool use_primary = false; struct kms_plane *plane; bool use_cursor = false; bool verbose = false; unsigned int i; int opt, idx; int fd, err; while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) { switch (opt) { case 'c': use_cursor = true; break; case 'h': break; case 'o': use_overlay = true; break; case 'p': use_primary = true; 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++) { const char *type = NULL; plane = device->planes[i]; 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); } } if (use_cursor) { unsigned int x, y; uint32_t format; plane = kms_device_find_plane_by_type(device, DRM_PLANE_TYPE_CURSOR, 0); if (!plane) { fprintf(stderr, "no cursor plane found\n"); return 1; } format = choose_format(plane); if (!format) { fprintf(stderr, "no matching format found\n"); return 1; } cursor = kms_framebuffer_create(device, 32, 32, format); if (!cursor) { fprintf(stderr, "failed to create cursor buffer\n"); return 1; } prepare_framebuffer(cursor, false); x = (device->screens[0]->width - cursor->width) / 2; y = (device->screens[0]->height - cursor->height) / 2; kms_plane_set(plane, cursor, x, y); } if (use_overlay) { uint32_t format; plane = kms_device_find_plane_by_type(device, DRM_PLANE_TYPE_OVERLAY, 0); if (!plane) { fprintf(stderr, "no overlay plane found\n"); return 1; } format = choose_format(plane); if (!format) { fprintf(stderr, "no matching format found\n"); return 1; } fb = kms_framebuffer_create(device, 320, 240, format); if (!fb) return 1; prepare_framebuffer(fb, false); kms_plane_set(plane, fb, 0, 0); } if (use_primary) { unsigned int x, y; uint32_t format; plane = kms_device_find_plane_by_type(device, DRM_PLANE_TYPE_PRIMARY, 0); if (!plane) { fprintf(stderr, "no primary plane found\n"); return 1; } format = choose_format(plane); if (!format) { fprintf(stderr, "no matching format found\n"); return 1; } root = kms_framebuffer_create(device, 640, 480, format); if (!root) return 1; prepare_framebuffer(root, true); x = (device->screens[0]->width - root->width) / 2; y = (device->screens[0]->height - root->height) / 2; kms_plane_set(plane, root, 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; } if (cursor) kms_framebuffer_free(cursor); if (root) kms_framebuffer_free(root); if (fb) kms_framebuffer_free(fb); kms_device_close(device); close(fd); return 0; }