PD#158474: add chromiumos drm-tests
Change-Id: I33b220ec40c8147bc6e6228cecff164f8555582f
Signed-off-by: Yalong Liu <yalong.liu@amlogic.com>
diff --git a/drm-tests/mmap_test.c b/drm-tests/mmap_test.c
new file mode 100644
index 0000000..321e33e
--- /dev/null
+++ b/drm-tests/mmap_test.c
@@ -0,0 +1,293 @@
+/*
+ * 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++) {
+ 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();
+ 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;
+}