blob: 1fc47dca8733d0c3cf502e03499a6b787de3d946 [file] [log] [blame]
Yalong Liu1df84372018-01-24 17:10:12 +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 */
6
7#include <getopt.h>
8
9#include "bs_drm.h"
10
11#define BUFFERS 2
12#define NUM_FRAMES 0x40
13
14struct framebuffer {
15 struct gbm_bo *bo;
16 uint32_t id;
17};
18
19struct context {
20 int display_fd;
21 uint32_t crtc_id;
22
23 struct framebuffer fbs[BUFFERS];
24 struct bs_mapper *mapper;
25
26 int vgem_device_fd;
27};
28
29static void disable_psr()
30{
31 const char psr_path[] = "/sys/module/i915/parameters/enable_psr";
32 int psr_fd = open(psr_path, O_WRONLY);
33
34 if (psr_fd < 0)
35 return;
36
37 if (write(psr_fd, "0", 1) == -1) {
38 bs_debug_error("failed to disable psr");
39 } else {
40 printf("disabled psr");
41 }
42
43 close(psr_fd);
44}
45
46static void do_fixes()
47{
48 disable_psr();
49}
50
51#define STEP_SKIP 0
52#define STEP_MMAP 1
53#define STEP_FAULT 2
54#define STEP_FLIP 3
55#define STEP_DRAW 4
56
57static void show_sequence(const int *sequence)
58{
59 int sequence_subindex;
60 printf("starting sequence: ");
61 for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
62 switch (sequence[sequence_subindex]) {
63 case STEP_SKIP:
64 break;
65 case STEP_MMAP:
66 printf("mmap ");
67 break;
68 case STEP_FAULT:
69 printf("fault ");
70 break;
71 case STEP_FLIP:
72 printf("flip ");
73 break;
74 case STEP_DRAW:
75 printf("draw ");
76 break;
77 default:
78 bs_debug_error("<unknown step %d> (aborting!)",
79 sequence[sequence_subindex]);
80 abort();
81 break;
82 }
83 }
84 printf("\n");
85}
86
87static void draw(struct context *ctx)
88{
89 // Run the drawing routine with the key driver events in different
90 // sequences.
91 const int sequences[4][4] = {
92 { STEP_MMAP, STEP_FAULT, STEP_FLIP, STEP_DRAW },
93 { STEP_MMAP, STEP_FLIP, STEP_DRAW, STEP_SKIP },
94 { STEP_MMAP, STEP_DRAW, STEP_FLIP, STEP_SKIP },
95 { STEP_FLIP, STEP_MMAP, STEP_DRAW, STEP_SKIP },
96 };
97
98 int sequence_index = 0;
99 int sequence_subindex = 0;
100
101 int fb_idx = 1;
102
103 for (sequence_index = 0; sequence_index < 4; sequence_index++) {
104 show_sequence(sequences[sequence_index]);
Yalong Liu257f41b2018-05-04 10:15:20 +0800105 for (int frame_index = 0; frame_index < NUM_FRAMES; frame_index += 2) {
Yalong Liu1df84372018-01-24 17:10:12 +0800106 struct framebuffer *fb = &ctx->fbs[fb_idx];
107 size_t bo_stride = gbm_bo_get_plane_stride(fb->bo, 0);
108 size_t bo_size = gbm_bo_get_plane_size(fb->bo, 0);
109 const uint32_t width = gbm_bo_get_width(fb->bo);
110 const uint32_t height = gbm_bo_get_height(fb->bo);
111 uint32_t *bo_ptr;
112 volatile uint32_t *ptr;
113 void *map_data;
114
115 for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
116 switch (sequences[sequence_index][sequence_subindex]) {
117 case STEP_MMAP:
118 bo_ptr = bs_mapper_map(ctx->mapper, fb->bo, 0,
119 &map_data);
120 if (bo_ptr == MAP_FAILED)
121 bs_debug_error("failed to mmap gbm bo");
122
123 ptr = bo_ptr;
124 break;
125
126 case STEP_FAULT:
127 *ptr = 1234567;
128 break;
129
130 case STEP_FLIP:
131 drmModePageFlip(ctx->display_fd, ctx->crtc_id,
132 ctx->fbs[fb_idx].id, 0, NULL);
133 break;
134
135 case STEP_DRAW:
136 for (ptr = bo_ptr;
137 ptr < bo_ptr + (bo_size / sizeof(*bo_ptr));
138 ptr++) {
139 int y = ((void *)ptr - (void *)bo_ptr) /
140 bo_stride;
141 int x = ((void *)ptr - (void *)bo_ptr -
142 bo_stride * y) /
143 sizeof(*ptr);
144 x -= frame_index * (width / NUM_FRAMES);
145 y -= frame_index * (height / NUM_FRAMES);
146 *ptr = 0xff000000;
147 if (x * x + y * y <
148 frame_index * frame_index)
149 *ptr |= (frame_index % 0x100) << 8;
150 else
151 *ptr |= 0xff |
152 (sequence_index * 64 << 16);
153 }
154 break;
155
156 case STEP_SKIP:
157 default:
158 break;
159 }
160 }
161
162 bs_mapper_unmap(ctx->mapper, fb->bo, map_data);
163
164 usleep(1e6 / 120); /* 120 Hz */
165
166 fb_idx = fb_idx ^ 1;
167 }
168 }
169}
170
171static const struct option longopts[] = {
172 { "help", no_argument, NULL, 'h' },
173 { "dma-buf", no_argument, NULL, 'b' },
174 { "gem", no_argument, NULL, 'g' },
175 { "dumb", no_argument, NULL, 'd' },
176 { "vgem", no_argument, NULL, 'v' },
177 { "scanout", no_argument, NULL, 's' },
178 { 0, 0, 0, 0 },
179};
180
181static void print_help(const char *argv0)
182{
183 printf("Usage: %s [OPTIONS]\n", argv0);
184 printf(" -h, --help Print help.\n");
185 printf(" -b, --dma-buf Use dma-buf mmap (by default).\n");
186 printf(" -g, --gem Use GEM map.\n");
187 printf(" -d, --dumb Use dump map.\n");
188 printf(" -v, --vgem Use vgem dump map.\n");
189 printf(" -s, --scanout Use buffer optimized for scanout.\n");
190}
191
192int main(int argc, char **argv)
193{
194 struct context ctx = { 0 };
195
196 do_fixes();
197
198 ctx.display_fd = bs_drm_open_main_display();
199 if (ctx.display_fd < 0) {
200 bs_debug_error("failed to open card for display");
201 return 1;
202 }
203
204 struct gbm_device *gbm = gbm_create_device(ctx.display_fd);
205 if (!gbm) {
206 bs_debug_error("failed to create gbm device");
207 return 1;
208 }
209
210 int c;
211 uint32_t flags = GBM_BO_USE_SCANOUT;
212 while ((c = getopt_long(argc, argv, "bgdvsh", longopts, NULL)) != -1) {
213 switch (c) {
214 case 'b':
215 ctx.mapper = bs_mapper_dma_buf_new();
216 flags |= GBM_BO_USE_LINEAR;
217 printf("started dma-buf mmap.\n");
218 break;
219 case 'g':
220 ctx.mapper = bs_mapper_gem_new();
221 flags |= GBM_BO_USE_SW_READ_OFTEN | GBM_BO_USE_SW_WRITE_OFTEN;
222 printf("started GEM map.\n");
223 break;
224 case 'd':
225 ctx.mapper = bs_mapper_dumb_new(gbm_device_get_fd(gbm));
226 flags |= GBM_BO_USE_LINEAR;
227 printf("started dumb map.\n");
228 break;
229 case 'v':
230 ctx.vgem_device_fd = bs_drm_open_vgem();
231 ctx.mapper = bs_mapper_dumb_new(ctx.vgem_device_fd);
232 printf("started vgem map.\n");
233 break;
234 case 's':
235 flags = GBM_BO_USE_SCANOUT;
236 break;
237 case 'h':
238 default:
239 print_help(argv[0]);
240 return 1;
241 }
242 }
243
244 // Use dma-buf mmap by default, in case any arguments aren't selected.
245 if (!ctx.mapper) {
246 ctx.mapper = bs_mapper_dma_buf_new();
Yalong Liu257f41b2018-05-04 10:15:20 +0800247 flags |= GBM_BO_USE_LINEAR;
Yalong Liu1df84372018-01-24 17:10:12 +0800248 printf("started dma-buf mmap.\n");
249 }
250
251 if (ctx.mapper == NULL) {
252 bs_debug_error("failed to create mapper object");
253 return 1;
254 }
255
256 struct bs_drm_pipe pipe = { 0 };
257 if (!bs_drm_pipe_make(ctx.display_fd, &pipe)) {
258 bs_debug_error("failed to make pipe");
259 return 1;
260 }
261
262 drmModeConnector *connector = drmModeGetConnector(ctx.display_fd, pipe.connector_id);
263 drmModeModeInfo *mode = &connector->modes[0];
264 ctx.crtc_id = pipe.crtc_id;
265
266 printf("display size: %ux%u\n", mode->hdisplay, mode->vdisplay);
267
268 for (size_t fb_index = 0; fb_index < BUFFERS; ++fb_index) {
269 struct framebuffer *fb = &ctx.fbs[fb_index];
270 fb->bo =
271 gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, GBM_FORMAT_XRGB8888, flags);
272
273 if (!fb->bo) {
274 bs_debug_error("failed to create buffer object");
275 return 1;
276 }
277
278 fb->id = bs_drm_fb_create_gbm(fb->bo);
279 if (fb->id == 0) {
280 bs_debug_error("failed to create fb");
281 return 1;
282 }
283 }
284
285 if (drmModeSetCrtc(ctx.display_fd, pipe.crtc_id, ctx.fbs[0].id, 0, 0, &pipe.connector_id, 1,
286 mode)) {
287 bs_debug_error("failed to set CRTC");
288 return 1;
289 }
290
291 draw(&ctx);
292
293 return 0;
294}