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 #include <fcntl.h>
25 #include <getopt.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #if HAVE_SYS_SELECT_H
32 #include <sys/select.h>
33 #endif
34
35 #include <drm_fourcc.h>
36 #include "xf86drm.h"
37
38 #include "util/common.h"
39 #include "libkms-test.h"
40
41 static const uint32_t formats[] = {
42 DRM_FORMAT_XRGB8888,
43 DRM_FORMAT_XBGR8888,
44 DRM_FORMAT_RGBA8888,
45 };
46
choose_format(struct kms_plane * plane)47 static uint32_t choose_format(struct kms_plane *plane)
48 {
49 unsigned int i;
50
51 for (i = 0; i < ARRAY_SIZE(formats); i++)
52 if (kms_plane_supports_format(plane, formats[i]))
53 return formats[i];
54
55 return 0;
56 }
57
prepare_framebuffer(struct kms_framebuffer * fb,bool invert)58 static void prepare_framebuffer(struct kms_framebuffer *fb, bool invert)
59 {
60 const unsigned int block_size = 16;
61 uint32_t colors[2];
62 unsigned int i, j;
63 uint32_t *buf;
64 void *ptr;
65 int err;
66
67 switch (fb->format) {
68 case DRM_FORMAT_XRGB8888:
69 printf("using XRGB8888 format\n");
70 /* XXRRGGBB */
71 colors[0] = 0xffff0000;
72 colors[1] = 0xff0000ff;
73 break;
74
75 case DRM_FORMAT_XBGR8888:
76 printf("using XBGR8888 format\n");
77 /* XXBBGGRR */
78 colors[0] = 0xff0000ff;
79 colors[1] = 0xffff0000;
80 break;
81
82 case DRM_FORMAT_RGBA8888:
83 printf("using RGBA8888 format\n");
84 /* RRGGBBAA */
85 colors[0] = 0xff0000ff;
86 colors[1] = 0x0000ffff;
87 break;
88
89 default:
90 colors[0] = 0xffffffff;
91 colors[1] = 0xffffffff;
92 break;
93 }
94
95 err = kms_framebuffer_map(fb, &ptr);
96 if (err < 0) {
97 fprintf(stderr, "kms_framebuffer_map() failed: %s\n",
98 strerror(-err));
99 return;
100 }
101
102 buf = ptr;
103
104 for (j = 0; j < fb->height; j++) {
105 for (i = 0; i < fb->width; i++) {
106 unsigned int color = (j / block_size) ^
107 (i / block_size);
108
109 if (invert)
110 color ^= color;
111
112 *buf++ = colors[color & 1];
113 }
114 }
115
116 kms_framebuffer_unmap(fb);
117 }
118
main(int argc,char * argv[])119 int main(int argc, char *argv[])
120 {
121 static const char opts[] = "chopv";
122 static struct option options[] = {
123 { "cursor", 0, 0, 'c' },
124 { "help", 0, 0, 'h' },
125 { "overlay", 0, 0, 'o' },
126 { "primary", 0, 0, 'p' },
127 { "verbose", 0, 0, 'v' },
128 { 0, 0, 0, 0 },
129 };
130 struct kms_framebuffer *cursor = NULL;
131 struct kms_framebuffer *root = NULL;
132 struct kms_framebuffer *fb = NULL;
133 struct kms_device *device;
134 bool use_overlay = false;
135 bool use_primary = false;
136 struct kms_plane *plane;
137 bool use_cursor = false;
138 bool verbose = false;
139 unsigned int i;
140 int opt, idx;
141 int fd, err;
142
143 while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) {
144 switch (opt) {
145 case 'c':
146 use_cursor = true;
147 break;
148
149 case 'h':
150 break;
151
152 case 'o':
153 use_overlay = true;
154 break;
155
156 case 'p':
157 use_primary = true;
158 break;
159
160 case 'v':
161 verbose = true;
162 break;
163
164 default:
165 printf("unknown option \"%c\"\n", opt);
166 return 1;
167 }
168 }
169
170 if (optind >= argc) {
171 fprintf(stderr, "usage: %s [options] DEVICE\n", argv[0]);
172 return 1;
173 }
174
175 fd = open(argv[optind], O_RDWR);
176 if (fd < 0) {
177 fprintf(stderr, "open() failed: %m\n");
178 return 1;
179 }
180
181 err = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
182 if (err < 0) {
183 fprintf(stderr, "drmSetClientCap() failed: %d\n", err);
184 return 1;
185 }
186
187 device = kms_device_open(fd);
188 if (!device)
189 return 1;
190
191 if (verbose) {
192 printf("Screens: %u\n", device->num_screens);
193
194 for (i = 0; i < device->num_screens; i++) {
195 struct kms_screen *screen = device->screens[i];
196 const char *status = "disconnected";
197
198 if (screen->connected)
199 status = "connected";
200
201 printf(" %u: %x\n", i, screen->id);
202 printf(" Status: %s\n", status);
203 printf(" Name: %s\n", screen->name);
204 printf(" Resolution: %ux%u\n", screen->width,
205 screen->height);
206 }
207
208 printf("Planes: %u\n", device->num_planes);
209
210 for (i = 0; i < device->num_planes; i++) {
211 const char *type = NULL;
212
213 plane = device->planes[i];
214 switch (plane->type) {
215 case DRM_PLANE_TYPE_OVERLAY:
216 type = "overlay";
217 break;
218
219 case DRM_PLANE_TYPE_PRIMARY:
220 type = "primary";
221 break;
222
223 case DRM_PLANE_TYPE_CURSOR:
224 type = "cursor";
225 break;
226 }
227
228 printf(" %u: %p\n", i, plane);
229 printf(" ID: %x\n", plane->id);
230 printf(" CRTC: %x\n", plane->crtc->id);
231 printf(" Type: %x (%s)\n", plane->type, type);
232 }
233 }
234
235 if (use_cursor) {
236 unsigned int x, y;
237 uint32_t format;
238
239 plane = kms_device_find_plane_by_type(device,
240 DRM_PLANE_TYPE_CURSOR,
241 0);
242 if (!plane) {
243 fprintf(stderr, "no cursor plane found\n");
244 return 1;
245 }
246
247 format = choose_format(plane);
248 if (!format) {
249 fprintf(stderr, "no matching format found\n");
250 return 1;
251 }
252
253 cursor = kms_framebuffer_create(device, 32, 32, format);
254 if (!cursor) {
255 fprintf(stderr, "failed to create cursor buffer\n");
256 return 1;
257 }
258
259 prepare_framebuffer(cursor, false);
260
261 x = (device->screens[0]->width - cursor->width) / 2;
262 y = (device->screens[0]->height - cursor->height) / 2;
263
264 kms_plane_set(plane, cursor, x, y);
265 }
266
267 if (use_overlay) {
268 uint32_t format;
269
270 plane = kms_device_find_plane_by_type(device,
271 DRM_PLANE_TYPE_OVERLAY,
272 0);
273 if (!plane) {
274 fprintf(stderr, "no overlay plane found\n");
275 return 1;
276 }
277
278 format = choose_format(plane);
279 if (!format) {
280 fprintf(stderr, "no matching format found\n");
281 return 1;
282 }
283
284 fb = kms_framebuffer_create(device, 320, 240, format);
285 if (!fb)
286 return 1;
287
288 prepare_framebuffer(fb, false);
289
290 kms_plane_set(plane, fb, 0, 0);
291 }
292
293 if (use_primary) {
294 unsigned int x, y;
295 uint32_t format;
296
297 plane = kms_device_find_plane_by_type(device,
298 DRM_PLANE_TYPE_PRIMARY,
299 0);
300 if (!plane) {
301 fprintf(stderr, "no primary plane found\n");
302 return 1;
303 }
304
305 format = choose_format(plane);
306 if (!format) {
307 fprintf(stderr, "no matching format found\n");
308 return 1;
309 }
310
311 root = kms_framebuffer_create(device, 640, 480, format);
312 if (!root)
313 return 1;
314
315 prepare_framebuffer(root, true);
316
317 x = (device->screens[0]->width - root->width) / 2;
318 y = (device->screens[0]->height - root->height) / 2;
319
320 kms_plane_set(plane, root, x, y);
321 }
322
323 while (1) {
324 struct timeval timeout = { 1, 0 };
325 fd_set fds;
326
327 FD_ZERO(&fds);
328 FD_SET(STDIN_FILENO, &fds);
329
330 err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout);
331 if (err < 0) {
332 fprintf(stderr, "select() failed: %m\n");
333 break;
334 }
335
336 /* timeout */
337 if (err == 0)
338 continue;
339
340 if (FD_ISSET(STDIN_FILENO, &fds))
341 break;
342 }
343
344 if (cursor)
345 kms_framebuffer_free(cursor);
346
347 if (root)
348 kms_framebuffer_free(root);
349
350 if (fb)
351 kms_framebuffer_free(fb);
352
353 kms_device_close(device);
354 close(fd);
355
356 return 0;
357 }
358