Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 1 | /* |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 2 | * Copyright 2017 The Chromium OS Authors. All rights reserved. |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 3 | * Use of this source code is governed by a BSD-style license that can be |
| 4 | * found in the LICENSE file. |
| 5 | */ |
| 6 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 7 | #include <getopt.h> |
| 8 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 9 | #include "bs_drm.h" |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 10 | |
| 11 | #define BUFFERS 2 |
| 12 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 13 | struct framebuffer { |
| 14 | struct gbm_bo *bo; |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 15 | int drm_prime_fd; |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 16 | uint32_t vgem_handle; |
| 17 | uint32_t id; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 18 | }; |
| 19 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 20 | struct context; |
| 21 | typedef uint32_t *(*mmap_t)(struct context *ctx, struct framebuffer *fb, size_t size); |
| 22 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 23 | struct context { |
| 24 | int display_fd; |
| 25 | int vgem_fd; |
| 26 | uint32_t crtc_id; |
| 27 | |
| 28 | struct framebuffer fbs[BUFFERS]; |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 29 | mmap_t mmap_fn; |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 30 | }; |
| 31 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 32 | static void disable_psr() |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 33 | { |
Zach Reizner | 299fab7 | 2015-04-28 16:56:14 -0700 | [diff] [blame] | 34 | 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 Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 41 | bs_debug_error("failed to disable psr"); |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 42 | } else { |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 43 | printf("disabled psr"); |
Zach Reizner | 299fab7 | 2015-04-28 16:56:14 -0700 | [diff] [blame] | 44 | } |
| 45 | |
| 46 | close(psr_fd); |
| 47 | } |
| 48 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 49 | static void do_fixes() |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 50 | { |
Zach Reizner | 299fab7 | 2015-04-28 16:56:14 -0700 | [diff] [blame] | 51 | disable_psr(); |
| 52 | } |
| 53 | |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 54 | #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 Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 60 | static void show_sequence(const int *sequence) |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 61 | { |
| 62 | int sequence_subindex; |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 63 | printf("starting sequence: "); |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 64 | for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) { |
| 65 | switch (sequence[sequence_subindex]) { |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 66 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 85 | } |
| 86 | } |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 87 | printf("\n"); |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 88 | } |
| 89 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 90 | static void draw(struct context *ctx) |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 91 | { |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 92 | // 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 Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 96 | { 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 99 | }; |
| 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 Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 108 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 112 | 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 Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 117 | case STEP_MMAP: |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 118 | bo_ptr = ctx->mmap_fn(ctx, fb, bo_size); |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 119 | ptr = bo_ptr; |
| 120 | break; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 121 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 122 | case STEP_FAULT: |
| 123 | *ptr = 1234567; |
| 124 | break; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 125 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 126 | case STEP_FLIP: |
| 127 | drmModePageFlip(ctx->display_fd, ctx->crtc_id, |
| 128 | ctx->fbs[fb_idx].id, 0, NULL); |
| 129 | break; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 130 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 131 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 151 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 152 | case STEP_SKIP: |
| 153 | default: |
| 154 | break; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 155 | } |
| 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 Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 167 | static 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 | |
| 175 | static 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 | |
| 183 | static 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 | |
| 188 | static 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 | |
| 193 | static 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 | |
| 200 | static 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 213 | int main(int argc, char **argv) |
| 214 | { |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 215 | struct context ctx = { 0 }; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 216 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 217 | 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 Reizner | 299fab7 | 2015-04-28 16:56:14 -0700 | [diff] [blame] | 247 | do_fixes(); |
| 248 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 249 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 253 | } |
| 254 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 255 | if (is_vgem_test && create_vgem(&ctx)) { |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 256 | bs_debug_error("failed to open vgem card"); |
| 257 | return 1; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 258 | } |
| 259 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 260 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 264 | } |
| 265 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 266 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 270 | } |
| 271 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 272 | drmModeConnector *connector = drmModeGetConnector(ctx.display_fd, pipe.connector_id); |
| 273 | drmModeModeInfo *mode = &connector->modes[0]; |
| 274 | ctx.crtc_id = pipe.crtc_id; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 275 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 276 | printf("display size: %ux%u\n", mode->hdisplay, mode->vdisplay); |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 277 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 278 | 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 Hwang | d4a3412 | 2016-04-25 15:46:32 +0300 | [diff] [blame] | 281 | GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR); |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 282 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 283 | if (!fb->bo) { |
| 284 | bs_debug_error("failed to create buffer object"); |
| 285 | return 1; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 286 | } |
| 287 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 288 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 293 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 294 | fb->drm_prime_fd = gbm_bo_get_fd(fb->bo); |
| 295 | if (fb->drm_prime_fd < 0) { |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 296 | bs_debug_error("failed to turn handle into fd"); |
| 297 | return 1; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 298 | } |
| 299 | |
Dongseong Hwang | 59ff9f9 | 2016-04-22 17:39:32 +0300 | [diff] [blame] | 300 | if (is_vgem_test && vgem_prime_fd_to_handle(&ctx, fb)) { |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 301 | bs_debug_error("failed to import handle"); |
| 302 | return 1; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 303 | } |
| 304 | } |
| 305 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 306 | 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 Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | draw(&ctx); |
| 313 | |
Zach Reizner | 7d84989 | 2016-02-24 17:30:27 -0800 | [diff] [blame] | 314 | return 0; |
Zach Reizner | c09812f | 2015-01-12 16:49:49 -0800 | [diff] [blame] | 315 | } |