blob: 9a2a091e47b9ff5de50516589d25068ecb381f75 [file] [log] [blame]
Zach Reiznerc09812f2015-01-12 16:49:49 -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
7#define _GNU_SOURCE
8#include <assert.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <stdbool.h>
12#include <stdio.h>
13#include <string.h>
14#include <stdlib.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <unistd.h>
19
20#include <gbm.h>
21#include <drm_fourcc.h>
22#include <xf86drm.h>
23#include <xf86drmMode.h>
24
25#define BUFFERS 2
26
27struct context {
28 int drm_card_fd;
29 int vgem_card_fd;
30 struct gbm_device *drm_gbm;
31
32 drmModeRes *resources;
33 drmModeConnector *connector;
34 drmModeEncoder *encoder;
35 drmModeModeInfo *mode;
36
37 struct gbm_bo *gbm_buffer[BUFFERS];
38 uint32_t vgem_bo_handle[BUFFERS];
39 uint32_t drm_fb_id[BUFFERS];
40
41};
42
Zach Reizner299fab72015-04-28 16:56:14 -070043void disable_psr() {
44 const char psr_path[] = "/sys/module/i915/parameters/enable_psr";
45 int psr_fd = open(psr_path, O_WRONLY);
46
47 if (psr_fd < 0)
48 return;
49
50 if (write(psr_fd, "0", 1) == -1) {
51 fprintf(stderr, "failed to disable psr\n");
52 } else {
53 fprintf(stderr, "disabled psr\n");
54 }
55
56 close(psr_fd);
57}
58
59void do_fixes() {
60 disable_psr();
61}
62
Zach Reiznerc09812f2015-01-12 16:49:49 -080063const char g_sys_card_path_format[] =
64 "/sys/bus/platform/devices/vgem/drm/card%d";
65const char g_dev_card_path_format[] =
66 "/dev/dri/card%d";
67
68int drm_open_vgem()
69{
70 char *name;
71 int i, fd;
72
73 for (i = 0; i < 16; i++) {
74 struct stat _stat;
75 int ret;
76 ret = asprintf(&name, g_sys_card_path_format, i);
77 assert(ret != -1);
78
79 if (stat(name, &_stat) == -1) {
80 free(name);
81 continue;
82 }
83
84 free(name);
85 ret = asprintf(&name, g_dev_card_path_format, i);
86 assert(ret != -1);
87
88 fd = open(name, O_RDWR);
89 free(name);
90 if (fd == -1) {
91 continue;
92 }
93 return fd;
94 }
95 return -1;
96}
97
98void * mmap_dumb_bo(int fd, int handle, size_t size)
99{
100 struct drm_mode_map_dumb mmap_arg;
101 void *ptr;
102 int ret;
103
104 memset(&mmap_arg, 0, sizeof(mmap_arg));
105
106 mmap_arg.handle = handle;
107
108 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg);
109 assert(ret == 0);
110 assert(mmap_arg.offset != 0);
111
112 ptr = mmap(NULL, size, (PROT_READ|PROT_WRITE), MAP_SHARED, fd,
113 mmap_arg.offset);
114
115 assert(ptr != MAP_FAILED);
116
117 return ptr;
118}
119
120bool setup_drm(struct context *ctx)
121{
122 int fd = ctx->drm_card_fd;
123 drmModeRes *resources = NULL;
124 drmModeConnector *connector = NULL;
125 drmModeEncoder *encoder = NULL;
126 int i, j;
127
128 resources = drmModeGetResources(fd);
129 if (!resources) {
130 fprintf(stderr, "drmModeGetResources failed\n");
131 return false;
132 }
133
134 for (i = 0; i < resources->count_connectors; i++) {
135 connector = drmModeGetConnector(fd, resources->connectors[i]);
136 if (connector == NULL)
137 continue;
138
139 if (connector->connection == DRM_MODE_CONNECTED &&
140 connector->count_modes > 0)
141 break;
142
143 drmModeFreeConnector(connector);
144 }
145
146 if (i == resources->count_connectors) {
147 fprintf(stderr, "no currently active connector found\n");
148 drmModeFreeResources(resources);
149 return false;
150 }
151
152 for (i = 0; i < resources->count_encoders; i++) {
153 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
154
155 if (encoder == NULL)
156 continue;
157
158 for (j = 0; j < connector->count_encoders; j++) {
159 if (encoder->encoder_id == connector->encoders[j])
160 break;
161 }
162
163 if (j == connector->count_encoders) {
164 drmModeFreeEncoder(encoder);
165 continue;
166 }
167
168 break;
169 }
170
171 if (i == resources->count_encoders) {
172 fprintf(stderr, "no supported encoder found\n");
173 drmModeFreeConnector(connector);
174 drmModeFreeResources(resources);
175 return false;
176 }
177
178 for (i = 0; i < resources->count_crtcs; i++) {
179 if (encoder->possible_crtcs & (1 << i)) {
180 encoder->crtc_id = resources->crtcs[i];
181 break;
182 }
183 }
184
185 if (i == resources->count_crtcs) {
186 fprintf(stderr, "no possible crtc found\n");
187 drmModeFreeEncoder(encoder);
188 drmModeFreeConnector(connector);
189 drmModeFreeResources(resources);
190 return false;
191 }
192
193 ctx->resources = resources;
194 ctx->connector = connector;
195 ctx->encoder = encoder;
196 ctx->mode = &connector->modes[0];
197
198 return true;
199}
200
201#define STEP_SKIP 0
202#define STEP_MMAP 1
203#define STEP_FAULT 2
204#define STEP_FLIP 3
205#define STEP_DRAW 4
206
207void show_sequence(const int *sequence)
208{
209 int sequence_subindex;
210 fprintf(stderr, "starting sequence: ");
211 for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
212 switch (sequence[sequence_subindex]) {
213 case STEP_SKIP:
214 break;
215 case STEP_MMAP:
216 fprintf(stderr, "mmap ");
217 break;
218 case STEP_FAULT:
219 fprintf(stderr, "fault ");
220 break;
221 case STEP_FLIP:
222 fprintf(stderr, "flip ");
223 break;
224 case STEP_DRAW:
225 fprintf(stderr, "draw ");
226 break;
227 default:
228 fprintf(stderr, "<unknown step %d> (aborting!)\n", sequence[sequence_subindex]);
229 abort();
230 break;
231 }
232 }
233 fprintf(stderr, "\n");
234}
235
236void draw(struct context *ctx)
237{
238 int i;
239
240 // Run the drawing routine with the key driver events in different
241 // sequences.
242 const int sequences[4][4] = {
243 { STEP_MMAP, STEP_FAULT, STEP_FLIP, STEP_DRAW },
244 { STEP_MMAP, STEP_FLIP, STEP_DRAW, STEP_SKIP },
245 { STEP_MMAP, STEP_DRAW, STEP_FLIP, STEP_SKIP },
246 { STEP_FLIP, STEP_MMAP, STEP_DRAW, STEP_SKIP },
247 };
248
249 int sequence_index = 0;
250 int sequence_subindex = 0;
251
252 int fb_idx = 1;
253
254 for (sequence_index = 0; sequence_index < 4; sequence_index++) {
255 show_sequence(sequences[sequence_index]);
256 for (i = 0; i < 0x100; i++) {
257 size_t bo_stride = gbm_bo_get_stride(ctx->gbm_buffer[fb_idx]);
258 size_t bo_size = gbm_bo_get_stride(ctx->gbm_buffer[fb_idx]) * gbm_bo_get_height(ctx->gbm_buffer[fb_idx]);
259 uint32_t *bo_ptr;
260 volatile uint32_t *ptr;
261
262 for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
263 switch (sequences[sequence_index][sequence_subindex]) {
264 case STEP_MMAP:
265 bo_ptr = mmap_dumb_bo(ctx->vgem_card_fd, ctx->vgem_bo_handle[fb_idx], bo_size);
266 ptr = bo_ptr;
267 break;
268
269 case STEP_FAULT:
270 *ptr = 1234567;
271 break;
272
273 case STEP_FLIP:
274 drmModePageFlip(ctx->drm_card_fd, ctx->encoder->crtc_id,
275 ctx->drm_fb_id[fb_idx],
276 0,
277 NULL);
278 break;
279
280 case STEP_DRAW:
281 for (ptr = bo_ptr; ptr < bo_ptr + (bo_size / sizeof(*bo_ptr)); ptr++) {
282 int y = ((void*)ptr - (void*)bo_ptr) / bo_stride;
283 int x = ((void*)ptr - (void*)bo_ptr - bo_stride * y) / sizeof(*ptr);
284 x -= 100;
285 y -= 100;
286 *ptr = 0xff000000;
287 if (x * x + y * y < i * i)
288 *ptr |= (i % 0x100) << 8;
289 else
290 *ptr |= 0xff | (sequence_index * 64 << 16);
291 }
292 break;
293
294 case STEP_SKIP:
295 default:
296 break;
297 }
298 }
299
300 munmap(bo_ptr, bo_size);
301
302 usleep(1e6 / 120); /* 120 Hz */
303
304 fb_idx = fb_idx ^ 1;
305 }
306 }
307}
308
309int main(int argc, char **argv)
310{
311 int ret = 0;
312 struct context ctx;
313 uint32_t bo_handle;
314 uint32_t bo_stride;
315 int drm_prime_fd;
316 size_t i;
317 char *drm_card_path = "/dev/dri/card0";
318
319 if (argc >= 2)
320 drm_card_path = argv[1];
321
Zach Reizner299fab72015-04-28 16:56:14 -0700322 do_fixes();
323
Zach Reiznerc09812f2015-01-12 16:49:49 -0800324 ctx.drm_card_fd = open(drm_card_path, O_RDWR);
325 if (ctx.drm_card_fd < 0) {
326 fprintf(stderr, "failed to open %s\n", drm_card_path);
327 ret = 1;
328 goto fail;
329 }
330
331 ctx.vgem_card_fd = drm_open_vgem();
332 if (ctx.vgem_card_fd < 0) {
333 fprintf(stderr, "failed to open vgem card\n");
334 ret = 1;
335 goto close_drm_card;
336 }
337
338 ctx.drm_gbm = gbm_create_device(ctx.drm_card_fd);
339 if (!ctx.drm_gbm) {
340 fprintf(stderr, "failed to create gbm device on %s\n", drm_card_path);
341 ret = 1;
342 goto close_vgem_card;
343 }
344
345 if (!setup_drm(&ctx)) {
346 fprintf(stderr, "failed to setup drm resources\n");
347 ret = 1;
348 goto destroy_drm_gbm;
349 }
350
351 fprintf(stderr, "display size: %dx%d\n",
352 ctx.mode->hdisplay, ctx.mode->vdisplay);
353
354
355 for (i = 0; i < BUFFERS; ++i) {
356 ctx.gbm_buffer[i] = gbm_bo_create(ctx.drm_gbm,
357 ctx.mode->hdisplay, ctx.mode->vdisplay, GBM_BO_FORMAT_XRGB8888,
358 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
359
360 if (!ctx.gbm_buffer[i]) {
361 fprintf(stderr, "failed to create buffer object\n");
362 ret = 1;
363 goto free_buffers;
364 }
365
366 bo_handle = gbm_bo_get_handle(ctx.gbm_buffer[i]).u32;
367 bo_stride = gbm_bo_get_stride(ctx.gbm_buffer[i]);
368
369 drm_prime_fd = gbm_bo_get_fd(ctx.gbm_buffer[i]);
370
371 if (drm_prime_fd < 0) {
372 fprintf(stderr, "failed to turn handle into fd\n");
373 ret = 1;
374 goto free_buffers;
375 }
376
377 ret = drmPrimeFDToHandle(ctx.vgem_card_fd, drm_prime_fd,
378 &ctx.vgem_bo_handle[i]);
379 if (ret) {
380 fprintf(stderr, "failed to import handle\n");
381 ret = 1;
382 goto free_buffers;
383 }
384
385 ret = drmModeAddFB(ctx.drm_card_fd, ctx.mode->hdisplay, ctx.mode->vdisplay,
386 24, 32, bo_stride, bo_handle, &ctx.drm_fb_id[i]);
387
388 if (ret) {
389 fprintf(stderr, "failed to add fb\n");
390 ret = 1;
391 goto free_buffers;
392 }
393 }
394
395 if (drmModeSetCrtc(ctx.drm_card_fd, ctx.encoder->crtc_id, ctx.drm_fb_id[0],
396 0, 0, &ctx.connector->connector_id, 1, ctx.mode)) {
397 fprintf(stderr, "failed to set CRTC\n");
398 ret = 1;
399 goto free_buffers;
400 }
401
402 draw(&ctx);
403
404free_buffers:
405 for (i = 0; i < BUFFERS; ++i) {
406 if (ctx.drm_fb_id[i])
407 drmModeRmFB(ctx.drm_card_fd, ctx.drm_fb_id[i]);
408 if (ctx.gbm_buffer[i])
409 gbm_bo_destroy(ctx.gbm_buffer[i]);
410 }
411
412 drmModeFreeConnector(ctx.connector);
413 drmModeFreeEncoder(ctx.encoder);
414 drmModeFreeResources(ctx.resources);
415destroy_drm_gbm:
416 gbm_device_destroy(ctx.drm_gbm);
417close_vgem_card:
418 close(ctx.vgem_card_fd);
419close_drm_card:
420 close(ctx.drm_card_fd);
421fail:
422 return ret;
423}