295 lines
6.8 KiB
C
295 lines
6.8 KiB
C
/*
|
|
* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
|
|
#include "bs_drm.h"
|
|
|
|
#define BUFFERS 2
|
|
#define NUM_FRAMES 0x40
|
|
|
|
struct framebuffer {
|
|
struct gbm_bo *bo;
|
|
uint32_t id;
|
|
};
|
|
|
|
struct context {
|
|
int display_fd;
|
|
uint32_t crtc_id;
|
|
|
|
struct framebuffer fbs[BUFFERS];
|
|
struct bs_mapper *mapper;
|
|
|
|
int vgem_device_fd;
|
|
};
|
|
|
|
static void disable_psr()
|
|
{
|
|
const char psr_path[] = "/sys/module/i915/parameters/enable_psr";
|
|
int psr_fd = open(psr_path, O_WRONLY);
|
|
|
|
if (psr_fd < 0)
|
|
return;
|
|
|
|
if (write(psr_fd, "0", 1) == -1) {
|
|
bs_debug_error("failed to disable psr");
|
|
} else {
|
|
printf("disabled psr");
|
|
}
|
|
|
|
close(psr_fd);
|
|
}
|
|
|
|
static void do_fixes()
|
|
{
|
|
disable_psr();
|
|
}
|
|
|
|
#define STEP_SKIP 0
|
|
#define STEP_MMAP 1
|
|
#define STEP_FAULT 2
|
|
#define STEP_FLIP 3
|
|
#define STEP_DRAW 4
|
|
|
|
static void show_sequence(const int *sequence)
|
|
{
|
|
int sequence_subindex;
|
|
printf("starting sequence: ");
|
|
for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
|
|
switch (sequence[sequence_subindex]) {
|
|
case STEP_SKIP:
|
|
break;
|
|
case STEP_MMAP:
|
|
printf("mmap ");
|
|
break;
|
|
case STEP_FAULT:
|
|
printf("fault ");
|
|
break;
|
|
case STEP_FLIP:
|
|
printf("flip ");
|
|
break;
|
|
case STEP_DRAW:
|
|
printf("draw ");
|
|
break;
|
|
default:
|
|
bs_debug_error("<unknown step %d> (aborting!)",
|
|
sequence[sequence_subindex]);
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
static void draw(struct context *ctx)
|
|
{
|
|
// Run the drawing routine with the key driver events in different
|
|
// sequences.
|
|
const int sequences[4][4] = {
|
|
{ STEP_MMAP, STEP_FAULT, STEP_FLIP, STEP_DRAW },
|
|
{ STEP_MMAP, STEP_FLIP, STEP_DRAW, STEP_SKIP },
|
|
{ STEP_MMAP, STEP_DRAW, STEP_FLIP, STEP_SKIP },
|
|
{ STEP_FLIP, STEP_MMAP, STEP_DRAW, STEP_SKIP },
|
|
};
|
|
|
|
int sequence_index = 0;
|
|
int sequence_subindex = 0;
|
|
|
|
int fb_idx = 1;
|
|
|
|
for (sequence_index = 0; sequence_index < 4; sequence_index++) {
|
|
show_sequence(sequences[sequence_index]);
|
|
for (int frame_index = 0; frame_index < NUM_FRAMES; frame_index += 2) {
|
|
struct framebuffer *fb = &ctx->fbs[fb_idx];
|
|
size_t bo_stride = gbm_bo_get_plane_stride(fb->bo, 0);
|
|
size_t bo_size = gbm_bo_get_plane_size(fb->bo, 0);
|
|
const uint32_t width = gbm_bo_get_width(fb->bo);
|
|
const uint32_t height = gbm_bo_get_height(fb->bo);
|
|
uint32_t *bo_ptr;
|
|
volatile uint32_t *ptr;
|
|
void *map_data;
|
|
|
|
for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
|
|
switch (sequences[sequence_index][sequence_subindex]) {
|
|
case STEP_MMAP:
|
|
bo_ptr = bs_mapper_map(ctx->mapper, fb->bo, 0,
|
|
&map_data);
|
|
if (bo_ptr == MAP_FAILED)
|
|
bs_debug_error("failed to mmap gbm bo");
|
|
|
|
ptr = bo_ptr;
|
|
break;
|
|
|
|
case STEP_FAULT:
|
|
*ptr = 1234567;
|
|
break;
|
|
|
|
case STEP_FLIP:
|
|
drmModePageFlip(ctx->display_fd, ctx->crtc_id,
|
|
ctx->fbs[fb_idx].id, 0, NULL);
|
|
break;
|
|
|
|
case STEP_DRAW:
|
|
for (ptr = bo_ptr;
|
|
ptr < bo_ptr + (bo_size / sizeof(*bo_ptr));
|
|
ptr++) {
|
|
int y = ((void *)ptr - (void *)bo_ptr) /
|
|
bo_stride;
|
|
int x = ((void *)ptr - (void *)bo_ptr -
|
|
bo_stride * y) /
|
|
sizeof(*ptr);
|
|
x -= frame_index * (width / NUM_FRAMES);
|
|
y -= frame_index * (height / NUM_FRAMES);
|
|
*ptr = 0xff000000;
|
|
if (x * x + y * y <
|
|
frame_index * frame_index)
|
|
*ptr |= (frame_index % 0x100) << 8;
|
|
else
|
|
*ptr |= 0xff |
|
|
(sequence_index * 64 << 16);
|
|
}
|
|
break;
|
|
|
|
case STEP_SKIP:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bs_mapper_unmap(ctx->mapper, fb->bo, map_data);
|
|
|
|
usleep(1e6 / 120); /* 120 Hz */
|
|
|
|
fb_idx = fb_idx ^ 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const struct option longopts[] = {
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ "dma-buf", no_argument, NULL, 'b' },
|
|
{ "gem", no_argument, NULL, 'g' },
|
|
{ "dumb", no_argument, NULL, 'd' },
|
|
{ "vgem", no_argument, NULL, 'v' },
|
|
{ "scanout", no_argument, NULL, 's' },
|
|
{ 0, 0, 0, 0 },
|
|
};
|
|
|
|
static void print_help(const char *argv0)
|
|
{
|
|
printf("Usage: %s [OPTIONS]\n", argv0);
|
|
printf(" -h, --help Print help.\n");
|
|
printf(" -b, --dma-buf Use dma-buf mmap (by default).\n");
|
|
printf(" -g, --gem Use GEM map.\n");
|
|
printf(" -d, --dumb Use dump map.\n");
|
|
printf(" -v, --vgem Use vgem dump map.\n");
|
|
printf(" -s, --scanout Use buffer optimized for scanout.\n");
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct context ctx = { 0 };
|
|
|
|
do_fixes();
|
|
|
|
ctx.display_fd = bs_drm_open_main_display();
|
|
if (ctx.display_fd < 0) {
|
|
bs_debug_error("failed to open card for display");
|
|
return 1;
|
|
}
|
|
|
|
struct gbm_device *gbm = gbm_create_device(ctx.display_fd);
|
|
if (!gbm) {
|
|
bs_debug_error("failed to create gbm device");
|
|
return 1;
|
|
}
|
|
|
|
int c;
|
|
uint32_t flags = GBM_BO_USE_SCANOUT;
|
|
while ((c = getopt_long(argc, argv, "bgdvsh", longopts, NULL)) != -1) {
|
|
switch (c) {
|
|
case 'b':
|
|
ctx.mapper = bs_mapper_dma_buf_new();
|
|
flags |= GBM_BO_USE_LINEAR;
|
|
printf("started dma-buf mmap.\n");
|
|
break;
|
|
case 'g':
|
|
ctx.mapper = bs_mapper_gem_new();
|
|
flags |= GBM_BO_USE_SW_READ_OFTEN | GBM_BO_USE_SW_WRITE_OFTEN;
|
|
printf("started GEM map.\n");
|
|
break;
|
|
case 'd':
|
|
ctx.mapper = bs_mapper_dumb_new(gbm_device_get_fd(gbm));
|
|
flags |= GBM_BO_USE_LINEAR;
|
|
printf("started dumb map.\n");
|
|
break;
|
|
case 'v':
|
|
ctx.vgem_device_fd = bs_drm_open_vgem();
|
|
ctx.mapper = bs_mapper_dumb_new(ctx.vgem_device_fd);
|
|
printf("started vgem map.\n");
|
|
break;
|
|
case 's':
|
|
flags = GBM_BO_USE_SCANOUT;
|
|
break;
|
|
case 'h':
|
|
default:
|
|
print_help(argv[0]);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Use dma-buf mmap by default, in case any arguments aren't selected.
|
|
if (!ctx.mapper) {
|
|
ctx.mapper = bs_mapper_dma_buf_new();
|
|
flags |= GBM_BO_USE_LINEAR;
|
|
printf("started dma-buf mmap.\n");
|
|
}
|
|
|
|
if (ctx.mapper == NULL) {
|
|
bs_debug_error("failed to create mapper object");
|
|
return 1;
|
|
}
|
|
|
|
struct bs_drm_pipe pipe = { 0 };
|
|
if (!bs_drm_pipe_make(ctx.display_fd, &pipe)) {
|
|
bs_debug_error("failed to make pipe");
|
|
return 1;
|
|
}
|
|
|
|
drmModeConnector *connector = drmModeGetConnector(ctx.display_fd, pipe.connector_id);
|
|
drmModeModeInfo *mode = &connector->modes[0];
|
|
ctx.crtc_id = pipe.crtc_id;
|
|
|
|
printf("display size: %ux%u\n", mode->hdisplay, mode->vdisplay);
|
|
|
|
for (size_t fb_index = 0; fb_index < BUFFERS; ++fb_index) {
|
|
struct framebuffer *fb = &ctx.fbs[fb_index];
|
|
fb->bo =
|
|
gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, GBM_FORMAT_XRGB8888, flags);
|
|
|
|
if (!fb->bo) {
|
|
bs_debug_error("failed to create buffer object");
|
|
return 1;
|
|
}
|
|
|
|
fb->id = bs_drm_fb_create_gbm(fb->bo);
|
|
if (fb->id == 0) {
|
|
bs_debug_error("failed to create fb");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (drmModeSetCrtc(ctx.display_fd, pipe.crtc_id, ctx.fbs[0].id, 0, 0, &pipe.connector_id, 1,
|
|
mode)) {
|
|
bs_debug_error("failed to set CRTC");
|
|
return 1;
|
|
}
|
|
|
|
draw(&ctx);
|
|
|
|
return 0;
|
|
}
|