blob: d663528aef81bc187e5fc710a5cb69cdc8a0a5b8 [file] [log] [blame]
Zach Reiznerc09812f2015-01-12 16:49:49 -08001/*
Dongseong Hwang59ff9f92016-04-22 17:39:32 +03002 * Copyright 2017 The Chromium OS Authors. All rights reserved.
Zach Reiznerc09812f2015-01-12 16:49:49 -08003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Dongseong Hwang59ff9f92016-04-22 17:39:32 +03007#include <getopt.h>
8
Zach Reizner7d849892016-02-24 17:30:27 -08009#include "bs_drm.h"
Zach Reiznerc09812f2015-01-12 16:49:49 -080010
11#define BUFFERS 2
12
Zach Reizner7d849892016-02-24 17:30:27 -080013struct framebuffer {
14 struct gbm_bo *bo;
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030015 int drm_prime_fd;
Zach Reizner7d849892016-02-24 17:30:27 -080016 uint32_t vgem_handle;
17 uint32_t id;
Zach Reiznerc09812f2015-01-12 16:49:49 -080018};
19
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030020struct context;
21typedef uint32_t *(*mmap_t)(struct context *ctx, struct framebuffer *fb, size_t size);
22
Zach Reizner7d849892016-02-24 17:30:27 -080023struct context {
24 int display_fd;
25 int vgem_fd;
26 uint32_t crtc_id;
27
28 struct framebuffer fbs[BUFFERS];
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030029 mmap_t mmap_fn;
Zach Reizner7d849892016-02-24 17:30:27 -080030};
31
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030032static void disable_psr()
Zach Reizner7d849892016-02-24 17:30:27 -080033{
Zach Reizner299fab72015-04-28 16:56:14 -070034 const char psr_path[] = "/sys/module/i915/parameters/enable_psr";
35 int psr_fd = open(psr_path, O_WRONLY);
36
37 if (psr_fd < 0)
38 return;
39
40 if (write(psr_fd, "0", 1) == -1) {
Zach Reizner7d849892016-02-24 17:30:27 -080041 bs_debug_error("failed to disable psr");
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030042 } else {
Zach Reizner7d849892016-02-24 17:30:27 -080043 printf("disabled psr");
Zach Reizner299fab72015-04-28 16:56:14 -070044 }
45
46 close(psr_fd);
47}
48
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030049static void do_fixes()
Zach Reizner7d849892016-02-24 17:30:27 -080050{
Zach Reizner299fab72015-04-28 16:56:14 -070051 disable_psr();
52}
53
Zach Reiznerc09812f2015-01-12 16:49:49 -080054#define STEP_SKIP 0
55#define STEP_MMAP 1
56#define STEP_FAULT 2
57#define STEP_FLIP 3
58#define STEP_DRAW 4
59
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030060static void show_sequence(const int *sequence)
Zach Reiznerc09812f2015-01-12 16:49:49 -080061{
62 int sequence_subindex;
Zach Reizner7d849892016-02-24 17:30:27 -080063 printf("starting sequence: ");
Zach Reiznerc09812f2015-01-12 16:49:49 -080064 for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
65 switch (sequence[sequence_subindex]) {
Zach Reizner7d849892016-02-24 17:30:27 -080066 case STEP_SKIP:
67 break;
68 case STEP_MMAP:
69 printf("mmap ");
70 break;
71 case STEP_FAULT:
72 printf("fault ");
73 break;
74 case STEP_FLIP:
75 printf("flip ");
76 break;
77 case STEP_DRAW:
78 printf("draw ");
79 break;
80 default:
81 bs_debug_error("<unknown step %d> (aborting!)",
82 sequence[sequence_subindex]);
83 abort();
84 break;
Zach Reiznerc09812f2015-01-12 16:49:49 -080085 }
86 }
Zach Reizner7d849892016-02-24 17:30:27 -080087 printf("\n");
Zach Reiznerc09812f2015-01-12 16:49:49 -080088}
89
Dongseong Hwang59ff9f92016-04-22 17:39:32 +030090static void draw(struct context *ctx)
Zach Reiznerc09812f2015-01-12 16:49:49 -080091{
Zach Reiznerc09812f2015-01-12 16:49:49 -080092 // Run the drawing routine with the key driver events in different
93 // sequences.
94 const int sequences[4][4] = {
95 { STEP_MMAP, STEP_FAULT, STEP_FLIP, STEP_DRAW },
Zach Reizner7d849892016-02-24 17:30:27 -080096 { STEP_MMAP, STEP_FLIP, STEP_DRAW, STEP_SKIP },
97 { STEP_MMAP, STEP_DRAW, STEP_FLIP, STEP_SKIP },
98 { STEP_FLIP, STEP_MMAP, STEP_DRAW, STEP_SKIP },
Zach Reiznerc09812f2015-01-12 16:49:49 -080099 };
100
101 int sequence_index = 0;
102 int sequence_subindex = 0;
103
104 int fb_idx = 1;
105
106 for (sequence_index = 0; sequence_index < 4; sequence_index++) {
107 show_sequence(sequences[sequence_index]);
Zach Reizner7d849892016-02-24 17:30:27 -0800108 for (int frame_index = 0; frame_index < 0x100; frame_index++) {
109 struct framebuffer *fb = &ctx->fbs[fb_idx];
110 size_t bo_stride = gbm_bo_get_stride(fb->bo);
111 size_t bo_size = bo_stride * gbm_bo_get_height(fb->bo);
Zach Reiznerc09812f2015-01-12 16:49:49 -0800112 uint32_t *bo_ptr;
113 volatile uint32_t *ptr;
114
115 for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
116 switch (sequences[sequence_index][sequence_subindex]) {
Zach Reizner7d849892016-02-24 17:30:27 -0800117 case STEP_MMAP:
Dongseong Hwang59ff9f92016-04-22 17:39:32 +0300118 bo_ptr = ctx->mmap_fn(ctx, fb, bo_size);
Zach Reizner7d849892016-02-24 17:30:27 -0800119 ptr = bo_ptr;
120 break;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800121
Zach Reizner7d849892016-02-24 17:30:27 -0800122 case STEP_FAULT:
123 *ptr = 1234567;
124 break;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800125
Zach Reizner7d849892016-02-24 17:30:27 -0800126 case STEP_FLIP:
127 drmModePageFlip(ctx->display_fd, ctx->crtc_id,
128 ctx->fbs[fb_idx].id, 0, NULL);
129 break;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800130
Zach Reizner7d849892016-02-24 17:30:27 -0800131 case STEP_DRAW:
132 for (ptr = bo_ptr;
133 ptr < bo_ptr + (bo_size / sizeof(*bo_ptr));
134 ptr++) {
135 int y = ((void *)ptr - (void *)bo_ptr) /
136 bo_stride;
137 int x = ((void *)ptr - (void *)bo_ptr -
138 bo_stride * y) /
139 sizeof(*ptr);
140 x -= 100;
141 y -= 100;
142 *ptr = 0xff000000;
143 if (x * x + y * y <
144 frame_index * frame_index)
145 *ptr |= (frame_index % 0x100) << 8;
146 else
147 *ptr |= 0xff |
148 (sequence_index * 64 << 16);
149 }
150 break;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800151
Zach Reizner7d849892016-02-24 17:30:27 -0800152 case STEP_SKIP:
153 default:
154 break;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800155 }
156 }
157
158 munmap(bo_ptr, bo_size);
159
160 usleep(1e6 / 120); /* 120 Hz */
161
162 fb_idx = fb_idx ^ 1;
163 }
164 }
165}
166
Dongseong Hwang59ff9f92016-04-22 17:39:32 +0300167static int create_vgem(struct context *ctx)
168{
169 ctx->vgem_fd = bs_drm_open_vgem();
170 if (ctx->vgem_fd < 0)
171 return 1;
172 return 0;
173}
174
175static int vgem_prime_fd_to_handle(struct context *ctx, struct framebuffer *fb)
176{
177 int ret = drmPrimeFDToHandle(ctx->vgem_fd, fb->drm_prime_fd, &fb->vgem_handle);
178 if (ret)
179 return 1;
180 return 0;
181}
182
183static uint32_t *vgem_mmap_internal(struct context *ctx, struct framebuffer *fb, size_t size)
184{
185 return bs_dumb_mmap(ctx->vgem_fd, fb->vgem_handle, size);
186}
187
188static uint32_t *dma_buf_mmap_internal(struct context *ctx, struct framebuffer *fb, size_t size)
189{
190 return bs_dma_buf_mmap(fb->bo);
191}
192
193static const struct option longopts[] = {
194 { "help", no_argument, NULL, 'h' },
195 { "use_vgem", no_argument, NULL, 'v' },
196 { "use_dma_buf", no_argument, NULL, 'd' },
197 { 0, 0, 0, 0 },
198};
199
200static void print_help(const char *argv0)
201{
202 const char help_text[] =
203 "Usage: %s [OPTIONS]\n"
204 " -h, --help\n"
205 " Print help.\n"
206 " -d, --use_dma_buf\n"
207 " Use dma_buf mmap.\n"
208 " -v, --use_vgem\n"
209 " Use vgem mmap.\n";
210 printf(help_text, argv0);
211}
212
Zach Reiznerc09812f2015-01-12 16:49:49 -0800213int main(int argc, char **argv)
214{
Zach Reizner7d849892016-02-24 17:30:27 -0800215 struct context ctx = { 0 };
Zach Reiznerc09812f2015-01-12 16:49:49 -0800216
Dongseong Hwang59ff9f92016-04-22 17:39:32 +0300217 bool is_vgem_test = false;
218 bool is_help = false;
219 ctx.mmap_fn = dma_buf_mmap_internal;
220 int c;
221 while ((c = getopt_long(argc, argv, "vdh", longopts, NULL)) != -1) {
222 switch (c) {
223 case 'v':
224 ctx.mmap_fn = vgem_mmap_internal;
225 is_vgem_test = true;
226 break;
227 case 'd':
228 break;
229 case 'h':
230 default:
231 is_help = true;
232 break;
233 }
234 }
235
236 if (is_help) {
237 print_help(argv[0]);
238 return 1;
239 }
240
241 if (is_vgem_test) {
242 printf("started vgem mmap test.\n");
243 } else {
244 printf("started dma_buf mmap test.\n");
245 }
246
Zach Reizner299fab72015-04-28 16:56:14 -0700247 do_fixes();
248
Zach Reizner7d849892016-02-24 17:30:27 -0800249 ctx.display_fd = bs_drm_open_main_display();
250 if (ctx.display_fd < 0) {
251 bs_debug_error("failed to open card for display");
252 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800253 }
254
Dongseong Hwang59ff9f92016-04-22 17:39:32 +0300255 if (is_vgem_test && create_vgem(&ctx)) {
Zach Reizner7d849892016-02-24 17:30:27 -0800256 bs_debug_error("failed to open vgem card");
257 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800258 }
259
Zach Reizner7d849892016-02-24 17:30:27 -0800260 struct gbm_device *gbm = gbm_create_device(ctx.display_fd);
261 if (!gbm) {
262 bs_debug_error("failed to create gbm device");
263 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800264 }
265
Zach Reizner7d849892016-02-24 17:30:27 -0800266 struct bs_drm_pipe pipe = { 0 };
267 if (!bs_drm_pipe_make(ctx.display_fd, &pipe)) {
268 bs_debug_error("failed to make pipe");
269 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800270 }
271
Zach Reizner7d849892016-02-24 17:30:27 -0800272 drmModeConnector *connector = drmModeGetConnector(ctx.display_fd, pipe.connector_id);
273 drmModeModeInfo *mode = &connector->modes[0];
274 ctx.crtc_id = pipe.crtc_id;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800275
Zach Reizner7d849892016-02-24 17:30:27 -0800276 printf("display size: %ux%u\n", mode->hdisplay, mode->vdisplay);
Zach Reiznerc09812f2015-01-12 16:49:49 -0800277
Zach Reizner7d849892016-02-24 17:30:27 -0800278 for (size_t fb_index = 0; fb_index < BUFFERS; ++fb_index) {
279 struct framebuffer *fb = &ctx.fbs[fb_index];
280 fb->bo = gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, GBM_FORMAT_XRGB8888,
Dongseong Hwangd4a34122016-04-25 15:46:32 +0300281 GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
Zach Reiznerc09812f2015-01-12 16:49:49 -0800282
Zach Reizner7d849892016-02-24 17:30:27 -0800283 if (!fb->bo) {
284 bs_debug_error("failed to create buffer object");
285 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800286 }
287
Zach Reizner7d849892016-02-24 17:30:27 -0800288 fb->id = bs_drm_fb_create_gbm(fb->bo);
289 if (fb->id == 0) {
290 bs_debug_error("failed to create fb");
291 return 1;
292 }
Zach Reiznerc09812f2015-01-12 16:49:49 -0800293
Dongseong Hwang59ff9f92016-04-22 17:39:32 +0300294 fb->drm_prime_fd = gbm_bo_get_fd(fb->bo);
295 if (fb->drm_prime_fd < 0) {
Zach Reizner7d849892016-02-24 17:30:27 -0800296 bs_debug_error("failed to turn handle into fd");
297 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800298 }
299
Dongseong Hwang59ff9f92016-04-22 17:39:32 +0300300 if (is_vgem_test && vgem_prime_fd_to_handle(&ctx, fb)) {
Zach Reizner7d849892016-02-24 17:30:27 -0800301 bs_debug_error("failed to import handle");
302 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800303 }
304 }
305
Zach Reizner7d849892016-02-24 17:30:27 -0800306 if (drmModeSetCrtc(ctx.display_fd, pipe.crtc_id, ctx.fbs[0].id, 0, 0, &pipe.connector_id, 1,
307 mode)) {
308 bs_debug_error("failed to set CRTC");
309 return 1;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800310 }
311
312 draw(&ctx);
313
Zach Reizner7d849892016-02-24 17:30:27 -0800314 return 0;
Zach Reiznerc09812f2015-01-12 16:49:49 -0800315}