blob: aee52dd44fbc4fd6da6c49b1f0f1e3519944e39e [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>
George Burgess IV3b753d22019-05-03 22:59:57 -070019#include <inttypes.h>
Daniele Castagna0827c312018-07-05 18:54:35 -040020#include <pthread.h>
Ilja H. Friedel950ddfd2020-10-11 21:28:05 +000021#include <sync/sync.h>
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -070022
Gurchetan Singh0d714272017-01-26 11:58:49 -080023#include "bs_drm.h"
Haixia Shifc476462015-04-22 16:25:04 -070024
Dongseong Hwang9093afe2017-03-20 19:16:28 -070025#define CHECK(cond) \
26 do { \
27 if (!(cond)) { \
28 bs_debug_error("check %s failed", #cond); \
29 return -1; \
30 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080031 } while (0)
32
Dongseong Hwang9093afe2017-03-20 19:16:28 -070033#define CHECK_RESULT(ret) \
34 do { \
35 if ((ret) < 0) { \
36 bs_debug_error("failed with error: %d", ret); \
37 return -1; \
38 } \
Gurchetan Singh0d714272017-01-26 11:58:49 -080039 } while (0)
40
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +080041#define MAX(a, b) ((a) > (b) ? (a) : (b))
42
Gurchetan Singh0d714272017-01-26 11:58:49 -080043#define CURSOR_SIZE 64
44
Daniele Castagna0827c312018-07-05 18:54:35 -040045// TODO(dcastagna): Remove these declarations once they're exported in a libsync header.
46int sw_sync_timeline_create(void);
47int sw_sync_timeline_inc(int fd, unsigned count);
48int sw_sync_fence_create(int fd, const char *name, unsigned value);
49
Daniele Castagna0fea43f2017-04-06 17:47:11 -040050// TODO(gsingh) This is defined in upstream libdrm -- remove when CROS libdrm is updated.
51#ifndef DRM_ROTATE_0
52#define DRM_ROTATE_0 (1UL << 0)
53#endif
54
55#ifndef DRM_REFLECT_Y
56#define DRM_REFLECT_Y (1UL << 5)
57#endif
58
Shirish S5f3e6d42018-02-16 11:15:22 +053059#define TEST_COMMIT_FAIL 1
60
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -040061#define GAMMA_MAX_VALUE ((1 << 16) - 1)
62
Gurchetan Singh0d714272017-01-26 11:58:49 -080063static const uint32_t yuv_formats[] = {
Shirish S95c374f2018-01-25 14:25:26 +053064 DRM_FORMAT_NV12,
65 DRM_FORMAT_YVU420,
Gurchetan Singh0d714272017-01-26 11:58:49 -080066};
67
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -040068/*
69 * The blob for the CTM propery is a drm_color_ctm.
70 * drm_color_ctm contains a 3x3 u64 matrix. Every element is represented as
71 * sign and U31.32. The sign is the MSB.
72 */
73// clang-format off
74static int64_t identity_ctm[9] = {
75 0x100000000, 0x0, 0x0,
76 0x0, 0x100000000, 0x0,
77 0x0, 0x0, 0x100000000
78};
79static int64_t red_shift_ctm[9] = {
80 0x140000000, 0x0, 0x0,
81 0x0, 0xC0000000, 0x0,
82 0x0, 0x0, 0xC0000000
83};
84// clang-format on
85
Gurchetan Singh08025e82018-04-19 15:51:30 -070086static bool automatic = false;
Gurchetan Singh0d714272017-01-26 11:58:49 -080087static struct gbm_device *gbm = NULL;
88
89static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
90 unsigned int tv_usec, void *user_data)
Haixia Shifc476462015-04-22 16:25:04 -070091{
Gurchetan Singh0d714272017-01-26 11:58:49 -080092 // Nothing to do.
Haixia Shifc476462015-04-22 16:25:04 -070093}
94
Gurchetan Singh0d714272017-01-26 11:58:49 -080095struct atomictest_property {
96 uint32_t pid;
Daniele Castagna6adafc52018-07-02 23:43:01 -040097 uint64_t value;
Gurchetan Singh0d714272017-01-26 11:58:49 -080098};
Haixia Shifc476462015-04-22 16:25:04 -070099
Gurchetan Singh0d714272017-01-26 11:58:49 -0800100struct atomictest_plane {
101 drmModePlane drm_plane;
102 struct gbm_bo *bo;
Haixia Shifc476462015-04-22 16:25:04 -0700103
Gurchetan Singh0d714272017-01-26 11:58:49 -0800104 uint32_t format_idx;
105
106 /* Properties. */
107 struct atomictest_property crtc_id;
108 struct atomictest_property crtc_x;
109 struct atomictest_property crtc_y;
110 struct atomictest_property crtc_w;
111 struct atomictest_property crtc_h;
112 struct atomictest_property fb_id;
113 struct atomictest_property src_x;
114 struct atomictest_property src_y;
115 struct atomictest_property src_w;
116 struct atomictest_property src_h;
117 struct atomictest_property type;
Daniele Castagna0827c312018-07-05 18:54:35 -0400118 struct atomictest_property in_fence_fd;
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400119 struct atomictest_property rotation;
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500120 struct atomictest_property ctm;
Wei Li59ca2932019-02-28 17:10:14 -0800121 struct atomictest_property alpha;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800122};
123
124struct atomictest_connector {
125 uint32_t connector_id;
126 struct atomictest_property crtc_id;
127 struct atomictest_property edid;
128 struct atomictest_property dpms;
129};
130
131struct atomictest_crtc {
132 uint32_t crtc_id;
133 uint32_t width;
134 uint32_t height;
135 uint32_t *primary_idx;
136 uint32_t *cursor_idx;
137 uint32_t *overlay_idx;
138 uint32_t num_primary;
139 uint32_t num_cursor;
140 uint32_t num_overlay;
141
142 struct atomictest_plane *planes;
143 struct atomictest_property mode_id;
144 struct atomictest_property active;
Daniele Castagna6adafc52018-07-02 23:43:01 -0400145 struct atomictest_property out_fence_ptr;
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400146 struct atomictest_property ctm;
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400147 struct atomictest_property gamma_lut;
148 struct atomictest_property gamma_lut_size;
Wei Lic27f5222018-09-18 14:35:23 -0700149 struct atomictest_property background_color;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800150};
151
152struct atomictest_mode {
153 uint32_t height;
154 uint32_t width;
155 uint32_t id;
156};
157
158struct atomictest_context {
159 int fd;
160 uint32_t num_crtcs;
161 uint32_t num_connectors;
162 uint32_t num_modes;
163
164 struct atomictest_connector *connectors;
165 struct atomictest_crtc *crtcs;
166 struct atomictest_mode *modes;
Dominik Behre0f1c182016-01-25 14:38:22 -0800167 drmModeAtomicReqPtr pset;
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +0800168 drmModeResPtr res;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800169 drmEventContext drm_event_ctx;
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700170
171 struct bs_mapper *mapper;
Fritz Koenig9af57ea2020-04-09 22:08:01 -0700172
173 uint64_t modifier;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800174};
Haixia Shifc476462015-04-22 16:25:04 -0700175
Gurchetan Singhd61875a2017-06-02 17:03:19 -0700176typedef int (*test_function)(struct atomictest_context *ctx, struct atomictest_crtc *crtc);
177
178struct atomictest_testcase {
Gurchetan Singh0d714272017-01-26 11:58:49 -0800179 const char *name;
Gurchetan Singhd61875a2017-06-02 17:03:19 -0700180 test_function test_func;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800181};
Haixia Shifc476462015-04-22 16:25:04 -0700182
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700183// clang-format off
184enum draw_format_type {
185 DRAW_NONE = 0,
186 DRAW_STRIPE = 1,
Daniele Castagnad34afd72018-03-30 14:48:53 -0400187 DRAW_TRANSPARENT_HOLE = 2,
188 DRAW_ELLIPSE = 3,
189 DRAW_CURSOR = 4,
190 DRAW_LINES = 5,
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700191};
192// clang-format on
193
Daniele Castagna6adafc52018-07-02 23:43:01 -0400194static int drmModeCreatePropertyBlob64(int fd, const void *data, size_t length, uint64_t *id)
195{
196 uint32_t ctm_blob_id = 0;
197 int ret = drmModeCreatePropertyBlob(fd, data, length, &ctm_blob_id);
198 *id = ctm_blob_id;
199 return ret;
200}
201
202static int drmModeDestroyPropertyBlob64(int fd, uint64_t id)
203{
204 CHECK(id < (1ull << 32));
205 return drmModeDestroyPropertyBlob(fd, (uint32_t)id);
206}
207
Gurchetan Singh0d714272017-01-26 11:58:49 -0800208static int32_t get_format_idx(struct atomictest_plane *plane, uint32_t format)
209{
210 for (int32_t i = 0; i < plane->drm_plane.count_formats; i++)
211 if (plane->drm_plane.formats[i] == format)
212 return i;
213 return -1;
214}
215
216static void copy_drm_plane(drmModePlane *dest, drmModePlane *src)
217{
218 memcpy(dest, src, sizeof(drmModePlane));
219 dest->formats = calloc(src->count_formats, sizeof(uint32_t));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800220 memcpy(dest->formats, src->formats, src->count_formats * sizeof(uint32_t));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800221}
222
223static struct atomictest_plane *get_plane(struct atomictest_crtc *crtc, uint32_t idx, uint64_t type)
224{
225 uint32_t index;
226 switch (type) {
227 case DRM_PLANE_TYPE_OVERLAY:
228 index = crtc->overlay_idx[idx];
229 break;
230 case DRM_PLANE_TYPE_PRIMARY:
231 index = crtc->primary_idx[idx];
232 break;
233 case DRM_PLANE_TYPE_CURSOR:
234 index = crtc->cursor_idx[idx];
235 break;
236 default:
237 bs_debug_error("invalid plane type returned");
238 return NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700239 }
240
Gurchetan Singh0d714272017-01-26 11:58:49 -0800241 return &crtc->planes[index];
242}
Haixia Shifc476462015-04-22 16:25:04 -0700243
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700244static int draw_to_plane(struct bs_mapper *mapper, struct atomictest_plane *plane,
245 enum draw_format_type pattern)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800246{
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700247 struct gbm_bo *bo = plane->bo;
Gurchetan Singha676f1b2017-10-16 18:33:29 -0700248 uint32_t format = gbm_bo_get_format(bo);
249 const struct bs_draw_format *draw_format = bs_get_draw_format(format);
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700250
251 if (draw_format && pattern) {
252 switch (pattern) {
253 case DRAW_STRIPE:
254 CHECK(bs_draw_stripe(mapper, bo, draw_format));
255 break;
Daniele Castagnad34afd72018-03-30 14:48:53 -0400256 case DRAW_TRANSPARENT_HOLE:
257 CHECK(bs_draw_transparent_hole(mapper, bo, draw_format));
258 break;
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700259 case DRAW_ELLIPSE:
260 CHECK(bs_draw_ellipse(mapper, bo, draw_format, 0));
261 break;
262 case DRAW_CURSOR:
263 CHECK(bs_draw_cursor(mapper, bo, draw_format));
264 break;
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700265 case DRAW_LINES:
266 CHECK(bs_draw_lines(mapper, bo, draw_format));
267 break;
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700268 default:
269 bs_debug_error("invalid draw type");
270 return -1;
271 }
272 } else {
273 // DRM_FORMAT_RGB565 --> red, DRM_FORMAT_BGR565 --> blue,
274 // everything else --> something
275 void *map_data;
276 uint16_t value = 0xF800;
Satyajit Sahub7e47dd2018-05-07 12:35:50 +0530277 uint32_t stride;
278 void *addr = bs_mapper_map(mapper, bo, 0, &map_data, &stride);
279 uint32_t num_shorts = stride * gbm_bo_get_height(bo) / sizeof(uint16_t);
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700280 uint16_t *pixel = (uint16_t *)addr;
281
282 CHECK(addr);
283 for (uint32_t i = 0; i < num_shorts; i++)
284 pixel[i] = value;
285
286 bs_mapper_unmap(mapper, bo, map_data);
287 }
288
289 return 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800290}
291
292static int get_prop(int fd, drmModeObjectPropertiesPtr props, const char *name,
293 struct atomictest_property *bs_prop)
294{
295 /* Property ID should always be > 0. */
296 bs_prop->pid = 0;
297 drmModePropertyPtr prop;
298 for (uint32_t i = 0; i < props->count_props; i++) {
299 if (bs_prop->pid)
300 break;
301
302 prop = drmModeGetProperty(fd, props->props[i]);
303 if (prop) {
304 if (!strcmp(prop->name, name)) {
305 bs_prop->pid = prop->prop_id;
306 bs_prop->value = props->prop_values[i];
307 }
308 drmModeFreeProperty(prop);
309 }
310 }
311
312 return (bs_prop->pid == 0) ? -1 : 0;
313}
314
315static int get_connector_props(int fd, struct atomictest_connector *connector,
316 drmModeObjectPropertiesPtr props)
317{
Gurchetan Singh476ce542017-06-02 09:06:01 -0700318 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &connector->crtc_id));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800319 CHECK_RESULT(get_prop(fd, props, "EDID", &connector->edid));
320 CHECK_RESULT(get_prop(fd, props, "DPMS", &connector->dpms));
321 return 0;
322}
323
324static int get_crtc_props(int fd, struct atomictest_crtc *crtc, drmModeObjectPropertiesPtr props)
325{
326 CHECK_RESULT(get_prop(fd, props, "MODE_ID", &crtc->mode_id));
327 CHECK_RESULT(get_prop(fd, props, "ACTIVE", &crtc->active));
Daniele Castagna6adafc52018-07-02 23:43:01 -0400328 CHECK_RESULT(get_prop(fd, props, "OUT_FENCE_PTR", &crtc->out_fence_ptr));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400329
330 /*
331 * The atomic API makes no guarantee a property is present in object. This test
332 * requires the above common properties since a plane is undefined without them.
333 * Other properties (i.e: ctm) are optional.
334 */
335 get_prop(fd, props, "CTM", &crtc->ctm);
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400336 get_prop(fd, props, "GAMMA_LUT", &crtc->gamma_lut);
337 get_prop(fd, props, "GAMMA_LUT_SIZE", &crtc->gamma_lut_size);
Wei Lic27f5222018-09-18 14:35:23 -0700338 get_prop(fd, props, "BACKGROUND_COLOR", &crtc->background_color);
339
Gurchetan Singh0d714272017-01-26 11:58:49 -0800340 return 0;
341}
342
343static int get_plane_props(int fd, struct atomictest_plane *plane, drmModeObjectPropertiesPtr props)
344{
345 CHECK_RESULT(get_prop(fd, props, "CRTC_ID", &plane->crtc_id));
346 CHECK_RESULT(get_prop(fd, props, "FB_ID", &plane->fb_id));
347 CHECK_RESULT(get_prop(fd, props, "CRTC_X", &plane->crtc_x));
348 CHECK_RESULT(get_prop(fd, props, "CRTC_Y", &plane->crtc_y));
349 CHECK_RESULT(get_prop(fd, props, "CRTC_W", &plane->crtc_w));
350 CHECK_RESULT(get_prop(fd, props, "CRTC_H", &plane->crtc_h));
351 CHECK_RESULT(get_prop(fd, props, "SRC_X", &plane->src_x));
352 CHECK_RESULT(get_prop(fd, props, "SRC_Y", &plane->src_y));
353 CHECK_RESULT(get_prop(fd, props, "SRC_W", &plane->src_w));
354 CHECK_RESULT(get_prop(fd, props, "SRC_H", &plane->src_h));
355 CHECK_RESULT(get_prop(fd, props, "type", &plane->type));
Daniele Castagna0827c312018-07-05 18:54:35 -0400356 CHECK_RESULT(get_prop(fd, props, "IN_FENCE_FD", &plane->in_fence_fd));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400357
358 /*
359 * The atomic API makes no guarantee a property is present in object. This test
360 * requires the above common properties since a plane is undefined without them.
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500361 * Other properties (i.e: rotation and ctm) are optional.
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400362 */
363 get_prop(fd, props, "rotation", &plane->rotation);
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500364 get_prop(fd, props, "PLANE_CTM", &plane->ctm);
Wei Li59ca2932019-02-28 17:10:14 -0800365 get_prop(fd, props, "alpha", &plane->alpha);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800366 return 0;
367}
368
369int set_connector_props(struct atomictest_connector *conn, drmModeAtomicReqPtr pset)
370{
371 uint32_t id = conn->connector_id;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800372 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, conn->crtc_id.pid, conn->crtc_id.value));
373 return 0;
374}
375
376int set_crtc_props(struct atomictest_crtc *crtc, drmModeAtomicReqPtr pset)
377{
378 uint32_t id = crtc->crtc_id;
379 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->mode_id.pid, crtc->mode_id.value));
380 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->active.pid, crtc->active.value));
Daniele Castagna6adafc52018-07-02 23:43:01 -0400381 if (crtc->out_fence_ptr.value)
382 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->out_fence_ptr.pid,
383 crtc->out_fence_ptr.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400384 if (crtc->ctm.pid)
385 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->ctm.pid, crtc->ctm.value));
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400386 if (crtc->gamma_lut.pid)
387 CHECK_RESULT(
388 drmModeAtomicAddProperty(pset, id, crtc->gamma_lut.pid, crtc->gamma_lut.value));
Wei Lic27f5222018-09-18 14:35:23 -0700389 if (crtc->background_color.pid) {
390 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, crtc->background_color.pid,
391 crtc->background_color.value));
392 }
393
Gurchetan Singh0d714272017-01-26 11:58:49 -0800394 return 0;
395}
396
397int set_plane_props(struct atomictest_plane *plane, drmModeAtomicReqPtr pset)
398{
399 uint32_t id = plane->drm_plane.plane_id;
400 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_id.pid, plane->crtc_id.value));
401 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->fb_id.pid, plane->fb_id.value));
402 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_x.pid, plane->crtc_x.value));
403 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_y.pid, plane->crtc_y.value));
404 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_w.pid, plane->crtc_w.value));
405 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->crtc_h.pid, plane->crtc_h.value));
406 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_x.pid, plane->src_x.value));
407 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_y.pid, plane->src_y.value));
408 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_w.pid, plane->src_w.value));
409 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->src_h.pid, plane->src_h.value));
Daniele Castagna0827c312018-07-05 18:54:35 -0400410 CHECK_RESULT(
411 drmModeAtomicAddProperty(pset, id, plane->in_fence_fd.pid, plane->in_fence_fd.value));
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400412 if (plane->rotation.pid)
413 CHECK_RESULT(
414 drmModeAtomicAddProperty(pset, id, plane->rotation.pid, plane->rotation.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500415 if (plane->ctm.pid)
416 CHECK_RESULT(drmModeAtomicAddProperty(pset, id, plane->ctm.pid, plane->ctm.value));
Wei Li59ca2932019-02-28 17:10:14 -0800417 if (plane->alpha.pid) {
418 CHECK_RESULT(
419 drmModeAtomicAddProperty(pset, id, plane->alpha.pid, plane->alpha.value));
420 }
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400421
Gurchetan Singh0d714272017-01-26 11:58:49 -0800422 return 0;
423}
424
425static int remove_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
426{
427 if (plane->bo && plane->fb_id.value) {
428 CHECK_RESULT(drmModeRmFB(ctx->fd, plane->fb_id.value));
429 gbm_bo_destroy(plane->bo);
430 plane->bo = NULL;
431 plane->fb_id.value = 0;
432 }
433
434 return 0;
435}
436
437static int add_plane_fb(struct atomictest_context *ctx, struct atomictest_plane *plane)
438{
439 if (plane->format_idx < plane->drm_plane.count_formats) {
440 CHECK_RESULT(remove_plane_fb(ctx, plane));
441 uint32_t flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
442 : GBM_BO_USE_SCANOUT;
Gurchetan Singh71ba4e82021-02-18 14:49:04 -0800443 flags |= GBM_BO_USE_LINEAR;
Fritz Koenig9af57ea2020-04-09 22:08:01 -0700444 if (ctx->modifier != DRM_FORMAT_MOD_INVALID) {
445 plane->bo = gbm_bo_create_with_modifiers(
446 gbm, plane->crtc_w.value, plane->crtc_h.value,
447 plane->drm_plane.formats[plane->format_idx], &(ctx->modifier), 1);
448 } else {
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -0800449 plane->bo =
450 gbm_bo_create(gbm, plane->crtc_w.value, plane->crtc_h.value,
451 plane->drm_plane.formats[plane->format_idx], flags);
Fritz Koenig9af57ea2020-04-09 22:08:01 -0700452 }
Gurchetan Singh0d714272017-01-26 11:58:49 -0800453
454 CHECK(plane->bo);
455 plane->fb_id.value = bs_drm_fb_create_gbm(plane->bo);
456 CHECK(plane->fb_id.value);
457 CHECK_RESULT(set_plane_props(plane, ctx->pset));
458 }
459
460 return 0;
461}
462
463static int init_plane(struct atomictest_context *ctx, struct atomictest_plane *plane,
464 uint32_t format, uint32_t x, uint32_t y, uint32_t w, uint32_t h,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700465 uint32_t crtc_id)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800466{
467 int32_t idx = get_format_idx(plane, format);
468 if (idx < 0)
469 return -EINVAL;
470
471 plane->format_idx = idx;
472 plane->crtc_x.value = x;
473 plane->crtc_y.value = y;
474 plane->crtc_w.value = w;
475 plane->crtc_h.value = h;
476 plane->src_w.value = plane->crtc_w.value << 16;
477 plane->src_h.value = plane->crtc_h.value << 16;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800478 plane->crtc_id.value = crtc_id;
479
480 CHECK_RESULT(add_plane_fb(ctx, plane));
481 return 0;
482}
483
Shirish S95c374f2018-01-25 14:25:26 +0530484static int init_plane_any_format(struct atomictest_context *ctx, struct atomictest_plane *plane,
485 uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t crtc_id,
486 bool yuv)
Gurchetan Singh763dc642017-10-24 13:51:41 -0700487{
Shirish S95c374f2018-01-25 14:25:26 +0530488 if (yuv) {
489 uint32_t i;
490 for (i = 0; i < BS_ARRAY_LEN(yuv_formats); i++)
491 if (!init_plane(ctx, plane, yuv_formats[i], x, y, w, h, crtc_id))
492 return 0;
493 } else {
494 // XRGB888 works well with our draw code, so try that first.
495 if (!init_plane(ctx, plane, DRM_FORMAT_XRGB8888, x, y, w, h, crtc_id))
Gurchetan Singh763dc642017-10-24 13:51:41 -0700496 return 0;
497
Shirish S95c374f2018-01-25 14:25:26 +0530498 for (uint32_t format_idx = 0; format_idx < plane->drm_plane.count_formats;
499 format_idx++) {
Gurchetan Singh71ba4e82021-02-18 14:49:04 -0800500 if (!gbm_device_is_format_supported(gbm,
501 plane->drm_plane.formats[format_idx],
502 GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR))
Shirish S95c374f2018-01-25 14:25:26 +0530503 continue;
504
505 if (!init_plane(ctx, plane, plane->drm_plane.formats[format_idx], x, y, w,
506 h, crtc_id))
507 return 0;
508 }
509 }
510
Gurchetan Singh763dc642017-10-24 13:51:41 -0700511 return -EINVAL;
512}
513
Gurchetan Singh0d714272017-01-26 11:58:49 -0800514static int disable_plane(struct atomictest_context *ctx, struct atomictest_plane *plane)
515{
516 plane->format_idx = 0;
517 plane->crtc_x.value = 0;
518 plane->crtc_y.value = 0;
519 plane->crtc_w.value = 0;
520 plane->crtc_h.value = 0;
521 plane->src_w.value = 0;
522 plane->src_h.value = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800523 plane->crtc_id.value = 0;
Drew Davenportc7f04e42018-09-11 14:21:10 -0600524 plane->in_fence_fd.value = -1;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800525
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400526 if (plane->rotation.pid)
527 plane->rotation.value = DRM_ROTATE_0;
Daniele Castagna4d527ab2018-01-17 14:07:50 -0500528 if (plane->ctm.pid)
529 plane->ctm.value = 0;
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400530
Gurchetan Singh0d714272017-01-26 11:58:49 -0800531 CHECK_RESULT(remove_plane_fb(ctx, plane));
532 CHECK_RESULT(set_plane_props(plane, ctx->pset));
533 return 0;
534}
535
536static int move_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
537 struct atomictest_plane *plane, uint32_t dx, uint32_t dy)
538{
539 if (plane->crtc_x.value < (crtc->width - plane->crtc_w.value) &&
540 plane->crtc_y.value < (crtc->height - plane->crtc_h.value)) {
541 plane->crtc_x.value += dx;
542 plane->crtc_y.value += dy;
543 CHECK_RESULT(set_plane_props(plane, ctx->pset));
544 return 0;
545 }
546
547 return -1;
548}
549
Gurchetan Singhd78c5872017-10-20 18:53:37 -0700550static int scale_plane(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
551 struct atomictest_plane *plane, float dw, float dh)
552{
553 int32_t plane_w = (int32_t)plane->crtc_w.value + dw * plane->crtc_w.value;
554 int32_t plane_h = (int32_t)plane->crtc_h.value + dh * plane->crtc_h.value;
555 if (plane_w > 0 && plane_h > 0 && (plane->crtc_x.value + plane_w < crtc->width) &&
556 (plane->crtc_h.value + plane_h < crtc->height)) {
557 plane->crtc_w.value = BS_ALIGN((uint32_t)plane_w, 2);
558 plane->crtc_h.value = BS_ALIGN((uint32_t)plane_h, 2);
559 CHECK_RESULT(set_plane_props(plane, ctx->pset));
560 return 0;
561 }
562
563 return -1;
564}
565
Ilja H. Friedel950ddfd2020-10-11 21:28:05 +0000566static void log(struct atomictest_context *ctx)
Gurchetan Singhf873d8f2017-10-24 16:51:22 -0700567{
568 printf("Committing the following configuration: \n");
569 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
570 struct atomictest_plane *plane;
571 struct atomictest_crtc *crtc = &ctx->crtcs[i];
572 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
573 if (!crtc->active.value)
574 continue;
575
576 printf("----- [CRTC: %u] -----\n", crtc->crtc_id);
577 for (uint32_t j = 0; j < num_planes; j++) {
578 plane = &crtc->planes[j];
579 if (plane->crtc_id.value == crtc->crtc_id && plane->fb_id.value) {
580 uint32_t format = gbm_bo_get_format(plane->bo);
581 char *fourcc = (char *)&format;
582 printf("\t{Plane ID: %u, ", plane->drm_plane.plane_id);
583 printf("Plane format: %c%c%c%c, ", fourcc[0], fourcc[1], fourcc[2],
584 fourcc[3]);
585 printf("Plane type: ");
586 switch (plane->type.value) {
587 case DRM_PLANE_TYPE_OVERLAY:
588 printf("overlay, ");
589 break;
590 case DRM_PLANE_TYPE_PRIMARY:
591 printf("primary, ");
592 break;
593 case DRM_PLANE_TYPE_CURSOR:
594 printf("cursor, ");
595 break;
596 }
597
George Burgess IV3b753d22019-05-03 22:59:57 -0700598 printf("CRTC_X: %" PRIu64 ", CRTC_Y: %" PRIu64 ", CRTC_W: %" PRIu64
599 ", CRTC_H: %" PRIu64 "}\n",
Gurchetan Singhf873d8f2017-10-24 16:51:22 -0700600 plane->crtc_x.value, plane->crtc_y.value,
601 plane->crtc_w.value, plane->crtc_h.value);
602 }
603 }
604 }
605}
606
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400607static int test_commit(struct atomictest_context *ctx)
608{
Daniele Castagnabe01c0c2018-03-28 23:19:32 -0400609 return drmModeAtomicCommit(ctx->fd, ctx->pset,
610 DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_TEST_ONLY, NULL);
Daniele Castagna0fea43f2017-04-06 17:47:11 -0400611}
612
Gurchetan Singh0d714272017-01-26 11:58:49 -0800613static int commit(struct atomictest_context *ctx)
614{
615 int ret;
616 fd_set fds;
617 FD_ZERO(&fds);
618 FD_SET(ctx->fd, &fds);
619
Ilja H. Friedel950ddfd2020-10-11 21:28:05 +0000620 log(ctx);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800621 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
622 DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
623 CHECK_RESULT(ret);
624 do {
625 ret = select(ctx->fd + 1, &fds, NULL, NULL, NULL);
626 } while (ret == -1 && errno == EINTR);
627
628 CHECK_RESULT(ret);
629 if (FD_ISSET(ctx->fd, &fds))
630 drmHandleEvent(ctx->fd, &ctx->drm_event_ctx);
631
632 return 0;
633}
634
Gurchetan Singh08025e82018-04-19 15:51:30 -0700635static int test_and_commit(struct atomictest_context *ctx, uint32_t sleep_micro_secs)
Shirish S5f3e6d42018-02-16 11:15:22 +0530636{
Gurchetan Singh08025e82018-04-19 15:51:30 -0700637 sleep_micro_secs = automatic ? 0 : sleep_micro_secs;
Shirish S5f3e6d42018-02-16 11:15:22 +0530638 if (!test_commit(ctx)) {
639 CHECK_RESULT(commit(ctx));
Gurchetan Singh08025e82018-04-19 15:51:30 -0700640 usleep(sleep_micro_secs);
Shirish S5f3e6d42018-02-16 11:15:22 +0530641 } else {
642 return TEST_COMMIT_FAIL;
643 }
644
645 return 0;
646}
647
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700648static int pageflip_formats(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
649 struct atomictest_plane *plane)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800650{
Shirish S5f3e6d42018-02-16 11:15:22 +0530651 int ret = 0;
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700652 uint32_t flags;
653 for (uint32_t i = 0; i < plane->drm_plane.count_formats; i++) {
654 flags = (plane->type.value == DRM_PLANE_TYPE_CURSOR) ? GBM_BO_USE_CURSOR
655 : GBM_BO_USE_SCANOUT;
Gurchetan Singh71ba4e82021-02-18 14:49:04 -0800656
657 flags |= GBM_BO_USE_LINEAR;
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700658 if (!gbm_device_is_format_supported(gbm, plane->drm_plane.formats[i], flags))
Shirish Scd098332017-09-26 16:31:07 +0530659 continue;
660
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700661 CHECK_RESULT(init_plane(ctx, plane, plane->drm_plane.formats[i], 0, 0, crtc->width,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700662 crtc->height, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700663 CHECK_RESULT(draw_to_plane(ctx->mapper, plane, DRAW_ELLIPSE));
Gurchetan Singh08025e82018-04-19 15:51:30 -0700664 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -0700665
666 // disable, but don't commit, since we can't have an active CRTC without any planes.
667 CHECK_RESULT(disable_plane(ctx, plane));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800668 }
669
Shirish S5f3e6d42018-02-16 11:15:22 +0530670 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800671}
672
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700673static uint32_t get_connection(struct atomictest_crtc *crtc, uint32_t crtc_index)
674{
675 uint32_t connector_id = 0;
676 uint32_t crtc_mask = 1u << crtc_index;
677 struct bs_drm_pipe pipe = { 0 };
678 struct bs_drm_pipe_plumber *plumber = bs_drm_pipe_plumber_new();
679 bs_drm_pipe_plumber_crtc_mask(plumber, crtc_mask);
680 if (bs_drm_pipe_plumber_make(plumber, &pipe))
681 connector_id = pipe.connector_id;
682
683 bs_drm_pipe_plumber_destroy(&plumber);
684 return connector_id;
685}
686
687static int enable_crtc(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800688{
689 drmModeAtomicSetCursor(ctx->pset, 0);
690
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700691 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
692 ctx->connectors[i].crtc_id.value = 0;
693 set_connector_props(&ctx->connectors[i], ctx->pset);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800694 }
695
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700696 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
697 if (&ctx->crtcs[i] == crtc) {
698 uint32_t connector_id = get_connection(crtc, i);
699 CHECK(connector_id);
700 for (uint32_t j = 0; j < ctx->num_connectors; j++) {
701 if (connector_id == ctx->connectors[j].connector_id) {
702 ctx->connectors[j].crtc_id.value = crtc->crtc_id;
703 set_connector_props(&ctx->connectors[j], ctx->pset);
704 break;
705 }
706 }
707
708 break;
709 }
Gurchetan Singh0d714272017-01-26 11:58:49 -0800710 }
711
712 int ret = -EINVAL;
713 int cursor = drmModeAtomicGetCursor(ctx->pset);
714
715 for (uint32_t i = 0; i < ctx->num_modes; i++) {
716 struct atomictest_mode *mode = &ctx->modes[i];
717 drmModeAtomicSetCursor(ctx->pset, cursor);
718
719 crtc->mode_id.value = mode->id;
720 crtc->active.value = 1;
721 crtc->width = mode->width;
722 crtc->height = mode->height;
723
724 set_crtc_props(crtc, ctx->pset);
725 ret = drmModeAtomicCommit(ctx->fd, ctx->pset,
726 DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET,
727 NULL);
728 if (!ret)
729 return 0;
730 }
731
732 bs_debug_error("[CRTC:%d]: failed to find mode", crtc->crtc_id);
733 return ret;
734}
735
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700736static int disable_crtc(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
737{
738 for (uint32_t i = 0; i < ctx->num_connectors; i++) {
739 ctx->connectors[i].crtc_id.value = 0;
740 set_connector_props(&ctx->connectors[i], ctx->pset);
741 }
742
743 crtc->mode_id.value = 0;
744 crtc->active.value = 0;
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400745 if (crtc->ctm.pid)
746 crtc->ctm.value = 0;
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -0400747 if (crtc->gamma_lut.pid)
748 crtc->gamma_lut.value = 0;
Wei Lic27f5222018-09-18 14:35:23 -0700749 if (crtc->background_color.pid)
750 crtc->background_color.value = 0;
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -0400751
Gurchetan Singhb60e7652017-06-02 12:54:34 -0700752 set_crtc_props(crtc, ctx->pset);
753 int ret = drmModeAtomicCommit(ctx->fd, ctx->pset, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
754 CHECK_RESULT(ret);
755 return ret;
756}
757
Gurchetan Singhbcfaf082017-06-02 12:58:10 -0700758static struct atomictest_context *new_context(uint32_t num_connectors, uint32_t num_crtcs,
759 uint32_t num_planes)
760{
761 struct atomictest_context *ctx = calloc(1, sizeof(*ctx));
762
763 ctx->mapper = bs_mapper_gem_new();
764 if (ctx->mapper == NULL) {
765 bs_debug_error("failed to create mapper object");
766 free(ctx);
767 return NULL;
768 }
769
770 ctx->connectors = calloc(num_connectors, sizeof(*ctx->connectors));
771 ctx->crtcs = calloc(num_crtcs, sizeof(*ctx->crtcs));
772 for (uint32_t i = 0; i < num_crtcs; i++) {
773 ctx->crtcs[i].planes = calloc(num_planes, sizeof(*ctx->crtcs[i].planes));
774 ctx->crtcs[i].overlay_idx = calloc(num_planes, sizeof(uint32_t));
775 ctx->crtcs[i].primary_idx = calloc(num_planes, sizeof(uint32_t));
776 ctx->crtcs[i].cursor_idx = calloc(num_planes, sizeof(uint32_t));
777 }
778
779 ctx->num_connectors = num_connectors;
780 ctx->num_crtcs = num_crtcs;
781 ctx->num_modes = 0;
782 ctx->modes = NULL;
783 ctx->pset = drmModeAtomicAlloc();
784 ctx->drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
785 ctx->drm_event_ctx.page_flip_handler = page_flip_handler;
786
787 return ctx;
788}
789
Gurchetan Singh0d714272017-01-26 11:58:49 -0800790static void free_context(struct atomictest_context *ctx)
791{
792 for (uint32_t i = 0; i < ctx->num_crtcs; i++) {
793 uint32_t num_planes = ctx->crtcs[i].num_primary + ctx->crtcs[i].num_cursor +
794 ctx->crtcs[i].num_overlay;
795
796 for (uint32_t j = 0; j < num_planes; j++) {
797 remove_plane_fb(ctx, &ctx->crtcs[i].planes[j]);
798 free(ctx->crtcs[i].planes[j].drm_plane.formats);
Haixia Shifc476462015-04-22 16:25:04 -0700799 }
800
Gurchetan Singh0d714272017-01-26 11:58:49 -0800801 free(ctx->crtcs[i].planes);
802 free(ctx->crtcs[i].overlay_idx);
803 free(ctx->crtcs[i].cursor_idx);
804 free(ctx->crtcs[i].primary_idx);
805 }
806
807 drmModeAtomicFree(ctx->pset);
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +0800808 drmModeFreeResources(ctx->res);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800809 free(ctx->modes);
810 free(ctx->crtcs);
811 free(ctx->connectors);
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700812 bs_mapper_destroy(ctx->mapper);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800813 free(ctx);
814}
815
Gurchetan Singh83df8832017-06-02 14:06:48 -0700816static struct atomictest_context *query_kms(int fd)
Gurchetan Singh0d714272017-01-26 11:58:49 -0800817{
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +0800818 drmModeResPtr res = drmModeGetResources(fd);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800819 if (res == NULL) {
820 bs_debug_error("failed to get drm resources");
821 return false;
822 }
823
824 drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
825 if (plane_res == NULL) {
826 bs_debug_error("failed to get plane resources");
827 drmModeFreeResources(res);
828 return NULL;
829 }
830
831 struct atomictest_context *ctx =
832 new_context(res->count_connectors, res->count_crtcs, plane_res->count_planes);
833 if (ctx == NULL) {
834 bs_debug_error("failed to allocate atomic context");
835 drmModeFreePlaneResources(plane_res);
836 drmModeFreeResources(res);
837 return NULL;
838 }
839
Gurchetan Singh0d714272017-01-26 11:58:49 -0800840 ctx->fd = fd;
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +0800841 ctx->res = res;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800842 drmModeObjectPropertiesPtr props = NULL;
843
844 for (uint32_t conn_index = 0; conn_index < res->count_connectors; conn_index++) {
845 uint32_t conn_id = res->connectors[conn_index];
846 ctx->connectors[conn_index].connector_id = conn_id;
847 props = drmModeObjectGetProperties(fd, conn_id, DRM_MODE_OBJECT_CONNECTOR);
848 get_connector_props(fd, &ctx->connectors[conn_index], props);
849
850 drmModeConnector *connector = drmModeGetConnector(fd, conn_id);
851 for (uint32_t mode_index = 0; mode_index < connector->count_modes; mode_index++) {
Dongseong Hwang326d08f2017-06-13 14:42:31 -0700852 ctx->modes =
853 realloc(ctx->modes, (ctx->num_modes + 1) * sizeof(*ctx->modes));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800854 drmModeCreatePropertyBlob(fd, &connector->modes[mode_index],
855 sizeof(drmModeModeInfo),
856 &ctx->modes[ctx->num_modes].id);
857 ctx->modes[ctx->num_modes].width = connector->modes[mode_index].hdisplay;
858 ctx->modes[ctx->num_modes].height = connector->modes[mode_index].vdisplay;
859 ctx->num_modes++;
Haixia Shifc476462015-04-22 16:25:04 -0700860 }
861
Gurchetan Singh0d714272017-01-26 11:58:49 -0800862 drmModeFreeConnector(connector);
863 drmModeFreeObjectProperties(props);
864 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700865 }
866
Gurchetan Singh0d714272017-01-26 11:58:49 -0800867 uint32_t crtc_index;
868 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
869 ctx->crtcs[crtc_index].crtc_id = res->crtcs[crtc_index];
870 props =
871 drmModeObjectGetProperties(fd, res->crtcs[crtc_index], DRM_MODE_OBJECT_CRTC);
872 get_crtc_props(fd, &ctx->crtcs[crtc_index], props);
873
874 drmModeFreeObjectProperties(props);
875 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700876 }
877
Gurchetan Singh0d714272017-01-26 11:58:49 -0800878 uint32_t overlay_idx, primary_idx, cursor_idx, idx;
Haixia Shifc476462015-04-22 16:25:04 -0700879
Gurchetan Singh0d714272017-01-26 11:58:49 -0800880 for (uint32_t plane_index = 0; plane_index < plane_res->count_planes; plane_index++) {
Kristian H. Kristensenabc63d42017-10-31 09:41:00 -0700881 drmModePlane *plane = drmModeGetPlane(fd, plane_res->planes[plane_index]);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800882 if (plane == NULL) {
883 bs_debug_error("failed to get plane id %u", plane_res->planes[plane_index]);
884 continue;
885 }
Haixia Shifc476462015-04-22 16:25:04 -0700886
Gurchetan Singh0d714272017-01-26 11:58:49 -0800887 uint32_t crtc_mask = 0;
888
889 drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(
890 fd, plane_res->planes[plane_index], DRM_MODE_OBJECT_PLANE);
891
892 for (crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
893 crtc_mask = (1 << crtc_index);
894 if (plane->possible_crtcs & crtc_mask) {
895 struct atomictest_crtc *crtc = &ctx->crtcs[crtc_index];
896 cursor_idx = crtc->num_cursor;
897 primary_idx = crtc->num_primary;
898 overlay_idx = crtc->num_overlay;
899 idx = cursor_idx + primary_idx + overlay_idx;
900 copy_drm_plane(&crtc->planes[idx].drm_plane, plane);
901 get_plane_props(fd, &crtc->planes[idx], props);
902 switch (crtc->planes[idx].type.value) {
903 case DRM_PLANE_TYPE_OVERLAY:
904 crtc->overlay_idx[overlay_idx] = idx;
905 crtc->num_overlay++;
906 break;
907 case DRM_PLANE_TYPE_PRIMARY:
908 crtc->primary_idx[primary_idx] = idx;
909 crtc->num_primary++;
910 break;
911 case DRM_PLANE_TYPE_CURSOR:
912 crtc->cursor_idx[cursor_idx] = idx;
913 crtc->num_cursor++;
914 break;
915 default:
916 bs_debug_error("invalid plane type returned");
917 return NULL;
918 }
Gurchetan Singh04e756b2017-12-08 14:25:00 -0800919
920 /*
921 * The DRM UAPI states that cursor and overlay framebuffers may be
922 * present after a CRTC disable, so zero this out so we can get a
923 * clean slate.
924 */
925 crtc->planes[idx].fb_id.value = 0;
Haixia Shifc476462015-04-22 16:25:04 -0700926 }
927 }
928
Gurchetan Singh0d714272017-01-26 11:58:49 -0800929 drmModeFreePlane(plane);
930 drmModeFreeObjectProperties(props);
931 props = NULL;
Haixia Shifc476462015-04-22 16:25:04 -0700932 }
933
Gurchetan Singh0d714272017-01-26 11:58:49 -0800934 drmModeFreePlaneResources(plane_res);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800935 return ctx;
936}
Haixia Shifc476462015-04-22 16:25:04 -0700937
Gurchetan Singh0d714272017-01-26 11:58:49 -0800938static int test_multiple_planes(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
939{
Shirish S5f3e6d42018-02-16 11:15:22 +0530940 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800941 struct atomictest_plane *primary, *overlay, *cursor;
942 for (uint32_t i = 0; i < crtc->num_primary; i++) {
Gurchetan Singh763dc642017-10-24 13:51:41 -0700943 bool video = true;
Gurchetan Singh0d714272017-01-26 11:58:49 -0800944 uint32_t x, y;
945 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
946 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
947 x = crtc->width >> (j + 2);
948 y = crtc->height >> (j + 2);
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +0800949 x = MAX(x, ctx->res->min_width);
950 y = MAX(y, ctx->res->min_height);
Dongseong Hwang326d08f2017-06-13 14:42:31 -0700951 // drmModeAddFB2 requires the height and width are even for sub-sampled YUV
952 // formats.
953 x = BS_ALIGN(x, 2);
954 y = BS_ALIGN(y, 2);
Shirish S95c374f2018-01-25 14:25:26 +0530955 if (video &&
956 !init_plane_any_format(ctx, overlay, x, y, x, y, crtc->crtc_id, true)) {
Gurchetan Singh763dc642017-10-24 13:51:41 -0700957 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
958 video = false;
959 } else {
Shirish S95c374f2018-01-25 14:25:26 +0530960 CHECK_RESULT(init_plane_any_format(ctx, overlay, x, y, x, y,
961 crtc->crtc_id, false));
Gurchetan Singhe07faed2017-10-18 16:32:34 -0700962 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800963 }
964 }
965
966 for (uint32_t j = 0; j < crtc->num_cursor; j++) {
967 x = crtc->width >> (j + 2);
968 y = crtc->height >> (j + 2);
969 cursor = get_plane(crtc, j, DRM_PLANE_TYPE_CURSOR);
Dongseong Hwangd0a45fc2017-04-12 17:10:11 -0700970 CHECK_RESULT(init_plane(ctx, cursor, DRM_FORMAT_ARGB8888, x, y, CURSOR_SIZE,
Gurchetan Singh24d6a122017-10-23 16:56:16 -0700971 CURSOR_SIZE, crtc->crtc_id));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700972 CHECK_RESULT(draw_to_plane(ctx->mapper, cursor, DRAW_CURSOR));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800973 }
974
975 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Shirish S95c374f2018-01-25 14:25:26 +0530976 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
977 crtc->crtc_id, false));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -0700978 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
Gurchetan Singh0d714272017-01-26 11:58:49 -0800979
980 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
981 int done = 0;
982 struct atomictest_plane *plane;
983 while (!done) {
984 done = 1;
985 for (uint32_t j = 0; j < num_planes; j++) {
986 plane = &crtc->planes[j];
987 if (plane->type.value != DRM_PLANE_TYPE_PRIMARY)
Stéphane Marchesinf6fe9b72018-04-02 14:57:55 -0700988 done &= move_plane(ctx, crtc, plane, 40, 40);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800989 }
990
Gurchetan Singh08025e82018-04-19 15:51:30 -0700991 ret |= test_and_commit(ctx, 1e6 / 60);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800992 }
993
Gurchetan Singh08025e82018-04-19 15:51:30 -0700994 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -0800995
996 /* Disable primary plane and verify overlays show up. */
997 CHECK_RESULT(disable_plane(ctx, primary));
Gurchetan Singh08025e82018-04-19 15:51:30 -0700998 ret |= test_and_commit(ctx, 1e6);
Shirish Sd9e1caa2020-03-05 15:24:17 +0530999
1000 for (uint32_t j = 0; j < crtc->num_cursor; j++) {
1001 cursor = get_plane(crtc, j, DRM_PLANE_TYPE_CURSOR);
1002 CHECK_RESULT(disable_plane(ctx, cursor));
1003 }
Gurchetan Singh0d714272017-01-26 11:58:49 -08001004 }
1005
Shirish S5f3e6d42018-02-16 11:15:22 +05301006 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001007}
1008
1009static int test_video_overlay(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1010{
Shirish S5f3e6d42018-02-16 11:15:22 +05301011 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001012 struct atomictest_plane *overlay;
1013 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1014 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Shirish S95c374f2018-01-25 14:25:26 +05301015 if (init_plane_any_format(ctx, overlay, 0, 0, 800, 800, crtc->crtc_id, true))
Gurchetan Singh763dc642017-10-24 13:51:41 -07001016 continue;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001017
Gurchetan Singh763dc642017-10-24 13:51:41 -07001018 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
Stéphane Marchesinf6fe9b72018-04-02 14:57:55 -07001019 while (!move_plane(ctx, crtc, overlay, 40, 40))
Gurchetan Singh08025e82018-04-19 15:51:30 -07001020 ret |= test_and_commit(ctx, 1e6 / 60);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001021 }
1022
Shirish S5f3e6d42018-02-16 11:15:22 +05301023 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001024}
1025
Daniele Castagnaff333692019-09-10 14:08:13 -04001026static int prop_contains_value(drmModePropertyPtr prop, uint64_t value)
1027{
1028 for (uint32_t i = 0; i < prop->count_values; i++) {
1029 if (prop->values[i] == value)
1030 return 1;
1031 }
1032 return 0;
1033}
1034
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001035static int test_orientation(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1036{
Shirish S5f3e6d42018-02-16 11:15:22 +05301037 int ret = 0;
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001038 struct atomictest_plane *primary, *overlay;
Daniele Castagnaff333692019-09-10 14:08:13 -04001039 drmModePropertyPtr rotation_prop;
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001040 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1041 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
1042 if (!overlay->rotation.pid)
1043 continue;
1044
Daniele Castagnaff333692019-09-10 14:08:13 -04001045 rotation_prop = drmModeGetProperty(ctx->fd, overlay->rotation.pid);
1046 CHECK(rotation_prop);
Shirish S95c374f2018-01-25 14:25:26 +05301047 CHECK_RESULT(init_plane_any_format(ctx, overlay, 0, 0, crtc->width, crtc->height,
1048 crtc->crtc_id, false));
Daniele Castagnaff333692019-09-10 14:08:13 -04001049 CHECK(prop_contains_value(rotation_prop, DRM_ROTATE_0));
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001050 overlay->rotation.value = DRM_ROTATE_0;
1051 set_plane_props(overlay, ctx->pset);
1052 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001053 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001054
Daniele Castagnaff333692019-09-10 14:08:13 -04001055 if (prop_contains_value(rotation_prop, DRM_REFLECT_Y)) {
1056 overlay->rotation.value = DRM_REFLECT_Y;
1057 set_plane_props(overlay, ctx->pset);
1058 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001059
Daniele Castagnaff333692019-09-10 14:08:13 -04001060 CHECK_RESULT(disable_plane(ctx, overlay));
1061 }
1062 drmModeFreeProperty(rotation_prop);
1063 rotation_prop = NULL;
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001064 }
1065
1066 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1067 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1068 if (!primary->rotation.pid)
1069 continue;
1070
Daniele Castagnaff333692019-09-10 14:08:13 -04001071 rotation_prop = drmModeGetProperty(ctx->fd, primary->rotation.pid);
1072 CHECK(rotation_prop);
Shirish S95c374f2018-01-25 14:25:26 +05301073 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1074 crtc->crtc_id, false));
Daniele Castagnaff333692019-09-10 14:08:13 -04001075 CHECK(prop_contains_value(rotation_prop, DRM_ROTATE_0));
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001076 primary->rotation.value = DRM_ROTATE_0;
1077 set_plane_props(primary, ctx->pset);
1078 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001079 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001080
Daniele Castagnaff333692019-09-10 14:08:13 -04001081 if (prop_contains_value(rotation_prop, DRM_REFLECT_Y)) {
1082 primary->rotation.value = DRM_REFLECT_Y;
1083 set_plane_props(primary, ctx->pset);
1084 ret |= test_and_commit(ctx, 1e6);
1085 }
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001086
1087 CHECK_RESULT(disable_plane(ctx, primary));
Daniele Castagnaff333692019-09-10 14:08:13 -04001088 drmModeFreeProperty(rotation_prop);
1089 rotation_prop = NULL;
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001090 }
1091
Shirish S5f3e6d42018-02-16 11:15:22 +05301092 return ret;
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001093}
1094
Wei Li59ca2932019-02-28 17:10:14 -08001095static int test_plane_alpha(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1096{
1097 int ret = 0;
1098 struct atomictest_plane *primary, *overlay;
1099 int offset_x = crtc->width / 5, offset_y = crtc->height / 5;
1100
1101 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1102 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1103 if (!primary->alpha.pid)
1104 return 0;
1105
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -08001106 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1107 crtc->crtc_id, false));
Wei Li59ca2932019-02-28 17:10:14 -08001108 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
1109 primary->alpha.value = 0xffff;
1110 set_plane_props(primary, ctx->pset);
1111 ret |= test_and_commit(ctx, 1e6 / 2);
1112
1113 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
1114 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
1115 if (!overlay->alpha.pid)
1116 return 0;
1117
1118 CHECK_RESULT(init_plane_any_format(
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -08001119 ctx, overlay, offset_x, offset_y, crtc->width - offset_x * 2,
1120 crtc->height - offset_y * 2, crtc->crtc_id, false));
Wei Li59ca2932019-02-28 17:10:14 -08001121 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_STRIPE));
1122 ret |= test_and_commit(ctx, 1e6 / 2);
1123
1124 for (uint32_t a = 0xffff; a > 0; a = a >> 1) {
1125 overlay->alpha.value = a;
1126 set_plane_props(overlay, ctx->pset);
1127 ret |= test_and_commit(ctx, 1e6 / 5);
1128 }
1129 overlay->alpha.value = 0xffff;
1130 set_plane_props(overlay, ctx->pset);
1131 }
1132
1133 for (uint32_t a = 0xffff; a > 0; a = a >> 1) {
1134 primary->alpha.value = a;
1135 set_plane_props(primary, ctx->pset);
1136 ret |= test_and_commit(ctx, 1e6 / 5);
1137 }
1138 }
1139
1140 return ret;
1141}
1142
Daniele Castagna0827c312018-07-05 18:54:35 -04001143static void *inc_timeline(void *user_data)
1144{
Ilja H. Friedel950ddfd2020-10-11 21:28:05 +00001145 int timeline_fd = *(int *)user_data;
Daniele Castagna0827c312018-07-05 18:54:35 -04001146 uint32_t sleep_micro_secs = automatic ? 1e3 : 1e5;
1147 usleep(sleep_micro_secs);
1148 sw_sync_timeline_inc(timeline_fd, 1);
1149 return NULL;
1150}
1151
1152static int test_in_fence(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1153{
1154 int ret = 0;
1155 pthread_t inc_timeline_thread;
1156 struct atomictest_plane *primary = NULL;
1157
1158 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1159 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1160 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1161 crtc->crtc_id, false));
1162 break;
1163 }
1164
Ilja H. Friedel950ddfd2020-10-11 21:28:05 +00001165 int timeline = sw_sync_timeline_create();
Daniele Castagna0827c312018-07-05 18:54:35 -04001166 CHECK(fcntl(timeline, F_GETFD, 0) >= 0);
1167 int in_fence = sw_sync_fence_create(timeline, "test_in_fence", 1);
1168 CHECK(fcntl(in_fence, F_GETFD, 0) >= 0);
1169
1170 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1171
1172 primary->in_fence_fd.value = in_fence;
1173 set_plane_props(primary, ctx->pset);
1174 set_crtc_props(crtc, ctx->pset);
1175
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -08001176 CHECK(!pthread_create(&inc_timeline_thread, NULL, inc_timeline, &timeline));
Daniele Castagna0827c312018-07-05 18:54:35 -04001177
1178 ret |= test_and_commit(ctx, 1e6);
1179 CHECK(!pthread_join(inc_timeline_thread, NULL));
1180
1181 ret |= test_and_commit(ctx, 1e6);
1182 close(in_fence);
1183 close(timeline);
1184
1185 return ret;
1186}
1187
Daniele Castagna6adafc52018-07-02 23:43:01 -04001188static int test_out_fence(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1189{
1190 int ret = 0;
1191 struct atomictest_plane *primary = NULL;
1192
1193 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1194 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1195 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1196 crtc->crtc_id, false));
1197 break;
1198 }
1199
1200 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1201 set_plane_props(primary, ctx->pset);
1202 int out_fence_fd = 0;
1203 crtc->out_fence_ptr.value = (uint64_t)&out_fence_fd;
1204 set_crtc_props(crtc, ctx->pset);
1205 ret |= test_and_commit(ctx, 1e6);
1206 CHECK(out_fence_fd);
Daniele Castagna0827c312018-07-05 18:54:35 -04001207 // |out_fence_fd| will signal when the currently scanned out buffers are replaced.
1208 // In this case we're waiting with a timeout of 0 only to check that |out_fence_fd|
1209 // is a valid fence.
Daniele Castagna6adafc52018-07-02 23:43:01 -04001210 CHECK(!sync_wait(out_fence_fd, 0));
1211 close(out_fence_fd);
1212 return ret;
1213}
1214
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001215static int test_plane_ctm(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1216{
Shirish S5f3e6d42018-02-16 11:15:22 +05301217 int ret = 0;
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001218 struct atomictest_plane *primary, *overlay;
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001219
1220 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1221 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
1222 if (!overlay->ctm.pid)
1223 continue;
1224
1225 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1226 crtc->height, crtc->crtc_id));
1227
Daniele Castagna6adafc52018-07-02 23:43:01 -04001228 CHECK_RESULT(drmModeCreatePropertyBlob64(
1229 ctx->fd, identity_ctm, sizeof(identity_ctm), &overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001230 set_plane_props(overlay, ctx->pset);
1231 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001232 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001233 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001234
Daniele Castagna6adafc52018-07-02 23:43:01 -04001235 CHECK_RESULT(drmModeCreatePropertyBlob64(
1236 ctx->fd, red_shift_ctm, sizeof(red_shift_ctm), &overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001237 set_plane_props(overlay, ctx->pset);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001238 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001239 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, overlay->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001240
1241 CHECK_RESULT(disable_plane(ctx, overlay));
1242 }
1243
1244 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1245 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1246 if (!primary->ctm.pid)
1247 continue;
1248
Shirish S95c374f2018-01-25 14:25:26 +05301249 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1250 crtc->crtc_id, false));
Daniele Castagna6adafc52018-07-02 23:43:01 -04001251 CHECK_RESULT(drmModeCreatePropertyBlob64(
1252 ctx->fd, identity_ctm, sizeof(identity_ctm), &primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001253 set_plane_props(primary, ctx->pset);
1254 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001255 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001256 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001257
Daniele Castagna6adafc52018-07-02 23:43:01 -04001258 CHECK_RESULT(drmModeCreatePropertyBlob64(
1259 ctx->fd, red_shift_ctm, sizeof(red_shift_ctm), &primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001260 set_plane_props(primary, ctx->pset);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001261 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001262 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, primary->ctm.value));
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001263
1264 CHECK_RESULT(disable_plane(ctx, primary));
1265 }
1266
Shirish S5f3e6d42018-02-16 11:15:22 +05301267 return ret;
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001268}
1269
Daniele Castagnad34afd72018-03-30 14:48:53 -04001270static int test_video_underlay(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1271{
1272 int ret = 0;
1273 int i = 0;
1274 struct atomictest_plane *underlay = 0;
1275 struct atomictest_plane *primary = 0;
1276
1277 for (; i < crtc->num_primary + crtc->num_overlay; ++i) {
1278 if (crtc->planes[i].type.value != DRM_PLANE_TYPE_CURSOR) {
1279 if (!underlay) {
1280 underlay = &crtc->planes[i];
1281 } else {
1282 primary = &crtc->planes[i];
1283 break;
1284 }
1285 }
1286 }
1287 if (!underlay || !primary)
1288 return 0;
1289
Daniele Castagnadd271042018-04-27 18:10:52 -04001290 if (init_plane_any_format(ctx, underlay, 0, 0, crtc->width >> 2, crtc->height >> 2,
1291 crtc->crtc_id, true)) {
1292 // Fall back to a non YUV format.
1293 CHECK_RESULT(init_plane_any_format(ctx, underlay, 0, 0, crtc->width >> 2,
1294 crtc->height >> 2, crtc->crtc_id, false));
1295 }
1296
Daniele Castagnad34afd72018-03-30 14:48:53 -04001297 CHECK_RESULT(draw_to_plane(ctx->mapper, underlay, DRAW_LINES));
1298
1299 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_ARGB8888, 0, 0, crtc->width, crtc->height,
1300 crtc->crtc_id));
1301 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_TRANSPARENT_HOLE));
1302
1303 while (!move_plane(ctx, crtc, underlay, 50, 20))
Gurchetan Singh08025e82018-04-19 15:51:30 -07001304 ret |= test_and_commit(ctx, 1e6 / 60);
Daniele Castagnad34afd72018-03-30 14:48:53 -04001305
1306 return ret;
1307}
1308
Gurchetan Singh0d714272017-01-26 11:58:49 -08001309static int test_fullscreen_video(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1310{
Shirish S5f3e6d42018-02-16 11:15:22 +05301311 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001312 struct atomictest_plane *primary;
1313 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1314 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Shirish S95c374f2018-01-25 14:25:26 +05301315 if (init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1316 crtc->crtc_id, true))
Gurchetan Singh763dc642017-10-24 13:51:41 -07001317 continue;
Dongseong Hwangd0a45fc2017-04-12 17:10:11 -07001318
Gurchetan Singh763dc642017-10-24 13:51:41 -07001319 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001320 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001321 }
1322
Shirish S5f3e6d42018-02-16 11:15:22 +05301323 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001324}
1325
1326static int test_disable_primary(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1327{
Shirish S5f3e6d42018-02-16 11:15:22 +05301328 int ret = 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001329 struct atomictest_plane *primary, *overlay;
1330 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1331 for (uint32_t j = 0; j < crtc->num_overlay; j++) {
1332 overlay = get_plane(crtc, j, DRM_PLANE_TYPE_OVERLAY);
1333 uint32_t x = crtc->width >> (j + 2);
1334 uint32_t y = crtc->height >> (j + 2);
Hsin-Yi, Wang0d589d42019-01-09 12:44:02 +08001335 x = MAX(x, ctx->res->min_width);
1336 y = MAX(y, ctx->res->min_height);
Shirish S95c374f2018-01-25 14:25:26 +05301337 CHECK_RESULT(
1338 init_plane_any_format(ctx, overlay, x, y, x, y, crtc->crtc_id, false));
Gurchetan Singhe07faed2017-10-18 16:32:34 -07001339 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001340 }
1341
Gurchetan Singh0d714272017-01-26 11:58:49 -08001342 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Shirish S95c374f2018-01-25 14:25:26 +05301343 CHECK_RESULT(init_plane_any_format(ctx, primary, 0, 0, crtc->width, crtc->height,
1344 crtc->crtc_id, false));
Gurchetan Singhc3b543e2017-10-17 09:28:47 -07001345 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_ELLIPSE));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001346 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001347
1348 /* Disable primary plane. */
1349 disable_plane(ctx, primary);
Gurchetan Singh08025e82018-04-19 15:51:30 -07001350 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singh0d714272017-01-26 11:58:49 -08001351 }
1352
Shirish S5f3e6d42018-02-16 11:15:22 +05301353 return ret;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001354}
1355
Daniele Castagna08420052018-03-28 23:05:13 -04001356static int test_rgba_primary(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1357{
1358 int ret = 0;
1359 struct atomictest_plane *primary;
1360 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1361 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Mark Yacoub317bfd82019-07-30 15:12:19 -04001362 bool has_argb = false;
1363 for (uint32_t i = 0; i < primary->drm_plane.count_formats; ++i) {
1364 if (primary->drm_plane.formats[i] == DRM_FORMAT_ARGB8888) {
1365 has_argb = true;
1366 break;
1367 }
1368 }
1369 if (!has_argb)
1370 return 0;
1371
Daniele Castagna08420052018-03-28 23:05:13 -04001372 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_ARGB8888, 0, 0, crtc->width,
1373 crtc->height, crtc->crtc_id));
1374
1375 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1376
Gurchetan Singh08025e82018-04-19 15:51:30 -07001377 ret |= test_and_commit(ctx, 1e6);
Daniele Castagna08420052018-03-28 23:05:13 -04001378 }
1379
1380 return ret;
1381}
1382
Gurchetan Singh0d714272017-01-26 11:58:49 -08001383static int test_overlay_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1384{
1385 struct atomictest_plane *overlay;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001386 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1387 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -07001388 CHECK_RESULT(pageflip_formats(ctx, crtc, overlay));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001389 }
1390
1391 return 0;
1392}
1393
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001394static int test_overlay_downscaling(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1395{
Shirish S5f3e6d42018-02-16 11:15:22 +05301396 int ret = 0;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001397 struct atomictest_plane *overlay;
1398 uint32_t w = BS_ALIGN(crtc->width / 2, 2);
1399 uint32_t h = BS_ALIGN(crtc->height / 2, 2);
1400 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1401 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Shirish S95c374f2018-01-25 14:25:26 +05301402 if (init_plane_any_format(ctx, overlay, 0, 0, w, h, crtc->crtc_id, true))
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001403 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, w, h,
1404 crtc->crtc_id));
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001405 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001406 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001407
1408 while (!scale_plane(ctx, crtc, overlay, -.1f, -.1f) && !test_commit(ctx)) {
1409 CHECK_RESULT(commit(ctx));
1410 usleep(1e6);
1411 }
1412
1413 disable_plane(ctx, overlay);
1414 }
1415
Shirish S5f3e6d42018-02-16 11:15:22 +05301416 return ret;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001417}
1418
1419static int test_overlay_upscaling(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1420{
Shirish S5f3e6d42018-02-16 11:15:22 +05301421 int ret = 0;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001422 struct atomictest_plane *overlay;
1423 uint32_t w = BS_ALIGN(crtc->width / 4, 2);
1424 uint32_t h = BS_ALIGN(crtc->height / 4, 2);
1425 for (uint32_t i = 0; i < crtc->num_overlay; i++) {
1426 overlay = get_plane(crtc, i, DRM_PLANE_TYPE_OVERLAY);
Shirish S95c374f2018-01-25 14:25:26 +05301427 if (init_plane_any_format(ctx, overlay, 0, 0, w, h, crtc->crtc_id, true))
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001428 CHECK_RESULT(init_plane(ctx, overlay, DRM_FORMAT_XRGB8888, 0, 0, w, h,
1429 crtc->crtc_id));
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001430 CHECK_RESULT(draw_to_plane(ctx->mapper, overlay, DRAW_LINES));
Gurchetan Singh08025e82018-04-19 15:51:30 -07001431 ret |= test_and_commit(ctx, 1e6);
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001432
1433 while (!scale_plane(ctx, crtc, overlay, .1f, .1f) && !test_commit(ctx)) {
1434 CHECK_RESULT(commit(ctx));
1435 usleep(1e6);
1436 }
1437
1438 disable_plane(ctx, overlay);
1439 }
1440
Shirish S5f3e6d42018-02-16 11:15:22 +05301441 return ret;
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001442}
1443
Gurchetan Singh0d714272017-01-26 11:58:49 -08001444static int test_primary_pageflip(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1445{
Gurchetan Singh0d714272017-01-26 11:58:49 -08001446 struct atomictest_plane *primary;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001447 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1448 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
Gurchetan Singh1f4e15e2017-10-16 14:04:19 -07001449 CHECK_RESULT(pageflip_formats(ctx, crtc, primary));
Gurchetan Singh0d714272017-01-26 11:58:49 -08001450 }
1451
1452 return 0;
1453}
1454
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001455static int test_crtc_ctm(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1456{
1457 int ret = 0;
1458 struct atomictest_plane *primary;
1459 if (!crtc->ctm.pid)
1460 return 0;
1461
Daniele Castagna6adafc52018-07-02 23:43:01 -04001462 CHECK_RESULT(drmModeCreatePropertyBlob64(ctx->fd, identity_ctm, sizeof(identity_ctm),
1463 &crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001464 set_crtc_props(crtc, ctx->pset);
1465 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1466 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1467
1468 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1469 crtc->height, crtc->crtc_id));
1470 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_LINES));
1471 ret |= test_and_commit(ctx, 1e6);
1472
1473 primary->crtc_id.value = 0;
1474 CHECK_RESULT(set_plane_props(primary, ctx->pset));
1475 }
1476
Daniele Castagna6adafc52018-07-02 23:43:01 -04001477 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001478
Daniele Castagna6adafc52018-07-02 23:43:01 -04001479 CHECK_RESULT(drmModeCreatePropertyBlob64(ctx->fd, red_shift_ctm, sizeof(red_shift_ctm),
1480 &crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001481 set_crtc_props(crtc, ctx->pset);
1482 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1483 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1484 primary->crtc_id.value = crtc->crtc_id;
1485 CHECK_RESULT(set_plane_props(primary, ctx->pset));
1486
1487 ret |= test_and_commit(ctx, 1e6);
1488
1489 primary->crtc_id.value = 0;
1490 CHECK_RESULT(disable_plane(ctx, primary));
1491 }
1492
Daniele Castagna6adafc52018-07-02 23:43:01 -04001493 CHECK_RESULT(drmModeDestroyPropertyBlob64(ctx->fd, crtc->ctm.value));
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001494
1495 return ret;
1496}
1497
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001498static void gamma_linear(struct drm_color_lut *table, int size)
1499{
1500 for (int i = 0; i < size; i++) {
1501 float v = (float)(i) / (float)(size - 1);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001502 v *= (float)GAMMA_MAX_VALUE;
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001503 table[i].red = (uint16_t)v;
1504 table[i].green = (uint16_t)v;
1505 table[i].blue = (uint16_t)v;
1506 }
1507}
1508
1509static void gamma_step(struct drm_color_lut *table, int size)
1510{
1511 for (int i = 0; i < size; i++) {
1512 float v = (i < size / 2) ? 0 : GAMMA_MAX_VALUE;
1513 table[i].red = (uint16_t)v;
1514 table[i].green = (uint16_t)v;
1515 table[i].blue = (uint16_t)v;
1516 }
1517}
1518
1519static int test_crtc_gamma(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1520{
1521 int ret = 0;
1522 struct atomictest_plane *primary;
1523 if (!crtc->gamma_lut.pid || !crtc->gamma_lut_size.pid)
1524 return 0;
1525
1526 if (crtc->gamma_lut_size.value == 0)
1527 return 0;
1528
1529 struct drm_color_lut *gamma_table =
1530 calloc(crtc->gamma_lut_size.value, sizeof(*gamma_table));
1531
1532 gamma_linear(gamma_table, crtc->gamma_lut_size.value);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001533 CHECK_RESULT(drmModeCreatePropertyBlob64(
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001534 ctx->fd, gamma_table, sizeof(struct drm_color_lut) * crtc->gamma_lut_size.value,
1535 &crtc->gamma_lut.value));
1536 set_crtc_props(crtc, ctx->pset);
1537
1538 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1539 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1540
1541 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1542 crtc->height, crtc->crtc_id));
1543
1544 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
1545 ret |= test_and_commit(ctx, 1e6);
1546
1547 CHECK_RESULT(disable_plane(ctx, primary));
1548 }
1549
1550 CHECK_RESULT(drmModeDestroyPropertyBlob(ctx->fd, crtc->gamma_lut.value));
1551
1552 gamma_step(gamma_table, crtc->gamma_lut_size.value);
Daniele Castagna6adafc52018-07-02 23:43:01 -04001553 CHECK_RESULT(drmModeCreatePropertyBlob64(
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001554 ctx->fd, gamma_table, sizeof(struct drm_color_lut) * crtc->gamma_lut_size.value,
1555 &crtc->gamma_lut.value));
1556 set_crtc_props(crtc, ctx->pset);
1557
1558 for (uint32_t i = 0; i < crtc->num_primary; i++) {
1559 primary = get_plane(crtc, i, DRM_PLANE_TYPE_PRIMARY);
1560
1561 CHECK_RESULT(init_plane(ctx, primary, DRM_FORMAT_XRGB8888, 0, 0, crtc->width,
1562 crtc->height, crtc->crtc_id));
1563
1564 CHECK_RESULT(draw_to_plane(ctx->mapper, primary, DRAW_STRIPE));
1565 ret |= test_and_commit(ctx, 1e6);
1566
1567 CHECK_RESULT(disable_plane(ctx, primary));
1568 }
1569
1570 CHECK_RESULT(drmModeDestroyPropertyBlob(ctx->fd, crtc->gamma_lut.value));
1571 free(gamma_table);
1572
1573 return ret;
1574}
1575
Wei Lic27f5222018-09-18 14:35:23 -07001576static inline uint64_t pack_rgba_64(uint64_t red, uint64_t green, uint64_t blue, uint64_t alpha)
1577{
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -08001578 return alpha << 48 | blue << 32 | green << 16 | red;
Wei Lic27f5222018-09-18 14:35:23 -07001579}
1580
1581static int test_crtc_background_color(struct atomictest_context *ctx, struct atomictest_crtc *crtc)
1582{
1583 int ret = 0;
1584
1585 if (!crtc->background_color.pid)
1586 return 0;
1587
1588 struct crtc_background_color {
1589 const char *name;
1590 uint64_t rgba_value;
1591 };
1592
1593 const struct crtc_background_color colors[] = {
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -08001594 { "black", pack_rgba_64(0, 0, 0, 0xffff) },
1595 { "red", pack_rgba_64(0xffff, 0, 0, 0xffff) },
1596 { "green", pack_rgba_64(0, 0xffff, 0, 0xffff) },
1597 { "blue", pack_rgba_64(0, 0, 0xffff, 0xffff) },
Wei Lic27f5222018-09-18 14:35:23 -07001598 };
1599
1600 for (int i = 0; i < BS_ARRAY_LEN(colors); i++) {
1601 crtc->background_color.value = colors[i].rgba_value;
1602 set_crtc_props(crtc, ctx->pset);
1603 ret |= test_and_commit(ctx, 1e6);
1604 }
1605
1606 return ret;
1607}
1608
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001609static const struct atomictest_testcase cases[] = {
Gurchetan Singh0d714272017-01-26 11:58:49 -08001610 { "disable_primary", test_disable_primary },
Daniele Castagna08420052018-03-28 23:05:13 -04001611 { "rgba_primary", test_rgba_primary },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001612 { "fullscreen_video", test_fullscreen_video },
1613 { "multiple_planes", test_multiple_planes },
1614 { "overlay_pageflip", test_overlay_pageflip },
Gurchetan Singhd78c5872017-10-20 18:53:37 -07001615 { "overlay_downscaling", test_overlay_downscaling },
1616 { "overlay_upscaling", test_overlay_upscaling },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001617 { "primary_pageflip", test_primary_pageflip },
1618 { "video_overlay", test_video_overlay },
Daniele Castagna0fea43f2017-04-06 17:47:11 -04001619 { "orientation", test_orientation },
Daniele Castagnad34afd72018-03-30 14:48:53 -04001620 { "video_underlay", test_video_underlay },
Daniele Castagna0827c312018-07-05 18:54:35 -04001621 { "in_fence", test_in_fence },
Daniele Castagna6adafc52018-07-02 23:43:01 -04001622 { "out_fence", test_out_fence },
Daniele Castagna4d527ab2018-01-17 14:07:50 -05001623 /* CTM stands for Color Transform Matrix. */
1624 { "plane_ctm", test_plane_ctm },
Wei Li59ca2932019-02-28 17:10:14 -08001625 { "plane_alpha", test_plane_alpha },
Daniel Nicoarac9a2a3d2018-04-24 14:20:32 -04001626 { "crtc_ctm", test_crtc_ctm },
Daniel Nicoaraa2cb1672018-04-26 12:09:24 -04001627 { "crtc_gamma", test_crtc_gamma },
Wei Lic27f5222018-09-18 14:35:23 -07001628 { "crtc_background_color", test_crtc_background_color },
Gurchetan Singh0d714272017-01-26 11:58:49 -08001629};
1630
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001631static int run_testcase(struct atomictest_context *ctx, struct atomictest_crtc *crtc,
1632 test_function func)
1633{
1634 int cursor = drmModeAtomicGetCursor(ctx->pset);
1635 uint32_t num_planes = crtc->num_primary + crtc->num_cursor + crtc->num_overlay;
1636
1637 int ret = func(ctx, crtc);
1638
1639 for (uint32_t i = 0; i < num_planes; i++)
1640 disable_plane(ctx, &crtc->planes[i]);
1641
Azhar Shaikh013037e2017-08-08 13:47:02 -07001642 drmModeAtomicSetCursor(ctx->pset, cursor);
1643
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001644 CHECK_RESULT(commit(ctx));
1645 usleep(1e6 / 60);
1646
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001647 return ret;
1648}
1649
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001650static int run_atomictest(const char *name, uint32_t crtc_mask, uint64_t modifier)
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001651{
1652 int ret = 0;
1653 uint32_t num_run = 0;
1654 int fd = bs_drm_open_main_display();
1655 CHECK_RESULT(fd);
1656
1657 gbm = gbm_create_device(fd);
1658 if (!gbm) {
1659 bs_debug_error("failed to create gbm device");
1660 ret = -1;
1661 goto destroy_fd;
1662 }
1663
1664 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1665 if (ret) {
1666 bs_debug_error("failed to enable DRM_CLIENT_CAP_UNIVERSAL_PLANES");
1667 ret = -1;
1668 goto destroy_gbm_device;
1669 }
1670
1671 ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
1672 if (ret) {
Stéphane Marchesin86ff9062019-11-08 17:59:35 -08001673 bs_debug_warning("failed to enable DRM_CLIENT_CAP_ATOMIC");
1674 /* We want to allow per-board disabling of atomic */
1675 ret = 0;
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001676 goto destroy_gbm_device;
1677 }
1678
1679 struct atomictest_context *ctx = query_kms(fd);
1680 if (!ctx) {
1681 bs_debug_error("querying atomictest failed.");
1682 ret = -1;
1683 goto destroy_gbm_device;
1684 }
1685
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001686 ctx->modifier = modifier;
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001687 struct atomictest_crtc *crtc;
1688 for (uint32_t crtc_index = 0; crtc_index < ctx->num_crtcs; crtc_index++) {
1689 crtc = &ctx->crtcs[crtc_index];
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001690 if (!((1 << crtc_index) & crtc_mask))
1691 continue;
1692
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001693 for (uint32_t i = 0; i < BS_ARRAY_LEN(cases); i++) {
1694 if (strcmp(cases[i].name, name) && strcmp("all", name))
1695 continue;
1696
1697 num_run++;
1698 ret = enable_crtc(ctx, crtc);
1699 if (ret)
Stéphane Marchesin2c7f0712020-11-16 20:26:29 -08001700 continue;
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001701
1702 ret = run_testcase(ctx, crtc, cases[i].test_func);
Shirish S5f3e6d42018-02-16 11:15:22 +05301703 if (ret < 0)
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001704 goto out;
Shirish S5f3e6d42018-02-16 11:15:22 +05301705 else if (ret == TEST_COMMIT_FAIL)
1706 bs_debug_warning("%s failed test commit, testcase not run.",
1707 cases[i].name);
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001708
1709 ret = disable_crtc(ctx, crtc);
1710 if (ret)
1711 goto out;
1712 }
1713 }
1714
1715 ret = (num_run == 0);
1716
1717out:
1718 free_context(ctx);
1719destroy_gbm_device:
1720 gbm_device_destroy(gbm);
1721destroy_fd:
1722 close(fd);
1723
1724 return ret;
1725}
1726
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001727static const struct option longopts[] = {
Gurchetan Singhf2bf0ed2021-02-18 16:09:40 -08001728 { "crtc", required_argument, NULL, 'c' }, { "test_name", required_argument, NULL, 't' },
1729 { "help", no_argument, NULL, 'h' }, { "automatic", no_argument, NULL, 'a' },
1730 { "modifier", required_argument, NULL, 'm' }, { 0, 0, 0, 0 },
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001731};
1732
Gurchetan Singh0d714272017-01-26 11:58:49 -08001733static void print_help(const char *argv0)
1734{
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001735 printf("usage: %s [OPTIONS]\n", argv0);
1736 printf(" -t, --test_name <test_name> name of test to run.\n");
1737 printf(" -c, --crtc <crtc_index> index of crtc to run against.\n");
1738 printf(" -a, --automatic don't sleep between tests.\n");
1739 printf(" -m, --modifier <modifier> pass modifiers.\n");
1740 printf(" <test_name> is one the following:\n");
Gurchetan Singhd61875a2017-06-02 17:03:19 -07001741 for (uint32_t i = 0; i < BS_ARRAY_LEN(cases); i++)
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001742 printf(" %s\n", cases[i].name);
1743 printf(" all\n");
1744
1745 int fd = bs_drm_open_main_display();
1746 if (fd) {
1747 printf(" <modifier> must be one of ");
1748 bs_print_supported_modifiers(fd);
1749 close(fd);
1750 } else {
1751 printf("unable to show supported modifiers\n");
1752 }
Gurchetan Singh0d714272017-01-26 11:58:49 -08001753}
1754
1755int main(int argc, char **argv)
1756{
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001757 int c;
1758 char *name = NULL;
1759 int32_t crtc_idx = -1;
1760 uint32_t crtc_mask = ~0;
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001761 uint64_t modifier = DRM_FORMAT_MOD_INVALID;
1762 while ((c = getopt_long(argc, argv, "c:t:h:am:", longopts, NULL)) != -1) {
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001763 switch (c) {
Gurchetan Singh08025e82018-04-19 15:51:30 -07001764 case 'a':
1765 automatic = true;
1766 break;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001767 case 'c':
1768 if (sscanf(optarg, "%d", &crtc_idx) != 1)
1769 goto print;
1770 break;
1771 case 't':
1772 if (name) {
1773 free(name);
1774 name = NULL;
1775 }
1776
1777 name = strdup(optarg);
1778 break;
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001779 case 'm':
1780 modifier = bs_string_to_modifier(optarg);
1781 if (modifier == -1) {
1782 bs_debug_error("unsupported modifier: %s", optarg);
1783 goto print;
1784 }
1785 break;
Gurchetan Singh3008ce62017-10-17 10:51:36 -07001786 case 'h':
1787 goto print;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001788 default:
1789 goto print;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001790 }
1791 }
1792
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001793 if (!name)
1794 goto print;
1795
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001796 if (crtc_idx >= 0)
1797 crtc_mask = 1 << crtc_idx;
1798
Fritz Koenig9af57ea2020-04-09 22:08:01 -07001799 int ret = run_atomictest(name, crtc_mask, modifier);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001800 if (ret == 0)
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001801 printf("[ PASSED ] atomictest.%s\n", name);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001802 else if (ret < 0)
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001803 printf("[ FAILED ] atomictest.%s\n", name);
Gurchetan Singhafcea5b2017-06-09 15:28:20 -07001804
1805 free(name);
1806
1807 if (ret > 0)
1808 goto print;
1809
1810 return ret;
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001811
1812print:
Gurchetan Singh0d714272017-01-26 11:58:49 -08001813 print_help(argv[0]);
Gurchetan Singhe6afe0a2017-06-02 18:02:03 -07001814 return 0;
Gurchetan Singh0d714272017-01-26 11:58:49 -08001815}