blob: b14050a84f81a948c5f688d957666d225470d901 [file] [log] [blame]
Zach Reiznerd847a7e2016-04-28 16:48:32 -07001/*
2 * Copyright 2015 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 */
6
7#include <ctype.h>
Zach Reiznerfa0547a2016-05-11 18:43:40 -07008#include <getopt.h>
9#include <math.h>
Zach Reiznerd847a7e2016-04-28 16:48:32 -070010
11#include "bs_drm.h"
12
Zach Reiznerfa0547a2016-05-11 18:43:40 -070013#define MAX_TEST_PLANES 4
14
Miguel Casasd96d9812021-04-07 18:45:10 -040015static int64_t ns_since(struct timespec* since) {
16 struct timespec now;
17 clock_gettime(CLOCK_MONOTONIC, &now);
Zach Reiznerfa0547a2016-05-11 18:43:40 -070018
Miguel Casasd96d9812021-04-07 18:45:10 -040019 return (int64_t)(now.tv_sec - since->tv_sec) * 1000000000 +
20 (int64_t)now.tv_nsec - (int64_t)since->tv_nsec;
Zach Reiznerfa0547a2016-05-11 18:43:40 -070021}
Zach Reiznerd847a7e2016-04-28 16:48:32 -070022
Miguel Casasd96d9812021-04-07 18:45:10 -040023static drmModeModeInfoPtr find_best_mode(int mode_count,
24 drmModeModeInfoPtr modes) {
25 if (mode_count <= 0 || modes == NULL)
26 return NULL;
Zach Reiznerd847a7e2016-04-28 16:48:32 -070027
Miguel Casasd96d9812021-04-07 18:45:10 -040028 for (int m = 0; m < mode_count; m++)
29 if (modes[m].type & DRM_MODE_TYPE_PREFERRED)
30 return &modes[m];
Zach Reiznerd847a7e2016-04-28 16:48:32 -070031
Miguel Casasd96d9812021-04-07 18:45:10 -040032 return &modes[0];
Zach Reiznerd847a7e2016-04-28 16:48:32 -070033}
34
Miguel Casasd96d9812021-04-07 18:45:10 -040035static bool is_format_supported(uint32_t format_count,
36 uint32_t* formats,
37 uint32_t format) {
38 for (uint32_t i = 0; i < format_count; i++)
39 if (formats[i] == format)
40 return true;
41 return false;
Zach Reiznerd847a7e2016-04-28 16:48:32 -070042}
43
Miguel Casasd96d9812021-04-07 18:45:10 -040044static bool find_overlay_planes(int fd,
45 uint32_t crtc_id,
46 size_t plane_count,
47 uint32_t* formats,
48 uint32_t* plane_ids) {
49 drmModeRes* res = drmModeGetResources(fd);
50 if (res == NULL) {
51 bs_debug_error("failed to get drm resources");
52 return false;
53 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -070054
Miguel Casasd96d9812021-04-07 18:45:10 -040055 uint32_t crtc_mask = 0;
56 for (int crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
57 if (res->crtcs[crtc_index] == crtc_id) {
58 crtc_mask = (1 << crtc_index);
59 break;
60 }
61 }
62 if (crtc_mask == 0) {
63 bs_debug_error("invalid crtc id %u", crtc_id);
64 drmModeFreeResources(res);
65 return false;
66 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -070067
Miguel Casasd96d9812021-04-07 18:45:10 -040068 drmModePlaneRes* plane_res = drmModeGetPlaneResources(fd);
69 if (plane_res == NULL) {
70 bs_debug_error("failed to get plane resources");
71 drmModeFreeResources(res);
72 return false;
73 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -070074
Miguel Casasd96d9812021-04-07 18:45:10 -040075 for (size_t out_index = 0; out_index < plane_count; out_index++)
76 plane_ids[out_index] = 0;
Zach Reiznerfa0547a2016-05-11 18:43:40 -070077
Miguel Casasd96d9812021-04-07 18:45:10 -040078 size_t remaining_out = plane_count;
79 for (uint32_t plane_index = 0;
80 remaining_out > 0 && plane_index < plane_res->count_planes;
81 plane_index++) {
82 drmModePlane* plane = drmModeGetPlane(fd, plane_res->planes[plane_index]);
83 if (plane == NULL) {
84 bs_debug_error("failed to get plane id %u",
85 plane_res->planes[plane_index]);
86 continue;
87 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -070088
Miguel Casasd96d9812021-04-07 18:45:10 -040089 size_t out_index;
90 for (out_index = 0; out_index < plane_count; out_index++) {
91 if (plane_ids[out_index] == 0 &&
92 is_format_supported(plane->count_formats, plane->formats,
93 formats[out_index]))
94 break;
95 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -070096
Miguel Casasd96d9812021-04-07 18:45:10 -040097 if ((plane->possible_crtcs & crtc_mask) == 0 || out_index == plane_count) {
98 drmModeFreePlane(plane);
99 continue;
100 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700101
Miguel Casasd96d9812021-04-07 18:45:10 -0400102 drmModeObjectPropertiesPtr props =
103 drmModeObjectGetProperties(fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
104 for (uint32_t prop_index = 0; prop_index < props->count_props;
105 ++prop_index) {
106 drmModePropertyPtr prop =
107 drmModeGetProperty(fd, props->props[prop_index]);
108 if (strcmp(prop->name, "type")) {
109 drmModeFreeProperty(prop);
110 continue;
111 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700112
Miguel Casasd96d9812021-04-07 18:45:10 -0400113 uint64_t desired_value = 0;
114 bool has_value = false;
115 for (int enum_index = 0; enum_index < prop->count_enums; enum_index++) {
116 struct drm_mode_property_enum* penum = &prop->enums[enum_index];
117 if (!strcmp(penum->name, "Overlay")) {
118 desired_value = penum->value;
119 has_value = true;
120 break;
121 }
122 }
123 drmModeFreeProperty(prop);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700124
Miguel Casasd96d9812021-04-07 18:45:10 -0400125 if (has_value && desired_value == props->prop_values[prop_index]) {
126 plane_ids[out_index] = plane->plane_id;
127 remaining_out--;
128 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700129
Miguel Casasd96d9812021-04-07 18:45:10 -0400130 break;
131 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700132
Miguel Casasd96d9812021-04-07 18:45:10 -0400133 drmModeFreeObjectProperties(props);
134 drmModeFreePlane(plane);
135 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700136
Miguel Casasd96d9812021-04-07 18:45:10 -0400137 drmModeFreePlaneResources(plane_res);
138 drmModeFreeResources(res);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700139
Miguel Casasd96d9812021-04-07 18:45:10 -0400140 return remaining_out == 0;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700141}
142
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700143struct test_plane {
Miguel Casasd96d9812021-04-07 18:45:10 -0400144 const struct bs_draw_format* format;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700145
Miguel Casasd96d9812021-04-07 18:45:10 -0400146 bool has_bo_size;
147 uint32_t bo_w;
148 uint32_t bo_h;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700149
Miguel Casasd96d9812021-04-07 18:45:10 -0400150 bool has_dst_position;
151 int32_t dst_x;
152 int32_t dst_y;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700153
Miguel Casasd96d9812021-04-07 18:45:10 -0400154 int32_t dst_center_x;
155 int32_t dst_center_y;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700156
Miguel Casasd96d9812021-04-07 18:45:10 -0400157 int32_t dst_vx;
158 int32_t dst_vy;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700159
Miguel Casasd96d9812021-04-07 18:45:10 -0400160 bool has_dst_size;
161 uint32_t dst_w;
162 uint32_t dst_h;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700163
Miguel Casasd96d9812021-04-07 18:45:10 -0400164 uint32_t dst_min_w;
165 uint32_t dst_max_w;
166 uint32_t dst_min_h;
167 uint32_t dst_max_h;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700168
Miguel Casasd96d9812021-04-07 18:45:10 -0400169 bool has_dst_scale;
170 uint32_t dst_downscale_factor;
171 uint32_t dst_upscale_factor;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700172
Miguel Casasd96d9812021-04-07 18:45:10 -0400173 int32_t src_x;
174 int32_t src_y;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700175
Miguel Casasd96d9812021-04-07 18:45:10 -0400176 int32_t src_vx;
177 int32_t src_vy;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700178
Miguel Casasd96d9812021-04-07 18:45:10 -0400179 bool has_src_size;
180 uint32_t src_w;
181 uint32_t src_h;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700182
Miguel Casasd96d9812021-04-07 18:45:10 -0400183 struct gbm_bo* bo;
184 uint32_t fb_id;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700185};
186
Miguel Casasd96d9812021-04-07 18:45:10 -0400187static bool update_test_plane(int step,
188 int32_t max_x,
189 int32_t max_y,
190 struct test_plane* tp) {
191 bool needs_set = (step == 0);
192 if (tp->has_dst_scale) {
193 float scale_factor = (sinf(step / 120.0f) / 2.0f + 0.5f);
194 scale_factor = powf(scale_factor, 4);
195 tp->dst_w = tp->dst_min_w + scale_factor * (tp->dst_max_w - tp->dst_min_w);
196 tp->dst_h = tp->dst_min_h + scale_factor * (tp->dst_max_h - tp->dst_min_h);
197 needs_set = true;
198 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700199
Miguel Casasd96d9812021-04-07 18:45:10 -0400200 if (tp->dst_vx != 0) {
201 tp->dst_center_x += tp->dst_vx;
202 if (tp->dst_center_x > max_x || tp->dst_center_x < 0) {
203 tp->dst_vx = -tp->dst_vx;
204 tp->dst_x += tp->dst_vx * 2;
205 }
206 needs_set = true;
207 }
208 tp->dst_x = tp->dst_center_x - tp->dst_w / 2;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700209
Miguel Casasd96d9812021-04-07 18:45:10 -0400210 if (tp->dst_vy != 0) {
211 tp->dst_center_y += tp->dst_vy;
212 if (tp->dst_center_y > max_y || tp->dst_center_y < 0) {
213 tp->dst_vy = -tp->dst_vy;
214 tp->dst_y += tp->dst_vy * 2;
215 }
216 needs_set = true;
217 }
218 tp->dst_y = tp->dst_center_y - tp->dst_h / 2;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700219
Miguel Casasd96d9812021-04-07 18:45:10 -0400220 if (tp->src_vx != 0) {
221 tp->src_x += tp->src_vx;
222 if (tp->src_x + tp->src_w > gbm_bo_get_width(tp->bo) || tp->src_x < 0) {
223 tp->src_vx = -tp->src_vx;
224 tp->src_x += tp->src_vx * 2;
225 }
226 needs_set = true;
227 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700228
Miguel Casasd96d9812021-04-07 18:45:10 -0400229 if (tp->src_vy != 0) {
230 tp->src_y += tp->src_vy;
231 if (tp->src_y + tp->src_h > gbm_bo_get_height(tp->bo) || tp->src_y < 0) {
232 tp->src_vy = -tp->src_vy;
233 tp->src_y += tp->src_vy * 2;
234 }
235 needs_set = true;
236 }
237 return needs_set;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700238}
239
Miguel Casasd96d9812021-04-07 18:45:10 -0400240static bool parse_size(const char* str, uint32_t* w, uint32_t* h) {
241 if (sscanf(str, "%ux%u", w, h) == 2)
242 return true;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700243
Miguel Casasd96d9812021-04-07 18:45:10 -0400244 printf("unrecognized size format \"%s\"\n", str);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700245
Miguel Casasd96d9812021-04-07 18:45:10 -0400246 return false;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700247}
248
Miguel Casasd96d9812021-04-07 18:45:10 -0400249static bool parse_scale(const char* str, uint32_t* down, uint32_t* up) {
250 if (sscanf(str, "%u/%u", down, up) == 2)
251 return true;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700252
Miguel Casasd96d9812021-04-07 18:45:10 -0400253 printf("unrecognized scale format \"%s\"\n", str);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700254
Miguel Casasd96d9812021-04-07 18:45:10 -0400255 return false;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700256}
257
Miguel Casasd96d9812021-04-07 18:45:10 -0400258static bool parse_rect(const char* str,
259 int32_t* x,
260 int32_t* y,
261 uint32_t* w,
262 uint32_t* h,
263 bool* has_position,
264 bool* has_size) {
265 if (sscanf(str, "%d,%d,%u,%u", x, y, w, h) == 4) {
266 if (has_position)
267 *has_position = true;
268 if (has_size)
269 *has_size = true;
270 return true;
271 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700272
Miguel Casasd96d9812021-04-07 18:45:10 -0400273 if (sscanf(str, "%d,%d", x, y) == 2) {
274 if (has_position)
275 *has_position = true;
276 if (has_size)
277 *has_size = false;
278 return true;
279 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700280
Miguel Casasd96d9812021-04-07 18:45:10 -0400281 if (sscanf(str, "%ux%u", w, h) == 2) {
282 if (has_position)
283 *has_position = false;
284 if (has_size)
285 *has_size = true;
286 return true;
287 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700288
Miguel Casasd96d9812021-04-07 18:45:10 -0400289 printf("unrecognized rectangle format \"%s\"\n", str);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700290
Miguel Casasd96d9812021-04-07 18:45:10 -0400291 return false;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700292}
293
294static const struct option longopts[] = {
Miguel Casasd96d9812021-04-07 18:45:10 -0400295 {"plane", no_argument, NULL, 'p'},
296 {"format", required_argument, NULL, 'f'},
297 {"size", required_argument, NULL, 'z'},
298 {"scale", required_argument, NULL, 'c'},
299 {"translate", no_argument, NULL, 't'},
300 {"src", required_argument, NULL, 's'},
301 {"dst", required_argument, NULL, 'd'},
302 {"help", no_argument, NULL, 'h'},
303 {0, 0, 0, 0},
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700304};
305
Miguel Casasd96d9812021-04-07 18:45:10 -0400306static void print_help(const char* argv0) {
307 // clang-format off
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700308 printf("usage: %s [OPTIONS]\n", argv0);
309 printf(" -p, --plane indicates that subsequent parameters are for a new plane\n");
310 printf(" -f, --format FOURCC format of source buffer (defaults to NV12)\n");
311 printf(" -z, --size WIDTHxHEIGHT size of the source buffer (defaults to screen size)\n");
312 printf(" -c, --scale DOWN/UP scale plane over time between (1/DOWN)x and UPx\n");
313 printf(" -t, --translate translate plane over time\n");
314 printf(" -s, --src RECT source rectangle (defaults to full buffer)\n");
315 printf(" -d, --dst RECT destination rectangle (defaults to buffer size centered in screen)\n");
316 printf(" -h, --help show help\n");
317 printf("\n");
318 printf("The format of RECT arguments is X,Y or X,Y,WIDTH,HEIGHT or WIDTHxHEIGHT.\n");
319 printf("To test more than one plane, separate plane arguments with -p. For example:\n");
320 printf(" %s --format NV12 --size 400x400 -p --format XR24 --size 100x100 --translate\n", argv0);
321 printf("\n");
Miguel Casasd96d9812021-04-07 18:45:10 -0400322 // clang-format on
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700323}
324
Miguel Casasd96d9812021-04-07 18:45:10 -0400325int main(int argc, char** argv) {
326 int ret = 0;
327 bool help_flag = false;
328 size_t test_planes_count = 1;
329 struct test_plane test_planes[MAX_TEST_PLANES] = {{0}};
330 uint32_t test_planes_formats[MAX_TEST_PLANES] = {0};
331 uint32_t test_planes_ids[MAX_TEST_PLANES] = {0};
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700332
Miguel Casasd96d9812021-04-07 18:45:10 -0400333 int c;
334 while ((c = getopt_long(argc, argv, "pf:z:c:ts:d:h", longopts, NULL)) != -1) {
335 struct test_plane* current_plane = &test_planes[test_planes_count - 1];
336 switch (c) {
337 case 'p':
338 test_planes_count++;
339 if (test_planes_count > MAX_TEST_PLANES) {
340 printf("only %d planes are allowed\n", MAX_TEST_PLANES);
341 return 1;
342 }
343 break;
344 case 'f':
345 if (!bs_parse_draw_format(optarg, &current_plane->format))
346 return 1;
347 break;
348 case 'z':
349 if (!parse_size(optarg, &current_plane->bo_w, &current_plane->bo_h))
350 return 1;
351 current_plane->has_bo_size = true;
352 break;
353 case 'c':
354 if (!parse_scale(optarg, &current_plane->dst_downscale_factor,
355 &current_plane->dst_upscale_factor))
356 return 1;
357 current_plane->has_dst_scale = true;
358 break;
359 case 't':
360 current_plane->dst_vx = 7;
361 current_plane->dst_vy = 7;
362 break;
363 case 's':
364 if (!parse_rect(optarg, &current_plane->src_x, &current_plane->src_y,
365 &current_plane->src_w, &current_plane->src_h, NULL,
366 &current_plane->has_src_size))
367 return 1;
368 break;
369 case 'd':
370 if (!parse_rect(optarg, &current_plane->dst_x, &current_plane->dst_y,
371 &current_plane->dst_w, &current_plane->dst_h,
372 &current_plane->has_dst_position,
373 &current_plane->has_dst_size))
374 return 1;
375 break;
376 case '?':
377 ret = 1;
378 case 'h':
379 help_flag = true;
380 break;
381 }
382 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700383
Miguel Casasd96d9812021-04-07 18:45:10 -0400384 if (help_flag)
385 print_help(argv[0]);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700386
Miguel Casasd96d9812021-04-07 18:45:10 -0400387 if (ret)
388 return ret;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700389
Miguel Casasd96d9812021-04-07 18:45:10 -0400390 drmModeConnector* connector;
391 struct bs_drm_pipe pipe = {0};
392 struct bs_drm_pipe_plumber* plumber = bs_drm_pipe_plumber_new();
393 bs_drm_pipe_plumber_connector_ranks(plumber, bs_drm_connectors_internal_rank);
394 bs_drm_pipe_plumber_connector_ptr(plumber, &connector);
395 if (!bs_drm_pipe_plumber_make(plumber, &pipe)) {
396 bs_debug_error("failed to make pipe");
397 return 1;
398 }
399 bs_drm_pipe_plumber_destroy(&plumber);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700400
Miguel Casasd96d9812021-04-07 18:45:10 -0400401 drmModeModeInfo* mode_ptr =
402 find_best_mode(connector->count_modes, connector->modes);
403 if (!mode_ptr) {
404 bs_debug_error("failed to find preferred mode");
405 return 1;
406 }
407 drmModeModeInfo mode = *mode_ptr;
408 drmModeFreeConnector(connector);
409 printf("Using mode %s\n", mode.name);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700410
Miguel Casasd96d9812021-04-07 18:45:10 -0400411 printf("Using CRTC:%u ENCODER:%u CONNECTOR:%u\n", pipe.crtc_id,
412 pipe.encoder_id, pipe.connector_id);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700413
Miguel Casasd96d9812021-04-07 18:45:10 -0400414 struct gbm_device* gbm = gbm_create_device(pipe.fd);
415 if (!gbm) {
416 bs_debug_error("failed to create gbm");
417 return 1;
418 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700419
Miguel Casasd96d9812021-04-07 18:45:10 -0400420 struct gbm_bo* bg_bo =
421 gbm_bo_create(gbm, mode.hdisplay, mode.vdisplay, GBM_FORMAT_XRGB8888,
422 GBM_BO_USE_SCANOUT | GBM_BO_USE_SW_WRITE_RARELY);
423 if (!bg_bo) {
424 bs_debug_error("failed to create background buffer ojbect");
425 return 1;
426 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700427
Miguel Casasd96d9812021-04-07 18:45:10 -0400428 struct bs_mapper* mapper = bs_mapper_gem_new();
429 if (mapper == NULL) {
430 bs_debug_error("failed to create mapper object");
431 return 1;
432 }
Dongseong Hwang9093afe2017-03-20 19:16:28 -0700433
Miguel Casasd96d9812021-04-07 18:45:10 -0400434 void* map_data;
435 uint32_t stride;
436 void* bo_ptr = bs_mapper_map(mapper, bg_bo, 0, &map_data, &stride);
437 if (bo_ptr == MAP_FAILED) {
438 bs_debug_error("failed to mmap background buffer object");
439 return 1;
440 }
441 memset(bo_ptr, 0, gbm_bo_get_height(bg_bo) * stride);
442 bs_mapper_unmap(mapper, bg_bo, map_data);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700443
Miguel Casasd96d9812021-04-07 18:45:10 -0400444 uint32_t crtc_fb_id = bs_drm_fb_create_gbm(bg_bo);
445 if (!crtc_fb_id) {
446 bs_debug_error("failed to create frame buffer for buffer object");
447 return 1;
448 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700449
Miguel Casasd96d9812021-04-07 18:45:10 -0400450 for (size_t test_plane_index = 0; test_plane_index < test_planes_count;
451 test_plane_index++) {
452 struct test_plane* tp = &test_planes[test_plane_index];
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700453
Miguel Casasd96d9812021-04-07 18:45:10 -0400454 if (!tp->format)
455 tp->format = bs_get_draw_format(GBM_FORMAT_NV12);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700456
Miguel Casasd96d9812021-04-07 18:45:10 -0400457 test_planes_formats[test_plane_index] = bs_get_pixel_format(tp->format);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700458
Miguel Casasd96d9812021-04-07 18:45:10 -0400459 if (!tp->has_bo_size) {
460 tp->bo_w = mode.hdisplay;
461 tp->bo_h = mode.vdisplay;
462 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700463
Miguel Casasd96d9812021-04-07 18:45:10 -0400464 if (!tp->has_src_size) {
465 tp->src_w = tp->bo_w;
466 tp->src_h = tp->bo_h;
467 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700468
Miguel Casasd96d9812021-04-07 18:45:10 -0400469 if (!tp->has_dst_size) {
470 tp->dst_w = tp->bo_w;
471 tp->dst_h = tp->bo_h;
472 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700473
Miguel Casasd96d9812021-04-07 18:45:10 -0400474 if (tp->has_dst_position) {
475 tp->dst_center_x = tp->dst_x + mode.hdisplay / 2;
476 tp->dst_center_y = tp->dst_y + mode.vdisplay / 2;
477 } else {
478 tp->dst_center_x = mode.hdisplay / 2;
479 tp->dst_center_y = mode.vdisplay / 2;
480 tp->dst_x = tp->dst_center_x - tp->dst_w / 2;
481 tp->dst_y = tp->dst_center_y - tp->dst_h / 2;
482 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700483
Miguel Casasd96d9812021-04-07 18:45:10 -0400484 if (tp->has_dst_scale) {
485 tp->dst_min_w = tp->dst_w / tp->dst_downscale_factor;
486 tp->dst_max_w = tp->dst_w * tp->dst_upscale_factor;
487 tp->dst_min_h = tp->dst_h / tp->dst_downscale_factor;
488 tp->dst_max_h = tp->dst_h * tp->dst_upscale_factor;
489 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700490
Miguel Casasd96d9812021-04-07 18:45:10 -0400491 printf("Creating buffer %ux%u %s\n", tp->bo_w, tp->bo_h,
492 bs_get_format_name(tp->format));
493 tp->bo = gbm_bo_create(gbm, tp->bo_w, tp->bo_h,
494 bs_get_pixel_format(tp->format), GBM_BO_USE_SCANOUT);
495 if (!tp->bo) {
496 bs_debug_error("failed to create buffer object");
497 return 1;
498 }
499 printf("Bytes per pixel: %d\n", gbm_bo_get_bpp(tp->bo));
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700500
Miguel Casasd96d9812021-04-07 18:45:10 -0400501 tp->fb_id = bs_drm_fb_create_gbm(tp->bo);
502 if (!tp->fb_id) {
503 bs_debug_error("failed to create plane frame buffer for buffer object");
504 return 1;
505 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700506
Miguel Casasd96d9812021-04-07 18:45:10 -0400507 if (!bs_draw_stripe(mapper, tp->bo, tp->format)) {
508 bs_debug_error("failed to draw pattern to buffer object");
509 return 1;
510 }
511 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700512
Miguel Casasd96d9812021-04-07 18:45:10 -0400513 if (!find_overlay_planes(pipe.fd, pipe.crtc_id, test_planes_count,
514 test_planes_formats, test_planes_ids)) {
515 bs_debug_error("failed to find overlay planes for given formats");
516 return 1;
517 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700518
Miguel Casasd96d9812021-04-07 18:45:10 -0400519 ret = drmModeSetCrtc(pipe.fd, pipe.crtc_id, crtc_fb_id, 0, 0,
520 &pipe.connector_id, 1, &mode);
521 if (ret < 0) {
522 bs_debug_error("Could not set mode on CRTC %d %s", pipe.crtc_id,
523 strerror(errno));
524 return 1;
525 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700526
Miguel Casasd96d9812021-04-07 18:45:10 -0400527 struct timespec start;
528 clock_gettime(CLOCK_MONOTONIC, &start);
529 const int64_t ten_seconds_in_ns = 10000000000;
530 for (int i = 0; ns_since(&start) < ten_seconds_in_ns; i++) {
531 for (size_t test_plane_index = 0; test_plane_index < test_planes_count;
532 test_plane_index++) {
533 struct test_plane* current_plane = &test_planes[test_plane_index];
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700534
Miguel Casasd96d9812021-04-07 18:45:10 -0400535 bool needs_set =
536 update_test_plane(i, mode.hdisplay, mode.vdisplay, current_plane);
537 if (!needs_set)
538 continue;
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700539
Miguel Casasd96d9812021-04-07 18:45:10 -0400540 ret = drmModeSetPlane(
541 pipe.fd, test_planes_ids[test_plane_index], pipe.crtc_id,
542 current_plane->fb_id, 0 /* flags */, current_plane->dst_x,
543 current_plane->dst_y, current_plane->dst_w, current_plane->dst_h,
544 current_plane->src_x << 16, current_plane->src_y << 16,
545 current_plane->src_w << 16, current_plane->src_h << 16);
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700546
Miguel Casasd96d9812021-04-07 18:45:10 -0400547 if (ret) {
548 bs_debug_error(
549 "failed to set plane "
550 "%d:\ndst[x,y,w,h]=%d,%d,%u,%u\nsrc[x,y,w,h]=%d,%d,%u,%u",
551 ret, current_plane->dst_x, current_plane->dst_y,
552 current_plane->dst_w, current_plane->dst_h, current_plane->src_x,
553 current_plane->src_y, current_plane->src_w, current_plane->src_h);
554 return 1;
555 }
556 }
557 usleep(1000000 / 60);
558 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700559
Miguel Casasd96d9812021-04-07 18:45:10 -0400560 ret = drmModeSetCrtc(pipe.fd, pipe.crtc_id, 0, 0, 0, NULL, 0, NULL);
561 if (ret < 0) {
562 bs_debug_error("Could not disable CRTC %d %s", pipe.crtc_id,
563 strerror(errno));
564 return 1;
565 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700566
Miguel Casasd96d9812021-04-07 18:45:10 -0400567 bs_mapper_destroy(mapper);
568 for (size_t test_plane_index = 0; test_plane_index < test_planes_count;
569 test_plane_index++) {
570 struct test_plane* current_plane = &test_planes[test_plane_index];
571 drmModeRmFB(pipe.fd, current_plane->fb_id);
572 gbm_bo_destroy(current_plane->bo);
573 }
574 drmModeRmFB(pipe.fd, crtc_fb_id);
575 gbm_bo_destroy(bg_bo);
576 gbm_device_destroy(gbm);
577 close(pipe.fd);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700578
Miguel Casasd96d9812021-04-07 18:45:10 -0400579 return 0;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700580}