blob: c1ee5695eab8fab56f18bb5a2bc6927172091d14 [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
13#define MAX_PLANES 4
14#define MAX_COMPONENTS 4
Zach Reiznerfa0547a2016-05-11 18:43:40 -070015#define MAX_TEST_PLANES 4
16
17static int64_t ns_since(struct timespec *since)
18{
19 struct timespec now;
20 clock_gettime(CLOCK_MONOTONIC, &now);
21
22 return (int64_t)(now.tv_sec - since->tv_sec) * 1000000000 + (int64_t)now.tv_nsec -
23 (int64_t)since->tv_nsec;
24}
Zach Reiznerd847a7e2016-04-28 16:48:32 -070025
26static drmModeModeInfoPtr find_best_mode(int mode_count, drmModeModeInfoPtr modes)
27{
28 if (mode_count <= 0 || modes == NULL)
29 return NULL;
30
31 for (int m = 0; m < mode_count; m++)
32 if (modes[m].type & DRM_MODE_TYPE_PREFERRED)
33 return &modes[m];
34
35 return &modes[0];
36}
37
38static bool is_format_supported(uint32_t format_count, uint32_t *formats, uint32_t format)
39{
40 for (uint32_t i = 0; i < format_count; i++)
41 if (formats[i] == format)
42 return true;
43 return false;
44}
45
Zach Reiznerfa0547a2016-05-11 18:43:40 -070046static bool find_overlay_planes(int fd, uint32_t crtc_id, size_t plane_count, uint32_t *formats,
47 uint32_t *plane_ids)
Zach Reiznerd847a7e2016-04-28 16:48:32 -070048{
49 drmModeRes *res = drmModeGetResources(fd);
50 if (res == NULL) {
51 bs_debug_error("failed to get drm resources");
Zach Reiznerfa0547a2016-05-11 18:43:40 -070052 return false;
Zach Reiznerd847a7e2016-04-28 16:48:32 -070053 }
54
55 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);
Zach Reiznerfa0547a2016-05-11 18:43:40 -070065 return false;
Zach Reiznerd847a7e2016-04-28 16:48:32 -070066 }
67
68 drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
69 if (plane_res == NULL) {
70 bs_debug_error("failed to get plane resources");
71 drmModeFreeResources(res);
Zach Reiznerfa0547a2016-05-11 18:43:40 -070072 return false;
Zach Reiznerd847a7e2016-04-28 16:48:32 -070073 }
74
Zach Reiznerfa0547a2016-05-11 18:43:40 -070075 for (size_t out_index = 0; out_index < plane_count; out_index++)
76 plane_ids[out_index] = 0;
77
78 size_t remaining_out = plane_count;
79 for (uint32_t plane_index = 0; remaining_out > 0 && plane_index < plane_res->count_planes;
Zach Reiznerd847a7e2016-04-28 16:48:32 -070080 plane_index++) {
81 drmModePlane *plane = drmModeGetPlane(fd, plane_res->planes[plane_index]);
82 if (plane == NULL) {
83 bs_debug_error("failed to get plane id %u", plane_res->planes[plane_index]);
84 continue;
85 }
86
Zach Reiznerfa0547a2016-05-11 18:43:40 -070087 size_t out_index;
88 for (out_index = 0; out_index < plane_count; out_index++) {
89 if (plane_ids[out_index] == 0 &&
90 is_format_supported(plane->count_formats, plane->formats,
91 formats[out_index]))
92 break;
93 }
94
95 if ((plane->possible_crtcs & crtc_mask) == 0 || out_index == plane_count) {
Zach Reiznerd847a7e2016-04-28 16:48:32 -070096 drmModeFreePlane(plane);
97 continue;
98 }
99
100 drmModeObjectPropertiesPtr props =
101 drmModeObjectGetProperties(fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
102 for (uint32_t prop_index = 0; prop_index < props->count_props; ++prop_index) {
103 drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[prop_index]);
104 if (strcmp(prop->name, "type")) {
105 drmModeFreeProperty(prop);
106 continue;
107 }
108
109 uint64_t desired_value = 0;
110 bool has_value = false;
111 for (int enum_index = 0; enum_index < prop->count_enums; enum_index++) {
112 struct drm_mode_property_enum *penum = &prop->enums[enum_index];
113 if (!strcmp(penum->name, "Overlay")) {
114 desired_value = penum->value;
115 has_value = true;
116 break;
117 }
118 }
119 drmModeFreeProperty(prop);
120
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700121 if (has_value && desired_value == props->prop_values[prop_index]) {
122 plane_ids[out_index] = plane->plane_id;
123 remaining_out--;
124 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700125
126 break;
127 }
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700128
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700129 drmModeFreeObjectProperties(props);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700130 drmModeFreePlane(plane);
131 }
132
133 drmModeFreePlaneResources(plane_res);
134 drmModeFreeResources(res);
135
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700136 return remaining_out == 0;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700137}
138
139struct draw_format_component {
140 float rgb_coeffs[3];
141 float value_offset;
142 uint32_t horizontal_subsample_rate;
143 uint32_t vertical_subsample_rate;
144 uint32_t pixel_skip;
145 uint32_t plane_index;
146 uint32_t plane_offset;
147};
148
149struct draw_format {
150 uint32_t pixel_format;
151 const char *name;
152 size_t component_count;
153 struct draw_format_component components[MAX_COMPONENTS];
154};
155
156#define PIXEL_FORMAT_AND_NAME(x) GBM_FORMAT_##x, #x
157
158static const struct draw_format g_draw_formats[] = {
159 {
160 PIXEL_FORMAT_AND_NAME(NV12),
161 3,
162 {
163 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
164 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 1, 1, 0 },
165 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 1, 1, 1 },
166 },
167 },
168 {
169 PIXEL_FORMAT_AND_NAME(XRGB8888),
170 3,
171 {
172 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
173 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
174 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
175 },
176 },
177 {
178 PIXEL_FORMAT_AND_NAME(ARGB8888),
179 4,
180 {
181 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
182 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
183 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
184 { { 0.0f, 0.0f, 0.0f }, 255.0f, 1, 1, 4, 0, 3 },
185 },
186 },
187};
188
189static uint8_t clampbyte(float f)
190{
191 if (f >= 255.0f)
192 return 255;
193 if (f <= 0.0f)
194 return 0;
195 return (uint8_t)f;
196}
197
198static uint8_t convert_color(const struct draw_format_component *comp, uint8_t r, uint8_t g,
199 uint8_t b)
200{
201 return clampbyte(comp->value_offset + r * comp->rgb_coeffs[0] + g * comp->rgb_coeffs[1] +
202 b * comp->rgb_coeffs[2]);
203}
204
205static const struct draw_format *get_draw_format(uint32_t pixel_format)
206{
207 for (size_t format_index = 0;
208 format_index < sizeof(g_draw_formats) / sizeof(g_draw_formats[0]); format_index++) {
209 const struct draw_format *format = &g_draw_formats[format_index];
210 if (format->pixel_format == pixel_format)
211 return format;
212 }
213
214 return NULL;
215}
216
217struct draw_plane {
218 uint32_t row_stride;
219 uint8_t *ptr;
220};
221
222static void unmmap_planes(struct gbm_bo *bo, size_t num_planes, struct draw_plane *planes)
223{
224 for (uint32_t plane_index = 0; plane_index < num_planes; plane_index++)
225 bs_dma_buf_unmmap_plane(bo, plane_index, planes[plane_index].ptr);
226}
227
228static size_t mmap_planes(struct gbm_bo *bo, struct draw_plane planes[MAX_PLANES])
229{
230 size_t num_planes = gbm_bo_get_num_planes(bo);
231 if (num_planes > MAX_PLANES) {
232 bs_debug_error("buffer object has unexpected number of planes %zu", num_planes);
233 return 0;
234 }
235
236 for (size_t plane_index = 0; plane_index < num_planes; plane_index++) {
237 struct draw_plane *plane = &planes[plane_index];
238 plane->row_stride = gbm_bo_get_plane_stride(bo, plane_index);
239 plane->ptr = bs_dma_buf_mmap_plane(bo, plane_index);
240 if (!plane->ptr) {
241 bs_debug_error("failed to mmap plane %zu of buffer object", plane_index);
242 unmmap_planes(bo, plane_index, planes);
243 return 0;
244 }
245 }
246
247 return true;
248}
249
250static bool draw_pattern(struct gbm_bo *bo, const struct draw_format *format)
251{
252 const uint32_t width = gbm_bo_get_width(bo);
253 const uint32_t height = gbm_bo_get_height(bo);
254 const uint32_t striph = height / 4;
255
256 struct draw_plane planes[MAX_PLANES];
257 size_t num_planes = mmap_planes(bo, planes);
258 if (num_planes == 0) {
259 bs_debug_error("failed to prepare to draw pattern to buffer object");
260 return false;
261 }
262
263 for (uint32_t s = 0; s < 4; s++) {
264 uint8_t r = 0, g = 0, b = 0;
265 switch (s) {
266 case 0:
267 r = g = b = 1;
268 break;
269 case 1:
270 r = 1;
271 break;
272 case 2:
273 g = 1;
274 break;
275 case 3:
276 b = 1;
277 break;
278 default:
279 r = g = b = 0;
280 break;
281 }
282 for (uint32_t y = s * striph; y < (s + 1) * striph; y++) {
283 uint8_t *rows[MAX_COMPONENTS] = { 0 };
284 for (size_t comp_index = 0; comp_index < format->component_count;
285 comp_index++) {
286 const struct draw_format_component *comp =
287 &format->components[comp_index];
288 struct draw_plane *plane = &planes[comp->plane_index];
289 rows[comp_index] =
290 plane->ptr + comp->plane_offset +
291 plane->row_stride * (y / comp->vertical_subsample_rate);
292 }
293 for (uint32_t x = 0; x < width; x++) {
294 const float i = (float)x / (float)width * 256.0f;
295 for (size_t comp_index = 0; comp_index < format->component_count;
296 comp_index++) {
297 const struct draw_format_component *comp =
298 &format->components[comp_index];
299 if ((y % comp->vertical_subsample_rate) == 0 &&
300 (x % comp->horizontal_subsample_rate) == 0)
301 *(rows[comp_index] + x * comp->pixel_skip) =
302 convert_color(comp, r * i, g * i, b * i);
303 }
304 }
305 }
306 }
307
308 unmmap_planes(bo, num_planes, planes);
309 return true;
310}
311
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700312struct test_plane {
313 const struct draw_format *format;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700314
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700315 bool has_bo_size;
316 uint32_t bo_w;
317 uint32_t bo_h;
318
319 bool has_dst_position;
320 int32_t dst_x;
321 int32_t dst_y;
322
323 int32_t dst_center_x;
324 int32_t dst_center_y;
325
326 int32_t dst_vx;
327 int32_t dst_vy;
328
329 bool has_dst_size;
330 uint32_t dst_w;
331 uint32_t dst_h;
332
333 uint32_t dst_min_w;
334 uint32_t dst_max_w;
335 uint32_t dst_min_h;
336 uint32_t dst_max_h;
337
338 bool has_dst_scale;
339 uint32_t dst_downscale_factor;
340 uint32_t dst_upscale_factor;
341
342 int32_t src_x;
343 int32_t src_y;
344
345 int32_t src_vx;
346 int32_t src_vy;
347
348 bool has_src_size;
349 uint32_t src_w;
350 uint32_t src_h;
351
352 struct gbm_bo *bo;
353 uint32_t fb_id;
354};
355
356static bool update_test_plane(int step, int32_t max_x, int32_t max_y, struct test_plane *tp)
357{
358 bool needs_set = (step == 0);
359 if (tp->has_dst_scale) {
360 float scale_factor = (sinf(step / 120.0f) / 2.0f + 0.5f);
361 scale_factor = powf(scale_factor, 4);
362 tp->dst_w = tp->dst_min_w + scale_factor * (tp->dst_max_w - tp->dst_min_w);
363 tp->dst_h = tp->dst_min_h + scale_factor * (tp->dst_max_h - tp->dst_min_h);
364 needs_set = true;
365 }
366
367 if (tp->dst_vx != 0) {
368 tp->dst_center_x += tp->dst_vx;
369 if (tp->dst_center_x > max_x || tp->dst_center_x < 0) {
370 tp->dst_vx = -tp->dst_vx;
371 tp->dst_x += tp->dst_vx * 2;
372 }
373 needs_set = true;
374 }
375 tp->dst_x = tp->dst_center_x - tp->dst_w / 2;
376
377 if (tp->dst_vy != 0) {
378 tp->dst_center_y += tp->dst_vy;
379 if (tp->dst_center_y > max_y || tp->dst_center_y < 0) {
380 tp->dst_vy = -tp->dst_vy;
381 tp->dst_y += tp->dst_vy * 2;
382 }
383 needs_set = true;
384 }
385 tp->dst_y = tp->dst_center_y - tp->dst_h / 2;
386
387 if (tp->src_vx != 0) {
388 tp->src_x += tp->src_vx;
389 if (tp->src_x + tp->src_w > gbm_bo_get_width(tp->bo) || tp->src_x < 0) {
390 tp->src_vx = -tp->src_vx;
391 tp->src_x += tp->src_vx * 2;
392 }
393 needs_set = true;
394 }
395
396 if (tp->src_vy != 0) {
397 tp->src_y += tp->src_vy;
398 if (tp->src_y + tp->src_h > gbm_bo_get_height(tp->bo) || tp->src_y < 0) {
399 tp->src_vy = -tp->src_vy;
400 tp->src_y += tp->src_vy * 2;
401 }
402 needs_set = true;
403 }
404
405 return needs_set;
406}
407
408static bool parse_format(const char *str, const struct draw_format **format)
409{
410 if (strlen(str) == 4) {
411 const struct draw_format *draw_format = get_draw_format(*(uint32_t *)str);
412 if (draw_format) {
413 *format = draw_format;
414 return true;
415 }
416 }
417 else {
418 for (size_t format_index = 0;
419 format_index < sizeof(g_draw_formats) / sizeof(g_draw_formats[0]);
420 format_index++) {
421 const struct draw_format *draw_format = &g_draw_formats[format_index];
422 if (!strcmp(str, draw_format->name)) {
423 *format = draw_format;
424 return true;
425 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700426 }
427 }
428
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700429 printf("plane format %s is not recognized\n", str);
430 return false;
431}
432
433static bool parse_size(const char *str, uint32_t *w, uint32_t *h)
434{
435 if (sscanf(str, "%ux%u", w, h) == 2)
436 return true;
437
438 printf("unrecognized size format \"%s\"\n", str);
439
440 return false;
441}
442
443static bool parse_scale(const char *str, uint32_t *down, uint32_t *up)
444{
445 if (sscanf(str, "%u/%u", down, up) == 2)
446 return true;
447
448 printf("unrecognized scale format \"%s\"\n", str);
449
450 return false;
451}
452
453static bool parse_rect(const char *str, int32_t *x, int32_t *y, uint32_t *w, uint32_t *h,
454 bool *has_position, bool *has_size)
455{
456 if (sscanf(str, "%d,%d,%u,%u", x, y, w, h) == 4) {
457 if (has_position)
458 *has_position = true;
459 if (has_size)
460 *has_size = true;
461 return true;
462 }
463
464 if (sscanf(str, "%d,%d", x, y) == 2) {
465 if (has_position)
466 *has_position = true;
467 if (has_size)
468 *has_size = false;
469 return true;
470 }
471
472 if (sscanf(str, "%ux%u", w, h) == 2) {
473 if (has_position)
474 *has_position = false;
475 if (has_size)
476 *has_size = true;
477 return true;
478 }
479
480 printf("unrecognized rectangle format \"%s\"\n", str);
481
482 return false;
483}
484
485static const struct option longopts[] = {
486 { "plane", no_argument, NULL, 'p' },
487 { "format", required_argument, NULL, 'f' },
488 { "size", required_argument, NULL, 'z' },
489 { "scale", required_argument, NULL, 'c' },
490 { "translate", no_argument, NULL, 't' },
491 { "src", required_argument, NULL, 's' },
492 { "dst", required_argument, NULL, 'd' },
493 { "help", no_argument, NULL, 'h' },
494 { 0, 0, 0, 0 },
495};
496
497static void print_help(const char *argv0)
498{
499 // clang-format off
500 printf("usage: %s [OPTIONS]\n", argv0);
501 printf(" -p, --plane indicates that subsequent parameters are for a new plane\n");
502 printf(" -f, --format FOURCC format of source buffer (defaults to NV12)\n");
503 printf(" -z, --size WIDTHxHEIGHT size of the source buffer (defaults to screen size)\n");
504 printf(" -c, --scale DOWN/UP scale plane over time between (1/DOWN)x and UPx\n");
505 printf(" -t, --translate translate plane over time\n");
506 printf(" -s, --src RECT source rectangle (defaults to full buffer)\n");
507 printf(" -d, --dst RECT destination rectangle (defaults to buffer size centered in screen)\n");
508 printf(" -h, --help show help\n");
509 printf("\n");
510 printf("The format of RECT arguments is X,Y or X,Y,WIDTH,HEIGHT or WIDTHxHEIGHT.\n");
511 printf("To test more than one plane, separate plane arguments with -p. For example:\n");
512 printf(" %s --format NV12 --size 400x400 -p --format XR24 --size 100x100 --translate\n", argv0);
513 printf("\n");
514 // clang-format on
515}
516
517int main(int argc, char **argv)
518{
519 int ret = 0;
520 bool help_flag = false;
521 size_t test_planes_count = 1;
522 struct test_plane test_planes[MAX_TEST_PLANES] = { { 0 } };
523 uint32_t test_planes_formats[MAX_TEST_PLANES] = { 0 };
524 uint32_t test_planes_ids[MAX_TEST_PLANES] = { 0 };
525
526 int c;
527 while ((c = getopt_long(argc, argv, "pf:z:c:ts:d:h", longopts, NULL)) != -1) {
528 struct test_plane *current_plane = &test_planes[test_planes_count - 1];
529 switch (c) {
530 case 'p':
531 test_planes_count++;
532 if (test_planes_count > MAX_TEST_PLANES) {
533 printf("only %d planes are allowed\n", MAX_TEST_PLANES);
534 return 1;
535 }
536 break;
537 case 'f':
538 if (!parse_format(optarg, &current_plane->format))
539 return 1;
540 break;
541 case 'z':
542 if (!parse_size(optarg, &current_plane->bo_w, &current_plane->bo_h))
543 return 1;
544 current_plane->has_bo_size = true;
545 break;
546 case 'c':
547 if (!parse_scale(optarg, &current_plane->dst_downscale_factor,
548 &current_plane->dst_upscale_factor))
549 return 1;
550 current_plane->has_dst_scale = true;
551 break;
552 case 't':
553 current_plane->dst_vx = 7;
554 current_plane->dst_vy = 7;
555 break;
556 case 's':
557 if (!parse_rect(optarg, &current_plane->src_x,
558 &current_plane->src_y, &current_plane->src_w,
559 &current_plane->src_h, NULL,
560 &current_plane->has_src_size))
561 return 1;
562 break;
563 case 'd':
564 if (!parse_rect(optarg, &current_plane->dst_x,
565 &current_plane->dst_y, &current_plane->dst_w,
566 &current_plane->dst_h,
567 &current_plane->has_dst_position,
568 &current_plane->has_dst_size))
569 return 1;
570 break;
571 case '?':
572 ret = 1;
573 case 'h':
574 help_flag = true;
575 break;
576 }
577 }
578
579 if (help_flag)
580 print_help(argv[0]);
581
582 if (ret)
583 return ret;
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700584
585 drmModeConnector *connector;
586 struct bs_drm_pipe pipe = { 0 };
587 struct bs_drm_pipe_plumber *plumber = bs_drm_pipe_plumber_new();
588 bs_drm_pipe_plumber_connector_ranks(plumber, bs_drm_connectors_internal_rank);
589 bs_drm_pipe_plumber_connector_ptr(plumber, &connector);
590 if (!bs_drm_pipe_plumber_make(plumber, &pipe)) {
591 bs_debug_error("failed to make pipe");
592 return 1;
593 }
594 bs_drm_pipe_plumber_destroy(&plumber);
595
596 drmModeModeInfo *mode_ptr = find_best_mode(connector->count_modes, connector->modes);
597 if (!mode_ptr) {
598 bs_debug_error("failed to find preferred mode");
599 return 1;
600 }
601 drmModeModeInfo mode = *mode_ptr;
602 drmModeFreeConnector(connector);
603 printf("Using mode %s\n", mode.name);
604
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700605 printf("Using CRTC:%u ENCODER:%u CONNECTOR:%u\n", pipe.crtc_id, pipe.encoder_id,
606 pipe.connector_id);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700607
608 struct gbm_device *gbm = gbm_create_device(pipe.fd);
609 if (!gbm) {
610 bs_debug_error("failed to create gbm");
611 return 1;
612 }
613
614 struct gbm_bo *bg_bo = gbm_bo_create(gbm, mode.hdisplay, mode.vdisplay, GBM_FORMAT_XRGB8888,
615 GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
616 if (!bg_bo) {
617 bs_debug_error("failed to create background buffer ojbect");
618 return 1;
619 }
620
621 void *bo_ptr = bs_dma_buf_mmap_plane(bg_bo, 0);
622 if (bo_ptr == NULL) {
623 bs_debug_error("failed to mmap background buffer object");
624 return 1;
625 }
626 memset(bo_ptr, 0xff, gbm_bo_get_height(bg_bo) * gbm_bo_get_stride(bg_bo));
627 bs_dma_buf_unmmap_plane(bg_bo, 0, bo_ptr);
628
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700629 uint32_t crtc_fb_id = bs_drm_fb_create_gbm(bg_bo);
630 if (!crtc_fb_id) {
631 bs_debug_error("failed to create frame buffer for buffer object");
632 return 1;
633 }
634
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700635 for (size_t test_plane_index = 0; test_plane_index < test_planes_count;
636 test_plane_index++) {
637 struct test_plane *tp = &test_planes[test_plane_index];
638
639 if (!tp->format)
640 tp->format = &g_draw_formats[0];
641
642 test_planes_formats[test_plane_index] = tp->format->pixel_format;
643
644 if (!tp->has_bo_size) {
645 tp->bo_w = mode.hdisplay;
646 tp->bo_h = mode.vdisplay;
647 }
648
649 if (!tp->has_src_size) {
650 tp->src_w = tp->bo_w;
651 tp->src_h = tp->bo_h;
652 }
653
654 if (!tp->has_dst_size) {
655 tp->dst_w = tp->bo_w;
656 tp->dst_h = tp->bo_h;
657 }
658
659 if (tp->has_dst_position) {
660 tp->dst_center_x = tp->dst_x + mode.hdisplay / 2;
661 tp->dst_center_y = tp->dst_y + mode.vdisplay / 2;
662 }
663 else {
664 tp->dst_center_x = mode.hdisplay / 2;
665 tp->dst_center_y = mode.vdisplay / 2;
666 tp->dst_x = tp->dst_center_x - tp->dst_w / 2;
667 tp->dst_y = tp->dst_center_y - tp->dst_h / 2;
668 }
669
670 if (tp->has_dst_scale) {
671 tp->dst_min_w = tp->dst_w / tp->dst_downscale_factor;
672 tp->dst_max_w = tp->dst_w * tp->dst_upscale_factor;
673 tp->dst_min_h = tp->dst_h / tp->dst_downscale_factor;
674 tp->dst_max_h = tp->dst_h * tp->dst_upscale_factor;
675 }
676
677 printf("Creating buffer %ux%u %s (%4.4s)\n", tp->bo_w, tp->bo_h, tp->format->name,
678 (char *)&tp->format->pixel_format);
679 tp->bo = gbm_bo_create(gbm, tp->bo_w, tp->bo_h, tp->format->pixel_format,
680 GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
681 if (!tp->bo) {
682 bs_debug_error("failed to create buffer object");
683 return 1;
684 }
685
686 tp->fb_id = bs_drm_fb_create_gbm(tp->bo);
687 if (!tp->fb_id) {
688 bs_debug_error("failed to create plane frame buffer for buffer object");
689 return 1;
690 }
691
692 if (!draw_pattern(tp->bo, tp->format)) {
693 bs_debug_error("failed to draw pattern to buffer object");
694 return 1;
695 }
696 }
697
698 if (!find_overlay_planes(pipe.fd, pipe.crtc_id, test_planes_count, test_planes_formats,
699 test_planes_ids)) {
700 bs_debug_error("failed to find overlay planes for given formats");
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700701 return 1;
702 }
703
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700704 ret = drmModeSetCrtc(pipe.fd, pipe.crtc_id, crtc_fb_id, 0, 0, &pipe.connector_id, 1, &mode);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700705 if (ret < 0) {
706 bs_debug_error("Could not set mode on CRTC %d %s", pipe.crtc_id, strerror(errno));
707 return 1;
708 }
709
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700710 struct timespec start;
711 clock_gettime(CLOCK_MONOTONIC, &start);
712 const int64_t ten_seconds_in_ns = 10000000000;
713 for (int i = 0; ns_since(&start) < ten_seconds_in_ns; i++) {
714 for (size_t test_plane_index = 0; test_plane_index < test_planes_count;
715 test_plane_index++) {
716 struct test_plane *current_plane = &test_planes[test_plane_index];
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700717
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700718 bool needs_set =
719 update_test_plane(i, mode.hdisplay, mode.vdisplay, current_plane);
720 if (!needs_set)
721 continue;
722
723 ret = drmModeSetPlane(
724 pipe.fd, test_planes_ids[test_plane_index], pipe.crtc_id,
725 current_plane->fb_id, 0 /* flags */, current_plane->dst_x,
726 current_plane->dst_y, current_plane->dst_w, current_plane->dst_h,
727 current_plane->src_x << 16, current_plane->src_y << 16,
728 current_plane->src_w << 16, current_plane->src_h << 16);
729
730 if (ret) {
731 bs_debug_error(
732 "failed to set plane "
733 "%d:\ndst[x,y,w,h]=%d,%d,%u,%u\nsrc[x,y,w,h]=%d,%d,%u,%u",
734 ret, current_plane->dst_x, current_plane->dst_y,
735 current_plane->dst_w, current_plane->dst_h,
736 current_plane->src_x, current_plane->src_y,
737 current_plane->src_w, current_plane->src_h);
738 return 1;
739 }
740 }
741
742 usleep(1000000 / 60);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700743 }
744
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700745 ret = drmModeSetCrtc(pipe.fd, pipe.crtc_id, 0, 0, 0, NULL, 0, NULL);
746 if (ret < 0) {
747 bs_debug_error("Could not disable CRTC %d %s", pipe.crtc_id, strerror(errno));
748 return 1;
749 }
750
Zach Reiznerfa0547a2016-05-11 18:43:40 -0700751 for (size_t test_plane_index = 0; test_plane_index < test_planes_count;
752 test_plane_index++) {
753 struct test_plane *current_plane = &test_planes[test_plane_index];
754 drmModeRmFB(pipe.fd, current_plane->fb_id);
755 gbm_bo_destroy(current_plane->bo);
756 }
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700757 drmModeRmFB(pipe.fd, crtc_fb_id);
Zach Reiznerd847a7e2016-04-28 16:48:32 -0700758 gbm_bo_destroy(bg_bo);
759 gbm_device_destroy(gbm);
760 close(pipe.fd);
761
762 return 0;
763}