blob: fb2da6661eabbef551c9a2083e957ca685cbc082 [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[] = {
14 GBM_FORMAT_XRGB8888,
15 GBM_FORMAT_XBGR8888,
16 GBM_FORMAT_XRGB2101010,
17 GBM_FORMAT_XBGR2101010,
18};
19
20const size_t allowed_formats_length = BS_ARRAY_LEN(allowed_formats);
21
Zach Reizner4dfdf602016-03-01 13:06:30 -080022static GLuint solid_shader_create()
Haixia Shie04ddfd2014-11-11 19:14:32 -080023{
Zach Reizner4dfdf602016-03-01 13:06:30 -080024 const GLchar *vert =
Zach Reizner38f0fd92016-02-18 14:28:02 -080025 "attribute vec4 vPosition;\n"
26 "attribute vec4 vColor;\n"
27 "varying vec4 vFillColor;\n"
28 "void main() {\n"
29 " gl_Position = vPosition;\n"
30 " vFillColor = vColor;\n"
31 "}\n";
Haixia Shie04ddfd2014-11-11 19:14:32 -080032
Zach Reizner4dfdf602016-03-01 13:06:30 -080033 const GLchar *frag =
Zach Reizner38f0fd92016-02-18 14:28:02 -080034 "precision mediump float;\n"
35 "varying vec4 vFillColor;\n"
36 "void main() {\n"
37 " gl_FragColor = vFillColor;\n"
38 "}\n";
Lauri Peltonen763ca462014-12-17 12:22:21 -080039
Zach Reizner4dfdf602016-03-01 13:06:30 -080040 struct bs_gl_program_create_binding bindings[] = {
Daniele Castagna72729122017-10-18 17:09:36 -040041 { 0, "vPosition" },
42 { 1, "vColor" },
43 { 0, NULL },
Zach Reizner4dfdf602016-03-01 13:06:30 -080044 };
Haixia Shie04ddfd2014-11-11 19:14:32 -080045
Zach Reizner4dfdf602016-03-01 13:06:30 -080046 return bs_gl_program_create_vert_frag_bind(vert, frag, bindings);
Haixia Shie04ddfd2014-11-11 19:14:32 -080047}
48
Lauri Peltonen95226da2014-12-18 16:39:54 -080049static float f(int i)
50{
Haixia Shie04ddfd2014-11-11 19:14:32 -080051 int a = i % 40;
52 int b = (i / 40) % 6;
53 switch (b) {
Zach Reizner38f0fd92016-02-18 14:28:02 -080054 case 0:
55 case 1:
56 return 0.0f;
57 case 3:
58 case 4:
59 return 1.0f;
60 case 2:
61 return (a / 40.0f);
62 case 5:
63 return 1.0f - (a / 40.0f);
64 default:
65 return 0.0f;
Haixia Shie04ddfd2014-11-11 19:14:32 -080066 }
67}
68
Zach Reizner38f0fd92016-02-18 14:28:02 -080069static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
70 void *data)
Haixia Shi4652b8c2014-11-19 17:55:38 -080071{
72 int *waiting_for_flip = data;
73 *waiting_for_flip = 0;
74}
75
Daniele Castagna72729122017-10-18 17:09:36 -040076static uint32_t find_format(char *fourcc)
77{
78 if (!fourcc || strlen(fourcc) < 4)
79 return 0;
80
81 uint32_t format = fourcc_code(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
82 for (int i = 0; i < allowed_formats_length; i++) {
83 if (allowed_formats[i] == format)
84 return format;
85 }
86
87 return 0;
88}
89
Daniele Castagna8a63a602016-10-10 18:43:29 -040090static const struct option longopts[] = {
Daniele Castagna72729122017-10-18 17:09:36 -040091 { "format", required_argument, NULL, 'f' },
92 { "test-page-flip-format-change", required_argument, NULL, 'p' },
Daniele Castagna8a63a602016-10-10 18:43:29 -040093 { "help", no_argument, NULL, 'h' },
94 { 0, 0, 0, 0 },
95};
96
97static void print_help(const char *argv0)
98{
Daniele Castagna72729122017-10-18 17:09:36 -040099 char allowed_formats_string[allowed_formats_length * 6];
100 int i;
101 for (i = 0; i < allowed_formats_length; i++) {
102 uint32_t format = allowed_formats[i];
103 sprintf(allowed_formats_string + i * 6, "%.4s, ", (char *)&format);
104 }
105
106 allowed_formats_string[i * 6 - 2] = 0;
107
Daniele Castagna8a63a602016-10-10 18:43:29 -0400108 // clang-format off
109 printf("usage: %s [OPTIONS] [drm_device_path]\n", argv0);
Daniele Castagna72729122017-10-18 17:09:36 -0400110 printf(" -f, --format <format> defines the fb format.\n");
111 printf(" -p, --test-page-flip-format-change <format> test page flips alternating formats.\n");
Daniele Castagna8a63a602016-10-10 18:43:29 -0400112 printf(" -h, --help show help\n");
113 printf("\n");
Daniele Castagna72729122017-10-18 17:09:36 -0400114 printf(" <format> must be one of [ %s ].\n", allowed_formats_string);
115 printf("\n");
Daniele Castagna8a63a602016-10-10 18:43:29 -0400116 printf("\n");
117 // clang-format on
118}
119
Zach Reizner38f0fd92016-02-18 14:28:02 -0800120int main(int argc, char **argv)
Haixia Shie04ddfd2014-11-11 19:14:32 -0800121{
Zach Reizner38f0fd92016-02-18 14:28:02 -0800122 int fd = -1;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400123 bool help_flag = false;
Daniele Castagna72729122017-10-18 17:09:36 -0400124 uint32_t format = GBM_FORMAT_XRGB8888;
125 uint32_t test_page_flip_format_change = GBM_FORMAT_XRGB8888;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400126
127 int c = -1;
Daniele Castagna72729122017-10-18 17:09:36 -0400128 while ((c = getopt_long(argc, argv, "hp:f:", longopts, NULL)) != -1) {
Daniele Castagna8a63a602016-10-10 18:43:29 -0400129 switch (c) {
Daniele Castagna72729122017-10-18 17:09:36 -0400130 case 'p':
131 test_page_flip_format_change = find_format(optarg);
132 if (!test_page_flip_format_change)
133 help_flag = true;
134 break;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400135 case 'f':
Daniele Castagna72729122017-10-18 17:09:36 -0400136 format = find_format(optarg);
137 if (!format)
138 help_flag = true;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400139 break;
140 case 'h':
141 help_flag = true;
142 break;
143 }
144 }
145
146 if (help_flag) {
147 print_help(*argv);
148 }
149
150 if (optind < argc) {
151 fd = open(argv[optind], O_RDWR);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800152 if (fd < 0) {
Daniele Castagna8a63a602016-10-10 18:43:29 -0400153 bs_debug_error("failed to open card %s", argv[optind]);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800154 return 1;
155 }
Zach Reiznerbf26be82016-09-15 16:06:21 -0700156 } else {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800157 fd = bs_drm_open_main_display();
158 if (fd < 0) {
159 bs_debug_error("failed to open card for display");
160 return 1;
161 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800162 }
163
Zach Reizner38f0fd92016-02-18 14:28:02 -0800164 struct gbm_device *gbm = gbm_create_device(fd);
165 if (!gbm) {
166 bs_debug_error("failed to create gbm");
167 return 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800168 }
169
Zach Reizner4dfdf602016-03-01 13:06:30 -0800170 struct bs_drm_pipe pipe = { 0 };
Zach Reizner38f0fd92016-02-18 14:28:02 -0800171 if (!bs_drm_pipe_make(fd, &pipe)) {
172 bs_debug_error("failed to make pipe");
173 return 1;
174 }
Haixia Shie04ddfd2014-11-11 19:14:32 -0800175
Zach Reizner38f0fd92016-02-18 14:28:02 -0800176 drmModeConnector *connector = drmModeGetConnector(fd, pipe.connector_id);
177 assert(connector);
178 drmModeModeInfo *mode = &connector->modes[0];
179
180 struct bs_egl *egl = bs_egl_new();
181 if (!bs_egl_setup(egl)) {
182 bs_debug_error("failed to setup egl context");
183 return 1;
184 }
185
Gurchetan Singh10008e62017-03-09 11:14:38 -0800186 struct gbm_bo *bos[NUM_BUFFERS];
187 uint32_t ids[NUM_BUFFERS];
188 struct bs_egl_fb *egl_fbs[NUM_BUFFERS];
189 EGLImageKHR egl_images[NUM_BUFFERS];
190 for (size_t fb_index = 0; fb_index < NUM_BUFFERS; fb_index++) {
Daniele Castagna8a63a602016-10-10 18:43:29 -0400191 if (test_page_flip_format_change && fb_index) {
Daniele Castagna72729122017-10-18 17:09:36 -0400192 format = test_page_flip_format_change;
Daniele Castagna8a63a602016-10-10 18:43:29 -0400193 }
194
Gurchetan Singh43380142017-03-09 10:45:01 -0800195 bos[fb_index] = gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, format,
196 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800197 if (bos[fb_index] == NULL) {
198 bs_debug_error("failed to allocate framebuffer");
199 return 1;
200 }
201
202 ids[fb_index] = bs_drm_fb_create_gbm(bos[fb_index]);
203 if (ids[fb_index] == 0) {
204 bs_debug_error("failed to create framebuffer id");
205 return 1;
206 }
207
208 EGLImageKHR egl_image = bs_egl_image_create_gbm(egl, bos[fb_index]);
209 if (egl_image == EGL_NO_IMAGE_KHR) {
210 bs_debug_error("failed to create EGLImageKHR from framebuffer");
211 return 1;
212 }
213
214 egl_fbs[fb_index] = bs_egl_fb_new(egl, egl_image);
215 if (!egl_fbs[fb_index]) {
216 bs_debug_error("failed to create framebuffer from EGLImageKHR");
217 return 1;
218 }
Haixia Shife4e2ff2016-10-17 14:28:55 -0700219 egl_images[fb_index] = egl_image;
Zach Reizner38f0fd92016-02-18 14:28:02 -0800220 }
221
222 int ret = drmModeSetCrtc(fd, pipe.crtc_id, ids[0], 0 /* x */, 0 /* y */, &pipe.connector_id,
223 1 /* connector count */, mode);
224 if (ret) {
225 bs_debug_error("failed to set CRTC");
226 return 1;
227 }
228
229 GLuint program = solid_shader_create();
Haixia Shie04ddfd2014-11-11 19:14:32 -0800230 if (!program) {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800231 bs_debug_error("failed to create solid shader");
232 return 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800233 }
234
Haixia Shi4652b8c2014-11-19 17:55:38 -0800235 int fb_idx = 1;
Zach Reizner38f0fd92016-02-18 14:28:02 -0800236 for (int i = 0; i <= 500; i++) {
Haixia Shi4652b8c2014-11-19 17:55:38 -0800237 int waiting_for_flip = 1;
Zach Reizner38f0fd92016-02-18 14:28:02 -0800238 // clang-format off
Haixia Shie04ddfd2014-11-11 19:14:32 -0800239 GLfloat verts[] = {
240 0.0f, -0.5f, 0.0f,
241 -0.5f, 0.5f, 0.0f,
242 0.5f, 0.5f, 0.0f
243 };
244 GLfloat colors[] = {
245 1.0f, 0.0f, 0.0f, 1.0f,
246 0.0f, 1.0f, 0.0f, 1.0f,
247 0.0f, 0.0f, 1.0f, 1.0f
248 };
Zach Reizner38f0fd92016-02-18 14:28:02 -0800249 // clang-format on
Haixia Shie04ddfd2014-11-11 19:14:32 -0800250
Zach Reizner38f0fd92016-02-18 14:28:02 -0800251 glBindFramebuffer(GL_FRAMEBUFFER, bs_egl_fb_name(egl_fbs[fb_idx]));
252 glViewport(0, 0, (GLint)mode->hdisplay, (GLint)mode->vdisplay);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800253
Haixia Shie04ddfd2014-11-11 19:14:32 -0800254 glClearColor(f(i), f(i + 80), f(i + 160), 0.0f);
255 glClear(GL_COLOR_BUFFER_BIT);
256
257 glUseProgram(program);
258 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, verts);
259 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors);
260 glEnableVertexAttribArray(0);
261 glEnableVertexAttribArray(1);
262 glDrawArrays(GL_TRIANGLES, 0, 3);
263
264 usleep(1e6 / 120); /* 120 Hz */
265 glFinish();
Haixia Shife4e2ff2016-10-17 14:28:55 -0700266
267 if (!bs_egl_image_flush_external(egl, egl_images[fb_idx])) {
268 bs_debug_error("failed to call image_flush_external");
269 return 1;
270 }
271
Zach Reizner38f0fd92016-02-18 14:28:02 -0800272 ret = drmModePageFlip(fd, pipe.crtc_id, ids[fb_idx], DRM_MODE_PAGE_FLIP_EVENT,
273 &waiting_for_flip);
274 if (ret) {
275 bs_debug_error("failed page flip: %d", ret);
276 return 1;
277 }
Haixia Shi4652b8c2014-11-19 17:55:38 -0800278
279 while (waiting_for_flip) {
280 drmEventContext evctx = {
Zach Reizner4dfdf602016-03-01 13:06:30 -0800281 .version = DRM_EVENT_CONTEXT_VERSION,
282 .page_flip_handler = page_flip_handler,
Haixia Shi4652b8c2014-11-19 17:55:38 -0800283 };
284
285 fd_set fds;
286 FD_ZERO(&fds);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800287 FD_SET(fd, &fds);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800288
Zach Reizner38f0fd92016-02-18 14:28:02 -0800289 ret = select(fd + 1, &fds, NULL, NULL, NULL);
Haixia Shi4652b8c2014-11-19 17:55:38 -0800290 if (ret < 0) {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800291 bs_debug_error("select err: %s", strerror(errno));
292 return 1;
Zach Reiznerbf26be82016-09-15 16:06:21 -0700293 } else if (ret == 0) {
Zach Reizner38f0fd92016-02-18 14:28:02 -0800294 bs_debug_error("select timeout");
295 return 1;
296 }
Zach Reizner38f0fd92016-02-18 14:28:02 -0800297 ret = drmHandleEvent(fd, &evctx);
298 if (ret) {
299 bs_debug_error("failed to wait for page flip: %d", ret);
300 return 1;
301 }
Haixia Shi4652b8c2014-11-19 17:55:38 -0800302 }
303 fb_idx = fb_idx ^ 1;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800304 }
305
Gurchetan Singh10008e62017-03-09 11:14:38 -0800306 for (size_t fb_index = 0; fb_index < NUM_BUFFERS; fb_index++) {
307 bs_egl_fb_destroy(&egl_fbs[fb_index]);
308 bs_egl_image_destroy(egl, &egl_images[fb_index]);
309 drmModeRmFB(fd, ids[fb_idx]);
310 gbm_bo_destroy(bos[fb_index]);
311 }
312
313 bs_egl_destroy(&egl);
314 gbm_device_destroy(gbm);
315 close(fd);
Zach Reizner38f0fd92016-02-18 14:28:02 -0800316 return 0;
Haixia Shie04ddfd2014-11-11 19:14:32 -0800317}