blob: 962618d7ba52f0f03a86f56d8f78ed881c5d3174 [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>
Daniele Castagna0827c312018-07-05 18:54:35 -040019#include <pthread.h>
Daniele Castagna6adafc52018-07-02 23:43:01 -040020#include <sync/sync.h>
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -070021
Gurchetan Singh0d714272017-01-26 11:58:49 -080022#include "bs_drm.h"
Haixia Shifc476462015-04-22 16:25:04 -070023
Dongseong Hwang9093afe2017-03-20 19:16:28 -070024#define CHECK(cond) \
25 do { \
26 if (!(cond)) { \
27 bs_debug_error("check %s failed", #cond); \
28 return -1; \
29 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080030 } while (0)
31
Dongseong Hwang9093afe2017-03-20 19:16:28 -070032#define CHECK_RESULT(ret) \
33 do { \
34 if ((ret) < 0) { \
35 bs_debug_error("failed with error: %d", ret); \
36 return -1; \
37 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080038 } while (0)
39
40#define CURSOR_SIZE 64
41
Daniele Castagna0827c312018-07-05 18:54:35 -040042// TODO(dcastagna): Remove these declarations once they're exported in a libsync header.
43int sw_sync_timeline_create(void);
44int sw_sync_timeline_inc(int fd, unsigned count);
45int sw_sync_fence_create(int fd, const char *name, unsigned value);
46
Daniele Castagna0fea43f2017-04-06 17:47:11 -040047// TODO(gsingh) This is defined in upstream libdrm -- remove when CROS libdrm is updated.
48#ifndef DRM_ROTATE_0
49#define DRM_ROTATE_0 (1UL << 0)
50#endif
51
52#ifndef DRM_REFLECT_Y
53#define DRM_REFLECT_Y (1UL << 5)
54#endif
55
Shirish S5f3e6d42018-02-16 11:15:22 +053056#define TEST_COMMIT_FAIL 1
57
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -040058#define GAMMA_MAX_VALUE ((1 << 16) - 1)
59
Gurchetan Singh0d714272017-01-26 11:58:49 -080060static const uint32_t yuv_formats[] = {
Shirish S95c374f2018-01-25 14:25:26 +053061 DRM_FORMAT_NV12,
62 DRM_FORMAT_YVU420,
Gurchetan Singh0d714272017-01-26 11:58:49 -080063};
64
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -040065/*
66 * The blob for the CTM propery is a drm_color_ctm.
67 * drm_color_ctm contains a 3x3 u64 matrix. Every element is represented as
68 * sign and U31.32. The sign is the MSB.
69 */
70// clang-format off
71static int64_t identity_ctm[9] = {
72 0x100000000, 0x0, 0x0,
73 0x0, 0x100000000, 0x0,
74 0x0, 0x0, 0x100000000
75};
76static int64_t red_shift_ctm[9] = {
77 0x140000000, 0x0, 0x0,
78 0x0, 0xC0000000, 0x0,
79 0x0, 0x0, 0xC0000000
80};
81// clang-format on
82
Gurchetan Singh08025e82018-04-19 15:51:30 -070083static bool automatic = false;
Gurchetan Singh0d714272017-01-26 11:58:49 -080084static struct gbm_device *gbm = NULL;
85
86static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
87 unsigned int tv_usec, void *user_data)
Haixia Shifc476462015-04-22 16:25:04 -070088{
Gurchetan Singh0d714272017-01-26 11:58:49 -080089 // Nothing to do.
Haixia Shifc476462015-04-22 16:25:04 -070090}
91
Gurchetan Singh0d714272017-01-26 11:58:49 -080092struct atomictest_property {
93 uint32_t pid;
Daniele Castagna6adafc52018-07-02 23:43:01 -040094 uint64_t value;
Gurchetan Singh0d714272017-01-26 11:58:49 -080095};
Haixia Shifc476462015-04-22 16:25:04 -070096
Gurchetan Singh0d714272017-01-26 11:58:49 -080097struct atomictest_plane {
98 drmModePlane drm_plane;
99 struct gbm_bo *bo;
Haixia Shifc476462015-04-22 16:25:04 -0700100
Gurchetan Singh0d714272017-01-26 11:58:49 -0800101 uint32_t format_idx;
102
103 /* Properties. */
104 struct atomictest_property crtc_id;
105 struct atomictest_property crtc_x;
106 struct atomictest_property crtc_y;
107 struct atomictest_property crtc_w;
108 struct atomictest_property crtc_h;
109 struct atomictest_property fb_id;
110 struct atomictest_property src_x;
111 struct atomictest_property src_y;
112 struct atomictest_property src_w;
113 struct atomictest_property src_h;
114 struct atomictest_property type;
Daniele Castagna0827c312018-07-05 18:54:35 -0400115 struct atomictest_property in_fence_fd;
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400116 struct atomictest_property rotation;
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500117 struct atomictest_property ctm;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800118};
119
120struct atomictest_connector {
121 uint32_t connector_id;
122 struct atomictest_property crtc_id;
123 struct atomictest_property edid;
124 struct atomictest_property dpms;
125};
126
127struct atomictest_crtc {
128 uint32_t crtc_id;
129 uint32_t width;
130 uint32_t height;
131 uint32_t *primary_idx;
132 uint32_t *cursor_idx;
133 uint32_t *overlay_idx;
134 uint32_t num_primary;
135 uint32_t num_cursor;
136 uint32_t num_overlay;
137
138 struct atomictest_plane *planes;
139 struct atomictest_property mode_id;
140 struct atomictest_property active;
Daniele Castagna6adafc52018-07-02 23:43:01 -0400141 struct atomictest_property out_fence_ptr;
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400142 struct atomictest_property ctm;
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400143 struct atomictest_property gamma_lut;
144 struct atomictest_property gamma_lut_size;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800145};
146
147struct atomictest_mode {
148 uint32_t height;
149 uint32_t width;
150 uint32_t id;
151};
152
153struct atomictest_context {
154 int fd;
155 uint32_t num_crtcs;
156 uint32_t num_connectors;
157 uint32_t num_modes;
158
159 struct atomictest_connector *connectors;
160 struct atomictest_crtc *crtcs;
161 struct atomictest_mode *modes;
Dominik Behre0f1c182016-01-25 14:38:22 -0800162 drmModeAtomicReqPtr pset;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800163 drmEventContext drm_event_ctx;
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700164
165 struct bs_mapper *mapper;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800166};
Haixia Shifc476462015-04-22 16:25:04 -0700167
Gurchetan Singhd61875a2017-06-02 17:03:19 -0700168typedef int (*test_function)(struct atomictest_context *ctx, struct atomictest_crtc *crtc);
169
170struct atomictest_testcase {
Gurchetan Singh0d714272017-01-26 11:58:49 -0800171 const char *name;
Gurchetan Singhd61875a2017-06-02 17:03:19 -0700172 test_function test_func;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800173};
Haixia Shifc476462015-04-22 16:25:04 -0700174
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700175// clang-format off
176enum draw_format_type {
177 DRAW_NONE = 0,
178 DRAW_STRIPE = 1,
Daniele Castagnad34afd72018-03-30 14:48:53 -0400179 DRAW_TRANSPARENT_HOLE = 2,
180 DRAW_ELLIPSE = 3,
181 DRAW_CURSOR = 4,
182 DRAW_LINES = 5,
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700183};
184// clang-format on
185
Daniele Castagna6adafc52018-07-02 23:43:01 -0400186static int drmModeCreatePropertyBlob64(int fd, const void *data, size_t length, uint64_t *id)
187{
188 uint32_t ctm_blob_id = 0;
189 int ret = drmModeCreatePropertyBlob(fd, data, length, &ctm_blob_id);
190 *id = ctm_blob_id;
191 return ret;
192}
193
194static int drmModeDestroyPropertyBlob64(int fd, uint64_t id)
195{
196 CHECK(id < (1ull << 32));
197 return drmModeDestroyPropertyBlob(fd, (uint32_t)id);
198}
199
Gurchetan Singh0d714272017-01-26 11:58:49 -0800200static int32_t get_format_idx(struct atomictest_plane *plane, uint32_t format)
201{
202 for (int32_t i = 0; i < plane->drm_plane.count_formats; i++)
203 if (plane->drm_plane.formats[i] == format)
204 return i;
205 return -1;
206}
207
208static void copy_drm_plane(drmModePlane *dest, drmModePlane *src)
209{
210 memcpy(dest, src, sizeof(drmModePlane));
211 dest->formats = calloc(src->count_formats, sizeof(uint32_t));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800212 memcpy(dest->formats, src->formats, src->count_formats * sizeof(uint32_t));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800213}
214
215static struct atomictest_plane *get_plane(struct atomictest_crtc *crtc, uint32_t idx, uint64_t type)
216{
217 uint32_t index;
218 switch (type) {
219 case DRM_PLANE_TYPE_OVERLAY:
220 index = crtc->overlay_idx[idx];
221 break;
222 case DRM_PLANE_TYPE_PRIMARY:
223 index = crtc->primary_idx[idx];
224 break;
225 case DRM_PLANE_TYPE_CURSOR:
226 index = crtc->cursor_idx[idx];
227 break;
228 default:
229 bs_debug_error("invalid plane type returned");
230 return NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700231 }
232
Gurchetan Singh0d714272017-01-26 11:58:49 -0800233 return &crtc->planes[index];
234}
Haixia Shifc476462015-04-22 16:25:04 -0700235
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700236static int draw_to_plane(struct bs_mapper *mapper, struct atomictest_plane *plane,
237 enum draw_format_type pattern)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800238{
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700239 struct gbm_bo *bo = plane->bo;
Gurchetan Singha676f1b2017-10-16 18:33:29 -0700240 uint32_t format = gbm_bo_get_format(bo);
241 const struct bs_draw_format *draw_format = bs_get_draw_format(format);
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700242
243 if (draw_format && pattern) {
244 switch (pattern) {
245 case DRAW_STRIPE:
246 CHECK(bs_draw_stripe(mapper, bo, draw_format));
247 break;
Daniele Castagnad34afd72018-03-30 14:48:53 -0400248 case DRAW_TRANSPARENT_HOLE:
249 CHECK(bs_draw_transparent_hole(mapper, bo, draw_format));
250 break;
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700251 case DRAW_ELLIPSE:
252 CHECK(bs_draw_ellipse(mapper, bo, draw_format, 0));
253 break;
254 case DRAW_CURSOR:
255 CHECK(bs_draw_cursor(mapper, bo, draw_format));
256 break;
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700257 case DRAW_LINES:
258 CHECK(bs_draw_lines(mapper, bo, draw_format));
259 break;
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700260 default:
261 bs_debug_error("invalid draw type");
262 return -1;
263 }
264 } else {
265 // DRM_FORMAT_RGB565 --> red, DRM_FORMAT_BGR565 --> blue,
266 // everything else --> something
267 void *map_data;
268 uint16_t value = 0xF800;
Satyajit Sahub7e47dd2018-05-07 12:35:50 +0530269 uint32_t stride;
270 void *addr = bs_mapper_map(mapper, bo, 0, &map_data, &stride);
271 uint32_t num_shorts = stride * gbm_bo_get_height(bo) / sizeof(uint16_t);
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700272 uint16_t *pixel = (uint16_t *)addr;
273
274 CHECK(addr);
275 for (uint32_t i = 0; i < num_shorts; i++)
276 pixel[i] = value;
277
278 bs_mapper_unmap(mapper, bo, map_data);
279 }
280
281 return 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800282}
283
284static int get_prop(int fd, drmModeObjectPropertiesPtr props, const char *name,
285 struct atomictest_property *bs_prop)
286{
287 /* Property ID should always be > 0. */
288 bs_prop->pid = 0;
289 drmModePropertyPtr prop;
290 for (uint32_t i = 0; i < props->count_props; i++) {
291 if (bs_prop->pid)
292 break;
293
294 prop = drmModeGetProperty(fd, props->props[i]);
295 if (prop) {
296 if (!strcmp(prop->name, name)) {
297 bs_prop->pid = prop->prop_id;
298 bs_prop->value = props->prop_values[i];
299 }
300 drmModeFreeProperty(prop);
301 }
302 }
303
304 return (bs_prop->pid == 0) ? -1 : 0;
305}
306
307static int get_connector_props(int fd, struct atomictest_connector *connector,
308 drmModeObjectPropertiesPtr props)
309{
Gurchetan Singh476ce542017-06-02 09:06:01 -0700310 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &connector->crtc_id));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800311 CHECK_RESULT(get_prop(fd, props, "EDID", &connector->edid));
312 CHECK_RESULT(get_prop(fd, props, "DPMS", &connector->dpms));
313 return 0;
314}
315
316static int get_crtc_props(int fd, struct atomictest_crtc *crtc, drmModeObjectPropertiesPtr props)
317{
318 CHECK_RESULT(get_prop(fd, props, "MODE_ID", &crtc->mode_id));
319 CHECK_RESULT(get_prop(fd, props, "ACTIVE", &crtc->active));
Daniele Castagna6adafc52018-07-02 23:43:01 -0400320 CHECK_RESULT(get_prop(fd, props, "OUT_FENCE_PTR", &crtc->out_fence_ptr));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400321
322 /*
323 * The atomic API makes no guarantee a property is present in object. This test
324 * requires the above common properties since a plane is undefined without them.
325 * Other properties (i.e: ctm) are optional.
326 */
327 get_prop(fd, props, "CTM", &crtc->ctm);
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400328 get_prop(fd, props, "GAMMA_LUT", &crtc->gamma_lut);
329 get_prop(fd, props, "GAMMA_LUT_SIZE", &crtc->gamma_lut_size);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800330 return 0;
331}
332
333static int get_plane_props(int fd, struct atomictest_plane *plane, drmModeObjectPropertiesPtr props)
334{
335 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &plane->crtc_id));
336 CHECK_RESULT(get_prop(fd, props, "FB_ID", &plane->fb_id));
337 CHECK_RESULT(get_prop(fd, props, "CRTC_X", &plane->crtc_x));
338 CHECK_RESULT(get_prop(fd, props, "CRTC_Y", &plane->crtc_y));
339 CHECK_RESULT(get_prop(fd, props, "CRTC_W", &plane->crtc_w));
340 CHECK_RESULT(get_prop(fd, props, "CRTC_H", &plane->crtc_h));
341 CHECK_RESULT(get_prop(fd, props, "SRC_X", &plane->src_x));
342 CHECK_RESULT(get_prop(fd, props, "SRC_Y", &plane->src_y));
343 CHECK_RESULT(get_prop(fd, props, "SRC_W", &plane->src_w));
344 CHECK_RESULT(get_prop(fd, props, "SRC_H", &plane->src_h));
345 CHECK_RESULT(get_prop(fd, props, "type", &plane->type));
Daniele Castagna0827c312018-07-05 18:54:35 -0400346 CHECK_RESULT(get_prop(fd, props, "IN_FENCE_FD", &plane->in_fence_fd));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400347
348 /*
349 * The atomic API makes no guarantee a property is present in object. This test
350 * requires the above common properties since a plane is undefined without them.
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500351 * Other properties (i.e: rotation and ctm) are optional.
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400352 */
353 get_prop(fd, props, "rotation", &plane->rotation);
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500354 get_prop(fd, props, "PLANE_CTM", &plane->ctm);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800355 return 0;
356}
357
358int set_connector_props(struct atomictest_connector *conn, drmModeAtomicReqPtr pset)
359{
360 uint32_t id = conn->connector_id;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800361 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, conn->crtc_id.pid, conn->crtc_id.value));
362 return 0;
363}
364
365int set_crtc_props(struct atomictest_crtc *crtc, drmModeAtomicReqPtr pset)
366{
367 uint32_t id = crtc->crtc_id;
368 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->mode_id.pid, crtc->mode_id.value));
369 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->active.pid, crtc->active.value));
Daniele Castagna6adafc52018-07-02 23:43:01 -0400370 if (crtc->out_fence_ptr.value)
371 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->out_fence_ptr.pid,
372 crtc->out_fence_ptr.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400373 if (crtc->ctm.pid)
374 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->ctm.pid, crtc->ctm.value));
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400375 if (crtc->gamma_lut.pid)
376 CHECK_RESULT(
377 drmModeAtomicAddProperty(pset, id, crtc->gamma_lut.pid, crtc->gamma_lut.value));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800378 return 0;
379}
380
381int set_plane_props(struct atomictest_plane *plane, drmModeAtomicReqPtr pset)
382{
383 uint32_t id = plane->drm_plane.plane_id;
384 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_id.pid, plane->crtc_id.value));
385 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->fb_id.pid, plane->fb_id.value));
386 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_x.pid, plane->crtc_x.value));
387 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_y.pid, plane->crtc_y.value));
388 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_w.pid, plane->crtc_w.value));
389 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_h.pid, plane->crtc_h.value));
390 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_x.pid, plane->src_x.value));
391 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_y.pid, plane->src_y.value));
392 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_w.pid, plane->src_w.value));
393 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_h.pid, plane->src_h.value));
Daniele Castagna0827c312018-07-05 18:54:35 -0400394 CHECK_RESULT(
395 drmModeAtomicAddProperty(pset, id, plane->in_fence_fd.pid, plane->in_fence_fd.value));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400396 if (plane->rotation.pid)
397 CHECK_RESULT(
398 drmModeAtomicAddProperty(pset, id, plane->rotation.pid, plane->rotation.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500399 if (plane->ctm.pid)
400 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->ctm.pid, plane->ctm.value));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400401
Gurchetan Singh0d714272017-01-26 11:58:49 -0800402 return 0;
403}
404
405static int remove_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
406{
407 if (plane->bo && plane->fb_id.value) {
408 CHECK_RESULT(drmModeRmFB(ctx->fd, plane->fb_id.value));
409 gbm_bo_destroy(plane->bo);
410 plane->bo = NULL;
411 plane->fb_id.value = 0;
412 }
413
414 return 0;
415}
416
417static int add_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
418{
419 if (plane->format_idx < plane->drm_plane.count_formats) {
420 CHECK_RESULT(remove_plane_fb(ctx, plane));
421 uint32_t flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
422 : GBM_BO_USE_SCANOUT;
Gurchetan Singh18a05992017-11-08 15:43:57 -0800423 flags |= GBM_BO_USE_SW_WRITE_RARELY;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800424 /* TODO(gsingh): add create with modifiers option. */
425 plane->bo = gbm_bo_create(gbm, plane->crtc_w.value, plane->crtc_h.value,
426 plane->drm_plane.formats[plane->format_idx], flags);
427
428 CHECK(plane->bo);
429 plane->fb_id.value = bs_drm_fb_create_gbm(plane->bo);
430 CHECK(plane->fb_id.value);
431 CHECK_RESULT(set_plane_props(plane, ctx->pset));
432 }
433
434 return 0;
435}
436
437static int init_plane(struct atomictest_context *ctx, struct atomictest_plane *plane,
438 uint32_t format, uint32_t x, uint32_t y, uint32_t w, uint32_t h,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700439 uint32_t crtc_id)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800440{
441 int32_t idx = get_format_idx(plane, format);
442 if (idx < 0)
443 return -EINVAL;
444
445 plane->format_idx = idx;
446 plane->crtc_x.value = x;
447 plane->crtc_y.value = y;
448 plane->crtc_w.value = w;
449 plane->crtc_h.value = h;
450 plane->src_w.value = plane->crtc_w.value << 16;
451 plane->src_h.value = plane->crtc_h.value << 16;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800452 plane->crtc_id.value = crtc_id;
453
454 CHECK_RESULT(add_plane_fb(ctx, plane));
455 return 0;
456}
457
Shirish S95c374f2018-01-25 14:25:26 +0530458static int init_plane_any_format(struct atomictest_context *ctx, struct atomictest_plane *plane,
459 uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t crtc_id,
460 bool yuv)
Gurchetan Singh763dc642017-10-24 13:51:41 -0700461{
Shirish S95c374f2018-01-25 14:25:26 +0530462 if (yuv) {
463 uint32_t i;
464 for (i = 0; i < BS_ARRAY_LEN(yuv_formats); i++)
465 if (!init_plane(ctx, plane, yuv_formats[i], x, y, w, h, crtc_id))
466 return 0;
467 } else {
468 // XRGB888 works well with our draw code, so try that first.
469 if (!init_plane(ctx, plane, DRM_FORMAT_XRGB8888, x, y, w, h, crtc_id))
Gurchetan Singh763dc642017-10-24 13:51:41 -0700470 return 0;
471
Shirish S95c374f2018-01-25 14:25:26 +0530472 for (uint32_t format_idx = 0; format_idx < plane->drm_plane.count_formats;
473 format_idx++) {
474 if (!gbm_device_is_format_supported(
475 gbm, plane->drm_plane.formats[format_idx], GBM_BO_USE_SCANOUT))
476 continue;
477
478 if (!init_plane(ctx, plane, plane->drm_plane.formats[format_idx], x, y, w,
479 h, crtc_id))
480 return 0;
481 }
482 }
483
Gurchetan Singh763dc642017-10-24 13:51:41 -0700484 return -EINVAL;
485}
486
Gurchetan Singh0d714272017-01-26 11:58:49 -0800487static int disable_plane(struct atomictest_context *ctx, struct atomictest_plane *plane)
488{
489 plane->format_idx = 0;
490 plane->crtc_x.value = 0;
491 plane->crtc_y.value = 0;
492 plane->crtc_w.value = 0;
493 plane->crtc_h.value = 0;
494 plane->src_w.value = 0;
495 plane->src_h.value = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800496 plane->crtc_id.value = 0;
Drew Davenportc7f04e42018-09-11 14:21:10 -0600497 plane->in_fence_fd.value = -1;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800498
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400499 if (plane->rotation.pid)
500 plane->rotation.value = DRM_ROTATE_0;
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500501 if (plane->ctm.pid)
502 plane->ctm.value = 0;
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400503
Gurchetan Singh0d714272017-01-26 11:58:49 -0800504 CHECK_RESULT(remove_plane_fb(ctx, plane));
505 CHECK_RESULT(set_plane_props(plane, ctx->pset));
506 return 0;
507}
508
509static int move_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
510 struct atomictest_plane *plane, uint32_t dx, uint32_t dy)
511{
512 if (plane->crtc_x.value < (crtc->width - plane->crtc_w.value) &&
513 plane->crtc_y.value < (crtc->height - plane->crtc_h.value)) {
514 plane->crtc_x.value += dx;
515 plane->crtc_y.value += dy;
516 CHECK_RESULT(set_plane_props(plane, ctx->pset));
517 return 0;
518 }
519
520 return -1;
521}
522
Gurchetan Singhd78c5872017-10-20 18:53:37 -0700523static int scale_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
524 struct atomictest_plane *plane, float dw, float dh)
525{
526 int32_t plane_w = (int32_t)plane->crtc_w.value + dw * plane->crtc_w.value;
527 int32_t plane_h = (int32_t)plane->crtc_h.value + dh * plane->crtc_h.value;
528 if (plane_w > 0 && plane_h > 0 && (plane->crtc_x.value + plane_w < crtc->width) &&
529 (plane->crtc_h.value + plane_h < crtc->height)) {
530 plane->crtc_w.value = BS_ALIGN((uint32_t)plane_w, 2);
531 plane->crtc_h.value = BS_ALIGN((uint32_t)plane_h, 2);
532 CHECK_RESULT(set_plane_props(plane, ctx->pset));
533 return 0;
534 }
535
536 return -1;
537}
538
Gurchetan Singhf873d8f2017-10-24 16:51:22 -0700539static void log(struct atomictest_context *ctx)
540{
541 printf("Committing the following configuration: \n");
542 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
543 struct atomictest_plane *plane;
544 struct atomictest_crtc *crtc = &ctx->crtcs[i];
545 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
546 if (!crtc->active.value)
547 continue;
548
549 printf("----- [CRTC: %u] -----\n", crtc->crtc_id);
550 for (uint32_t j = 0; j < num_planes; j++) {
551 plane = &crtc->planes[j];
552 if (plane->crtc_id.value == crtc->crtc_id && plane->fb_id.value) {
553 uint32_t format = gbm_bo_get_format(plane->bo);
554 char *fourcc = (char *)&format;
555 printf("\t{Plane ID: %u, ", plane->drm_plane.plane_id);
556 printf("Plane format: %c%c%c%c, ", fourcc[0], fourcc[1], fourcc[2],
557 fourcc[3]);
558 printf("Plane type: ");
559 switch (plane->type.value) {
560 case DRM_PLANE_TYPE_OVERLAY:
561 printf("overlay, ");
562 break;
563 case DRM_PLANE_TYPE_PRIMARY:
564 printf("primary, ");
565 break;
566 case DRM_PLANE_TYPE_CURSOR:
567 printf("cursor, ");
568 break;
569 }
570
571 printf("CRTC_X: %u, CRTC_Y: %u, CRTC_W: %u, CRTC_H: %u}\n",
572 plane->crtc_x.value, plane->crtc_y.value,
573 plane->crtc_w.value, plane->crtc_h.value);
574 }
575 }
576 }
577}
578
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400579static int test_commit(struct atomictest_context *ctx)
580{
Daniele Castagnabe01c0c2018-03-28 23:19:32 -0400581 return drmModeAtomicCommit(ctx->fd, ctx->pset,
582 DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_TEST_ONLY, NULL);
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400583}
584
Gurchetan Singh0d714272017-01-26 11:58:49 -0800585static int commit(struct atomictest_context *ctx)
586{
587 int ret;
588 fd_set fds;
589 FD_ZERO(&fds);
590 FD_SET(ctx->fd, &fds);
591
Gurchetan Singhf873d8f2017-10-24 16:51:22 -0700592 log(ctx);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800593 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
594 DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
595 CHECK_RESULT(ret);
596 do {
597 ret = select(ctx->fd + 1, &fds, NULL, NULL, NULL);
598 } while (ret == -1 && errno == EINTR);
599
600 CHECK_RESULT(ret);
601 if (FD_ISSET(ctx->fd, &fds))
602 drmHandleEvent(ctx->fd, &ctx->drm_event_ctx);
603
604 return 0;
605}
606
Gurchetan Singh08025e82018-04-19 15:51:30 -0700607static int test_and_commit(struct atomictest_context *ctx, uint32_t sleep_micro_secs)
Shirish S5f3e6d42018-02-16 11:15:22 +0530608{
Gurchetan Singh08025e82018-04-19 15:51:30 -0700609 sleep_micro_secs = automatic ? 0 : sleep_micro_secs;
Shirish S5f3e6d42018-02-16 11:15:22 +0530610 if (!test_commit(ctx)) {
611 CHECK_RESULT(commit(ctx));
Gurchetan Singh08025e82018-04-19 15:51:30 -0700612 usleep(sleep_micro_secs);
Shirish S5f3e6d42018-02-16 11:15:22 +0530613 } else {
614 return TEST_COMMIT_FAIL;
615 }
616
617 return 0;
618}
619
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700620static int pageflip_formats(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
621 struct atomictest_plane *plane)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800622{
Shirish S5f3e6d42018-02-16 11:15:22 +0530623 int ret = 0;
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700624 uint32_t flags;
625 for (uint32_t i = 0; i < plane->drm_plane.count_formats; i++) {
626 flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
627 : GBM_BO_USE_SCANOUT;
628 if (!gbm_device_is_format_supported(gbm, plane->drm_plane.formats[i], flags))
Shirish Scd098332017-09-26 16:31:07 +0530629 continue;
630
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700631 CHECK_RESULT(init_plane(ctx, plane, plane->drm_plane.formats[i], 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700632 crtc->height, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700633 CHECK_RESULT(draw_to_plane(ctx->mapper, plane, DRAW_ELLIPSE));
Gurchetan Singh08025e82018-04-19 15:51:30 -0700634 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700635
636 // disable, but don't commit, since we can't have an active CRTC without any planes.
637 CHECK_RESULT(disable_plane(ctx, plane));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800638 }
639
Shirish S5f3e6d42018-02-16 11:15:22 +0530640 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800641}
642
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700643static uint32_t get_connection(struct atomictest_crtc *crtc, uint32_t crtc_index)
644{
645 uint32_t connector_id = 0;
646 uint32_t crtc_mask = 1u << crtc_index;
647 struct bs_drm_pipe pipe = { 0 };
648 struct bs_drm_pipe_plumber *plumber = bs_drm_pipe_plumber_new();
649 bs_drm_pipe_plumber_crtc_mask(plumber, crtc_mask);
650 if (bs_drm_pipe_plumber_make(plumber, &pipe))
651 connector_id = pipe.connector_id;
652
653 bs_drm_pipe_plumber_destroy(&plumber);
654 return connector_id;
655}
656
657static int enable_crtc(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800658{
659 drmModeAtomicSetCursor(ctx->pset, 0);
660
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700661 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
662 ctx->connectors[i].crtc_id.value = 0;
663 set_connector_props(&ctx->connectors[i], ctx->pset);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800664 }
665
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700666 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
667 if (&ctx->crtcs[i] == crtc) {
668 uint32_t connector_id = get_connection(crtc, i);
669 CHECK(connector_id);
670 for (uint32_t j = 0; j < ctx->num_connectors; j++) {
671 if (connector_id == ctx->connectors[j].connector_id) {
672 ctx->connectors[j].crtc_id.value = crtc->crtc_id;
673 set_connector_props(&ctx->connectors[j], ctx->pset);
674 break;
675 }
676 }
677
678 break;
679 }
Gurchetan Singh0d714272017-01-26 11:58:49 -0800680 }
681
682 int ret = -EINVAL;
683 int cursor = drmModeAtomicGetCursor(ctx->pset);
684
685 for (uint32_t i = 0; i < ctx->num_modes; i++) {
686 struct atomictest_mode *mode = &ctx->modes[i];
687 drmModeAtomicSetCursor(ctx->pset, cursor);
688
689 crtc->mode_id.value = mode->id;
690 crtc->active.value = 1;
691 crtc->width = mode->width;
692 crtc->height = mode->height;
693
694 set_crtc_props(crtc, ctx->pset);
695 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
696 DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
697 NULL);
698 if (!ret)
699 return 0;
700 }
701
702 bs_debug_error("[CRTC:%d]: failed to find mode", crtc->crtc_id);
703 return ret;
704}
705
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700706static int disable_crtc(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
707{
708 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
709 ctx->connectors[i].crtc_id.value = 0;
710 set_connector_props(&ctx->connectors[i], ctx->pset);
711 }
712
713 crtc->mode_id.value = 0;
714 crtc->active.value = 0;
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400715 if (crtc->ctm.pid)
716 crtc->ctm.value = 0;
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400717 if (crtc->gamma_lut.pid)
718 crtc->gamma_lut.value = 0;
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400719
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700720 set_crtc_props(crtc, ctx->pset);
721 int ret = drmModeAtomicCommit(ctx->fd, ctx->pset, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
722 CHECK_RESULT(ret);
723 return ret;
724}
725
Gurchetan Singhbcfaf082017-06-02 12:58:10 -0700726static struct atomictest_context *new_context(uint32_t num_connectors, uint32_t num_crtcs,
727 uint32_t num_planes)
728{
729 struct atomictest_context *ctx = calloc(1, sizeof(*ctx));
730
731 ctx->mapper = bs_mapper_gem_new();
732 if (ctx->mapper == NULL) {
733 bs_debug_error("failed to create mapper object");
734 free(ctx);
735 return NULL;
736 }
737
738 ctx->connectors = calloc(num_connectors, sizeof(*ctx->connectors));
739 ctx->crtcs = calloc(num_crtcs, sizeof(*ctx->crtcs));
740 for (uint32_t i = 0; i < num_crtcs; i++) {
741 ctx->crtcs[i].planes = calloc(num_planes, sizeof(*ctx->crtcs[i].planes));
742 ctx->crtcs[i].overlay_idx = calloc(num_planes, sizeof(uint32_t));
743 ctx->crtcs[i].primary_idx = calloc(num_planes, sizeof(uint32_t));
744 ctx->crtcs[i].cursor_idx = calloc(num_planes, sizeof(uint32_t));
745 }
746
747 ctx->num_connectors = num_connectors;
748 ctx->num_crtcs = num_crtcs;
749 ctx->num_modes = 0;
750 ctx->modes = NULL;
751 ctx->pset = drmModeAtomicAlloc();
752 ctx->drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
753 ctx->drm_event_ctx.page_flip_handler = page_flip_handler;
754
755 return ctx;
756}
757
Gurchetan Singh0d714272017-01-26 11:58:49 -0800758static void free_context(struct atomictest_context *ctx)
759{
760 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
761 uint32_t num_planes = ctx->crtcs[i].num_primary + ctx->crtcs[i].num_cursor +
762 ctx->crtcs[i].num_overlay;
763
764 for (uint32_t j = 0; j < num_planes; j++) {
765 remove_plane_fb(ctx, &ctx->crtcs[i].planes[j]);
766 free(ctx->crtcs[i].planes[j].drm_plane.formats);
Haixia Shifc476462015-04-22 16:25:04 -0700767 }
768
Gurchetan Singh0d714272017-01-26 11:58:49 -0800769 free(ctx->crtcs[i].planes);
770 free(ctx->crtcs[i].overlay_idx);
771 free(ctx->crtcs[i].cursor_idx);
772 free(ctx->crtcs[i].primary_idx);
773 }
774
775 drmModeAtomicFree(ctx->pset);
776 free(ctx->modes);
777 free(ctx->crtcs);
778 free(ctx->connectors);
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700779 bs_mapper_destroy(ctx->mapper);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800780 free(ctx);
781}
782
Gurchetan Singh83df8832017-06-02 14:06:48 -0700783static struct atomictest_context *query_kms(int fd)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800784{
785 drmModeRes *res = drmModeGetResources(fd);
786 if (res == NULL) {
787 bs_debug_error("failed to get drm resources");
788 return false;
789 }
790
791 drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
792 if (plane_res == NULL) {
793 bs_debug_error("failed to get plane resources");
794 drmModeFreeResources(res);
795 return NULL;
796 }
797
798 struct atomictest_context *ctx =
799 new_context(res->count_connectors, res->count_crtcs, plane_res->count_planes);
800 if (ctx == NULL) {
801 bs_debug_error("failed to allocate atomic context");
802 drmModeFreePlaneResources(plane_res);
803 drmModeFreeResources(res);
804 return NULL;
805 }
806
Gurchetan Singh0d714272017-01-26 11:58:49 -0800807 ctx->fd = fd;
808 drmModeObjectPropertiesPtr props = NULL;
809
810 for (uint32_t conn_index = 0; conn_index < res->count_connectors; conn_index++) {
811 uint32_t conn_id = res->connectors[conn_index];
812 ctx->connectors[conn_index].connector_id = conn_id;
813 props = drmModeObjectGetProperties(fd, conn_id, DRM_MODE_OBJECT_CONNECTOR);
814 get_connector_props(fd, &ctx->connectors[conn_index], props);
815
816 drmModeConnector *connector = drmModeGetConnector(fd, conn_id);
817 for (uint32_t mode_index = 0; mode_index < connector->count_modes; mode_index++) {
Dongseong Hwang326d08f2017-06-13 14:42:31 -0700818 ctx->modes =
819 realloc(ctx->modes, (ctx->num_modes + 1) * sizeof(*ctx->modes));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800820 drmModeCreatePropertyBlob(fd, &connector->modes[mode_index],
821 sizeof(drmModeModeInfo),
822 &ctx->modes[ctx->num_modes].id);
823 ctx->modes[ctx->num_modes].width = connector->modes[mode_index].hdisplay;
824 ctx->modes[ctx->num_modes].height = connector->modes[mode_index].vdisplay;
825 ctx->num_modes++;
Haixia Shifc476462015-04-22 16:25:04 -0700826 }
827
Gurchetan Singh0d714272017-01-26 11:58:49 -0800828 drmModeFreeConnector(connector);
829 drmModeFreeObjectProperties(props);
830 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700831 }
832
Gurchetan Singh0d714272017-01-26 11:58:49 -0800833 uint32_t crtc_index;
834 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
835 ctx->crtcs[crtc_index].crtc_id = res->crtcs[crtc_index];
836 props =
837 drmModeObjectGetProperties(fd, res->crtcs[crtc_index], DRM_MODE_OBJECT_CRTC);
838 get_crtc_props(fd, &ctx->crtcs[crtc_index], props);
839
840 drmModeFreeObjectProperties(props);
841 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700842 }
843
Gurchetan Singh0d714272017-01-26 11:58:49 -0800844 uint32_t overlay_idx, primary_idx, cursor_idx, idx;
Haixia Shifc476462015-04-22 16:25:04 -0700845
Gurchetan Singh0d714272017-01-26 11:58:49 -0800846 for (uint32_t plane_index = 0; plane_index < plane_res->count_planes; plane_index++) {
Kristian H. Kristensenabc63d42017-10-31 09:41:00 -0700847 drmModePlane *plane = drmModeGetPlane(fd, plane_res->planes[plane_index]);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800848 if (plane == NULL) {
849 bs_debug_error("failed to get plane id %u", plane_res->planes[plane_index]);
850 continue;
851 }
Haixia Shifc476462015-04-22 16:25:04 -0700852
Gurchetan Singh0d714272017-01-26 11:58:49 -0800853 uint32_t crtc_mask = 0;
854
855 drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(
856 fd, plane_res->planes[plane_index], DRM_MODE_OBJECT_PLANE);
857
858 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
859 crtc_mask = (1 << crtc_index);
860 if (plane->possible_crtcs & crtc_mask) {
861 struct atomictest_crtc *crtc = &ctx->crtcs[crtc_index];
862 cursor_idx = crtc->num_cursor;
863 primary_idx = crtc->num_primary;
864 overlay_idx = crtc->num_overlay;
865 idx = cursor_idx + primary_idx + overlay_idx;
866 copy_drm_plane(&crtc->planes[idx].drm_plane, plane);
867 get_plane_props(fd, &crtc->planes[idx], props);
868 switch (crtc->planes[idx].type.value) {
869 case DRM_PLANE_TYPE_OVERLAY:
870 crtc->overlay_idx[overlay_idx] = idx;
871 crtc->num_overlay++;
872 break;
873 case DRM_PLANE_TYPE_PRIMARY:
874 crtc->primary_idx[primary_idx] = idx;
875 crtc->num_primary++;
876 break;
877 case DRM_PLANE_TYPE_CURSOR:
878 crtc->cursor_idx[cursor_idx] = idx;
879 crtc->num_cursor++;
880 break;
881 default:
882 bs_debug_error("invalid plane type returned");
883 return NULL;
884 }
Gurchetan Singh04e756b2017-12-08 14:25:00 -0800885
886 /*
887 * The DRM UAPI states that cursor and overlay framebuffers may be
888 * present after a CRTC disable, so zero this out so we can get a
889 * clean slate.
890 */
891 crtc->planes[idx].fb_id.value = 0;
Haixia Shifc476462015-04-22 16:25:04 -0700892 }
893 }
894
Gurchetan Singh0d714272017-01-26 11:58:49 -0800895 drmModeFreePlane(plane);
896 drmModeFreeObjectProperties(props);
897 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700898 }
899
Gurchetan Singh0d714272017-01-26 11:58:49 -0800900 drmModeFreePlaneResources(plane_res);
901 drmModeFreeResources(res);
902 return ctx;
903}
Haixia Shifc476462015-04-22 16:25:04 -0700904
Gurchetan Singh0d714272017-01-26 11:58:49 -0800905static int test_multiple_planes(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
906{
Shirish S5f3e6d42018-02-16 11:15:22 +0530907 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800908 struct atomictest_plane *primary, *overlay, *cursor;
909 for (uint32_t i = 0; i < crtc->num_primary; i++) {
Gurchetan Singh763dc642017-10-24 13:51:41 -0700910 bool video = true;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800911 uint32_t x, y;
912 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
913 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
914 x = crtc->width >> (j + 2);
915 y = crtc->height >> (j + 2);
Dongseong Hwang326d08f2017-06-13 14:42:31 -0700916 // drmModeAddFB2 requires the height and width are even for sub-sampled YUV
917 // formats.
918 x = BS_ALIGN(x, 2);
919 y = BS_ALIGN(y, 2);
Shirish S95c374f2018-01-25 14:25:26 +0530920 if (video &&
921 !init_plane_any_format(ctx, overlay, x, y, x, y, crtc->crtc_id, true)) {
Gurchetan Singh763dc642017-10-24 13:51:41 -0700922 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
923 video = false;
924 } else {
Shirish S95c374f2018-01-25 14:25:26 +0530925 CHECK_RESULT(init_plane_any_format(ctx, overlay, x, y, x, y,
926 crtc->crtc_id, false));
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700927 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800928 }
929 }
930
931 for (uint32_t j = 0; j < crtc->num_cursor; j++) {
932 x = crtc->width >> (j + 2);
933 y = crtc->height >> (j + 2);
934 cursor = get_plane(crtc, j, DRM_PLANE_TYPE_CURSOR);
Dongseong Hwangd0a45fc2017-04-12 17:10:11 -0700935 CHECK_RESULT(init_plane(ctx, cursor, DRM_FORMAT_ARGB8888, x, y, CURSOR_SIZE,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700936 CURSOR_SIZE, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700937 CHECK_RESULT(draw_to_plane(ctx->mapper, cursor, DRAW_CURSOR));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800938 }
939
940 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Shirish S95c374f2018-01-25 14:25:26 +0530941 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
942 crtc->crtc_id, false));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700943 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800944
945 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
946 int done = 0;
947 struct atomictest_plane *plane;
948 while (!done) {
949 done = 1;
950 for (uint32_t j = 0; j < num_planes; j++) {
951 plane = &crtc->planes[j];
952 if (plane->type.value != DRM_PLANE_TYPE_PRIMARY)
Stéphane Marchesinf6fe9b72018-04-02 14:57:55 -0700953 done &= move_plane(ctx, crtc, plane, 40, 40);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800954 }
955
Gurchetan Singh08025e82018-04-19 15:51:30 -0700956 ret |= test_and_commit(ctx, 1e6 / 60);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800957 }
958
Gurchetan Singh08025e82018-04-19 15:51:30 -0700959 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800960
961 /* Disable primary plane and verify overlays show up. */
962 CHECK_RESULT(disable_plane(ctx, primary));
Gurchetan Singh08025e82018-04-19 15:51:30 -0700963 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800964 }
965
Shirish S5f3e6d42018-02-16 11:15:22 +0530966 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800967}
968
969static int test_video_overlay(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
970{
Shirish S5f3e6d42018-02-16 11:15:22 +0530971 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800972 struct atomictest_plane *overlay;
973 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
974 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Shirish S95c374f2018-01-25 14:25:26 +0530975 if (init_plane_any_format(ctx, overlay, 0, 0, 800, 800, crtc->crtc_id, true))
Gurchetan Singh763dc642017-10-24 13:51:41 -0700976 continue;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800977
Gurchetan Singh763dc642017-10-24 13:51:41 -0700978 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
Stéphane Marchesinf6fe9b72018-04-02 14:57:55 -0700979 while (!move_plane(ctx, crtc, overlay, 40, 40))
Gurchetan Singh08025e82018-04-19 15:51:30 -0700980 ret |= test_and_commit(ctx, 1e6 / 60);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800981 }
982
Shirish S5f3e6d42018-02-16 11:15:22 +0530983 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800984}
985
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400986static int test_orientation(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
987{
Shirish S5f3e6d42018-02-16 11:15:22 +0530988 int ret = 0;
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400989 struct atomictest_plane *primary, *overlay;
990 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
991 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
992 if (!overlay->rotation.pid)
993 continue;
994
Shirish S95c374f2018-01-25 14:25:26 +0530995 CHECK_RESULT(init_plane_any_format(ctx, overlay, 0, 0, crtc->width, crtc->height,
996 crtc->crtc_id, false));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400997 overlay->rotation.value = DRM_ROTATE_0;
998 set_plane_props(overlay, ctx->pset);
999 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001000 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001001
1002 overlay->rotation.value = DRM_REFLECT_Y;
1003 set_plane_props(overlay, ctx->pset);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001004 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001005
1006 CHECK_RESULT(disable_plane(ctx, overlay));
1007 }
1008
1009 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1010 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1011 if (!primary->rotation.pid)
1012 continue;
1013
Shirish S95c374f2018-01-25 14:25:26 +05301014 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1015 crtc->crtc_id, false));
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001016
1017 primary->rotation.value = DRM_ROTATE_0;
1018 set_plane_props(primary, ctx->pset);
1019 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001020 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001021
1022 primary->rotation.value = DRM_REFLECT_Y;
1023 set_plane_props(primary, ctx->pset);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001024 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001025
1026 CHECK_RESULT(disable_plane(ctx, primary));
1027 }
1028
Shirish S5f3e6d42018-02-16 11:15:22 +05301029 return ret;
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001030}
1031
Daniele Castagna0827c312018-07-05 18:54:35 -04001032static void *inc_timeline(void *user_data)
1033{
1034 int timeline_fd = (int)user_data;
1035 uint32_t sleep_micro_secs = automatic ? 1e3 : 1e5;
1036 usleep(sleep_micro_secs);
1037 sw_sync_timeline_inc(timeline_fd, 1);
1038 return NULL;
1039}
1040
1041static int test_in_fence(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1042{
1043 int ret = 0;
1044 pthread_t inc_timeline_thread;
1045 struct atomictest_plane *primary = NULL;
1046
1047 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1048 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1049 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1050 crtc->crtc_id, false));
1051 break;
1052 }
1053
1054 int timeline = sw_sync_timeline_create();
1055 CHECK(fcntl(timeline, F_GETFD, 0) >= 0);
1056 int in_fence = sw_sync_fence_create(timeline, "test_in_fence", 1);
1057 CHECK(fcntl(in_fence, F_GETFD, 0) >= 0);
1058
1059 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1060
1061 primary->in_fence_fd.value = in_fence;
1062 set_plane_props(primary, ctx->pset);
1063 set_crtc_props(crtc, ctx->pset);
1064
1065 CHECK(
1066 !pthread_create(&inc_timeline_thread, NULL, inc_timeline, (void *)(uintptr_t)timeline));
1067
1068 ret |= test_and_commit(ctx, 1e6);
1069 CHECK(!pthread_join(inc_timeline_thread, NULL));
1070
1071 ret |= test_and_commit(ctx, 1e6);
1072 close(in_fence);
1073 close(timeline);
1074
1075 return ret;
1076}
1077
Daniele Castagna6adafc52018-07-02 23:43:01 -04001078static int test_out_fence(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1079{
1080 int ret = 0;
1081 struct atomictest_plane *primary = NULL;
1082
1083 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1084 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1085 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1086 crtc->crtc_id, false));
1087 break;
1088 }
1089
1090 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1091 set_plane_props(primary, ctx->pset);
1092 int out_fence_fd = 0;
1093 crtc->out_fence_ptr.value = (uint64_t)&out_fence_fd;
1094 set_crtc_props(crtc, ctx->pset);
1095 ret |= test_and_commit(ctx, 1e6);
1096 CHECK(out_fence_fd);
Daniele Castagna0827c312018-07-05 18:54:35 -04001097 // |out_fence_fd| will signal when the currently scanned out buffers are replaced.
1098 // In this case we're waiting with a timeout of 0 only to check that |out_fence_fd|
1099 // is a valid fence.
Daniele Castagna6adafc52018-07-02 23:43:01 -04001100 CHECK(!sync_wait(out_fence_fd, 0));
1101 close(out_fence_fd);
1102 return ret;
1103}
1104
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001105static int test_plane_ctm(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1106{
Shirish S5f3e6d42018-02-16 11:15:22 +05301107 int ret = 0;
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001108 struct atomictest_plane *primary, *overlay;
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001109
1110 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1111 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
1112 if (!overlay->ctm.pid)
1113 continue;
1114
1115 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1116 crtc->height, crtc->crtc_id));
1117
Daniele Castagna6adafc52018-07-02 23:43:01 -04001118 CHECK_RESULT(drmModeCreatePropertyBlob64(
1119 ctx->fd, identity_ctm, sizeof(identity_ctm), &overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001120 set_plane_props(overlay, ctx->pset);
1121 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001122 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001123 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001124
Daniele Castagna6adafc52018-07-02 23:43:01 -04001125 CHECK_RESULT(drmModeCreatePropertyBlob64(
1126 ctx->fd, red_shift_ctm, sizeof(red_shift_ctm), &overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001127 set_plane_props(overlay, ctx->pset);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001128 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001129 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001130
1131 CHECK_RESULT(disable_plane(ctx, overlay));
1132 }
1133
1134 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1135 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1136 if (!primary->ctm.pid)
1137 continue;
1138
Shirish S95c374f2018-01-25 14:25:26 +05301139 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1140 crtc->crtc_id, false));
Daniele Castagna6adafc52018-07-02 23:43:01 -04001141 CHECK_RESULT(drmModeCreatePropertyBlob64(
1142 ctx->fd, identity_ctm, sizeof(identity_ctm), &primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001143 set_plane_props(primary, ctx->pset);
1144 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001145 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001146 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001147
Daniele Castagna6adafc52018-07-02 23:43:01 -04001148 CHECK_RESULT(drmModeCreatePropertyBlob64(
1149 ctx->fd, red_shift_ctm, sizeof(red_shift_ctm), &primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001150 set_plane_props(primary, ctx->pset);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001151 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001152 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001153
1154 CHECK_RESULT(disable_plane(ctx, primary));
1155 }
1156
Shirish S5f3e6d42018-02-16 11:15:22 +05301157 return ret;
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001158}
1159
Daniele Castagnad34afd72018-03-30 14:48:53 -04001160static int test_video_underlay(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1161{
1162 int ret = 0;
1163 int i = 0;
1164 struct atomictest_plane *underlay = 0;
1165 struct atomictest_plane *primary = 0;
1166
1167 for (; i < crtc->num_primary + crtc->num_overlay; ++i) {
1168 if (crtc->planes[i].type.value != DRM_PLANE_TYPE_CURSOR) {
1169 if (!underlay) {
1170 underlay = &crtc->planes[i];
1171 } else {
1172 primary = &crtc->planes[i];
1173 break;
1174 }
1175 }
1176 }
1177 if (!underlay || !primary)
1178 return 0;
1179
Daniele Castagnadd271042018-04-27 18:10:52 -04001180 if (init_plane_any_format(ctx, underlay, 0, 0, crtc->width >> 2, crtc->height >> 2,
1181 crtc->crtc_id, true)) {
1182 // Fall back to a non YUV format.
1183 CHECK_RESULT(init_plane_any_format(ctx, underlay, 0, 0, crtc->width >> 2,
1184 crtc->height >> 2, crtc->crtc_id, false));
1185 }
1186
Daniele Castagnad34afd72018-03-30 14:48:53 -04001187 CHECK_RESULT(draw_to_plane(ctx->mapper, underlay, DRAW_LINES));
1188
1189 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_ARGB8888, 0, 0, crtc->width, crtc->height,
1190 crtc->crtc_id));
1191 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_TRANSPARENT_HOLE));
1192
1193 while (!move_plane(ctx, crtc, underlay, 50, 20))
Gurchetan Singh08025e82018-04-19 15:51:30 -07001194 ret |= test_and_commit(ctx, 1e6 / 60);
Daniele Castagnad34afd72018-03-30 14:48:53 -04001195
1196 return ret;
1197}
1198
Gurchetan Singh0d714272017-01-26 11:58:49 -08001199static int test_fullscreen_video(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1200{
Shirish S5f3e6d42018-02-16 11:15:22 +05301201 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001202 struct atomictest_plane *primary;
1203 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1204 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Shirish S95c374f2018-01-25 14:25:26 +05301205 if (init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1206 crtc->crtc_id, true))
Gurchetan Singh763dc642017-10-24 13:51:41 -07001207 continue;
Dongseong Hwangd0a45fc2017-04-12 17:10:11 -07001208
Gurchetan Singh763dc642017-10-24 13:51:41 -07001209 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001210 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001211 }
1212
Shirish S5f3e6d42018-02-16 11:15:22 +05301213 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001214}
1215
1216static int test_disable_primary(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1217{
Shirish S5f3e6d42018-02-16 11:15:22 +05301218 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001219 struct atomictest_plane *primary, *overlay;
1220 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1221 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
1222 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
1223 uint32_t x = crtc->width >> (j + 2);
1224 uint32_t y = crtc->height >> (j + 2);
Shirish S95c374f2018-01-25 14:25:26 +05301225 CHECK_RESULT(
1226 init_plane_any_format(ctx, overlay, x, y, x, y, crtc->crtc_id, false));
Gurchetan Singhe07faed2017-10-18 16:32:34 -07001227 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001228 }
1229
Gurchetan Singh0d714272017-01-26 11:58:49 -08001230 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Shirish S95c374f2018-01-25 14:25:26 +05301231 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1232 crtc->crtc_id, false));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -07001233 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001234 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001235
1236 /* Disable primary plane. */
1237 disable_plane(ctx, primary);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001238 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001239 }
1240
Shirish S5f3e6d42018-02-16 11:15:22 +05301241 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001242}
1243
Daniele Castagna08420052018-03-28 23:05:13 -04001244static int test_rgba_primary(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1245{
1246 int ret = 0;
1247 struct atomictest_plane *primary;
1248 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1249 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1250 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_ARGB8888, 0, 0, crtc->width,
1251 crtc->height, crtc->crtc_id));
1252
1253 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1254
Gurchetan Singh08025e82018-04-19 15:51:30 -07001255 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna08420052018-03-28 23:05:13 -04001256 }
1257
1258 return ret;
1259}
1260
Gurchetan Singh0d714272017-01-26 11:58:49 -08001261static int test_overlay_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1262{
1263 struct atomictest_plane *overlay;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001264 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1265 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -07001266 CHECK_RESULT(pageflip_formats(ctx, crtc, overlay));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001267 }
1268
1269 return 0;
1270}
1271
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001272static int test_overlay_downscaling(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1273{
Shirish S5f3e6d42018-02-16 11:15:22 +05301274 int ret = 0;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001275 struct atomictest_plane *overlay;
1276 uint32_t w = BS_ALIGN(crtc->width / 2, 2);
1277 uint32_t h = BS_ALIGN(crtc->height / 2, 2);
1278 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1279 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Shirish S95c374f2018-01-25 14:25:26 +05301280 if (init_plane_any_format(ctx, overlay, 0, 0, w, h, crtc->crtc_id, true))
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001281 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, w, h,
1282 crtc->crtc_id));
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001283 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001284 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001285
1286 while (!scale_plane(ctx, crtc, overlay, -.1f, -.1f) && !test_commit(ctx)) {
1287 CHECK_RESULT(commit(ctx));
1288 usleep(1e6);
1289 }
1290
1291 disable_plane(ctx, overlay);
1292 }
1293
Shirish S5f3e6d42018-02-16 11:15:22 +05301294 return ret;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001295}
1296
1297static int test_overlay_upscaling(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1298{
Shirish S5f3e6d42018-02-16 11:15:22 +05301299 int ret = 0;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001300 struct atomictest_plane *overlay;
1301 uint32_t w = BS_ALIGN(crtc->width / 4, 2);
1302 uint32_t h = BS_ALIGN(crtc->height / 4, 2);
1303 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1304 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Shirish S95c374f2018-01-25 14:25:26 +05301305 if (init_plane_any_format(ctx, overlay, 0, 0, w, h, crtc->crtc_id, true))
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001306 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, w, h,
1307 crtc->crtc_id));
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001308 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001309 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001310
1311 while (!scale_plane(ctx, crtc, overlay, .1f, .1f) && !test_commit(ctx)) {
1312 CHECK_RESULT(commit(ctx));
1313 usleep(1e6);
1314 }
1315
1316 disable_plane(ctx, overlay);
1317 }
1318
Shirish S5f3e6d42018-02-16 11:15:22 +05301319 return ret;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001320}
1321
Gurchetan Singh0d714272017-01-26 11:58:49 -08001322static int test_primary_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1323{
Gurchetan Singh0d714272017-01-26 11:58:49 -08001324 struct atomictest_plane *primary;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001325 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1326 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -07001327 CHECK_RESULT(pageflip_formats(ctx, crtc, primary));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001328 }
1329
1330 return 0;
1331}
1332
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001333static int test_crtc_ctm(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1334{
1335 int ret = 0;
1336 struct atomictest_plane *primary;
1337 if (!crtc->ctm.pid)
1338 return 0;
1339
Daniele Castagna6adafc52018-07-02 23:43:01 -04001340 CHECK_RESULT(drmModeCreatePropertyBlob64(ctx->fd, identity_ctm, sizeof(identity_ctm),
1341 &crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001342 set_crtc_props(crtc, ctx->pset);
1343 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1344 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1345
1346 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1347 crtc->height, crtc->crtc_id));
1348 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1349 ret |= test_and_commit(ctx, 1e6);
1350
1351 primary->crtc_id.value = 0;
1352 CHECK_RESULT(set_plane_props(primary, ctx->pset));
1353 }
1354
Daniele Castagna6adafc52018-07-02 23:43:01 -04001355 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001356
Daniele Castagna6adafc52018-07-02 23:43:01 -04001357 CHECK_RESULT(drmModeCreatePropertyBlob64(ctx->fd, red_shift_ctm, sizeof(red_shift_ctm),
1358 &crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001359 set_crtc_props(crtc, ctx->pset);
1360 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1361 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1362 primary->crtc_id.value = crtc->crtc_id;
1363 CHECK_RESULT(set_plane_props(primary, ctx->pset));
1364
1365 ret |= test_and_commit(ctx, 1e6);
1366
1367 primary->crtc_id.value = 0;
1368 CHECK_RESULT(disable_plane(ctx, primary));
1369 }
1370
Daniele Castagna6adafc52018-07-02 23:43:01 -04001371 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001372
1373 return ret;
1374}
1375
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001376static void gamma_linear(struct drm_color_lut *table, int size)
1377{
1378 for (int i = 0; i < size; i++) {
1379 float v = (float)(i) / (float)(size - 1);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001380 v *= (float)GAMMA_MAX_VALUE;
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001381 table[i].red = (uint16_t)v;
1382 table[i].green = (uint16_t)v;
1383 table[i].blue = (uint16_t)v;
1384 }
1385}
1386
1387static void gamma_step(struct drm_color_lut *table, int size)
1388{
1389 for (int i = 0; i < size; i++) {
1390 float v = (i < size / 2) ? 0 : GAMMA_MAX_VALUE;
1391 table[i].red = (uint16_t)v;
1392 table[i].green = (uint16_t)v;
1393 table[i].blue = (uint16_t)v;
1394 }
1395}
1396
1397static int test_crtc_gamma(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1398{
1399 int ret = 0;
1400 struct atomictest_plane *primary;
1401 if (!crtc->gamma_lut.pid || !crtc->gamma_lut_size.pid)
1402 return 0;
1403
1404 if (crtc->gamma_lut_size.value == 0)
1405 return 0;
1406
1407 struct drm_color_lut *gamma_table =
1408 calloc(crtc->gamma_lut_size.value, sizeof(*gamma_table));
1409
1410 gamma_linear(gamma_table, crtc->gamma_lut_size.value);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001411 CHECK_RESULT(drmModeCreatePropertyBlob64(
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001412 ctx->fd, gamma_table, sizeof(struct drm_color_lut) * crtc->gamma_lut_size.value,
1413 &crtc->gamma_lut.value));
1414 set_crtc_props(crtc, ctx->pset);
1415
1416 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1417 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1418
1419 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1420 crtc->height, crtc->crtc_id));
1421
1422 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
1423 ret |= test_and_commit(ctx, 1e6);
1424
1425 CHECK_RESULT(disable_plane(ctx, primary));
1426 }
1427
1428 CHECK_RESULT(drmModeDestroyPropertyBlob(ctx->fd, crtc->gamma_lut.value));
1429
1430 gamma_step(gamma_table, crtc->gamma_lut_size.value);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001431 CHECK_RESULT(drmModeCreatePropertyBlob64(
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001432 ctx->fd, gamma_table, sizeof(struct drm_color_lut) * crtc->gamma_lut_size.value,
1433 &crtc->gamma_lut.value));
1434 set_crtc_props(crtc, ctx->pset);
1435
1436 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1437 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1438
1439 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1440 crtc->height, crtc->crtc_id));
1441
1442 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
1443 ret |= test_and_commit(ctx, 1e6);
1444
1445 CHECK_RESULT(disable_plane(ctx, primary));
1446 }
1447
1448 CHECK_RESULT(drmModeDestroyPropertyBlob(ctx->fd, crtc->gamma_lut.value));
1449 free(gamma_table);
1450
1451 return ret;
1452}
1453
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001454static const struct atomictest_testcase cases[] = {
Gurchetan Singh0d714272017-01-26 11:58:49 -08001455 { "disable_primary", test_disable_primary },
Daniele Castagna08420052018-03-28 23:05:13 -04001456 { "rgba_primary", test_rgba_primary },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001457 { "fullscreen_video", test_fullscreen_video },
1458 { "multiple_planes", test_multiple_planes },
1459 { "overlay_pageflip", test_overlay_pageflip },
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001460 { "overlay_downscaling", test_overlay_downscaling },
1461 { "overlay_upscaling", test_overlay_upscaling },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001462 { "primary_pageflip", test_primary_pageflip },
1463 { "video_overlay", test_video_overlay },
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001464 { "orientation", test_orientation },
Daniele Castagnad34afd72018-03-30 14:48:53 -04001465 { "video_underlay", test_video_underlay },
Daniele Castagna0827c312018-07-05 18:54:35 -04001466 { "in_fence", test_in_fence },
Daniele Castagna6adafc52018-07-02 23:43:01 -04001467 { "out_fence", test_out_fence },
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001468 /* CTM stands for Color Transform Matrix. */
1469 { "plane_ctm", test_plane_ctm },
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001470 { "crtc_ctm", test_crtc_ctm },
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001471 { "crtc_gamma", test_crtc_gamma },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001472};
1473
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001474static int run_testcase(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
1475 test_function func)
1476{
1477 int cursor = drmModeAtomicGetCursor(ctx->pset);
1478 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
1479
1480 int ret = func(ctx, crtc);
1481
1482 for (uint32_t i = 0; i < num_planes; i++)
1483 disable_plane(ctx, &crtc->planes[i]);
1484
Azhar Shaikh013037e2017-08-08 13:47:02 -07001485 drmModeAtomicSetCursor(ctx->pset, cursor);
1486
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001487 CHECK_RESULT(commit(ctx));
1488 usleep(1e6 / 60);
1489
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001490 return ret;
1491}
1492
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001493static int run_atomictest(const char *name, uint32_t crtc_mask)
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001494{
1495 int ret = 0;
1496 uint32_t num_run = 0;
1497 int fd = bs_drm_open_main_display();
1498 CHECK_RESULT(fd);
1499
1500 gbm = gbm_create_device(fd);
1501 if (!gbm) {
1502 bs_debug_error("failed to create gbm device");
1503 ret = -1;
1504 goto destroy_fd;
1505 }
1506
1507 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1508 if (ret) {
1509 bs_debug_error("failed to enable DRM_CLIENT_CAP_UNIVERSAL_PLANES");
1510 ret = -1;
1511 goto destroy_gbm_device;
1512 }
1513
1514 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
1515 if (ret) {
1516 bs_debug_error("failed to enable DRM_CLIENT_CAP_ATOMIC");
1517 ret = -1;
1518 goto destroy_gbm_device;
1519 }
1520
1521 struct atomictest_context *ctx = query_kms(fd);
1522 if (!ctx) {
1523 bs_debug_error("querying atomictest failed.");
1524 ret = -1;
1525 goto destroy_gbm_device;
1526 }
1527
1528 struct atomictest_crtc *crtc;
1529 for (uint32_t crtc_index = 0; crtc_index < ctx->num_crtcs; crtc_index++) {
1530 crtc = &ctx->crtcs[crtc_index];
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001531 if (!((1 << crtc_index) & crtc_mask))
1532 continue;
1533
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001534 for (uint32_t i = 0; i < BS_ARRAY_LEN(cases); i++) {
1535 if (strcmp(cases[i].name, name) && strcmp("all", name))
1536 continue;
1537
1538 num_run++;
1539 ret = enable_crtc(ctx, crtc);
1540 if (ret)
1541 goto out;
1542
1543 ret = run_testcase(ctx, crtc, cases[i].test_func);
Shirish S5f3e6d42018-02-16 11:15:22 +05301544 if (ret < 0)
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001545 goto out;
Shirish S5f3e6d42018-02-16 11:15:22 +05301546 else if (ret == TEST_COMMIT_FAIL)
1547 bs_debug_warning("%s failed test commit, testcase not run.",
1548 cases[i].name);
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001549
1550 ret = disable_crtc(ctx, crtc);
1551 if (ret)
1552 goto out;
1553 }
1554 }
1555
1556 ret = (num_run == 0);
1557
1558out:
1559 free_context(ctx);
1560destroy_gbm_device:
1561 gbm_device_destroy(gbm);
1562destroy_fd:
1563 close(fd);
1564
1565 return ret;
1566}
1567
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001568static const struct option longopts[] = {
1569 { "crtc", required_argument, NULL, 'c' },
1570 { "test_name", required_argument, NULL, 't' },
Gurchetan Singh3008ce62017-10-17 10:51:36 -07001571 { "help", no_argument, NULL, 'h' },
Gurchetan Singh08025e82018-04-19 15:51:30 -07001572 { "automatic", no_argument, NULL, 'a' },
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001573 { 0, 0, 0, 0 },
1574};
1575
Gurchetan Singh0d714272017-01-26 11:58:49 -08001576static void print_help(const char *argv0)
1577{
Gurchetan Singh08025e82018-04-19 15:51:30 -07001578 printf("usage: %s -t <test_name> -c <crtc_index> -a (if running automatically)\n", argv0);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001579 printf("A valid name test is one the following:\n");
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001580 for (uint32_t i = 0; i < BS_ARRAY_LEN(cases); i++)
1581 printf("%s\n", cases[i].name);
1582 printf("all\n");
Gurchetan Singh0d714272017-01-26 11:58:49 -08001583}
1584
1585int main(int argc, char **argv)
1586{
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001587 int c;
1588 char *name = NULL;
1589 int32_t crtc_idx = -1;
1590 uint32_t crtc_mask = ~0;
Gurchetan Singh08025e82018-04-19 15:51:30 -07001591 while ((c = getopt_long(argc, argv, "c:t:h:a", longopts, NULL)) != -1) {
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001592 switch (c) {
Gurchetan Singh08025e82018-04-19 15:51:30 -07001593 case 'a':
1594 automatic = true;
1595 break;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001596 case 'c':
1597 if (sscanf(optarg, "%d", &crtc_idx) != 1)
1598 goto print;
1599 break;
1600 case 't':
1601 if (name) {
1602 free(name);
1603 name = NULL;
1604 }
1605
1606 name = strdup(optarg);
1607 break;
Gurchetan Singh3008ce62017-10-17 10:51:36 -07001608 case 'h':
1609 goto print;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001610 default:
1611 goto print;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001612 }
1613 }
1614
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001615 if (!name)
1616 goto print;
1617
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001618 if (crtc_idx >= 0)
1619 crtc_mask = 1 << crtc_idx;
1620
1621 int ret = run_atomictest(name, crtc_mask);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001622 if (ret == 0)
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001623 printf("[ PASSED ] atomictest.%s\n", name);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001624 else if (ret < 0)
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001625 printf("[ FAILED ] atomictest.%s\n", name);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001626
1627 free(name);
1628
1629 if (ret > 0)
1630 goto print;
1631
1632 return ret;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001633
1634print:
Gurchetan Singh0d714272017-01-26 11:58:49 -08001635 print_help(argv[0]);
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001636 return 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001637}