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