drm/tests/modedemo/demo.c

635 lines
13 KiB
C
Raw Normal View History

/*
* Some defines to define the behavior of the program
*/
#define CLEAN_FBDEV
#undef DEMO_CLONE
#define SIZE_X 2048
#define SIZE_Y 2048
/* Pitch needs to be power of two */
#define PITCH 2048
2008-01-09 21:03:13 -07:00
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
2008-02-20 12:54:36 -07:00
#ifdef CLEAN_FBDEV
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#endif
2008-03-12 03:47:52 -06:00
#include <signal.h>
2008-01-09 21:03:13 -07:00
#include "xf86drm.h"
#include "xf86drmMode.h"
2008-01-10 20:23:32 -07:00
/* old functions to be replaced */
drmModeFBPtr createFB(int fd, drmModeResPtr res);
void testCursor(int fd, uint32_t crtc);
void prettyColors(int fd, unsigned int handle);
void prettyCursor(int fd, unsigned int handle, unsigned int color);
2008-02-20 12:54:36 -07:00
#ifdef CLEAN_FBDEV
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
#endif
/* structs for the demo_driver */
struct demo_driver;
struct demo_screen
{
/* drm stuff */
drmBO buffer;
drmModeFBPtr fb;
drmModeCrtcPtr crtc;
size_t num_outputs;
uint32_t outputs_id[8];
drmModeOutputPtr outputs[8];
struct drm_mode_modeinfo *mode;
/* virtual buffer */
uint32_t virt_x;
uint32_t virt_y;
uint32_t pitch;
/* parent */
struct demo_driver *driver;
};
#define DEMO_MAX_SCREENS 4
#define MAX_FIND_OUTPUTS 8
struct demo_driver
{
/* drm stuff */
int fd;
drmModeResPtr res;
/* screens */
size_t numScreens;
struct demo_screen screens[DEMO_MAX_SCREENS];
};
struct demo_driver* demoCreateDriver(void);
void demoUpdateRes(struct demo_driver *driver);
int demoCreateScreens(struct demo_driver *driver);
int demoCreateScreenCloned(struct demo_driver *driver);
void demoTakeDownScreen(struct demo_screen *screen);
int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out);
drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output);
void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y);
/* yet to be implemented */
void demoMouseActivate(struct demo_screen *screen);
void demoMouseMove(struct demo_screen *screen, uint16_t x, uint16_t y);
2008-01-09 21:03:13 -07:00
static struct drm_mode_modeinfo mode = {
.name = "Test mode",
.clock = 25200,
.hdisplay = 640,
.hsync_start = 656,
.hsync_end = 752,
.htotal = 800,
.hskew = 0,
.vdisplay = 480,
.vsync_start = 490,
.vsync_end = 492,
.vtotal = 525,
.vscan = 0,
.vrefresh = 60000, /* vertical refresh * 1000 */
.flags = 10,
};
int main(int argc, char **argv)
{
struct demo_driver *driver;
int num;
int i;
2008-01-09 21:03:13 -07:00
2008-02-20 12:54:36 -07:00
#ifdef CLEAN_FBDEV
int fbdev_fd;
fbdev_fd = open("/dev/fb0", O_RDWR);
memset(&var, 0, sizeof(struct fb_var_screeninfo));
memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var))
printf("var %s\n", strerror(errno));
if (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix))
printf("fix %s\n", strerror(errno));
#endif
printf("starting demo\n");
2008-01-09 21:03:13 -07:00
driver = demoCreateDriver();
2008-01-09 21:03:13 -07:00
if (!driver) {
printf("failed to create driver\n");
2008-01-09 21:03:13 -07:00
return 1;
}
#ifndef DEMO_CLONE
num = demoCreateScreens(driver);
#else
num = demoCreateScreenCloned(driver);
#endif
if (num < 1) {
printf("no screens attached or an error occured\n");
2008-01-09 21:03:13 -07:00
return 1;
}
printf("created %i screens\n", num);
2008-01-09 21:03:13 -07:00
for (i = 0; i < num; i++) {
prettyColors(driver->fd, driver->screens[i].fb->handle);
2008-01-09 21:03:13 -07:00
}
sleep(1);
2008-01-09 21:03:13 -07:00
for (i = 0; i < num; i++) {
printf("%i: 100 0\n", i);
demoPanScreen(&driver->screens[i], 100, 0);
sleep(1);
printf("%i: 0 100\n", i);
demoPanScreen(&driver->screens[i], 0, 100);
sleep(1);
printf("%i: 100 100\n", i);
demoPanScreen(&driver->screens[i], 100, 100);
sleep(1);
printf("%i: 0 0\n", i);
demoPanScreen(&driver->screens[i], 0, 1);
sleep(1);
testCursor(driver->fd, driver->screens[i].crtc->crtc_id);
2008-01-09 21:03:13 -07:00
}
sleep(2);
printf("taking down screens\n");
for (i = 0; i < num; i++) {
demoTakeDownScreen(&driver->screens[i]);
}
#ifdef CLEAN_FBDEV
if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var))
printf("var %s\n", strerror(errno));
2008-02-20 12:54:36 -07:00
close(fbdev_fd);
#endif
2008-02-20 12:54:36 -07:00
printf("ok\n");
return 0;
}
int demoCreateScreens(struct demo_driver *driver)
{
drmModeOutputPtr out[MAX_FIND_OUTPUTS];
int num;
int num_screens = 0;
struct demo_screen *screen;
int ret = 0;
int i;
num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS);
if (num < 0)
return 0;
printf("found %i connected outputs\n", num);
for (i = 0; i < num; i++) {
screen = &driver->screens[i];
screen->crtc = demoFindFreeCrtc(driver, out[i]);
if (!screen->crtc) {
printf("found no free crtc for output\n");
drmModeFreeOutput(out[i]);
continue;
}
screen->fb = createFB(driver->fd, driver->res);
if (!screen->fb) {
drmModeFreeOutput(out[i]);
drmModeFreeCrtc(screen->crtc);
screen->crtc = 0;
printf("could not create framebuffer\n");
continue;
}
screen->virt_x = SIZE_X;
screen->virt_y = SIZE_Y;
screen->pitch = PITCH;
screen->outputs[0] = out[i];
screen->outputs_id[0] = out[i]->output_id;
screen->num_outputs = 1;
screen->mode = &mode;
screen->driver = driver;
ret = drmModeSetCrtc(
driver->fd,
screen->crtc->crtc_id,
screen->fb->buffer_id,
0, 0,
screen->outputs_id, screen->num_outputs,
screen->mode);
if (ret) {
printf("failed to set mode\n");
demoTakeDownScreen(screen);
} else {
num_screens++;
}
demoUpdateRes(driver);
2008-01-09 21:03:13 -07:00
}
return num_screens;
}
2008-01-10 20:23:32 -07:00
int demoCreateScreenCloned(struct demo_driver *driver)
{
drmModeOutputPtr out[MAX_FIND_OUTPUTS];
int num;
struct demo_screen *screen;
int ret = 0;
int i;
num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS);
if (num < 0)
return 0;
printf("found %i connected outputs\n", num);
screen = &driver->screens[0];
screen->fb = createFB(driver->fd, driver->res);
if (!screen->fb) {
printf("could not create framebuffer\n");
return 0;
}
screen->mode = &mode;
screen->driver = driver;
screen->virt_x = SIZE_X;
screen->virt_y = SIZE_Y;
screen->pitch = PITCH;
screen->num_outputs = 0;
for (i = 0; i < num; i++) {
screen->crtc = demoFindFreeCrtc(driver, out[i]);
if (!screen->crtc) {
printf("found no free crtc for output\n");
drmModeFreeOutput(out[i]);
continue;
}
screen->outputs[screen->num_outputs] = out[i];
screen->outputs_id[screen->num_outputs] = out[i]->output_id;
screen->num_outputs++;
printf("%u, %u\n", out[i]->output_id, screen->num_outputs);
}
ret = drmModeSetCrtc(
driver->fd,
screen->crtc->crtc_id,
screen->fb->buffer_id,
0, 0,
screen->outputs_id, screen->num_outputs,
screen->mode);
if (ret) {
printf("failed to set mode\n");
demoTakeDownScreen(screen);
return 0;
}
demoUpdateRes(driver);
return 1;
}
void demoTakeDownScreen(struct demo_screen *screen)
{
2008-02-07 11:22:38 -07:00
int fd = screen->driver->fd;
int i;
2008-02-07 11:22:38 -07:00
drmBO bo;
2008-02-20 12:54:36 -07:00
#if 0
/* This can bust the fbdev arrangement as it basically unhooks
* the outputs and the fbdev backend doesn't know how to put things
* back on track. Realistically, it's up to the crtc owner to restore
* things.....
*
* So if you are mixing API's make sure the modesetting owner puts
* back the original CRTC arrangement so fbdev can continue...
*
* Ho-hum..
*/
2008-02-07 11:22:38 -07:00
if (screen->crtc)
drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0);
2008-02-20 12:54:36 -07:00
#endif
2008-02-07 11:22:38 -07:00
if (screen->fb)
drmModeRmFB(fd, screen->fb->buffer_id);
/* maybe we should keep a pointer to the bo on the screen */
if (screen->fb && !drmBOReference(fd, screen->fb->handle, &bo)) {
drmBOUnreference(fd, &bo);
drmBOUnreference(fd, &bo);
} else {
printf("bo error\n");
}
2008-01-09 21:03:13 -07:00
for (i = 0; i < screen->num_outputs; i++) {
drmModeFreeOutput(screen->outputs[i]);
screen->outputs[i] = NULL;
}
drmModeFreeCrtc(screen->crtc);
2008-02-07 11:22:38 -07:00
drmModeFreeFB(screen->fb);
screen->crtc = NULL;
screen->fb = NULL;
}
2008-01-10 20:23:32 -07:00
drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output)
{
drmModeCrtcPtr crtc;
int i, j, used = 0;
drmModeResPtr res = driver->res;
2008-01-10 20:23:32 -07:00
for (i = 0; i < res->count_crtcs; i++) {
used = 0;
for (j = 0; j < DEMO_MAX_SCREENS; j++) {
crtc = driver->screens[j].crtc;
2008-01-27 19:12:29 -07:00
if (crtc && crtc->crtc_id == res->crtcs[i])
used = 1;
}
2008-01-27 19:12:29 -07:00
if (!used) {
crtc = drmModeGetCrtc(driver->fd, res->crtcs[i]);
break;
} else {
crtc = 0;
}
}
2008-01-09 21:03:13 -07:00
return crtc;
}
2008-01-09 21:03:13 -07:00
2008-03-12 03:47:52 -06:00
static int driverfd;
static void
hotplugSIGNAL(int sig, siginfo_t *si, void *d)
{
union drm_wait_hotplug hw;
int ret;
printf("GOT HOTPLUG EVENT!\n");
/* ask for another hotplug event ! */
memset(&hw, 0, sizeof(hw));
hw.request.type = _DRM_HOTPLUG_SIGNAL;
hw.request.signal = SIGUSR1;
ret = ioctl(driverfd, DRM_IOCTL_WAIT_HOTPLUG, &hw);
}
struct demo_driver* demoCreateDriver(void)
{
struct demo_driver* driver = malloc(sizeof(struct demo_driver));
2008-03-12 03:47:52 -06:00
union drm_wait_hotplug hw;
int ret = 0;
memset(driver, 0, sizeof(struct demo_driver));
2008-02-20 12:54:36 -07:00
driver->fd = drmOpen("i915",NULL);
if (driver->fd < 0) {
printf("Failed to open the card fb\n");
goto err_driver;
}
2008-03-12 03:47:52 -06:00
#if 0
/* ioctl wait for hotplug */
do {
memset(&hw, 0, sizeof(hw));
ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw);
printf("HOTPLUG %d %d %d\n",ret,errno,hw.reply.counter);
} while (ret && errno == EBUSY);
#else
/* signal for hotplug */
{
struct sigaction sa;
struct sigaction osa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = hotplugSIGNAL;
sigaction(SIGUSR1, &sa, &osa);
driverfd = driver->fd;
memset(&hw, 0, sizeof(hw));
hw.request.type = _DRM_HOTPLUG_SIGNAL;
hw.request.signal = SIGUSR1;
ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw);
}
#endif
demoUpdateRes(driver);
if (!driver->res) {
printf("could not retrive resources\n");
goto err_res;
}
return driver;
err_res:
drmClose(driver->fd);
err_driver:
free(driver);
return NULL;
}
void demoUpdateRes(struct demo_driver *driver)
{
if (driver->res)
drmModeFreeResources(driver->res);
driver->res = drmModeGetResources(driver->fd);
if (!driver->res)
printf("failed to get resources from kernel\n");
}
int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out)
{
int count = 0;
2008-03-05 03:33:16 -07:00
int i,j;
int fd = driver->fd;
drmModeResPtr res = driver->res;
drmModeOutputPtr output;
for (i = 0; i < res->count_outputs && count < max_out; i++) {
output = drmModeGetOutput(fd, res->outputs[i]);
if (!output)
continue;
2008-03-05 03:33:16 -07:00
if (output->connection == DRM_MODE_DISCONNECTED) {
drmModeFreeOutput(output);
continue;
}
2008-03-05 03:33:16 -07:00
for (j = 0; j < output->count_props; j++) {
drmModePropertyPtr prop;
prop = drmModeGetProperty(fd, output->props[j]);
printf("Property: %s\n",prop->name);
if (prop->count_enums)
printf("%s\n",prop->enums[output->prop_values[j]].name);
}
out[count++] = output;
}
return count;
}
void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y)
{
drmModeSetCrtc(
screen->driver->fd,
screen->crtc->crtc_id,
screen->fb->buffer_id,
x, y,
screen->outputs_id, screen->num_outputs,
screen->mode);
2008-01-09 21:03:13 -07:00
}
drmModeFBPtr createFB(int fd, drmModeResPtr res)
{
2008-01-10 20:23:32 -07:00
drmModeFBPtr frame;
unsigned int fb = 0;
int ret = 0;
drmBO bo;
ret = drmBOCreate(fd, SIZE_X * SIZE_Y * 4, 0, 0,
DRM_BO_FLAG_READ |
DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_TT |
DRM_BO_FLAG_MEM_VRAM |
DRM_BO_FLAG_NO_EVICT,
DRM_BO_HINT_DONT_FENCE, &bo);
if (ret) {
printf("failed to create framebuffer (ret %d)\n",ret);
2008-01-10 20:23:32 -07:00
goto err;
}
2008-01-10 20:23:32 -07:00
2008-03-05 03:33:16 -07:00
ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo.handle, &fb);
2008-01-10 20:23:32 -07:00
if (ret)
goto err_bo;
frame = drmModeGetFB(fd, fb);
if (!frame)
goto err_bo;
return frame;
err_bo:
drmBOUnreference(fd, &bo);
err:
return 0;
2008-01-10 20:23:32 -07:00
}
void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr)
{
int i, j;
for (i = x; i < x + w; i++)
for(j = y; j < y + h; j++)
2008-01-11 09:13:48 -07:00
ptr[(i * PITCH) + j] = v;
2008-01-10 20:23:32 -07:00
}
void prettyColors(int fd, unsigned int handle)
{
drmBO bo;
unsigned int *ptr;
2008-01-11 09:13:48 -07:00
int i;
2008-01-10 20:23:32 -07:00
drmBOReference(fd, handle, &bo);
drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
for (i = 0; i < (SIZE_X*SIZE_Y); i++)
ptr[i] = 0xFFFFFFFF;
for (i = 0; i < 8; i++)
2008-01-11 09:13:48 -07:00
draw(i * 40, i * 40, 40, 40, 0, ptr);
2008-01-10 20:23:32 -07:00
draw(200, 100, 40, 40, 0xff00ff, ptr);
draw(100, 200, 40, 40, 0xff00ff, ptr);
drmBOUnmap(fd, &bo);
2008-01-09 21:03:13 -07:00
}
2008-01-27 19:12:29 -07:00
void testCursor(int fd, uint32_t crtc)
{
drmBO bo;
int ret;
ret = drmBOCreate(fd, 64 * 64 * 4, 0, 0,
DRM_BO_FLAG_READ |
DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_VRAM |
DRM_BO_FLAG_NO_EVICT,
DRM_BO_HINT_DONT_FENCE, &bo);
prettyCursor(fd, bo.handle, 0xFFFF00FF);
2008-01-27 19:12:29 -07:00
printf("set cursor\n");
drmModeSetCursor(fd, crtc, bo.handle, 64, 64);
2008-01-27 19:12:29 -07:00
printf("move cursor 0, 0\n");
drmModeMoveCursor(fd, crtc, 0, 0);
sleep(1);
prettyCursor(fd, bo.handle, 0xFFFF0000);
2008-01-27 19:12:29 -07:00
printf("move cursor 40, 40\n");
drmModeMoveCursor(fd, crtc, 40, 40);
sleep(1);
printf("move cursor 100, 100\n");
drmModeMoveCursor(fd, crtc, 100, 100);
sleep(1);
drmModeSetCursor(fd, crtc, 0, 0, 0);
2008-01-27 19:12:29 -07:00
}
void prettyCursor(int fd, unsigned int handle, unsigned int color)
2008-01-27 19:12:29 -07:00
{
drmBO bo;
unsigned int *ptr;
int i;
drmBOReference(fd, handle, &bo);
drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
for (i = 0; i < (64 * 64); i++)
ptr[i] = color;
2008-01-27 19:12:29 -07:00
drmBOUnmap(fd, &bo);
2008-01-30 07:47:26 -07:00
drmBOUnreference(fd, &bo);
2008-01-27 19:12:29 -07:00
}