blob: a88ed01d36e70cfd6222bda54601b751aa9083e4 [file] [log] [blame]
Gurchetan Singh0d714272017-01-26 11:58:49 -08001/*
2 * Copyright 2017 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
Haixia Shifc476462015-04-22 16:25:04 -07006
Gurchetan Singh0d714272017-01-26 11:58:49 -08007/*
8 * This file performs some sanity checks on the DRM atomic API. To run a test, please run the
9 * following command:
10 *
11 * atomictest <testname>
12 *
13 * To get a list of possible tests, run:
14 *
15 * atomictest
16 */
Haixia Shifc476462015-04-22 16:25:04 -070017
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -070018#include <getopt.h>
19
Gurchetan Singh0d714272017-01-26 11:58:49 -080020#include "bs_drm.h"
Haixia Shifc476462015-04-22 16:25:04 -070021
Dongseong Hwang9093afe2017-03-20 19:16:28 -070022#define CHECK(cond) \
23 do { \
24 if (!(cond)) { \
25 bs_debug_error("check %s failed", #cond); \
26 return -1; \
27 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080028 } while (0)
29
Dongseong Hwang9093afe2017-03-20 19:16:28 -070030#define CHECK_RESULT(ret) \
31 do { \
32 if ((ret) < 0) { \
33 bs_debug_error("failed with error: %d", ret); \
34 return -1; \
35 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080036 } while (0)
37
38#define CURSOR_SIZE 64
39
Daniele Castagna0fea43f2017-04-06 17:47:11 -040040// TODO(gsingh) This is defined in upstream libdrm -- remove when CROS libdrm is updated.
41#ifndef DRM_ROTATE_0
42#define DRM_ROTATE_0 (1UL << 0)
43#endif
44
45#ifndef DRM_REFLECT_Y
46#define DRM_REFLECT_Y (1UL << 5)
47#endif
48
Gurchetan Singh0d714272017-01-26 11:58:49 -080049static const uint32_t yuv_formats[] = {
Gurchetan Singh763dc642017-10-24 13:51:41 -070050 DRM_FORMAT_NV12, DRM_FORMAT_YVU420,
Gurchetan Singh0d714272017-01-26 11:58:49 -080051};
52
53static struct gbm_device *gbm = NULL;
54
55static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
56 unsigned int tv_usec, void *user_data)
Haixia Shifc476462015-04-22 16:25:04 -070057{
Gurchetan Singh0d714272017-01-26 11:58:49 -080058 // Nothing to do.
Haixia Shifc476462015-04-22 16:25:04 -070059}
60
Gurchetan Singh0d714272017-01-26 11:58:49 -080061struct atomictest_property {
62 uint32_t pid;
63 uint32_t value;
64};
Haixia Shifc476462015-04-22 16:25:04 -070065
Gurchetan Singh0d714272017-01-26 11:58:49 -080066struct atomictest_plane {
67 drmModePlane drm_plane;
68 struct gbm_bo *bo;
Haixia Shifc476462015-04-22 16:25:04 -070069
Gurchetan Singh0d714272017-01-26 11:58:49 -080070 uint32_t format_idx;
71
72 /* Properties. */
73 struct atomictest_property crtc_id;
74 struct atomictest_property crtc_x;
75 struct atomictest_property crtc_y;
76 struct atomictest_property crtc_w;
77 struct atomictest_property crtc_h;
78 struct atomictest_property fb_id;
79 struct atomictest_property src_x;
80 struct atomictest_property src_y;
81 struct atomictest_property src_w;
82 struct atomictest_property src_h;
83 struct atomictest_property type;
Daniele Castagna0fea43f2017-04-06 17:47:11 -040084 struct atomictest_property rotation;
Gurchetan Singh0d714272017-01-26 11:58:49 -080085};
86
87struct atomictest_connector {
88 uint32_t connector_id;
89 struct atomictest_property crtc_id;
90 struct atomictest_property edid;
91 struct atomictest_property dpms;
92};
93
94struct atomictest_crtc {
95 uint32_t crtc_id;
96 uint32_t width;
97 uint32_t height;
98 uint32_t *primary_idx;
99 uint32_t *cursor_idx;
100 uint32_t *overlay_idx;
101 uint32_t num_primary;
102 uint32_t num_cursor;
103 uint32_t num_overlay;
104
105 struct atomictest_plane *planes;
106 struct atomictest_property mode_id;
107 struct atomictest_property active;
108};
109
110struct atomictest_mode {
111 uint32_t height;
112 uint32_t width;
113 uint32_t id;
114};
115
116struct atomictest_context {
117 int fd;
118 uint32_t num_crtcs;
119 uint32_t num_connectors;
120 uint32_t num_modes;
121
122 struct atomictest_connector *connectors;
123 struct atomictest_crtc *crtcs;
124 struct atomictest_mode *modes;
Dominik Behre0f1c182016-01-25 14:38:22 -0800125 drmModeAtomicReqPtr pset;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800126 drmEventContext drm_event_ctx;
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700127
128 struct bs_mapper *mapper;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800129};
Haixia Shifc476462015-04-22 16:25:04 -0700130
Gurchetan Singhd61875a2017-06-02 17:03:19 -0700131typedef int (*test_function)(struct atomictest_context *ctx, struct atomictest_crtc *crtc);
132
133struct atomictest_testcase {
Gurchetan Singh0d714272017-01-26 11:58:49 -0800134 const char *name;
Gurchetan Singhd61875a2017-06-02 17:03:19 -0700135 test_function test_func;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800136};
Haixia Shifc476462015-04-22 16:25:04 -0700137
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700138// clang-format off
139enum draw_format_type {
140 DRAW_NONE = 0,
141 DRAW_STRIPE = 1,
142 DRAW_ELLIPSE = 2,
143 DRAW_CURSOR = 3,
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700144 DRAW_LINES = 4,
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700145};
146// clang-format on
147
Gurchetan Singh0d714272017-01-26 11:58:49 -0800148static int32_t get_format_idx(struct atomictest_plane *plane, uint32_t format)
149{
150 for (int32_t i = 0; i < plane->drm_plane.count_formats; i++)
151 if (plane->drm_plane.formats[i] == format)
152 return i;
153 return -1;
154}
155
156static void copy_drm_plane(drmModePlane *dest, drmModePlane *src)
157{
158 memcpy(dest, src, sizeof(drmModePlane));
159 dest->formats = calloc(src->count_formats, sizeof(uint32_t));
160 dest->format_modifiers =
161 calloc(src->count_format_modifiers, sizeof(struct drm_format_modifier));
162 memcpy(dest->formats, src->formats, src->count_formats * sizeof(uint32_t));
163 memcpy(dest->format_modifiers, src->format_modifiers,
164 src->count_format_modifiers * sizeof(struct drm_format_modifier));
165}
166
167static struct atomictest_plane *get_plane(struct atomictest_crtc *crtc, uint32_t idx, uint64_t type)
168{
169 uint32_t index;
170 switch (type) {
171 case DRM_PLANE_TYPE_OVERLAY:
172 index = crtc->overlay_idx[idx];
173 break;
174 case DRM_PLANE_TYPE_PRIMARY:
175 index = crtc->primary_idx[idx];
176 break;
177 case DRM_PLANE_TYPE_CURSOR:
178 index = crtc->cursor_idx[idx];
179 break;
180 default:
181 bs_debug_error("invalid plane type returned");
182 return NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700183 }
184
Gurchetan Singh0d714272017-01-26 11:58:49 -0800185 return &crtc->planes[index];
186}
Haixia Shifc476462015-04-22 16:25:04 -0700187
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700188static int draw_to_plane(struct bs_mapper *mapper, struct atomictest_plane *plane,
189 enum draw_format_type pattern)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800190{
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700191 struct gbm_bo *bo = plane->bo;
Gurchetan Singha676f1b2017-10-16 18:33:29 -0700192 uint32_t format = gbm_bo_get_format(bo);
193 const struct bs_draw_format *draw_format = bs_get_draw_format(format);
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700194
195 if (draw_format && pattern) {
196 switch (pattern) {
197 case DRAW_STRIPE:
198 CHECK(bs_draw_stripe(mapper, bo, draw_format));
199 break;
200 case DRAW_ELLIPSE:
201 CHECK(bs_draw_ellipse(mapper, bo, draw_format, 0));
202 break;
203 case DRAW_CURSOR:
204 CHECK(bs_draw_cursor(mapper, bo, draw_format));
205 break;
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700206 case DRAW_LINES:
207 CHECK(bs_draw_lines(mapper, bo, draw_format));
208 break;
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700209 default:
210 bs_debug_error("invalid draw type");
211 return -1;
212 }
213 } else {
214 // DRM_FORMAT_RGB565 --> red, DRM_FORMAT_BGR565 --> blue,
215 // everything else --> something
216 void *map_data;
217 uint16_t value = 0xF800;
218 void *addr = bs_mapper_map(mapper, bo, 0, &map_data);
219 uint32_t num_shorts = gbm_bo_get_plane_size(bo, 0) / sizeof(uint16_t);
220 uint16_t *pixel = (uint16_t *)addr;
221
222 CHECK(addr);
223 for (uint32_t i = 0; i < num_shorts; i++)
224 pixel[i] = value;
225
226 bs_mapper_unmap(mapper, bo, map_data);
227 }
228
229 return 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800230}
231
232static int get_prop(int fd, drmModeObjectPropertiesPtr props, const char *name,
233 struct atomictest_property *bs_prop)
234{
235 /* Property ID should always be > 0. */
236 bs_prop->pid = 0;
237 drmModePropertyPtr prop;
238 for (uint32_t i = 0; i < props->count_props; i++) {
239 if (bs_prop->pid)
240 break;
241
242 prop = drmModeGetProperty(fd, props->props[i]);
243 if (prop) {
244 if (!strcmp(prop->name, name)) {
245 bs_prop->pid = prop->prop_id;
246 bs_prop->value = props->prop_values[i];
247 }
248 drmModeFreeProperty(prop);
249 }
250 }
251
252 return (bs_prop->pid == 0) ? -1 : 0;
253}
254
255static int get_connector_props(int fd, struct atomictest_connector *connector,
256 drmModeObjectPropertiesPtr props)
257{
Gurchetan Singh476ce542017-06-02 09:06:01 -0700258 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &connector->crtc_id));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800259 CHECK_RESULT(get_prop(fd, props, "EDID", &connector->edid));
260 CHECK_RESULT(get_prop(fd, props, "DPMS", &connector->dpms));
261 return 0;
262}
263
264static int get_crtc_props(int fd, struct atomictest_crtc *crtc, drmModeObjectPropertiesPtr props)
265{
266 CHECK_RESULT(get_prop(fd, props, "MODE_ID", &crtc->mode_id));
267 CHECK_RESULT(get_prop(fd, props, "ACTIVE", &crtc->active));
268 return 0;
269}
270
271static int get_plane_props(int fd, struct atomictest_plane *plane, drmModeObjectPropertiesPtr props)
272{
273 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &plane->crtc_id));
274 CHECK_RESULT(get_prop(fd, props, "FB_ID", &plane->fb_id));
275 CHECK_RESULT(get_prop(fd, props, "CRTC_X", &plane->crtc_x));
276 CHECK_RESULT(get_prop(fd, props, "CRTC_Y", &plane->crtc_y));
277 CHECK_RESULT(get_prop(fd, props, "CRTC_W", &plane->crtc_w));
278 CHECK_RESULT(get_prop(fd, props, "CRTC_H", &plane->crtc_h));
279 CHECK_RESULT(get_prop(fd, props, "SRC_X", &plane->src_x));
280 CHECK_RESULT(get_prop(fd, props, "SRC_Y", &plane->src_y));
281 CHECK_RESULT(get_prop(fd, props, "SRC_W", &plane->src_w));
282 CHECK_RESULT(get_prop(fd, props, "SRC_H", &plane->src_h));
283 CHECK_RESULT(get_prop(fd, props, "type", &plane->type));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400284
285 /*
286 * The atomic API makes no guarantee a property is present in object. This test
287 * requires the above common properties since a plane is undefined without them.
288 * Other properties (i.e, rotation) are optional.
289 */
290 get_prop(fd, props, "rotation", &plane->rotation);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800291 return 0;
292}
293
294int set_connector_props(struct atomictest_connector *conn, drmModeAtomicReqPtr pset)
295{
296 uint32_t id = conn->connector_id;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800297 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, conn->crtc_id.pid, conn->crtc_id.value));
298 return 0;
299}
300
301int set_crtc_props(struct atomictest_crtc *crtc, drmModeAtomicReqPtr pset)
302{
303 uint32_t id = crtc->crtc_id;
304 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->mode_id.pid, crtc->mode_id.value));
305 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->active.pid, crtc->active.value));
306 return 0;
307}
308
309int set_plane_props(struct atomictest_plane *plane, drmModeAtomicReqPtr pset)
310{
311 uint32_t id = plane->drm_plane.plane_id;
312 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_id.pid, plane->crtc_id.value));
313 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->fb_id.pid, plane->fb_id.value));
314 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_x.pid, plane->crtc_x.value));
315 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_y.pid, plane->crtc_y.value));
316 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_w.pid, plane->crtc_w.value));
317 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_h.pid, plane->crtc_h.value));
318 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_x.pid, plane->src_x.value));
319 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_y.pid, plane->src_y.value));
320 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_w.pid, plane->src_w.value));
321 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_h.pid, plane->src_h.value));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400322 if (plane->rotation.pid)
323 CHECK_RESULT(
324 drmModeAtomicAddProperty(pset, id, plane->rotation.pid, plane->rotation.value));
325
Gurchetan Singh0d714272017-01-26 11:58:49 -0800326 return 0;
327}
328
329static int remove_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
330{
331 if (plane->bo && plane->fb_id.value) {
332 CHECK_RESULT(drmModeRmFB(ctx->fd, plane->fb_id.value));
333 gbm_bo_destroy(plane->bo);
334 plane->bo = NULL;
335 plane->fb_id.value = 0;
336 }
337
338 return 0;
339}
340
341static int add_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
342{
343 if (plane->format_idx < plane->drm_plane.count_formats) {
344 CHECK_RESULT(remove_plane_fb(ctx, plane));
345 uint32_t flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
346 : GBM_BO_USE_SCANOUT;
347 /* TODO(gsingh): add create with modifiers option. */
348 plane->bo = gbm_bo_create(gbm, plane->crtc_w.value, plane->crtc_h.value,
349 plane->drm_plane.formats[plane->format_idx], flags);
350
351 CHECK(plane->bo);
352 plane->fb_id.value = bs_drm_fb_create_gbm(plane->bo);
353 CHECK(plane->fb_id.value);
354 CHECK_RESULT(set_plane_props(plane, ctx->pset));
355 }
356
357 return 0;
358}
359
360static int init_plane(struct atomictest_context *ctx, struct atomictest_plane *plane,
361 uint32_t format, uint32_t x, uint32_t y, uint32_t w, uint32_t h,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700362 uint32_t crtc_id)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800363{
364 int32_t idx = get_format_idx(plane, format);
365 if (idx < 0)
366 return -EINVAL;
367
368 plane->format_idx = idx;
369 plane->crtc_x.value = x;
370 plane->crtc_y.value = y;
371 plane->crtc_w.value = w;
372 plane->crtc_h.value = h;
373 plane->src_w.value = plane->crtc_w.value << 16;
374 plane->src_h.value = plane->crtc_h.value << 16;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800375 plane->crtc_id.value = crtc_id;
376
377 CHECK_RESULT(add_plane_fb(ctx, plane));
378 return 0;
379}
380
Gurchetan Singh763dc642017-10-24 13:51:41 -0700381static int init_yuv_plane(struct atomictest_context *ctx, struct atomictest_plane *plane,
382 uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t crtc_id)
383{
384 uint32_t i;
385 for (i = 0; i < BS_ARRAY_LEN(yuv_formats); i++)
386 if (!init_plane(ctx, plane, yuv_formats[i], x, y, w, h, crtc_id))
387 return 0;
388
389 return -EINVAL;
390}
391
Gurchetan Singh0d714272017-01-26 11:58:49 -0800392static int disable_plane(struct atomictest_context *ctx, struct atomictest_plane *plane)
393{
394 plane->format_idx = 0;
395 plane->crtc_x.value = 0;
396 plane->crtc_y.value = 0;
397 plane->crtc_w.value = 0;
398 plane->crtc_h.value = 0;
399 plane->src_w.value = 0;
400 plane->src_h.value = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800401 plane->crtc_id.value = 0;
402
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400403 if (plane->rotation.pid)
404 plane->rotation.value = DRM_ROTATE_0;
405
Gurchetan Singh0d714272017-01-26 11:58:49 -0800406 CHECK_RESULT(remove_plane_fb(ctx, plane));
407 CHECK_RESULT(set_plane_props(plane, ctx->pset));
408 return 0;
409}
410
411static int move_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
412 struct atomictest_plane *plane, uint32_t dx, uint32_t dy)
413{
414 if (plane->crtc_x.value < (crtc->width - plane->crtc_w.value) &&
415 plane->crtc_y.value < (crtc->height - plane->crtc_h.value)) {
416 plane->crtc_x.value += dx;
417 plane->crtc_y.value += dy;
418 CHECK_RESULT(set_plane_props(plane, ctx->pset));
419 return 0;
420 }
421
422 return -1;
423}
424
Gurchetan Singhd78c5872017-10-20 18:53:37 -0700425static int scale_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
426 struct atomictest_plane *plane, float dw, float dh)
427{
428 int32_t plane_w = (int32_t)plane->crtc_w.value + dw * plane->crtc_w.value;
429 int32_t plane_h = (int32_t)plane->crtc_h.value + dh * plane->crtc_h.value;
430 if (plane_w > 0 && plane_h > 0 && (plane->crtc_x.value + plane_w < crtc->width) &&
431 (plane->crtc_h.value + plane_h < crtc->height)) {
432 plane->crtc_w.value = BS_ALIGN((uint32_t)plane_w, 2);
433 plane->crtc_h.value = BS_ALIGN((uint32_t)plane_h, 2);
434 CHECK_RESULT(set_plane_props(plane, ctx->pset));
435 return 0;
436 }
437
438 return -1;
439}
440
Gurchetan Singhf873d8f2017-10-24 16:51:22 -0700441static void log(struct atomictest_context *ctx)
442{
443 printf("Committing the following configuration: \n");
444 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
445 struct atomictest_plane *plane;
446 struct atomictest_crtc *crtc = &ctx->crtcs[i];
447 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
448 if (!crtc->active.value)
449 continue;
450
451 printf("----- [CRTC: %u] -----\n", crtc->crtc_id);
452 for (uint32_t j = 0; j < num_planes; j++) {
453 plane = &crtc->planes[j];
454 if (plane->crtc_id.value == crtc->crtc_id && plane->fb_id.value) {
455 uint32_t format = gbm_bo_get_format(plane->bo);
456 char *fourcc = (char *)&format;
457 printf("\t{Plane ID: %u, ", plane->drm_plane.plane_id);
458 printf("Plane format: %c%c%c%c, ", fourcc[0], fourcc[1], fourcc[2],
459 fourcc[3]);
460 printf("Plane type: ");
461 switch (plane->type.value) {
462 case DRM_PLANE_TYPE_OVERLAY:
463 printf("overlay, ");
464 break;
465 case DRM_PLANE_TYPE_PRIMARY:
466 printf("primary, ");
467 break;
468 case DRM_PLANE_TYPE_CURSOR:
469 printf("cursor, ");
470 break;
471 }
472
473 printf("CRTC_X: %u, CRTC_Y: %u, CRTC_W: %u, CRTC_H: %u}\n",
474 plane->crtc_x.value, plane->crtc_y.value,
475 plane->crtc_w.value, plane->crtc_h.value);
476 }
477 }
478 }
479}
480
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400481static int test_commit(struct atomictest_context *ctx)
482{
483 return drmModeAtomicCommit(ctx->fd, ctx->pset, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
484}
485
Gurchetan Singh0d714272017-01-26 11:58:49 -0800486static int commit(struct atomictest_context *ctx)
487{
488 int ret;
489 fd_set fds;
490 FD_ZERO(&fds);
491 FD_SET(ctx->fd, &fds);
492
Gurchetan Singhf873d8f2017-10-24 16:51:22 -0700493 log(ctx);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800494 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
495 DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
496 CHECK_RESULT(ret);
497 do {
498 ret = select(ctx->fd + 1, &fds, NULL, NULL, NULL);
499 } while (ret == -1 && errno == EINTR);
500
501 CHECK_RESULT(ret);
502 if (FD_ISSET(ctx->fd, &fds))
503 drmHandleEvent(ctx->fd, &ctx->drm_event_ctx);
504
505 return 0;
506}
507
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700508static int pageflip_formats(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
509 struct atomictest_plane *plane)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800510{
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700511 uint32_t flags;
512 for (uint32_t i = 0; i < plane->drm_plane.count_formats; i++) {
513 flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
514 : GBM_BO_USE_SCANOUT;
515 if (!gbm_device_is_format_supported(gbm, plane->drm_plane.formats[i], flags))
Shirish Scd098332017-09-26 16:31:07 +0530516 continue;
517
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700518 CHECK_RESULT(init_plane(ctx, plane, plane->drm_plane.formats[i], 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700519 crtc->height, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700520 CHECK_RESULT(draw_to_plane(ctx->mapper, plane, DRAW_ELLIPSE));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800521 CHECK_RESULT(commit(ctx));
522 usleep(1e6);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700523
524 // disable, but don't commit, since we can't have an active CRTC without any planes.
525 CHECK_RESULT(disable_plane(ctx, plane));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800526 }
527
528 return 0;
529}
530
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700531static uint32_t get_connection(struct atomictest_crtc *crtc, uint32_t crtc_index)
532{
533 uint32_t connector_id = 0;
534 uint32_t crtc_mask = 1u << crtc_index;
535 struct bs_drm_pipe pipe = { 0 };
536 struct bs_drm_pipe_plumber *plumber = bs_drm_pipe_plumber_new();
537 bs_drm_pipe_plumber_crtc_mask(plumber, crtc_mask);
538 if (bs_drm_pipe_plumber_make(plumber, &pipe))
539 connector_id = pipe.connector_id;
540
541 bs_drm_pipe_plumber_destroy(&plumber);
542 return connector_id;
543}
544
545static int enable_crtc(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800546{
547 drmModeAtomicSetCursor(ctx->pset, 0);
548
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700549 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
550 ctx->connectors[i].crtc_id.value = 0;
551 set_connector_props(&ctx->connectors[i], ctx->pset);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800552 }
553
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700554 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
555 if (&ctx->crtcs[i] == crtc) {
556 uint32_t connector_id = get_connection(crtc, i);
557 CHECK(connector_id);
558 for (uint32_t j = 0; j < ctx->num_connectors; j++) {
559 if (connector_id == ctx->connectors[j].connector_id) {
560 ctx->connectors[j].crtc_id.value = crtc->crtc_id;
561 set_connector_props(&ctx->connectors[j], ctx->pset);
562 break;
563 }
564 }
565
566 break;
567 }
Gurchetan Singh0d714272017-01-26 11:58:49 -0800568 }
569
570 int ret = -EINVAL;
571 int cursor = drmModeAtomicGetCursor(ctx->pset);
572
573 for (uint32_t i = 0; i < ctx->num_modes; i++) {
574 struct atomictest_mode *mode = &ctx->modes[i];
575 drmModeAtomicSetCursor(ctx->pset, cursor);
576
577 crtc->mode_id.value = mode->id;
578 crtc->active.value = 1;
579 crtc->width = mode->width;
580 crtc->height = mode->height;
581
582 set_crtc_props(crtc, ctx->pset);
583 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
584 DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
585 NULL);
586 if (!ret)
587 return 0;
588 }
589
590 bs_debug_error("[CRTC:%d]: failed to find mode", crtc->crtc_id);
591 return ret;
592}
593
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700594static int disable_crtc(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
595{
596 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
597 ctx->connectors[i].crtc_id.value = 0;
598 set_connector_props(&ctx->connectors[i], ctx->pset);
599 }
600
601 crtc->mode_id.value = 0;
602 crtc->active.value = 0;
603 set_crtc_props(crtc, ctx->pset);
604 int ret = drmModeAtomicCommit(ctx->fd, ctx->pset, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
605 CHECK_RESULT(ret);
606 return ret;
607}
608
Gurchetan Singhbcfaf082017-06-02 12:58:10 -0700609static struct atomictest_context *new_context(uint32_t num_connectors, uint32_t num_crtcs,
610 uint32_t num_planes)
611{
612 struct atomictest_context *ctx = calloc(1, sizeof(*ctx));
613
614 ctx->mapper = bs_mapper_gem_new();
615 if (ctx->mapper == NULL) {
616 bs_debug_error("failed to create mapper object");
617 free(ctx);
618 return NULL;
619 }
620
621 ctx->connectors = calloc(num_connectors, sizeof(*ctx->connectors));
622 ctx->crtcs = calloc(num_crtcs, sizeof(*ctx->crtcs));
623 for (uint32_t i = 0; i < num_crtcs; i++) {
624 ctx->crtcs[i].planes = calloc(num_planes, sizeof(*ctx->crtcs[i].planes));
625 ctx->crtcs[i].overlay_idx = calloc(num_planes, sizeof(uint32_t));
626 ctx->crtcs[i].primary_idx = calloc(num_planes, sizeof(uint32_t));
627 ctx->crtcs[i].cursor_idx = calloc(num_planes, sizeof(uint32_t));
628 }
629
630 ctx->num_connectors = num_connectors;
631 ctx->num_crtcs = num_crtcs;
632 ctx->num_modes = 0;
633 ctx->modes = NULL;
634 ctx->pset = drmModeAtomicAlloc();
635 ctx->drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
636 ctx->drm_event_ctx.page_flip_handler = page_flip_handler;
637
638 return ctx;
639}
640
Gurchetan Singh0d714272017-01-26 11:58:49 -0800641static void free_context(struct atomictest_context *ctx)
642{
643 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
644 uint32_t num_planes = ctx->crtcs[i].num_primary + ctx->crtcs[i].num_cursor +
645 ctx->crtcs[i].num_overlay;
646
647 for (uint32_t j = 0; j < num_planes; j++) {
648 remove_plane_fb(ctx, &ctx->crtcs[i].planes[j]);
649 free(ctx->crtcs[i].planes[j].drm_plane.formats);
650 free(ctx->crtcs[i].planes[j].drm_plane.format_modifiers);
Haixia Shifc476462015-04-22 16:25:04 -0700651 }
652
Gurchetan Singh0d714272017-01-26 11:58:49 -0800653 free(ctx->crtcs[i].planes);
654 free(ctx->crtcs[i].overlay_idx);
655 free(ctx->crtcs[i].cursor_idx);
656 free(ctx->crtcs[i].primary_idx);
657 }
658
659 drmModeAtomicFree(ctx->pset);
660 free(ctx->modes);
661 free(ctx->crtcs);
662 free(ctx->connectors);
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700663 bs_mapper_destroy(ctx->mapper);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800664 free(ctx);
665}
666
Gurchetan Singh83df8832017-06-02 14:06:48 -0700667static struct atomictest_context *query_kms(int fd)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800668{
669 drmModeRes *res = drmModeGetResources(fd);
670 if (res == NULL) {
671 bs_debug_error("failed to get drm resources");
672 return false;
673 }
674
675 drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
676 if (plane_res == NULL) {
677 bs_debug_error("failed to get plane resources");
678 drmModeFreeResources(res);
679 return NULL;
680 }
681
682 struct atomictest_context *ctx =
683 new_context(res->count_connectors, res->count_crtcs, plane_res->count_planes);
684 if (ctx == NULL) {
685 bs_debug_error("failed to allocate atomic context");
686 drmModeFreePlaneResources(plane_res);
687 drmModeFreeResources(res);
688 return NULL;
689 }
690
Gurchetan Singh0d714272017-01-26 11:58:49 -0800691 ctx->fd = fd;
692 drmModeObjectPropertiesPtr props = NULL;
693
694 for (uint32_t conn_index = 0; conn_index < res->count_connectors; conn_index++) {
695 uint32_t conn_id = res->connectors[conn_index];
696 ctx->connectors[conn_index].connector_id = conn_id;
697 props = drmModeObjectGetProperties(fd, conn_id, DRM_MODE_OBJECT_CONNECTOR);
698 get_connector_props(fd, &ctx->connectors[conn_index], props);
699
700 drmModeConnector *connector = drmModeGetConnector(fd, conn_id);
701 for (uint32_t mode_index = 0; mode_index < connector->count_modes; mode_index++) {
Dongseong Hwang326d08f2017-06-13 14:42:31 -0700702 ctx->modes =
703 realloc(ctx->modes, (ctx->num_modes + 1) * sizeof(*ctx->modes));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800704 drmModeCreatePropertyBlob(fd, &connector->modes[mode_index],
705 sizeof(drmModeModeInfo),
706 &ctx->modes[ctx->num_modes].id);
707 ctx->modes[ctx->num_modes].width = connector->modes[mode_index].hdisplay;
708 ctx->modes[ctx->num_modes].height = connector->modes[mode_index].vdisplay;
709 ctx->num_modes++;
Haixia Shifc476462015-04-22 16:25:04 -0700710 }
711
Gurchetan Singh0d714272017-01-26 11:58:49 -0800712 drmModeFreeConnector(connector);
713 drmModeFreeObjectProperties(props);
714 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700715 }
716
Gurchetan Singh0d714272017-01-26 11:58:49 -0800717 uint32_t crtc_index;
718 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
719 ctx->crtcs[crtc_index].crtc_id = res->crtcs[crtc_index];
720 props =
721 drmModeObjectGetProperties(fd, res->crtcs[crtc_index], DRM_MODE_OBJECT_CRTC);
722 get_crtc_props(fd, &ctx->crtcs[crtc_index], props);
723
724 drmModeFreeObjectProperties(props);
725 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700726 }
727
Gurchetan Singh0d714272017-01-26 11:58:49 -0800728 uint32_t overlay_idx, primary_idx, cursor_idx, idx;
Haixia Shifc476462015-04-22 16:25:04 -0700729
Gurchetan Singh0d714272017-01-26 11:58:49 -0800730 for (uint32_t plane_index = 0; plane_index < plane_res->count_planes; plane_index++) {
Kristian H. Kristensenfe6e6fa2017-05-01 15:12:20 -0700731 drmModePlane *plane = drmModeGetPlane2(fd, plane_res->planes[plane_index]);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800732 if (plane == NULL) {
733 bs_debug_error("failed to get plane id %u", plane_res->planes[plane_index]);
734 continue;
735 }
Haixia Shifc476462015-04-22 16:25:04 -0700736
Gurchetan Singh0d714272017-01-26 11:58:49 -0800737 uint32_t crtc_mask = 0;
738
739 drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(
740 fd, plane_res->planes[plane_index], DRM_MODE_OBJECT_PLANE);
741
742 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
743 crtc_mask = (1 << crtc_index);
744 if (plane->possible_crtcs & crtc_mask) {
745 struct atomictest_crtc *crtc = &ctx->crtcs[crtc_index];
746 cursor_idx = crtc->num_cursor;
747 primary_idx = crtc->num_primary;
748 overlay_idx = crtc->num_overlay;
749 idx = cursor_idx + primary_idx + overlay_idx;
750 copy_drm_plane(&crtc->planes[idx].drm_plane, plane);
751 get_plane_props(fd, &crtc->planes[idx], props);
752 switch (crtc->planes[idx].type.value) {
753 case DRM_PLANE_TYPE_OVERLAY:
754 crtc->overlay_idx[overlay_idx] = idx;
755 crtc->num_overlay++;
756 break;
757 case DRM_PLANE_TYPE_PRIMARY:
758 crtc->primary_idx[primary_idx] = idx;
759 crtc->num_primary++;
760 break;
761 case DRM_PLANE_TYPE_CURSOR:
762 crtc->cursor_idx[cursor_idx] = idx;
763 crtc->num_cursor++;
764 break;
765 default:
766 bs_debug_error("invalid plane type returned");
767 return NULL;
768 }
Haixia Shifc476462015-04-22 16:25:04 -0700769 }
770 }
771
Gurchetan Singh0d714272017-01-26 11:58:49 -0800772 drmModeFreePlane(plane);
773 drmModeFreeObjectProperties(props);
774 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700775 }
776
Gurchetan Singh0d714272017-01-26 11:58:49 -0800777 drmModeFreePlaneResources(plane_res);
778 drmModeFreeResources(res);
779 return ctx;
780}
Haixia Shifc476462015-04-22 16:25:04 -0700781
Gurchetan Singh0d714272017-01-26 11:58:49 -0800782static int test_multiple_planes(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
783{
784 struct atomictest_plane *primary, *overlay, *cursor;
785 for (uint32_t i = 0; i < crtc->num_primary; i++) {
Gurchetan Singh763dc642017-10-24 13:51:41 -0700786 bool video = true;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800787 uint32_t x, y;
788 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
789 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
790 x = crtc->width >> (j + 2);
791 y = crtc->height >> (j + 2);
Dongseong Hwang326d08f2017-06-13 14:42:31 -0700792 // drmModeAddFB2 requires the height and width are even for sub-sampled YUV
793 // formats.
794 x = BS_ALIGN(x, 2);
795 y = BS_ALIGN(y, 2);
Gurchetan Singh763dc642017-10-24 13:51:41 -0700796 if (video && !init_yuv_plane(ctx, overlay, x, y, x, y, crtc->crtc_id)) {
797 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
798 video = false;
799 } else {
Gurchetan Singh0d714272017-01-26 11:58:49 -0800800 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, x, y, x,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700801 y, crtc->crtc_id));
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700802 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800803 }
804 }
805
806 for (uint32_t j = 0; j < crtc->num_cursor; j++) {
807 x = crtc->width >> (j + 2);
808 y = crtc->height >> (j + 2);
809 cursor = get_plane(crtc, j, DRM_PLANE_TYPE_CURSOR);
Dongseong Hwangd0a45fc2017-04-12 17:10:11 -0700810 CHECK_RESULT(init_plane(ctx, cursor, DRM_FORMAT_ARGB8888, x, y, CURSOR_SIZE,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700811 CURSOR_SIZE, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700812 CHECK_RESULT(draw_to_plane(ctx->mapper, cursor, DRAW_CURSOR));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800813 }
814
815 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
816 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700817 crtc->height, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700818 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800819
820 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
821 int done = 0;
822 struct atomictest_plane *plane;
823 while (!done) {
824 done = 1;
825 for (uint32_t j = 0; j < num_planes; j++) {
826 plane = &crtc->planes[j];
827 if (plane->type.value != DRM_PLANE_TYPE_PRIMARY)
828 done &= move_plane(ctx, crtc, plane, 20, 20);
829 }
830
831 CHECK_RESULT(commit(ctx));
832 usleep(1e6 / 60);
833 }
834
835 CHECK_RESULT(commit(ctx));
836 usleep(1e6);
837
838 /* Disable primary plane and verify overlays show up. */
839 CHECK_RESULT(disable_plane(ctx, primary));
840 CHECK_RESULT(commit(ctx));
841 usleep(1e6);
842 }
843
844 return 0;
845}
846
847static int test_video_overlay(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
848{
849 struct atomictest_plane *overlay;
850 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
851 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Gurchetan Singh763dc642017-10-24 13:51:41 -0700852 if (init_yuv_plane(ctx, overlay, 0, 0, 800, 800, crtc->crtc_id))
853 continue;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800854
Gurchetan Singh763dc642017-10-24 13:51:41 -0700855 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
856 while (!move_plane(ctx, crtc, overlay, 20, 20)) {
857 CHECK_RESULT(commit(ctx));
858 usleep(1e6 / 60);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800859 }
860 }
861
862 return 0;
863}
864
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400865static int test_orientation(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
866{
867 struct atomictest_plane *primary, *overlay;
868 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
869 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
870 if (!overlay->rotation.pid)
871 continue;
872
873 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700874 crtc->height, crtc->crtc_id));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400875
876 overlay->rotation.value = DRM_ROTATE_0;
877 set_plane_props(overlay, ctx->pset);
878 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
879 CHECK_RESULT(commit(ctx));
880 usleep(1e6);
881
882 overlay->rotation.value = DRM_REFLECT_Y;
883 set_plane_props(overlay, ctx->pset);
884 if (!test_commit(ctx)) {
885 CHECK_RESULT(commit(ctx));
886 usleep(1e6);
887 }
888
889 CHECK_RESULT(disable_plane(ctx, overlay));
890 }
891
892 for (uint32_t i = 0; i < crtc->num_primary; i++) {
893 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
894 if (!primary->rotation.pid)
895 continue;
896
897 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700898 crtc->height, crtc->crtc_id));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400899
900 primary->rotation.value = DRM_ROTATE_0;
901 set_plane_props(primary, ctx->pset);
902 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
903 CHECK_RESULT(commit(ctx));
904 usleep(1e6);
905
906 primary->rotation.value = DRM_REFLECT_Y;
907 set_plane_props(primary, ctx->pset);
908 if (!test_commit(ctx)) {
909 CHECK_RESULT(commit(ctx));
910 usleep(1e6);
911 }
912
913 CHECK_RESULT(disable_plane(ctx, primary));
914 }
915
916 return 0;
917}
918
Gurchetan Singh0d714272017-01-26 11:58:49 -0800919static int test_fullscreen_video(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
920{
921 struct atomictest_plane *primary;
922 for (uint32_t i = 0; i < crtc->num_primary; i++) {
923 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Gurchetan Singh763dc642017-10-24 13:51:41 -0700924 if (init_yuv_plane(ctx, primary, 0, 0, crtc->width, crtc->height, crtc->crtc_id))
925 continue;
Dongseong Hwangd0a45fc2017-04-12 17:10:11 -0700926
Gurchetan Singh763dc642017-10-24 13:51:41 -0700927 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
928 CHECK_RESULT(commit(ctx));
929 usleep(1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800930 }
931
932 return 0;
933}
934
935static int test_disable_primary(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
936{
Gurchetan Singh0d714272017-01-26 11:58:49 -0800937 struct atomictest_plane *primary, *overlay;
938 for (uint32_t i = 0; i < crtc->num_primary; i++) {
939 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
940 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
941 uint32_t x = crtc->width >> (j + 2);
942 uint32_t y = crtc->height >> (j + 2);
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700943 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, x, y, x, y,
Gurchetan Singh0d714272017-01-26 11:58:49 -0800944 crtc->crtc_id));
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700945 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800946 }
947
Gurchetan Singh0d714272017-01-26 11:58:49 -0800948 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
949 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700950 crtc->height, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700951 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800952 CHECK_RESULT(commit(ctx));
953 usleep(1e6);
954
955 /* Disable primary plane. */
956 disable_plane(ctx, primary);
957 CHECK_RESULT(commit(ctx));
958 usleep(1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800959 }
960
961 return 0;
962}
963
964static int test_overlay_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
965{
966 struct atomictest_plane *overlay;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800967 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
968 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700969 CHECK_RESULT(pageflip_formats(ctx, crtc, overlay));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800970 }
971
972 return 0;
973}
974
Gurchetan Singhd78c5872017-10-20 18:53:37 -0700975static int test_overlay_downscaling(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
976{
977 struct atomictest_plane *overlay;
978 uint32_t w = BS_ALIGN(crtc->width / 2, 2);
979 uint32_t h = BS_ALIGN(crtc->height / 2, 2);
980 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
981 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
982 if (init_yuv_plane(ctx, overlay, 0, 0, w, h, crtc->crtc_id)) {
983 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, w, h,
984 crtc->crtc_id));
985 }
986
987 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
988 CHECK_RESULT(commit(ctx));
989 usleep(1e6);
990
991 while (!scale_plane(ctx, crtc, overlay, -.1f, -.1f) && !test_commit(ctx)) {
992 CHECK_RESULT(commit(ctx));
993 usleep(1e6);
994 }
995
996 disable_plane(ctx, overlay);
997 }
998
999 return 0;
1000}
1001
1002static int test_overlay_upscaling(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1003{
1004 struct atomictest_plane *overlay;
1005 uint32_t w = BS_ALIGN(crtc->width / 4, 2);
1006 uint32_t h = BS_ALIGN(crtc->height / 4, 2);
1007 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1008 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
1009 if (init_yuv_plane(ctx, overlay, 0, 0, w, h, crtc->crtc_id)) {
1010 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, w, h,
1011 crtc->crtc_id));
1012 }
1013
1014 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
1015 CHECK_RESULT(commit(ctx));
1016 usleep(1e6);
1017
1018 while (!scale_plane(ctx, crtc, overlay, .1f, .1f) && !test_commit(ctx)) {
1019 CHECK_RESULT(commit(ctx));
1020 usleep(1e6);
1021 }
1022
1023 disable_plane(ctx, overlay);
1024 }
1025
1026 return 0;
1027}
1028
Gurchetan Singh0d714272017-01-26 11:58:49 -08001029static int test_primary_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1030{
Gurchetan Singh0d714272017-01-26 11:58:49 -08001031 struct atomictest_plane *primary;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001032 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1033 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -07001034 CHECK_RESULT(pageflip_formats(ctx, crtc, primary));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001035 }
1036
1037 return 0;
1038}
1039
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001040static const struct atomictest_testcase cases[] = {
Gurchetan Singh0d714272017-01-26 11:58:49 -08001041 { "disable_primary", test_disable_primary },
1042 { "fullscreen_video", test_fullscreen_video },
1043 { "multiple_planes", test_multiple_planes },
1044 { "overlay_pageflip", test_overlay_pageflip },
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001045 { "overlay_downscaling", test_overlay_downscaling },
1046 { "overlay_upscaling", test_overlay_upscaling },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001047 { "primary_pageflip", test_primary_pageflip },
1048 { "video_overlay", test_video_overlay },
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001049 { "orientation", test_orientation },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001050};
1051
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001052static int run_testcase(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
1053 test_function func)
1054{
1055 int cursor = drmModeAtomicGetCursor(ctx->pset);
1056 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
1057
1058 int ret = func(ctx, crtc);
1059
1060 for (uint32_t i = 0; i < num_planes; i++)
1061 disable_plane(ctx, &crtc->planes[i]);
1062
Azhar Shaikh013037e2017-08-08 13:47:02 -07001063 drmModeAtomicSetCursor(ctx->pset, cursor);
1064
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001065 CHECK_RESULT(commit(ctx));
1066 usleep(1e6 / 60);
1067
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001068 return ret;
1069}
1070
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001071static int run_atomictest(const char *name, uint32_t crtc_mask)
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001072{
1073 int ret = 0;
1074 uint32_t num_run = 0;
1075 int fd = bs_drm_open_main_display();
1076 CHECK_RESULT(fd);
1077
1078 gbm = gbm_create_device(fd);
1079 if (!gbm) {
1080 bs_debug_error("failed to create gbm device");
1081 ret = -1;
1082 goto destroy_fd;
1083 }
1084
1085 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1086 if (ret) {
1087 bs_debug_error("failed to enable DRM_CLIENT_CAP_UNIVERSAL_PLANES");
1088 ret = -1;
1089 goto destroy_gbm_device;
1090 }
1091
1092 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
1093 if (ret) {
1094 bs_debug_error("failed to enable DRM_CLIENT_CAP_ATOMIC");
1095 ret = -1;
1096 goto destroy_gbm_device;
1097 }
1098
1099 struct atomictest_context *ctx = query_kms(fd);
1100 if (!ctx) {
1101 bs_debug_error("querying atomictest failed.");
1102 ret = -1;
1103 goto destroy_gbm_device;
1104 }
1105
1106 struct atomictest_crtc *crtc;
1107 for (uint32_t crtc_index = 0; crtc_index < ctx->num_crtcs; crtc_index++) {
1108 crtc = &ctx->crtcs[crtc_index];
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001109 if (!((1 << crtc_index) & crtc_mask))
1110 continue;
1111
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001112 for (uint32_t i = 0; i < BS_ARRAY_LEN(cases); i++) {
1113 if (strcmp(cases[i].name, name) && strcmp("all", name))
1114 continue;
1115
1116 num_run++;
1117 ret = enable_crtc(ctx, crtc);
1118 if (ret)
1119 goto out;
1120
1121 ret = run_testcase(ctx, crtc, cases[i].test_func);
1122 if (ret)
1123 goto out;
1124
1125 ret = disable_crtc(ctx, crtc);
1126 if (ret)
1127 goto out;
1128 }
1129 }
1130
1131 ret = (num_run == 0);
1132
1133out:
1134 free_context(ctx);
1135destroy_gbm_device:
1136 gbm_device_destroy(gbm);
1137destroy_fd:
1138 close(fd);
1139
1140 return ret;
1141}
1142
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001143static const struct option longopts[] = {
1144 { "crtc", required_argument, NULL, 'c' },
1145 { "test_name", required_argument, NULL, 't' },
Gurchetan Singh3008ce62017-10-17 10:51:36 -07001146 { "help", no_argument, NULL, 'h' },
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001147 { 0, 0, 0, 0 },
1148};
1149
Gurchetan Singh0d714272017-01-26 11:58:49 -08001150static void print_help(const char *argv0)
1151{
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001152 printf("usage: %s -t <test_name> -c <crtc_index>\n", argv0);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001153 printf("A valid name test is one the following:\n");
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001154 for (uint32_t i = 0; i < BS_ARRAY_LEN(cases); i++)
1155 printf("%s\n", cases[i].name);
1156 printf("all\n");
Gurchetan Singh0d714272017-01-26 11:58:49 -08001157}
1158
1159int main(int argc, char **argv)
1160{
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001161 int c;
1162 char *name = NULL;
1163 int32_t crtc_idx = -1;
1164 uint32_t crtc_mask = ~0;
Gurchetan Singh3008ce62017-10-17 10:51:36 -07001165 while ((c = getopt_long(argc, argv, "c:t:h", longopts, NULL)) != -1) {
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001166 switch (c) {
1167 case 'c':
1168 if (sscanf(optarg, "%d", &crtc_idx) != 1)
1169 goto print;
1170 break;
1171 case 't':
1172 if (name) {
1173 free(name);
1174 name = NULL;
1175 }
1176
1177 name = strdup(optarg);
1178 break;
Gurchetan Singh3008ce62017-10-17 10:51:36 -07001179 case 'h':
1180 goto print;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001181 default:
1182 goto print;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001183 }
1184 }
1185
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001186 if (!name)
1187 goto print;
1188
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001189 if (crtc_idx >= 0)
1190 crtc_mask = 1 << crtc_idx;
1191
1192 int ret = run_atomictest(name, crtc_mask);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001193 if (ret == 0)
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001194 printf("[ PASSED ] atomictest.%s\n", name);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001195 else if (ret < 0)
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001196 printf("[ FAILED ] atomictest.%s\n", name);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001197
1198 free(name);
1199
1200 if (ret > 0)
1201 goto print;
1202
1203 return ret;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001204
1205print:
Gurchetan Singh0d714272017-01-26 11:58:49 -08001206 print_help(argv[0]);
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001207 return 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001208}