blob: 1bc484252229b8fe1956141bd3b20d6141f46a9b [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 Singh0d714272017-01-26 11:58:49 -080018#include "bs_drm.h"
Haixia Shifc476462015-04-22 16:25:04 -070019
Dongseong Hwang9093afe2017-03-20 19:16:28 -070020#define CHECK(cond) \
21 do { \
22 if (!(cond)) { \
23 bs_debug_error("check %s failed", #cond); \
24 return -1; \
25 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080026 } while (0)
27
Dongseong Hwang9093afe2017-03-20 19:16:28 -070028#define CHECK_RESULT(ret) \
29 do { \
30 if ((ret) < 0) { \
31 bs_debug_error("failed with error: %d", ret); \
32 return -1; \
33 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080034 } while (0)
35
36#define CURSOR_SIZE 64
37
38static const uint32_t yuv_formats[] = {
Gurchetan Singh07a45152017-04-27 18:08:18 -070039 DRM_FORMAT_NV12, DRM_FORMAT_UYVY, DRM_FORMAT_YUYV, DRM_FORMAT_YVU420,
Gurchetan Singh0d714272017-01-26 11:58:49 -080040};
41
42static struct gbm_device *gbm = NULL;
43
44static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
45 unsigned int tv_usec, void *user_data)
Haixia Shifc476462015-04-22 16:25:04 -070046{
Gurchetan Singh0d714272017-01-26 11:58:49 -080047 // Nothing to do.
Haixia Shifc476462015-04-22 16:25:04 -070048}
49
Gurchetan Singh0d714272017-01-26 11:58:49 -080050struct atomictest_property {
51 uint32_t pid;
52 uint32_t value;
53};
Haixia Shifc476462015-04-22 16:25:04 -070054
Gurchetan Singh0d714272017-01-26 11:58:49 -080055struct atomictest_plane {
56 drmModePlane drm_plane;
57 struct gbm_bo *bo;
Haixia Shifc476462015-04-22 16:25:04 -070058
Gurchetan Singh0d714272017-01-26 11:58:49 -080059 uint32_t format_idx;
60
61 /* Properties. */
62 struct atomictest_property crtc_id;
63 struct atomictest_property crtc_x;
64 struct atomictest_property crtc_y;
65 struct atomictest_property crtc_w;
66 struct atomictest_property crtc_h;
67 struct atomictest_property fb_id;
68 struct atomictest_property src_x;
69 struct atomictest_property src_y;
70 struct atomictest_property src_w;
71 struct atomictest_property src_h;
72 struct atomictest_property type;
73 struct atomictest_property zpos;
74};
75
76struct atomictest_connector {
77 uint32_t connector_id;
78 struct atomictest_property crtc_id;
79 struct atomictest_property edid;
80 struct atomictest_property dpms;
81};
82
83struct atomictest_crtc {
84 uint32_t crtc_id;
85 uint32_t width;
86 uint32_t height;
87 uint32_t *primary_idx;
88 uint32_t *cursor_idx;
89 uint32_t *overlay_idx;
90 uint32_t num_primary;
91 uint32_t num_cursor;
92 uint32_t num_overlay;
93
94 struct atomictest_plane *planes;
95 struct atomictest_property mode_id;
96 struct atomictest_property active;
97};
98
99struct atomictest_mode {
100 uint32_t height;
101 uint32_t width;
102 uint32_t id;
103};
104
105struct atomictest_context {
106 int fd;
107 uint32_t num_crtcs;
108 uint32_t num_connectors;
109 uint32_t num_modes;
110
111 struct atomictest_connector *connectors;
112 struct atomictest_crtc *crtcs;
113 struct atomictest_mode *modes;
Dominik Behre0f1c182016-01-25 14:38:22 -0800114 drmModeAtomicReqPtr pset;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800115 drmEventContext drm_event_ctx;
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700116
117 struct bs_mapper *mapper;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800118};
Haixia Shifc476462015-04-22 16:25:04 -0700119
Gurchetan Singh0d714272017-01-26 11:58:49 -0800120struct atomictest {
121 const char *name;
122 int (*run_test)(struct atomictest_context *ctx, struct atomictest_crtc *crtc);
123};
Haixia Shifc476462015-04-22 16:25:04 -0700124
Gurchetan Singh0d714272017-01-26 11:58:49 -0800125static int32_t get_format_idx(struct atomictest_plane *plane, uint32_t format)
126{
127 for (int32_t i = 0; i < plane->drm_plane.count_formats; i++)
128 if (plane->drm_plane.formats[i] == format)
129 return i;
130 return -1;
131}
132
133static void copy_drm_plane(drmModePlane *dest, drmModePlane *src)
134{
135 memcpy(dest, src, sizeof(drmModePlane));
136 dest->formats = calloc(src->count_formats, sizeof(uint32_t));
137 dest->format_modifiers =
138 calloc(src->count_format_modifiers, sizeof(struct drm_format_modifier));
139 memcpy(dest->formats, src->formats, src->count_formats * sizeof(uint32_t));
140 memcpy(dest->format_modifiers, src->format_modifiers,
141 src->count_format_modifiers * sizeof(struct drm_format_modifier));
142}
143
144static struct atomictest_plane *get_plane(struct atomictest_crtc *crtc, uint32_t idx, uint64_t type)
145{
146 uint32_t index;
147 switch (type) {
148 case DRM_PLANE_TYPE_OVERLAY:
149 index = crtc->overlay_idx[idx];
150 break;
151 case DRM_PLANE_TYPE_PRIMARY:
152 index = crtc->primary_idx[idx];
153 break;
154 case DRM_PLANE_TYPE_CURSOR:
155 index = crtc->cursor_idx[idx];
156 break;
157 default:
158 bs_debug_error("invalid plane type returned");
159 return NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700160 }
161
Gurchetan Singh0d714272017-01-26 11:58:49 -0800162 return &crtc->planes[index];
163}
Haixia Shifc476462015-04-22 16:25:04 -0700164
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700165static void write_to_buffer(struct bs_mapper *mapper, struct gbm_bo *bo, uint32_t u32, uint16_t u16)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800166{
167 void *map_data;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800168 uint32_t num_ints;
169 uint32_t format = gbm_bo_get_format(bo);
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700170 void *addr = bs_mapper_map(mapper, bo, 0, &map_data);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800171
172 if (format == GBM_FORMAT_RGB565 || format == GBM_FORMAT_BGR565) {
173 num_ints = gbm_bo_get_plane_size(bo, 0) / sizeof(uint16_t);
174 uint16_t *pixel = (uint16_t *)addr;
175 for (uint32_t i = 0; i < num_ints; i++)
176 pixel[i] = u16;
177 } else {
178 num_ints = gbm_bo_get_plane_size(bo, 0) / sizeof(uint32_t);
179 uint32_t *pixel = (uint32_t *)addr;
180 for (uint32_t i = 0; i < num_ints; i++)
181 pixel[i] = u32;
Haixia Shifc476462015-04-22 16:25:04 -0700182 }
183
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700184 bs_mapper_unmap(mapper, bo, map_data);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800185}
186
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700187static void draw_cursor(struct bs_mapper *mapper, struct gbm_bo *bo)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800188{
189 void *map_data;
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700190 uint32_t *cursor_ptr = bs_mapper_map(mapper, bo, 0, &map_data);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800191 for (size_t y = 0; y < gbm_bo_get_height(bo); y++) {
192 for (size_t x = 0; x < gbm_bo_get_width(bo); x++) {
193 // A white triangle pointing right
194 bool color_white = y > x / 2 && y < (gbm_bo_get_width(bo) - x / 2);
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700195 cursor_ptr[y * gbm_bo_get_height(bo) + x] =
Gurchetan Singh83df8832017-06-02 14:06:48 -0700196 color_white ? 0xFFFFFFFF : 0x00000000;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800197 }
198 }
199
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700200 bs_mapper_unmap(mapper, bo, map_data);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800201}
202
203static int get_prop(int fd, drmModeObjectPropertiesPtr props, const char *name,
204 struct atomictest_property *bs_prop)
205{
206 /* Property ID should always be > 0. */
207 bs_prop->pid = 0;
208 drmModePropertyPtr prop;
209 for (uint32_t i = 0; i < props->count_props; i++) {
210 if (bs_prop->pid)
211 break;
212
213 prop = drmModeGetProperty(fd, props->props[i]);
214 if (prop) {
215 if (!strcmp(prop->name, name)) {
216 bs_prop->pid = prop->prop_id;
217 bs_prop->value = props->prop_values[i];
218 }
219 drmModeFreeProperty(prop);
220 }
221 }
222
223 return (bs_prop->pid == 0) ? -1 : 0;
224}
225
226static int get_connector_props(int fd, struct atomictest_connector *connector,
227 drmModeObjectPropertiesPtr props)
228{
229 CHECK_RESULT(get_prop(fd, props, "EDID", &connector->edid));
230 CHECK_RESULT(get_prop(fd, props, "DPMS", &connector->dpms));
231 return 0;
232}
233
234static int get_crtc_props(int fd, struct atomictest_crtc *crtc, drmModeObjectPropertiesPtr props)
235{
236 CHECK_RESULT(get_prop(fd, props, "MODE_ID", &crtc->mode_id));
237 CHECK_RESULT(get_prop(fd, props, "ACTIVE", &crtc->active));
238 return 0;
239}
240
241static int get_plane_props(int fd, struct atomictest_plane *plane, drmModeObjectPropertiesPtr props)
242{
243 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &plane->crtc_id));
244 CHECK_RESULT(get_prop(fd, props, "FB_ID", &plane->fb_id));
245 CHECK_RESULT(get_prop(fd, props, "CRTC_X", &plane->crtc_x));
246 CHECK_RESULT(get_prop(fd, props, "CRTC_Y", &plane->crtc_y));
247 CHECK_RESULT(get_prop(fd, props, "CRTC_W", &plane->crtc_w));
248 CHECK_RESULT(get_prop(fd, props, "CRTC_H", &plane->crtc_h));
249 CHECK_RESULT(get_prop(fd, props, "SRC_X", &plane->src_x));
250 CHECK_RESULT(get_prop(fd, props, "SRC_Y", &plane->src_y));
251 CHECK_RESULT(get_prop(fd, props, "SRC_W", &plane->src_w));
252 CHECK_RESULT(get_prop(fd, props, "SRC_H", &plane->src_h));
253 CHECK_RESULT(get_prop(fd, props, "type", &plane->type));
254 return 0;
255}
256
257int set_connector_props(struct atomictest_connector *conn, drmModeAtomicReqPtr pset)
258{
259 uint32_t id = conn->connector_id;
260
261 /*
262 * Currently, kernel v4.4 doesn't have CRTC_ID as a property of the connector. It's
263 * required for the modeset to work, so we currently just take it from a plane. Also
264 * setting EDID or DPMS (even w/o modification) makes the kernel return -EINVAL, so
265 * let's keep them unset for now.
266 */
267 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, conn->crtc_id.pid, conn->crtc_id.value));
268 return 0;
269}
270
271int set_crtc_props(struct atomictest_crtc *crtc, drmModeAtomicReqPtr pset)
272{
273 uint32_t id = crtc->crtc_id;
274 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->mode_id.pid, crtc->mode_id.value));
275 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->active.pid, crtc->active.value));
276 return 0;
277}
278
279int set_plane_props(struct atomictest_plane *plane, drmModeAtomicReqPtr pset)
280{
281 uint32_t id = plane->drm_plane.plane_id;
282 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_id.pid, plane->crtc_id.value));
283 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->fb_id.pid, plane->fb_id.value));
284 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_x.pid, plane->crtc_x.value));
285 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_y.pid, plane->crtc_y.value));
286 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_w.pid, plane->crtc_w.value));
287 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_h.pid, plane->crtc_h.value));
288 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_x.pid, plane->src_x.value));
289 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_y.pid, plane->src_y.value));
290 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_w.pid, plane->src_w.value));
291 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_h.pid, plane->src_h.value));
292 return 0;
293}
294
295static int remove_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
296{
297 if (plane->bo && plane->fb_id.value) {
298 CHECK_RESULT(drmModeRmFB(ctx->fd, plane->fb_id.value));
299 gbm_bo_destroy(plane->bo);
300 plane->bo = NULL;
301 plane->fb_id.value = 0;
302 }
303
304 return 0;
305}
306
307static int add_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
308{
309 if (plane->format_idx < plane->drm_plane.count_formats) {
310 CHECK_RESULT(remove_plane_fb(ctx, plane));
311 uint32_t flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
312 : GBM_BO_USE_SCANOUT;
313 /* TODO(gsingh): add create with modifiers option. */
314 plane->bo = gbm_bo_create(gbm, plane->crtc_w.value, plane->crtc_h.value,
315 plane->drm_plane.formats[plane->format_idx], flags);
316
317 CHECK(plane->bo);
318 plane->fb_id.value = bs_drm_fb_create_gbm(plane->bo);
319 CHECK(plane->fb_id.value);
320 CHECK_RESULT(set_plane_props(plane, ctx->pset));
321 }
322
323 return 0;
324}
325
326static int init_plane(struct atomictest_context *ctx, struct atomictest_plane *plane,
327 uint32_t format, uint32_t x, uint32_t y, uint32_t w, uint32_t h,
328 uint32_t zpos, uint32_t crtc_id)
329{
330 int32_t idx = get_format_idx(plane, format);
331 if (idx < 0)
332 return -EINVAL;
333
334 plane->format_idx = idx;
335 plane->crtc_x.value = x;
336 plane->crtc_y.value = y;
337 plane->crtc_w.value = w;
338 plane->crtc_h.value = h;
339 plane->src_w.value = plane->crtc_w.value << 16;
340 plane->src_h.value = plane->crtc_h.value << 16;
341 plane->zpos.value = zpos;
342 plane->crtc_id.value = crtc_id;
343
344 CHECK_RESULT(add_plane_fb(ctx, plane));
345 return 0;
346}
347
348static int disable_plane(struct atomictest_context *ctx, struct atomictest_plane *plane)
349{
350 plane->format_idx = 0;
351 plane->crtc_x.value = 0;
352 plane->crtc_y.value = 0;
353 plane->crtc_w.value = 0;
354 plane->crtc_h.value = 0;
355 plane->src_w.value = 0;
356 plane->src_h.value = 0;
357 plane->zpos.value = 0;
358 plane->crtc_id.value = 0;
359
360 CHECK_RESULT(remove_plane_fb(ctx, plane));
361 CHECK_RESULT(set_plane_props(plane, ctx->pset));
362 return 0;
363}
364
365static int move_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
366 struct atomictest_plane *plane, uint32_t dx, uint32_t dy)
367{
368 if (plane->crtc_x.value < (crtc->width - plane->crtc_w.value) &&
369 plane->crtc_y.value < (crtc->height - plane->crtc_h.value)) {
370 plane->crtc_x.value += dx;
371 plane->crtc_y.value += dy;
372 CHECK_RESULT(set_plane_props(plane, ctx->pset));
373 return 0;
374 }
375
376 return -1;
377}
378
379static int commit(struct atomictest_context *ctx)
380{
381 int ret;
382 fd_set fds;
383 FD_ZERO(&fds);
384 FD_SET(ctx->fd, &fds);
385
386 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
387 DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
388 CHECK_RESULT(ret);
389 do {
390 ret = select(ctx->fd + 1, &fds, NULL, NULL, NULL);
391 } while (ret == -1 && errno == EINTR);
392
393 CHECK_RESULT(ret);
394 if (FD_ISSET(ctx->fd, &fds))
395 drmHandleEvent(ctx->fd, &ctx->drm_event_ctx);
396
397 return 0;
398}
399
400static int pageflip(struct atomictest_context *ctx, struct atomictest_plane *plane, uint32_t x,
401 uint32_t y, uint32_t w, uint32_t h, uint32_t zpos, uint32_t crtc_id,
402 uint32_t *formats, uint32_t count_formats)
403{
404 /* Check if plane support specified formats. */
405 for (uint32_t i = 0; i < count_formats; i++)
406 CHECK_RESULT(get_format_idx(plane, formats[i]));
407
408 for (uint32_t i = 0; i < count_formats; i++) {
409 CHECK_RESULT(init_plane(ctx, plane, formats[i], x, y, w, h, zpos, crtc_id));
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700410 write_to_buffer(ctx->mapper, plane->bo, 0x00FF0000, 0xF800);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800411 CHECK_RESULT(commit(ctx));
412 usleep(1e6);
413 }
414
415 return 0;
416}
417
418static int check_mode(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
419{
420 drmModeAtomicSetCursor(ctx->pset, 0);
421
422 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
423 if (&ctx->crtcs[i] != crtc) {
424 ctx->crtcs[i].mode_id.value = 0;
425 ctx->crtcs[i].active.value = 0;
426 set_crtc_props(&ctx->crtcs[i], ctx->pset);
427 }
428 }
429
430 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
431 ctx->connectors[i].crtc_id.value = crtc->crtc_id;
432 set_connector_props(&ctx->connectors[i], ctx->pset);
433 }
434
435 int ret = -EINVAL;
436 int cursor = drmModeAtomicGetCursor(ctx->pset);
437
438 for (uint32_t i = 0; i < ctx->num_modes; i++) {
439 struct atomictest_mode *mode = &ctx->modes[i];
440 drmModeAtomicSetCursor(ctx->pset, cursor);
441
442 crtc->mode_id.value = mode->id;
443 crtc->active.value = 1;
444 crtc->width = mode->width;
445 crtc->height = mode->height;
446
447 set_crtc_props(crtc, ctx->pset);
448 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
449 DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
450 NULL);
451 if (!ret)
452 return 0;
453 }
454
455 bs_debug_error("[CRTC:%d]: failed to find mode", crtc->crtc_id);
456 return ret;
457}
458
Gurchetan Singhbcfaf082017-06-02 12:58:10 -0700459static struct atomictest_context *new_context(uint32_t num_connectors, uint32_t num_crtcs,
460 uint32_t num_planes)
461{
462 struct atomictest_context *ctx = calloc(1, sizeof(*ctx));
463
464 ctx->mapper = bs_mapper_gem_new();
465 if (ctx->mapper == NULL) {
466 bs_debug_error("failed to create mapper object");
467 free(ctx);
468 return NULL;
469 }
470
471 ctx->connectors = calloc(num_connectors, sizeof(*ctx->connectors));
472 ctx->crtcs = calloc(num_crtcs, sizeof(*ctx->crtcs));
473 for (uint32_t i = 0; i < num_crtcs; i++) {
474 ctx->crtcs[i].planes = calloc(num_planes, sizeof(*ctx->crtcs[i].planes));
475 ctx->crtcs[i].overlay_idx = calloc(num_planes, sizeof(uint32_t));
476 ctx->crtcs[i].primary_idx = calloc(num_planes, sizeof(uint32_t));
477 ctx->crtcs[i].cursor_idx = calloc(num_planes, sizeof(uint32_t));
478 }
479
480 ctx->num_connectors = num_connectors;
481 ctx->num_crtcs = num_crtcs;
482 ctx->num_modes = 0;
483 ctx->modes = NULL;
484 ctx->pset = drmModeAtomicAlloc();
485 ctx->drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
486 ctx->drm_event_ctx.page_flip_handler = page_flip_handler;
487
488 return ctx;
489}
490
Gurchetan Singh0d714272017-01-26 11:58:49 -0800491static void free_context(struct atomictest_context *ctx)
492{
493 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
494 uint32_t num_planes = ctx->crtcs[i].num_primary + ctx->crtcs[i].num_cursor +
495 ctx->crtcs[i].num_overlay;
496
497 for (uint32_t j = 0; j < num_planes; j++) {
498 remove_plane_fb(ctx, &ctx->crtcs[i].planes[j]);
499 free(ctx->crtcs[i].planes[j].drm_plane.formats);
500 free(ctx->crtcs[i].planes[j].drm_plane.format_modifiers);
Haixia Shifc476462015-04-22 16:25:04 -0700501 }
502
Gurchetan Singh0d714272017-01-26 11:58:49 -0800503 free(ctx->crtcs[i].planes);
504 free(ctx->crtcs[i].overlay_idx);
505 free(ctx->crtcs[i].cursor_idx);
506 free(ctx->crtcs[i].primary_idx);
507 }
508
509 drmModeAtomicFree(ctx->pset);
510 free(ctx->modes);
511 free(ctx->crtcs);
512 free(ctx->connectors);
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700513 bs_mapper_destroy(ctx->mapper);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800514 free(ctx);
515}
516
Gurchetan Singh83df8832017-06-02 14:06:48 -0700517static struct atomictest_context *query_kms(int fd)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800518{
519 drmModeRes *res = drmModeGetResources(fd);
520 if (res == NULL) {
521 bs_debug_error("failed to get drm resources");
522 return false;
523 }
524
525 drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
526 if (plane_res == NULL) {
527 bs_debug_error("failed to get plane resources");
528 drmModeFreeResources(res);
529 return NULL;
530 }
531
532 struct atomictest_context *ctx =
533 new_context(res->count_connectors, res->count_crtcs, plane_res->count_planes);
534 if (ctx == NULL) {
535 bs_debug_error("failed to allocate atomic context");
536 drmModeFreePlaneResources(plane_res);
537 drmModeFreeResources(res);
538 return NULL;
539 }
540
Gurchetan Singh0d714272017-01-26 11:58:49 -0800541 ctx->fd = fd;
542 drmModeObjectPropertiesPtr props = NULL;
543
544 for (uint32_t conn_index = 0; conn_index < res->count_connectors; conn_index++) {
545 uint32_t conn_id = res->connectors[conn_index];
546 ctx->connectors[conn_index].connector_id = conn_id;
547 props = drmModeObjectGetProperties(fd, conn_id, DRM_MODE_OBJECT_CONNECTOR);
548 get_connector_props(fd, &ctx->connectors[conn_index], props);
549
550 drmModeConnector *connector = drmModeGetConnector(fd, conn_id);
551 for (uint32_t mode_index = 0; mode_index < connector->count_modes; mode_index++) {
Kristian H. Kristensen56863512017-04-28 14:21:40 -0700552 ctx->modes = realloc(ctx->modes, (ctx->num_modes + 1) * sizeof(*ctx->modes));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800553 drmModeCreatePropertyBlob(fd, &connector->modes[mode_index],
554 sizeof(drmModeModeInfo),
555 &ctx->modes[ctx->num_modes].id);
556 ctx->modes[ctx->num_modes].width = connector->modes[mode_index].hdisplay;
557 ctx->modes[ctx->num_modes].height = connector->modes[mode_index].vdisplay;
558 ctx->num_modes++;
Haixia Shifc476462015-04-22 16:25:04 -0700559 }
560
Gurchetan Singh0d714272017-01-26 11:58:49 -0800561 drmModeFreeConnector(connector);
562 drmModeFreeObjectProperties(props);
563 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700564 }
565
Gurchetan Singh0d714272017-01-26 11:58:49 -0800566 uint32_t crtc_index;
567 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
568 ctx->crtcs[crtc_index].crtc_id = res->crtcs[crtc_index];
569 props =
570 drmModeObjectGetProperties(fd, res->crtcs[crtc_index], DRM_MODE_OBJECT_CRTC);
571 get_crtc_props(fd, &ctx->crtcs[crtc_index], props);
572
573 drmModeFreeObjectProperties(props);
574 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700575 }
576
Gurchetan Singh0d714272017-01-26 11:58:49 -0800577 uint32_t overlay_idx, primary_idx, cursor_idx, idx;
Haixia Shifc476462015-04-22 16:25:04 -0700578
Gurchetan Singh0d714272017-01-26 11:58:49 -0800579 for (uint32_t plane_index = 0; plane_index < plane_res->count_planes; plane_index++) {
Kristian H. Kristensenfe6e6fa2017-05-01 15:12:20 -0700580 drmModePlane *plane = drmModeGetPlane2(fd, plane_res->planes[plane_index]);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800581 if (plane == NULL) {
582 bs_debug_error("failed to get plane id %u", plane_res->planes[plane_index]);
583 continue;
584 }
Haixia Shifc476462015-04-22 16:25:04 -0700585
Gurchetan Singh0d714272017-01-26 11:58:49 -0800586 uint32_t crtc_mask = 0;
587
588 drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(
589 fd, plane_res->planes[plane_index], DRM_MODE_OBJECT_PLANE);
590
591 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
592 crtc_mask = (1 << crtc_index);
593 if (plane->possible_crtcs & crtc_mask) {
594 struct atomictest_crtc *crtc = &ctx->crtcs[crtc_index];
595 cursor_idx = crtc->num_cursor;
596 primary_idx = crtc->num_primary;
597 overlay_idx = crtc->num_overlay;
598 idx = cursor_idx + primary_idx + overlay_idx;
599 copy_drm_plane(&crtc->planes[idx].drm_plane, plane);
600 get_plane_props(fd, &crtc->planes[idx], props);
601 switch (crtc->planes[idx].type.value) {
602 case DRM_PLANE_TYPE_OVERLAY:
603 crtc->overlay_idx[overlay_idx] = idx;
604 crtc->num_overlay++;
605 break;
606 case DRM_PLANE_TYPE_PRIMARY:
607 crtc->primary_idx[primary_idx] = idx;
608 crtc->num_primary++;
609 break;
610 case DRM_PLANE_TYPE_CURSOR:
611 crtc->cursor_idx[cursor_idx] = idx;
612 crtc->num_cursor++;
613 break;
614 default:
615 bs_debug_error("invalid plane type returned");
616 return NULL;
617 }
Haixia Shifc476462015-04-22 16:25:04 -0700618 }
619 }
620
Gurchetan Singh0d714272017-01-26 11:58:49 -0800621 drmModeFreePlane(plane);
622 drmModeFreeObjectProperties(props);
623 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700624 }
625
Gurchetan Singh0d714272017-01-26 11:58:49 -0800626 /* HACK: Set connector CRTC pid to plane CRTC pid. */
627 for (uint32_t i = 0; i < ctx->num_connectors; i++)
628 ctx->connectors[i].crtc_id.pid = ctx->crtcs[0].planes[0].crtc_id.pid;
Haixia Shifc476462015-04-22 16:25:04 -0700629
Gurchetan Singh0d714272017-01-26 11:58:49 -0800630 drmModeFreePlaneResources(plane_res);
631 drmModeFreeResources(res);
632 return ctx;
633}
Haixia Shifc476462015-04-22 16:25:04 -0700634
Gurchetan Singh0d714272017-01-26 11:58:49 -0800635static int run_atomictest(const struct atomictest *test)
636{
637 int ret = 0;
638 int fd = bs_drm_open_main_display();
639 CHECK_RESULT(fd);
640
641 gbm = gbm_create_device(fd);
642 if (!gbm) {
643 bs_debug_error("failed to create gbm device");
644 ret = 1;
645 goto destroy_fd;
646 }
647
648 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
649 if (ret) {
650 bs_debug_error("failed to enable DRM_CLIENT_CAP_UNIVERSAL_PLANES");
651 ret = 1;
652 goto destroy_gbm_device;
653 }
654
655 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
656 if (ret) {
657 bs_debug_error("failed to enable DRM_CLIENT_CAP_ATOMIC");
658 ret = 1;
659 goto destroy_gbm_device;
660 }
661
Gurchetan Singh83df8832017-06-02 14:06:48 -0700662 struct atomictest_context *ctx = query_kms(fd);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800663 if (!ctx) {
Gurchetan Singh83df8832017-06-02 14:06:48 -0700664 bs_debug_error("querying atomictest failed.");
Gurchetan Singh0d714272017-01-26 11:58:49 -0800665 ret = 1;
666 goto destroy_gbm_device;
667 }
668
669 struct atomictest_crtc *crtc;
670 for (uint32_t crtc_index = 0; crtc_index < ctx->num_crtcs; crtc_index++) {
671 crtc = &ctx->crtcs[crtc_index];
672 if (!check_mode(ctx, crtc))
673 ret |= test->run_test(ctx, crtc);
674 else
675 ret |= 1;
676 }
677
678 free_context(ctx);
679
680destroy_gbm_device:
681 gbm_device_destroy(gbm);
682destroy_fd:
683 close(fd);
684
Haixia Shifc476462015-04-22 16:25:04 -0700685 return ret;
686}
Gurchetan Singh0d714272017-01-26 11:58:49 -0800687
688static int test_multiple_planes(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
689{
690 struct atomictest_plane *primary, *overlay, *cursor;
691 for (uint32_t i = 0; i < crtc->num_primary; i++) {
692 bool has_video = false;
693 uint32_t x, y;
694 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
695 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
696 x = crtc->width >> (j + 2);
697 y = crtc->height >> (j + 2);
698 bool added_video = false;
699 if (!has_video) {
700 uint32_t k = 0;
701 for (k = 0; k < BS_ARRAY_LEN(yuv_formats); k++) {
702 if (!init_plane(ctx, overlay, yuv_formats[k], x, y, x, y, j,
703 crtc->crtc_id)) {
704 has_video = true;
705 added_video = true;
706 break;
707 }
708 }
709
710 if (added_video) {
711 const struct bs_draw_format *draw_format =
712 bs_get_draw_format(yuv_formats[k]);
713 CHECK(draw_format);
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700714 CHECK(
Dongseong Hwang20c494c2016-04-27 11:26:19 +0300715 bs_draw_stripe(ctx->mapper, overlay->bo, draw_format));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800716 }
717 }
718
719 if (!added_video) {
720 added_video = true;
721 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, x, y, x,
722 y, i, crtc->crtc_id));
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700723 write_to_buffer(ctx->mapper, overlay->bo, 0x00FF0000, 0);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800724 }
725 }
726
727 for (uint32_t j = 0; j < crtc->num_cursor; j++) {
728 x = crtc->width >> (j + 2);
729 y = crtc->height >> (j + 2);
730 cursor = get_plane(crtc, j, DRM_PLANE_TYPE_CURSOR);
731 CHECK_RESULT(init_plane(ctx, cursor, DRM_FORMAT_XRGB8888, x, y, CURSOR_SIZE,
732 CURSOR_SIZE, crtc->num_overlay + j, crtc->crtc_id));
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700733 draw_cursor(ctx->mapper, cursor->bo);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800734 }
735
736 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
737 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
738 crtc->height, 0, crtc->crtc_id));
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700739 write_to_buffer(ctx->mapper, primary->bo, 0x00000FF, 0);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800740
741 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
742 int done = 0;
743 struct atomictest_plane *plane;
744 while (!done) {
745 done = 1;
746 for (uint32_t j = 0; j < num_planes; j++) {
747 plane = &crtc->planes[j];
748 if (plane->type.value != DRM_PLANE_TYPE_PRIMARY)
749 done &= move_plane(ctx, crtc, plane, 20, 20);
750 }
751
752 CHECK_RESULT(commit(ctx));
753 usleep(1e6 / 60);
754 }
755
756 CHECK_RESULT(commit(ctx));
757 usleep(1e6);
758
759 /* Disable primary plane and verify overlays show up. */
760 CHECK_RESULT(disable_plane(ctx, primary));
761 CHECK_RESULT(commit(ctx));
762 usleep(1e6);
763 }
764
765 return 0;
766}
767
768static int test_video_overlay(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
769{
770 struct atomictest_plane *overlay;
771 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
772 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
773 for (uint32_t j = 0; j < BS_ARRAY_LEN(yuv_formats); j++) {
774 if (init_plane(ctx, overlay, yuv_formats[j], 0, 0, 800, 800, 0,
775 crtc->crtc_id))
776 continue;
777
778 const struct bs_draw_format *draw_format =
779 bs_get_draw_format(yuv_formats[j]);
780 CHECK(draw_format);
Dongseong Hwang20c494c2016-04-27 11:26:19 +0300781 CHECK(bs_draw_stripe(ctx->mapper, overlay->bo, draw_format));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800782 while (!move_plane(ctx, crtc, overlay, 20, 20)) {
783 CHECK_RESULT(commit(ctx));
784 usleep(1e6 / 60);
785 }
786 }
787 }
788
789 return 0;
790}
791
792static int test_fullscreen_video(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
793{
794 struct atomictest_plane *primary;
795 for (uint32_t i = 0; i < crtc->num_primary; i++) {
796 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
797 for (uint32_t j = 0; j < BS_ARRAY_LEN(yuv_formats); j++) {
798 if (init_plane(ctx, primary, yuv_formats[j], 0, 0, crtc->width,
799 crtc->height, 0, crtc->crtc_id))
800 continue;
801 const struct bs_draw_format *draw_format =
802 bs_get_draw_format(yuv_formats[j]);
803 CHECK(draw_format);
804
Dongseong Hwang20c494c2016-04-27 11:26:19 +0300805 CHECK(bs_draw_stripe(ctx->mapper, primary->bo, draw_format));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800806 CHECK_RESULT(commit(ctx));
807 usleep(1e6);
808 }
809 }
810
811 return 0;
812}
813
814static int test_disable_primary(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
815{
816 int cursor;
817 struct atomictest_plane *primary, *overlay;
818 for (uint32_t i = 0; i < crtc->num_primary; i++) {
819 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
820 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
821 uint32_t x = crtc->width >> (j + 2);
822 uint32_t y = crtc->height >> (j + 2);
823 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, x, y, x, y, i,
824 crtc->crtc_id));
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700825 write_to_buffer(ctx->mapper, overlay->bo, 0x00FF0000, 0);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800826 }
827
828 cursor = drmModeAtomicGetCursor(ctx->pset);
829 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
830 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
831 crtc->height, 0, crtc->crtc_id));
Dongseong Hwangc19d6a62017-04-11 16:06:25 -0700832 write_to_buffer(ctx->mapper, primary->bo, 0x00000FF, 0);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800833 CHECK_RESULT(commit(ctx));
834 usleep(1e6);
835
836 /* Disable primary plane. */
837 disable_plane(ctx, primary);
838 CHECK_RESULT(commit(ctx));
839 usleep(1e6);
840 drmModeAtomicSetCursor(ctx->pset, cursor);
841 }
842
843 return 0;
844}
845
846static int test_overlay_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
847{
848 struct atomictest_plane *overlay;
849 uint32_t formats[3] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGB565 };
850 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
851 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
852 uint32_t x = crtc->width >> (i + 1);
853 uint32_t y = crtc->height >> (i + 1);
854
855 CHECK_RESULT(pageflip(ctx, overlay, x, y, x, y, i, crtc->crtc_id, formats,
856 BS_ARRAY_LEN(formats)));
857 }
858
859 return 0;
860}
861
862static int test_primary_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
863{
864 int cursor;
865 struct atomictest_plane *primary;
866 uint32_t formats[3] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGB565 };
867 for (uint32_t i = 0; i < crtc->num_primary; i++) {
868 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
869 cursor = drmModeAtomicGetCursor(ctx->pset);
870 CHECK_RESULT(pageflip(ctx, primary, 0, 0, crtc->width, crtc->height, 0,
871 crtc->crtc_id, formats, BS_ARRAY_LEN(formats)));
872
873 drmModeAtomicSetCursor(ctx->pset, cursor);
874 }
875
876 return 0;
877}
878
879static const struct atomictest tests[] = {
880 { "disable_primary", test_disable_primary },
881 { "fullscreen_video", test_fullscreen_video },
882 { "multiple_planes", test_multiple_planes },
883 { "overlay_pageflip", test_overlay_pageflip },
884 { "primary_pageflip", test_primary_pageflip },
885 { "video_overlay", test_video_overlay },
886};
887
888static void print_help(const char *argv0)
889{
890 printf("usage: %s <test_name>\n\n", argv0);
891 printf("A valid name test is one the following:\n");
892 for (uint32_t i = 0; i < BS_ARRAY_LEN(tests); i++)
893 printf("%s\n", tests[i].name);
894}
895
896int main(int argc, char **argv)
897{
898 if (argc == 2) {
899 char *name = argv[1];
900 for (uint32_t i = 0; i < BS_ARRAY_LEN(tests); i++) {
901 if (strcmp(tests[i].name, name))
902 continue;
903
904 int ret = run_atomictest(&tests[i]);
905 if (ret) {
906 printf("[ FAILED ] atomictest.%s\n", name);
907 return -1;
908 } else {
909 printf("[ PASSED ] atomictest.%s\n", name);
910 return 0;
911 }
912 }
913 }
914
915 print_help(argv[0]);
916
917 return -1;
918}