blob: 97dcd718e344e45de260951d7a4833c7925f01e3 [file] [log] [blame]
Haixia Shi4652b8c2014-11-19 17:55:38 -08001/*
2 * Copyright 2014 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
Zach Reizner38f0fd92016-02-18 14:28:02 -08007#include "bs_drm.h"
Haixia Shie04ddfd2014-11-11 19:14:32 -08008
Daniele Castagna8a63a602016-10-10 18:43:29 -04009#include <getopt.h>
10
Gurchetan Singh10008e62017-03-09 11:14:38 -080011#define NUM_BUFFERS 2
12
Daniele Castagna72729122017-10-18 17:09:36 -040013static uint32_t allowed_formats[] = {
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080014 GBM_FORMAT_XRGB8888, GBM_FORMAT_XBGR8888, GBM_FORMAT_XRGB2101010, GBM_FORMAT_XBGR2101010,
Daniele Castagna72729122017-10-18 17:09:36 -040015};
16
17const size_t allowed_formats_length = BS_ARRAY_LEN(allowed_formats);
18
Zach Reizner4dfdf602016-03-01 13:06:30 -080019static GLuint solid_shader_create()
Haixia Shie04ddfd2014-11-11 19:14:32 -080020{
Zach Reizner4dfdf602016-03-01 13:06:30 -080021 const GLchar *vert =
Zach Reizner38f0fd92016-02-18 14:28:02 -080022 "attribute vec4 vPosition;\n"
23 "attribute vec4 vColor;\n"
24 "varying vec4 vFillColor;\n"
25 "void main() {\n"
26 " gl_Position = vPosition;\n"
27 " vFillColor = vColor;\n"
28 "}\n";
Haixia Shie04ddfd2014-11-11 19:14:32 -080029
Zach Reizner4dfdf602016-03-01 13:06:30 -080030 const GLchar *frag =
Zach Reizner38f0fd92016-02-18 14:28:02 -080031 "precision mediump float;\n"
32 "varying vec4 vFillColor;\n"
33 "void main() {\n"
34 " gl_FragColor = vFillColor;\n"
35 "}\n";
Lauri Peltonen763ca462014-12-17 12:22:21 -080036
Zach Reizner4dfdf602016-03-01 13:06:30 -080037 struct bs_gl_program_create_binding bindings[] = {
Gurchetan Singh3f82d6d2017-11-08 14:43:20 -080038 { 0, "vPosition" }, { 1, "vColor" }, { 0, NULL },
Zach Reizner4dfdf602016-03-01 13:06:30 -080039 };
Haixia Shie04ddfd2014-11-11 19:14:32 -080040
Zach Reizner4dfdf602016-03-01 13:06:30 -080041 return bs_gl_program_create_vert_frag_bind(vert, frag, bindings);
Haixia Shie04ddfd2014-11-11 19:14:32 -080042}
43
Lauri Peltonen95226da2014-12-18 16:39:54 -080044static float f(int i)
45{
Haixia Shie04ddfd2014-11-11 19:14:32 -080046 int a = i % 40;
47 int b = (i / 40) % 6;
48 switch (b) {
Zach Reizner38f0fd92016-02-18 14:28:02 -080049 case 0:
50 case 1:
51 return 0.0f;
52 case 3:
53 case 4:
54 return 1.0f;
55 case 2:
56 return (a / 40.0f);
57 case 5:
58 return 1.0f - (a / 40.0f);
59 default:
60 return 0.0f;
Haixia Shie04ddfd2014-11-11 19:14:32 -080061 }
62}
63
Zach Reizner38f0fd92016-02-18 14:28:02 -080064static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
65 void *data)
Haixia Shi4652b8c2014-11-19 17:55:38 -080066{
67 int *waiting_for_flip = data;
68 *waiting_for_flip = 0;
69}
70
Daniele Castagna72729122017-10-18 17:09:36 -040071static uint32_t find_format(char *fourcc)
72{
73 if (!fourcc || strlen(fourcc) < 4)
74 return 0;
75
76 uint32_t format = fourcc_code(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
77 for (int i = 0; i < allowed_formats_length; i++) {
78 if (allowed_formats[i] == format)
79 return format;
80 }
81
82 return 0;
83}
84
Daniele Castagna8a63a602016-10-10 18:43:29 -040085static const struct option longopts[] = {
Daniele Castagna72729122017-10-18 17:09:36 -040086 { "format", required_argument, NULL, 'f' },
Fritz Koenig01ee3d42018-11-07 10:42:17 -080087 { "modifier", required_argument, NULL, 'm' },
Daniele Castagna72729122017-10-18 17:09:36 -040088 { "test-page-flip-format-change", required_argument, NULL, 'p' },
Miguel Casasab04f3e2019-03-21 14:40:37 -040089 { "banding", no_argument, NULL, 'b' },
Daniele Castagna8a63a602016-10-10 18:43:29 -040090 { "help", no_argument, NULL, 'h' },
91 { 0, 0, 0, 0 },
92};
93
Fritz Koenig01ee3d42018-11-07 10:42:17 -080094static void print_help(const char *argv0, int fd)
Daniele Castagna8a63a602016-10-10 18:43:29 -040095{
Daniele Castagna72729122017-10-18 17:09:36 -040096 char allowed_formats_string[allowed_formats_length * 6];
97 int i;
98 for (i = 0; i < allowed_formats_length; i++) {
99 uint32_t format = allowed_formats[i];
100 sprintf(allowed_formats_string + i * 6, "%.4s, ", (char *)&format);
101 }
102
103 allowed_formats_string[i * 6 - 2] = 0;
104
Daniele Castagna8a63a602016-10-10 18:43:29 -0400105 // clang-format off
106 printf("usage: %s [OPTIONS] [drm_device_path]\n", argv0);
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800107 printf(" -f, --format <format> defines the fb format.\n");
108 printf(" -m, --modifier <modifier> pass modifiers.\n");
109 printf(" -p, --test-page-flip-format-change <format> test page flips alternating formats.\n");
Miguel Casasab04f3e2019-03-21 14:40:37 -0400110 printf(" -b, --banding show a pattern that makes banding easy to spot if present.\n");
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800111 printf(" -h, --help show help\n");
Daniele Castagna8a63a602016-10-10 18:43:29 -0400112 printf("\n");
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800113 printf(" <format> must be one of [ %s ].\n", allowed_formats_string);
114 printf(" <modifier> must be one of ");
115 bs_print_supported_modifiers(fd);
Daniele Castagna72729122017-10-18 17:09:36 -0400116 printf("\n");
Daniele Castagna8a63a602016-10-10 18:43:29 -0400117 printf("\n");
118 // clang-format on
119}
120
Zach Reizner38f0fd92016-02-18 14:28:02 -0800121int main(int argc, char **argv)
Haixia Shie04ddfd2014-11-11 19:14:32 -0800122{
Zach Reizner38f0fd92016-02-18 14:28:02 -0800123 int fd = -1;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400124 bool help_flag = false;
Daniele Castagna72729122017-10-18 17:09:36 -0400125 uint32_t format = GBM_FORMAT_XRGB8888;
Daniele Castagna95d027f2017-11-01 21:56:58 -0400126 uint32_t test_page_flip_format_change = 0;
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800127 uint64_t modifier = DRM_FORMAT_MOD_INVALID;
Miguel Casasab04f3e2019-03-21 14:40:37 -0400128 bool banding_pattern = false;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400129
130 int c = -1;
Miguel Casasab04f3e2019-03-21 14:40:37 -0400131 while ((c = getopt_long(argc, argv, "m:hp:f:b", longopts, NULL)) != -1) {
Daniele Castagna8a63a602016-10-10 18:43:29 -0400132 switch (c) {
Daniele Castagna72729122017-10-18 17:09:36 -0400133 case 'p':
134 test_page_flip_format_change = find_format(optarg);
135 if (!test_page_flip_format_change)
136 help_flag = true;
137 break;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400138 case 'f':
Daniele Castagna72729122017-10-18 17:09:36 -0400139 format = find_format(optarg);
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800140 if (!format) {
141 bs_debug_error("unsupported format: %s", optarg);
Daniele Castagna72729122017-10-18 17:09:36 -0400142 help_flag = true;
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800143 }
144 break;
145 case 'm':
146 modifier = bs_string_to_modifier(optarg);
147 if (modifier == -1) {
148 bs_debug_error("unsupported modifier: %s", optarg);
149 help_flag = true;
150 }
Daniele Castagna8a63a602016-10-10 18:43:29 -0400151 break;
Miguel Casasab04f3e2019-03-21 14:40:37 -0400152 case 'b':
153 banding_pattern = true;
154 break;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400155 case 'h':
156 help_flag = true;
157 break;
158 }
159 }
160
Daniele Castagna8a63a602016-10-10 18:43:29 -0400161 if (optind < argc) {
162 fd = open(argv[optind], O_RDWR);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800163 if (fd < 0) {
Daniele Castagna8a63a602016-10-10 18:43:29 -0400164 bs_debug_error("failed to open card %s", argv[optind]);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800165 return 1;
166 }
Zach Reiznerbf26be82016-09-15 16:06:21 -0700167 } else {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800168 fd = bs_drm_open_main_display();
169 if (fd < 0) {
170 bs_debug_error("failed to open card for display");
171 return 1;
172 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800173 }
174
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800175 if (help_flag) {
176 print_help(*argv, fd);
177 close(fd);
178 return 1;
179 }
180
Zach Reizner38f0fd92016-02-18 14:28:02 -0800181 struct gbm_device *gbm = gbm_create_device(fd);
182 if (!gbm) {
183 bs_debug_error("failed to create gbm");
184 return 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800185 }
186
Zach Reizner4dfdf602016-03-01 13:06:30 -0800187 struct bs_drm_pipe pipe = { 0 };
Zach Reizner38f0fd92016-02-18 14:28:02 -0800188 if (!bs_drm_pipe_make(fd, &pipe)) {
189 bs_debug_error("failed to make pipe");
190 return 1;
191 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800192
Zach Reizner38f0fd92016-02-18 14:28:02 -0800193 drmModeConnector *connector = drmModeGetConnector(fd, pipe.connector_id);
194 assert(connector);
195 drmModeModeInfo *mode = &connector->modes[0];
196
197 struct bs_egl *egl = bs_egl_new();
198 if (!bs_egl_setup(egl)) {
199 bs_debug_error("failed to setup egl context");
200 return 1;
201 }
202
Gurchetan Singh10008e62017-03-09 11:14:38 -0800203 struct gbm_bo *bos[NUM_BUFFERS];
204 uint32_t ids[NUM_BUFFERS];
205 struct bs_egl_fb *egl_fbs[NUM_BUFFERS];
206 EGLImageKHR egl_images[NUM_BUFFERS];
207 for (size_t fb_index = 0; fb_index < NUM_BUFFERS; fb_index++) {
Daniele Castagna8a63a602016-10-10 18:43:29 -0400208 if (test_page_flip_format_change && fb_index) {
Daniele Castagna72729122017-10-18 17:09:36 -0400209 format = test_page_flip_format_change;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400210 }
211
Fritz Koenig01ee3d42018-11-07 10:42:17 -0800212 if (modifier != DRM_FORMAT_MOD_INVALID) {
213 bos[fb_index] = gbm_bo_create_with_modifiers(
214 gbm, mode->hdisplay, mode->vdisplay, format, &modifier, 1);
215 } else {
216 bos[fb_index] = gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, format,
217 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
218 }
219
Zach Reizner38f0fd92016-02-18 14:28:02 -0800220 if (bos[fb_index] == NULL) {
221 bs_debug_error("failed to allocate framebuffer");
222 return 1;
223 }
224
225 ids[fb_index] = bs_drm_fb_create_gbm(bos[fb_index]);
226 if (ids[fb_index] == 0) {
227 bs_debug_error("failed to create framebuffer id");
228 return 1;
229 }
230
231 EGLImageKHR egl_image = bs_egl_image_create_gbm(egl, bos[fb_index]);
232 if (egl_image == EGL_NO_IMAGE_KHR) {
233 bs_debug_error("failed to create EGLImageKHR from framebuffer");
234 return 1;
235 }
236
237 egl_fbs[fb_index] = bs_egl_fb_new(egl, egl_image);
238 if (!egl_fbs[fb_index]) {
239 bs_debug_error("failed to create framebuffer from EGLImageKHR");
240 return 1;
241 }
Haixia Shife4e2ff2016-10-17 14:28:55 -0700242 egl_images[fb_index] = egl_image;
Zach Reizner38f0fd92016-02-18 14:28:02 -0800243 }
244
245 int ret = drmModeSetCrtc(fd, pipe.crtc_id, ids[0], 0 /* x */, 0 /* y */, &pipe.connector_id,
246 1 /* connector count */, mode);
247 if (ret) {
248 bs_debug_error("failed to set CRTC");
249 return 1;
250 }
251
252 GLuint program = solid_shader_create();
Haixia Shie04ddfd2014-11-11 19:14:32 -0800253 if (!program) {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800254 bs_debug_error("failed to create solid shader");
255 return 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800256 }
257
Miguel Casasab04f3e2019-03-21 14:40:37 -0400258 // clang-format off
259 const GLfloat triangle_vertices[] = {
Haixia Shie04ddfd2014-11-11 19:14:32 -0800260 0.0f, -0.5f, 0.0f,
261 -0.5f, 0.5f, 0.0f,
262 0.5f, 0.5f, 0.0f
263 };
Miguel Casasab04f3e2019-03-21 14:40:37 -0400264 const GLfloat triangle_colors[] = {
Haixia Shie04ddfd2014-11-11 19:14:32 -0800265 1.0f, 0.0f, 0.0f, 1.0f,
266 0.0f, 1.0f, 0.0f, 1.0f,
267 0.0f, 0.0f, 1.0f, 1.0f
268 };
Miguel Casasab04f3e2019-03-21 14:40:37 -0400269 const GLfloat square_vertices[] = {
270 -1.0f, -1.0f, 0.0f,
271 1.0f, -1.0f, 0.0f,
272 -1.0f, 1.0f, 0.0f,
273 1.0f, 1.0f, 0.0f,
274 };
275 const GLfloat square_colors[] = {
276 0.05f, 0.05f, 0.05f, 1.0f,
277 0.05f, 0.05f, 0.05f, 1.0f,
278 0.45f, 0.45f, 0.45f, 1.0f,
279 0.45f, 0.45f, 0.45f, 1.0f,
280 };
281 // clang-format on
282
283 int fb_idx = 1;
284 for (int i = 0; i <= 500; i++) {
285 int waiting_for_flip = 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800286
Zach Reizner38f0fd92016-02-18 14:28:02 -0800287 glBindFramebuffer(GL_FRAMEBUFFER, bs_egl_fb_name(egl_fbs[fb_idx]));
288 glViewport(0, 0, (GLint)mode->hdisplay, (GLint)mode->vdisplay);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800289
Haixia Shie04ddfd2014-11-11 19:14:32 -0800290 glClearColor(f(i), f(i + 80), f(i + 160), 0.0f);
291 glClear(GL_COLOR_BUFFER_BIT);
292
293 glUseProgram(program);
Miguel Casasab04f3e2019-03-21 14:40:37 -0400294 if (banding_pattern) {
295 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, square_vertices);
296 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, square_colors);
297 } else {
298 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, triangle_vertices);
299 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, triangle_colors);
300 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800301 glEnableVertexAttribArray(0);
302 glEnableVertexAttribArray(1);
Miguel Casasab04f3e2019-03-21 14:40:37 -0400303 glDrawArrays(GL_TRIANGLE_STRIP, 0, banding_pattern ? 4 : 3);
Haixia Shie04ddfd2014-11-11 19:14:32 -0800304
305 usleep(1e6 / 120); /* 120 Hz */
306 glFinish();
Haixia Shife4e2ff2016-10-17 14:28:55 -0700307
308 if (!bs_egl_image_flush_external(egl, egl_images[fb_idx])) {
309 bs_debug_error("failed to call image_flush_external");
310 return 1;
311 }
312
Zach Reizner38f0fd92016-02-18 14:28:02 -0800313 ret = drmModePageFlip(fd, pipe.crtc_id, ids[fb_idx], DRM_MODE_PAGE_FLIP_EVENT,
314 &waiting_for_flip);
315 if (ret) {
316 bs_debug_error("failed page flip: %d", ret);
317 return 1;
318 }
Haixia Shi4652b8c2014-11-19 17:55:38 -0800319
320 while (waiting_for_flip) {
321 drmEventContext evctx = {
Zach Reizner4dfdf602016-03-01 13:06:30 -0800322 .version = DRM_EVENT_CONTEXT_VERSION,
323 .page_flip_handler = page_flip_handler,
Haixia Shi4652b8c2014-11-19 17:55:38 -0800324 };
325
326 fd_set fds;
327 FD_ZERO(&fds);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800328 FD_SET(fd, &fds);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800329
Zach Reizner38f0fd92016-02-18 14:28:02 -0800330 ret = select(fd + 1, &fds, NULL, NULL, NULL);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800331 if (ret < 0) {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800332 bs_debug_error("select err: %s", strerror(errno));
333 return 1;
Zach Reiznerbf26be82016-09-15 16:06:21 -0700334 } else if (ret == 0) {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800335 bs_debug_error("select timeout");
336 return 1;
337 }
Zach Reizner38f0fd92016-02-18 14:28:02 -0800338 ret = drmHandleEvent(fd, &evctx);
339 if (ret) {
340 bs_debug_error("failed to wait for page flip: %d", ret);
341 return 1;
342 }
Haixia Shi4652b8c2014-11-19 17:55:38 -0800343 }
344 fb_idx = fb_idx ^ 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800345 }
346
Gurchetan Singh10008e62017-03-09 11:14:38 -0800347 for (size_t fb_index = 0; fb_index < NUM_BUFFERS; fb_index++) {
348 bs_egl_fb_destroy(&egl_fbs[fb_index]);
349 bs_egl_image_destroy(egl, &egl_images[fb_index]);
350 drmModeRmFB(fd, ids[fb_idx]);
351 gbm_bo_destroy(bos[fb_index]);
352 }
353
354 bs_egl_destroy(&egl);
355 gbm_device_destroy(gbm);
356 close(fd);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800357 return 0;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800358}