mirror of
https://github.com/tiagovignatti/intel-gpu-tools.git
synced 2025-06-11 01:46:14 +00:00
This commit wraps all VGEM related code with 'USE_VGEM' macro, which gives the chance to enable a different running path using DRM fd without VGEM. This is particularly useful to test and compare the characteristics of VGEM and DRM. One can switch VGEM or DRM in compilation time by defining 'USE_VGEM' (which is by default on). Self annotation: if we opt out VGEM, just like the vgem_fb_test is now doing here, we achieve the same feature promised of map graphics buffers imported from a different process that in turn had allocated them. I.e. there's no GEM (or driver) specific optimizations such as tiling, memory coherency, whatsoever. Am I missing something here? Reference: http://crbug.com/426172 Signed-off-by: Tiago Vignatti <tiago.vignatti@intel.com>
468 lines
10 KiB
C
468 lines
10 KiB
C
/*
|
|
* Copyright 2014 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.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <gbm.h>
|
|
#include <drm_fourcc.h>
|
|
#include <xf86drm.h>
|
|
#include <xf86drmMode.h>
|
|
|
|
#define BUFFERS 2
|
|
#define USE_VGEM
|
|
|
|
struct context {
|
|
int drm_card_fd;
|
|
#ifdef USE_VGEM
|
|
int vgem_card_fd;
|
|
#endif
|
|
int card_fd;
|
|
struct gbm_device *drm_gbm;
|
|
|
|
drmModeRes *resources;
|
|
drmModeConnector *connector;
|
|
drmModeEncoder *encoder;
|
|
drmModeModeInfo *mode;
|
|
|
|
struct gbm_bo *gbm_buffer[BUFFERS];
|
|
uint32_t bo_handle[BUFFERS];
|
|
uint32_t drm_fb_id[BUFFERS];
|
|
|
|
};
|
|
|
|
static int enable_profiling = false;
|
|
|
|
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) {
|
|
fprintf(stderr, "failed to disable psr\n");
|
|
} else {
|
|
fprintf(stderr, "disabled psr\n");
|
|
}
|
|
|
|
close(psr_fd);
|
|
}
|
|
|
|
void do_fixes() {
|
|
disable_psr();
|
|
}
|
|
|
|
#ifdef USE_VGEM
|
|
const char g_sys_card_path_format[] =
|
|
"/sys/bus/platform/devices/vgem/drm/card%d";
|
|
const char g_dev_card_path_format[] =
|
|
"/dev/dri/card%d";
|
|
|
|
int drm_open_vgem()
|
|
{
|
|
char *name;
|
|
int i, fd;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
struct stat _stat;
|
|
int ret;
|
|
ret = asprintf(&name, g_sys_card_path_format, i);
|
|
assert(ret != -1);
|
|
|
|
if (stat(name, &_stat) == -1) {
|
|
free(name);
|
|
continue;
|
|
}
|
|
|
|
free(name);
|
|
ret = asprintf(&name, g_dev_card_path_format, i);
|
|
assert(ret != -1);
|
|
|
|
fd = open(name, O_RDWR);
|
|
free(name);
|
|
if (fd == -1) {
|
|
continue;
|
|
}
|
|
return fd;
|
|
}
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
static double elapsed(const struct timeval *start, const struct timeval *end)
|
|
{
|
|
return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec);
|
|
}
|
|
|
|
void * mmap_dumb_bo(int fd, int handle, size_t size)
|
|
{
|
|
struct drm_mode_map_dumb mmap_arg;
|
|
void *ptr;
|
|
int ret;
|
|
|
|
memset(&mmap_arg, 0, sizeof(mmap_arg));
|
|
|
|
mmap_arg.handle = handle;
|
|
|
|
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg);
|
|
assert(ret == 0);
|
|
assert(mmap_arg.offset != 0);
|
|
|
|
ptr = mmap(NULL, size, (PROT_READ|PROT_WRITE), MAP_SHARED, fd,
|
|
mmap_arg.offset);
|
|
|
|
assert(ptr != MAP_FAILED);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
bool setup_drm(struct context *ctx)
|
|
{
|
|
int fd = ctx->drm_card_fd;
|
|
drmModeRes *resources = NULL;
|
|
drmModeConnector *connector = NULL;
|
|
drmModeEncoder *encoder = NULL;
|
|
int i, j;
|
|
|
|
resources = drmModeGetResources(fd);
|
|
if (!resources) {
|
|
fprintf(stderr, "drmModeGetResources failed\n");
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < resources->count_connectors; i++) {
|
|
connector = drmModeGetConnector(fd, resources->connectors[i]);
|
|
if (connector == NULL)
|
|
continue;
|
|
|
|
if (connector->connection == DRM_MODE_CONNECTED &&
|
|
connector->count_modes > 0)
|
|
break;
|
|
|
|
drmModeFreeConnector(connector);
|
|
}
|
|
|
|
if (i == resources->count_connectors) {
|
|
fprintf(stderr, "no currently active connector found\n");
|
|
drmModeFreeResources(resources);
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < resources->count_encoders; i++) {
|
|
encoder = drmModeGetEncoder(fd, resources->encoders[i]);
|
|
|
|
if (encoder == NULL)
|
|
continue;
|
|
|
|
for (j = 0; j < connector->count_encoders; j++) {
|
|
if (encoder->encoder_id == connector->encoders[j])
|
|
break;
|
|
}
|
|
|
|
if (j == connector->count_encoders) {
|
|
drmModeFreeEncoder(encoder);
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (i == resources->count_encoders) {
|
|
fprintf(stderr, "no supported encoder found\n");
|
|
drmModeFreeConnector(connector);
|
|
drmModeFreeResources(resources);
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < resources->count_crtcs; i++) {
|
|
if (encoder->possible_crtcs & (1 << i)) {
|
|
encoder->crtc_id = resources->crtcs[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == resources->count_crtcs) {
|
|
fprintf(stderr, "no possible crtc found\n");
|
|
drmModeFreeEncoder(encoder);
|
|
drmModeFreeConnector(connector);
|
|
drmModeFreeResources(resources);
|
|
return false;
|
|
}
|
|
|
|
ctx->resources = resources;
|
|
ctx->connector = connector;
|
|
ctx->encoder = encoder;
|
|
ctx->mode = &connector->modes[0];
|
|
|
|
return true;
|
|
}
|
|
|
|
#define STEP_SKIP 0
|
|
#define STEP_MMAP 1
|
|
#define STEP_FAULT 2
|
|
#define STEP_FLIP 3
|
|
#define STEP_DRAW 4
|
|
|
|
void show_sequence(const int *sequence)
|
|
{
|
|
int sequence_subindex;
|
|
fprintf(stderr, "starting sequence: ");
|
|
for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
|
|
switch (sequence[sequence_subindex]) {
|
|
case STEP_SKIP:
|
|
break;
|
|
case STEP_MMAP:
|
|
fprintf(stderr, "mmap ");
|
|
break;
|
|
case STEP_FAULT:
|
|
fprintf(stderr, "fault ");
|
|
break;
|
|
case STEP_FLIP:
|
|
fprintf(stderr, "flip ");
|
|
break;
|
|
case STEP_DRAW:
|
|
fprintf(stderr, "draw ");
|
|
break;
|
|
default:
|
|
fprintf(stderr, "<unknown step %d> (aborting!)\n", sequence[sequence_subindex]);
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
void draw(struct context *ctx)
|
|
{
|
|
int i;
|
|
|
|
// 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 (i = 0; i < 0x100; i++) {
|
|
size_t bo_stride = gbm_bo_get_stride(ctx->gbm_buffer[fb_idx]);
|
|
size_t bo_size = gbm_bo_get_stride(ctx->gbm_buffer[fb_idx]) * gbm_bo_get_height(ctx->gbm_buffer[fb_idx]);
|
|
uint32_t *bo_ptr;
|
|
volatile uint32_t *ptr;
|
|
struct timeval start, end;
|
|
|
|
for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
|
|
switch (sequences[sequence_index][sequence_subindex]) {
|
|
case STEP_MMAP:
|
|
if (enable_profiling)
|
|
gettimeofday(&start, NULL);
|
|
bo_ptr = mmap_dumb_bo(ctx->drm_card_fd, ctx->bo_handle[fb_idx], bo_size);
|
|
if (enable_profiling) {
|
|
gettimeofday(&end, NULL);
|
|
fprintf(stderr, "time to execute mmap: %7.3fms\n",
|
|
elapsed(&start, &end) / 1000);
|
|
}
|
|
ptr = bo_ptr;
|
|
break;
|
|
|
|
case STEP_FAULT:
|
|
*ptr = 1234567;
|
|
break;
|
|
|
|
case STEP_FLIP:
|
|
drmModePageFlip(ctx->drm_card_fd, ctx->encoder->crtc_id,
|
|
ctx->drm_fb_id[fb_idx],
|
|
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 -= 100;
|
|
y -= 100;
|
|
*ptr = 0xff000000;
|
|
if (x * x + y * y < i * i)
|
|
*ptr |= (i % 0x100) << 8;
|
|
else
|
|
*ptr |= 0xff | (sequence_index * 64 << 16);
|
|
}
|
|
break;
|
|
|
|
case STEP_SKIP:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
munmap(bo_ptr, bo_size);
|
|
|
|
usleep(1e6 / 120); /* 120 Hz */
|
|
|
|
fb_idx = fb_idx ^ 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const char optstr[] = "d:p";
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int ret = 0;
|
|
struct context ctx;
|
|
uint32_t bo_handle;
|
|
uint32_t bo_stride;
|
|
int drm_prime_fd;
|
|
size_t i;
|
|
char *drm_card_path = "/dev/dri/card0";
|
|
char c;
|
|
|
|
while ((c = getopt(argc, argv, optstr)) != -1) {
|
|
switch (c) {
|
|
case 'd':
|
|
drm_card_path = optarg;
|
|
break;
|
|
case 'p':
|
|
enable_profiling = true;
|
|
break;
|
|
default:
|
|
ret = 1;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
do_fixes();
|
|
|
|
ctx.drm_card_fd = open(drm_card_path, O_RDWR);
|
|
if (ctx.drm_card_fd < 0) {
|
|
fprintf(stderr, "failed to open %s\n", drm_card_path);
|
|
ret = 1;
|
|
goto fail;
|
|
}
|
|
#ifdef USE_VGEM
|
|
ctx.vgem_card_fd = drm_open_vgem();
|
|
if (ctx.vgem_card_fd < 0) {
|
|
fprintf(stderr, "failed to open vgem card\n");
|
|
ret = 1;
|
|
goto close_drm_card;
|
|
}
|
|
ctx.card_fd = ctx.vgem_card_fd;
|
|
fprintf(stderr, "Method to open video card: VGEM\n");
|
|
#else
|
|
ctx.card_fd = ctx.drm_card_fd;
|
|
fprintf(stderr, "Method to open video card: DRM\n");
|
|
#endif
|
|
|
|
ctx.drm_gbm = gbm_create_device(ctx.drm_card_fd);
|
|
if (!ctx.drm_gbm) {
|
|
fprintf(stderr, "failed to create gbm device on %s\n", drm_card_path);
|
|
ret = 1;
|
|
goto close_card;
|
|
}
|
|
|
|
if (!setup_drm(&ctx)) {
|
|
fprintf(stderr, "failed to setup drm resources\n");
|
|
ret = 1;
|
|
goto destroy_drm_gbm;
|
|
}
|
|
|
|
fprintf(stderr, "display size: %dx%d\n",
|
|
ctx.mode->hdisplay, ctx.mode->vdisplay);
|
|
|
|
|
|
for (i = 0; i < BUFFERS; ++i) {
|
|
ctx.gbm_buffer[i] = gbm_bo_create(ctx.drm_gbm,
|
|
ctx.mode->hdisplay, ctx.mode->vdisplay, GBM_BO_FORMAT_XRGB8888,
|
|
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
|
|
|
if (!ctx.gbm_buffer[i]) {
|
|
fprintf(stderr, "failed to create buffer object\n");
|
|
ret = 1;
|
|
goto free_buffers;
|
|
}
|
|
|
|
bo_handle = gbm_bo_get_handle(ctx.gbm_buffer[i]).u32;
|
|
bo_stride = gbm_bo_get_stride(ctx.gbm_buffer[i]);
|
|
|
|
drm_prime_fd = gbm_bo_get_fd(ctx.gbm_buffer[i]);
|
|
|
|
if (drm_prime_fd < 0) {
|
|
fprintf(stderr, "failed to turn handle into fd\n");
|
|
ret = 1;
|
|
goto free_buffers;
|
|
}
|
|
|
|
ret = drmPrimeFDToHandle(ctx.drm_card_fd, drm_prime_fd,
|
|
&ctx.bo_handle[i]);
|
|
if (ret) {
|
|
fprintf(stderr, "failed to import handle\n");
|
|
ret = 1;
|
|
goto free_buffers;
|
|
}
|
|
|
|
ret = drmModeAddFB(ctx.drm_card_fd, ctx.mode->hdisplay, ctx.mode->vdisplay,
|
|
24, 32, bo_stride, bo_handle, &ctx.drm_fb_id[i]);
|
|
|
|
if (ret) {
|
|
fprintf(stderr, "failed to add fb\n");
|
|
ret = 1;
|
|
goto free_buffers;
|
|
}
|
|
}
|
|
|
|
if (drmModeSetCrtc(ctx.drm_card_fd, ctx.encoder->crtc_id, ctx.drm_fb_id[0],
|
|
0, 0, &ctx.connector->connector_id, 1, ctx.mode)) {
|
|
fprintf(stderr, "failed to set CRTC\n");
|
|
ret = 1;
|
|
goto free_buffers;
|
|
}
|
|
|
|
draw(&ctx);
|
|
|
|
free_buffers:
|
|
for (i = 0; i < BUFFERS; ++i) {
|
|
if (ctx.drm_fb_id[i])
|
|
drmModeRmFB(ctx.drm_card_fd, ctx.drm_fb_id[i]);
|
|
if (ctx.gbm_buffer[i])
|
|
gbm_bo_destroy(ctx.gbm_buffer[i]);
|
|
}
|
|
|
|
drmModeFreeConnector(ctx.connector);
|
|
drmModeFreeEncoder(ctx.encoder);
|
|
drmModeFreeResources(ctx.resources);
|
|
destroy_drm_gbm:
|
|
gbm_device_destroy(ctx.drm_gbm);
|
|
close_card:
|
|
#ifdef USE_VGEM
|
|
close(ctx.vgem_card_fd);
|
|
#endif
|
|
close_drm_card:
|
|
close(ctx.drm_card_fd);
|
|
fail:
|
|
return ret;
|
|
}
|