1 /*
2 * Copyright © 2014 NVIDIA Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <fcntl.h>
29 #include <getopt.h>
30 #include <stdbool.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 #ifdef HAVE_SYS_SELECT_H
36 #include <sys/select.h>
37 #endif
38
39 #include <drm_fourcc.h>
40 #include "xf86drm.h"
41
42 #include "util/common.h"
43 #include "libkms-test.h"
44
45 static const uint32_t formats[] = {
46 DRM_FORMAT_XRGB8888,
47 DRM_FORMAT_XBGR8888,
48 DRM_FORMAT_RGBA8888,
49 };
50
choose_format(struct kms_plane * plane)51 static uint32_t choose_format(struct kms_plane *plane)
52 {
53 unsigned int i;
54
55 for (i = 0; i < ARRAY_SIZE(formats); i++)
56 if (kms_plane_supports_format(plane, formats[i]))
57 return formats[i];
58
59 return 0;
60 }
61
prepare_framebuffer(struct kms_framebuffer * fb,bool invert)62 static void prepare_framebuffer(struct kms_framebuffer *fb, bool invert)
63 {
64 const unsigned int block_size = 16;
65 uint32_t colors[2];
66 unsigned int i, j;
67 uint32_t *buf;
68 void *ptr;
69 int err;
70
71 switch (fb->format) {
72 case DRM_FORMAT_XRGB8888:
73 printf("using XRGB8888 format\n");
74 /* XXRRGGBB */
75 colors[0] = 0xffff0000;
76 colors[1] = 0xff0000ff;
77 break;
78
79 case DRM_FORMAT_XBGR8888:
80 printf("using XBGR8888 format\n");
81 /* XXBBGGRR */
82 colors[0] = 0xff0000ff;
83 colors[1] = 0xffff0000;
84 break;
85
86 case DRM_FORMAT_RGBA8888:
87 printf("using RGBA8888 format\n");
88 /* RRGGBBAA */
89 colors[0] = 0xff0000ff;
90 colors[1] = 0x0000ffff;
91 break;
92
93 default:
94 colors[0] = 0xffffffff;
95 colors[1] = 0xffffffff;
96 break;
97 }
98
99 err = kms_framebuffer_map(fb, &ptr);
100 if (err < 0) {
101 fprintf(stderr, "kms_framebuffer_map() failed: %s\n",
102 strerror(-err));
103 return;
104 }
105
106 buf = ptr;
107
108 for (j = 0; j < fb->height; j++) {
109 for (i = 0; i < fb->width; i++) {
110 unsigned int color = (j / block_size) ^
111 (i / block_size);
112
113 if (invert)
114 color ^= color;
115
116 *buf++ = colors[color & 1];
117 }
118 }
119
120 kms_framebuffer_unmap(fb);
121 }
122
main(int argc,char * argv[])123 int main(int argc, char *argv[])
124 {
125 static const char opts[] = "chopv";
126 static struct option options[] = {
127 { "cursor", 0, 0, 'c' },
128 { "help", 0, 0, 'h' },
129 { "overlay", 0, 0, 'o' },
130 { "primary", 0, 0, 'p' },
131 { "verbose", 0, 0, 'v' },
132 { 0, 0, 0, 0 },
133 };
134 struct kms_framebuffer *cursor = NULL;
135 struct kms_framebuffer *root = NULL;
136 struct kms_framebuffer *fb = NULL;
137 struct kms_device *device;
138 bool use_overlay = false;
139 bool use_primary = false;
140 struct kms_plane *plane;
141 bool use_cursor = false;
142 bool verbose = false;
143 unsigned int i;
144 int opt, idx;
145 int fd, err;
146
147 while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) {
148 switch (opt) {
149 case 'c':
150 use_cursor = true;
151 break;
152
153 case 'h':
154 break;
155
156 case 'o':
157 use_overlay = true;
158 break;
159
160 case 'p':
161 use_primary = true;
162 break;
163
164 case 'v':
165 verbose = true;
166 break;
167
168 default:
169 printf("unknown option \"%c\"\n", opt);
170 return 1;
171 }
172 }
173
174 if (optind >= argc) {
175 fprintf(stderr, "usage: %s [options] DEVICE\n", argv[0]);
176 return 1;
177 }
178
179 fd = open(argv[optind], O_RDWR);
180 if (fd < 0) {
181 fprintf(stderr, "open() failed: %m\n");
182 return 1;
183 }
184
185 err = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
186 if (err < 0) {
187 fprintf(stderr, "drmSetClientCap() failed: %d\n", err);
188 return 1;
189 }
190
191 device = kms_device_open(fd);
192 if (!device)
193 return 1;
194
195 if (verbose) {
196 printf("Screens: %u\n", device->num_screens);
197
198 for (i = 0; i < device->num_screens; i++) {
199 struct kms_screen *screen = device->screens[i];
200 const char *status = "disconnected";
201
202 if (screen->connected)
203 status = "connected";
204
205 printf(" %u: %x\n", i, screen->id);
206 printf(" Status: %s\n", status);
207 printf(" Name: %s\n", screen->name);
208 printf(" Resolution: %ux%u\n", screen->width,
209 screen->height);
210 }
211
212 printf("Planes: %u\n", device->num_planes);
213
214 for (i = 0; i < device->num_planes; i++) {
215 const char *type = NULL;
216
217 plane = device->planes[i];
218 switch (plane->type) {
219 case DRM_PLANE_TYPE_OVERLAY:
220 type = "overlay";
221 break;
222
223 case DRM_PLANE_TYPE_PRIMARY:
224 type = "primary";
225 break;
226
227 case DRM_PLANE_TYPE_CURSOR:
228 type = "cursor";
229 break;
230 }
231
232 printf(" %u: %p\n", i, plane);
233 printf(" ID: %x\n", plane->id);
234 printf(" CRTC: %x\n", plane->crtc->id);
235 printf(" Type: %x (%s)\n", plane->type, type);
236 }
237 }
238
239 if (use_cursor) {
240 unsigned int x, y;
241 uint32_t format;
242
243 plane = kms_device_find_plane_by_type(device,
244 DRM_PLANE_TYPE_CURSOR,
245 0);
246 if (!plane) {
247 fprintf(stderr, "no cursor plane found\n");
248 return 1;
249 }
250
251 format = choose_format(plane);
252 if (!format) {
253 fprintf(stderr, "no matching format found\n");
254 return 1;
255 }
256
257 cursor = kms_framebuffer_create(device, 32, 32, format);
258 if (!cursor) {
259 fprintf(stderr, "failed to create cursor buffer\n");
260 return 1;
261 }
262
263 prepare_framebuffer(cursor, false);
264
265 x = (device->screens[0]->width - cursor->width) / 2;
266 y = (device->screens[0]->height - cursor->height) / 2;
267
268 kms_plane_set(plane, cursor, x, y);
269 }
270
271 if (use_overlay) {
272 uint32_t format;
273
274 plane = kms_device_find_plane_by_type(device,
275 DRM_PLANE_TYPE_OVERLAY,
276 0);
277 if (!plane) {
278 fprintf(stderr, "no overlay plane found\n");
279 return 1;
280 }
281
282 format = choose_format(plane);
283 if (!format) {
284 fprintf(stderr, "no matching format found\n");
285 return 1;
286 }
287
288 fb = kms_framebuffer_create(device, 320, 240, format);
289 if (!fb)
290 return 1;
291
292 prepare_framebuffer(fb, false);
293
294 kms_plane_set(plane, fb, 0, 0);
295 }
296
297 if (use_primary) {
298 unsigned int x, y;
299 uint32_t format;
300
301 plane = kms_device_find_plane_by_type(device,
302 DRM_PLANE_TYPE_PRIMARY,
303 0);
304 if (!plane) {
305 fprintf(stderr, "no primary plane found\n");
306 return 1;
307 }
308
309 format = choose_format(plane);
310 if (!format) {
311 fprintf(stderr, "no matching format found\n");
312 return 1;
313 }
314
315 root = kms_framebuffer_create(device, 640, 480, format);
316 if (!root)
317 return 1;
318
319 prepare_framebuffer(root, true);
320
321 x = (device->screens[0]->width - root->width) / 2;
322 y = (device->screens[0]->height - root->height) / 2;
323
324 kms_plane_set(plane, root, x, y);
325 }
326
327 while (1) {
328 struct timeval timeout = { 1, 0 };
329 fd_set fds;
330
331 FD_ZERO(&fds);
332 FD_SET(STDIN_FILENO, &fds);
333
334 err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout);
335 if (err < 0) {
336 fprintf(stderr, "select() failed: %m\n");
337 break;
338 }
339
340 /* timeout */
341 if (err == 0)
342 continue;
343
344 if (FD_ISSET(STDIN_FILENO, &fds))
345 break;
346 }
347
348 if (cursor)
349 kms_framebuffer_free(cursor);
350
351 if (root)
352 kms_framebuffer_free(root);
353
354 if (fb)
355 kms_framebuffer_free(fb);
356
357 kms_device_close(device);
358 close(fd);
359
360 return 0;
361 }
362