diff --git a/kmscube.c b/kmscube.c
index bd32afed968b1bf8fccb9a26840a8debf176e978..5a18c322ad2dc5818c2825e779f8915105a525d8 100644 (file)
--- a/kmscube.c
+++ b/kmscube.c
/*
* Copyright (c) 2012 Arvin Schnell <arvin.schnell@gmail.com>
* Copyright (c) 2012 Rob Clark <rob@ti.com>
+ * Copyright (c) 2013 Anand Balagopalakrishnan <anandb@ti.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
+#include <signal.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "esUtil.h"
-
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define MAX_DISPLAYS (4)
+uint8_t DISP_ID = 0;
+uint8_t all_display = 0;
+int8_t connector_id = -1;
static struct {
EGLDisplay display;
GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
GLuint vbo;
GLuint positionsoffset, colorsoffset, normalsoffset;
+ GLuint vertex_shader, fragment_shader;
} gl;
static struct {
static struct {
int fd;
- drmModeModeInfo *mode;
- uint32_t crtc_id;
- uint32_t connector_id;
+ uint32_t ndisp;
+ uint32_t crtc_id[MAX_DISPLAYS];
+ uint32_t connector_id[MAX_DISPLAYS];
+ uint32_t resource_id;
+ uint32_t encoder[MAX_DISPLAYS];
+ drmModeModeInfo *mode[MAX_DISPLAYS];
+ drmModeConnector *connectors[MAX_DISPLAYS];
} drm;
struct drm_fb {
static int init_drm(void)
{
static const char *modules[] = {
- "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos"
+ "omapdrm", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
};
drmModeRes *resources;
drmModeConnector *connector = NULL;
drmModeEncoder *encoder = NULL;
- int i, area;
+ int i, j;
+ uint32_t maxRes, curRes;
for (i = 0; i < ARRAY_SIZE(modules); i++) {
printf("trying to load module %s...", modules[i]);
printf("drmModeGetResources failed: %s\n", strerror(errno));
return -1;
}
+ drm.resource_id = (uint32_t) resources;
/* find a connected connector: */
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
if (connector->connection == DRM_MODE_CONNECTED) {
- /* it's connected, let's use this! */
- break;
+ /* choose the first supported mode */
+ drm.mode[drm.ndisp] = &connector->modes[0];
+ drm.connector_id[drm.ndisp] = connector->connector_id;
+
+ for (j=0; j<resources->count_encoders; j++) {
+ encoder = drmModeGetEncoder(drm.fd, resources->encoders[j]);
+ if (encoder->encoder_id == connector->encoder_id)
+ break;
+
+ drmModeFreeEncoder(encoder);
+ encoder = NULL;
+ }
+
+ if (!encoder) {
+ printf("no encoder!\n");
+ return -1;
+ }
+
+ drm.encoder[drm.ndisp] = (uint32_t) encoder;
+ drm.crtc_id[drm.ndisp] = encoder->crtc_id;
+ drm.connectors[drm.ndisp] = connector;
+
+ printf("### Display [%d]: CRTC = %d, Connector = %d\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp]);
+ printf("\tMode chosen [%s] : Clock => %d, Vertical refresh => %d, Type => %d\n", drm.mode[drm.ndisp]->name, drm.mode[drm.ndisp]->clock, drm.mode[drm.ndisp]->vrefresh, drm.mode[drm.ndisp]->type);
+ printf("\tHorizontal => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->hdisplay, drm.mode[drm.ndisp]->hsync_start, drm.mode[drm.ndisp]->hsync_end, drm.mode[drm.ndisp]->htotal, drm.mode[drm.ndisp]->hskew);
+ printf("\tVertical => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->vdisplay, drm.mode[drm.ndisp]->vsync_start, drm.mode[drm.ndisp]->vsync_end, drm.mode[drm.ndisp]->vtotal, drm.mode[drm.ndisp]->vscan);
+
+ /* If a connector_id is specified, use the corresponding display */
+ if ((connector_id != -1) && (connector_id == drm.connector_id[drm.ndisp]))
+ DISP_ID = drm.ndisp;
+
+ /* If all displays are enabled, choose the connector with maximum
+ * resolution as the primary display */
+ if (all_display) {
+ maxRes = drm.mode[DISP_ID]->vdisplay * drm.mode[DISP_ID]->hdisplay;
+ curRes = drm.mode[drm.ndisp]->vdisplay * drm.mode[drm.ndisp]->hdisplay;
+
+ if (curRes > maxRes)
+ DISP_ID = drm.ndisp;
+ }
+
+ drm.ndisp++;
+ } else {
+ drmModeFreeConnector(connector);
}
- drmModeFreeConnector(connector);
- connector = NULL;
}
- if (!connector) {
+ if (drm.ndisp == 0) {
/* we could be fancy and listen for hotplug events and wait for
* a connector..
*/
return -1;
}
- /* find highest resolution mode: */
- for (i = 0, area = 0; i < connector->count_modes; i++) {
- drmModeModeInfo *current_mode = &connector->modes[i];
- int current_area = current_mode->hdisplay * current_mode->vdisplay;
- if (current_area > area) {
- drm.mode = current_mode;
- area = current_area;
- }
- }
-
- if (!drm.mode) {
- printf("could not find mode!\n");
- return -1;
- }
-
- /* find encoder: */
- for (i = 0; i < resources->count_encoders; i++) {
- encoder = drmModeGetEncoder(drm.fd, resources->encoders[i]);
- if (encoder->encoder_id == connector->encoder_id)
- break;
- drmModeFreeEncoder(encoder);
- encoder = NULL;
- }
-
- if (!encoder) {
- printf("no encoder!\n");
- return -1;
- }
-
- drm.crtc_id = encoder->crtc_id;
- drm.connector_id = connector->connector_id;
-
return 0;
}
gbm.dev = gbm_create_device(drm.fd);
gbm.surface = gbm_surface_create(gbm.dev,
- drm.mode->hdisplay, drm.mode->vdisplay,
+ drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (!gbm.surface) {
static int init_gl(void)
{
EGLint major, minor, n;
- GLuint vertex_shader, fragment_shader;
GLint ret;
static const GLfloat vVertices[] = {
eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
- vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ gl.vertex_shader = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
- glCompileShader(vertex_shader);
+ glShaderSource(gl.vertex_shader, 1, &vertex_shader_source, NULL);
+ glCompileShader(gl.vertex_shader);
- glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
+ glGetShaderiv(gl.vertex_shader, GL_COMPILE_STATUS, &ret);
if (!ret) {
char *log;
printf("vertex shader compilation failed!:\n");
- glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret);
+ glGetShaderiv(gl.vertex_shader, GL_INFO_LOG_LENGTH, &ret);
if (ret > 1) {
log = malloc(ret);
- glGetShaderInfoLog(vertex_shader, ret, NULL, log);
+ glGetShaderInfoLog(gl.vertex_shader, ret, NULL, log);
printf("%s", log);
}
return -1;
}
- fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ gl.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
- glCompileShader(fragment_shader);
+ glShaderSource(gl.fragment_shader, 1, &fragment_shader_source, NULL);
+ glCompileShader(gl.fragment_shader);
- glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
+ glGetShaderiv(gl.fragment_shader, GL_COMPILE_STATUS, &ret);
if (!ret) {
char *log;
printf("fragment shader compilation failed!:\n");
- glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret);
+ glGetShaderiv(gl.fragment_shader, GL_INFO_LOG_LENGTH, &ret);
if (ret > 1) {
log = malloc(ret);
- glGetShaderInfoLog(fragment_shader, ret, NULL, log);
+ glGetShaderInfoLog(gl.fragment_shader, ret, NULL, log);
printf("%s", log);
}
gl.program = glCreateProgram();
- glAttachShader(gl.program, vertex_shader);
- glAttachShader(gl.program, fragment_shader);
+ glAttachShader(gl.program, gl.vertex_shader);
+ glAttachShader(gl.program, gl.fragment_shader);
glBindAttribLocation(gl.program, 0, "in_position");
glBindAttribLocation(gl.program, 1, "in_normal");
gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
- glViewport(0, 0, drm.mode->hdisplay, drm.mode->vdisplay);
+ glViewport(0, 0, drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay);
glEnable(GL_CULL_FACE);
gl.positionsoffset = 0;
return 0;
}
+static void exit_gbm(void)
+{
+ gbm_surface_destroy(gbm.surface);
+ gbm_device_destroy(gbm.dev);
+ return;
+}
+
+static void exit_gl(void)
+{
+ glDeleteProgram(gl.program);
+ glDeleteBuffers(1, &gl.vbo);
+ glDeleteShader(gl.fragment_shader);
+ glDeleteShader(gl.vertex_shader);
+ eglDestroySurface(gl.display, gl.surface);
+ eglDestroyContext(gl.display, gl.context);
+ eglTerminate(gl.display);
+ return;
+}
+
+static void exit_drm(void)
+{
+
+ drmModeRes *resources;
+ int i;
+
+ resources = (drmModeRes *)drm.resource_id;
+ for (i = 0; i < resources->count_connectors; i++) {
+ drmModeFreeEncoder(drm.encoder[i]);
+ drmModeFreeConnector(drm.connectors[i]);
+ }
+ drmModeFreeResources(drm.resource_id);
+ drmClose(drm.fd);
+ return;
+}
+
+void cleanup_kmscube(void)
+{
+ exit_gl();
+ exit_gbm();
+ exit_drm();
+ printf("Cleanup of GL, GBM and DRM completed\n");
+ return;
+}
+
static void draw(uint32_t i)
{
ESMatrix modelview;
esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
- GLfloat aspect = (GLfloat)(drm.mode->vdisplay) / (GLfloat)(drm.mode->hdisplay);
+ GLfloat aspect = (GLfloat)(drm.mode[DISP_ID]->vdisplay) / (GLfloat)(drm.mode[DISP_ID]->hdisplay);
ESMatrix projection;
esMatrixLoadIdentity(&projection);
*waiting_for_flip = 0;
}
+void print_usage()
+{
+ printf("Usage : kmscube <options>\n");
+ printf("\t-h : Help\n");
+ printf("\t-a : Enable all displays\n");
+ printf("\t-c <id> : Display using connector_id [if not specified, use the first connected connector]\n");
+ printf("\t-n <number> (optional): Number of frames to render\n");
+}
+
+int kms_signalhandler(int signum)
+{
+ switch(signum) {
+ case SIGINT:
+ case SIGTERM:
+ /* Allow the pending page flip requests to be completed before
+ * the teardown sequence */
+ sleep(1);
+ printf("Handling signal number = %d\n", signum);
+ cleanup_kmscube();
+ break;
+ default:
+ printf("Unknown signal\n");
+ break;
+ }
+ exit(1);
+}
+
int main(int argc, char *argv[])
{
fd_set fds;
struct drm_fb *fb;
uint32_t i = 0;
int ret;
+ int opt;
+ int frame_count = -1;
+
+ signal(SIGINT, kms_signalhandler);
+ signal(SIGTERM, kms_signalhandler);
+
+ while ((opt = getopt(argc, argv, "ahc:n:")) != -1) {
+ switch(opt) {
+ case 'a':
+ all_display = 1;
+ break;
+
+ case 'h':
+ print_usage();
+ return 0;
+
+ case 'c':
+ connector_id = atoi(optarg);
+ break;
+ case 'n':
+ frame_count = atoi(optarg);
+ break;
+
+
+ default:
+ printf("Undefined option %s\n", argv[optind]);
+ print_usage();
+ return -1;
+ }
+ }
+
+ if (all_display) {
+ printf("### Enabling all displays\n");
+ connector_id = -1;
+ }
ret = init_drm();
if (ret) {
printf("failed to initialize DRM\n");
return ret;
}
+ printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n",
+ drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay,
+ drm.mode[DISP_ID]->vdisplay);
FD_ZERO(&fds);
- FD_SET(0, &fds);
FD_SET(drm.fd, &fds);
ret = init_gbm();
fb = drm_fb_get_from_bo(bo);
/* set mode: */
- ret = drmModeSetCrtc(drm.fd, drm.crtc_id, fb->fb_id, 0, 0,
- &drm.connector_id, 1, drm.mode);
- if (ret) {
- printf("failed to set mode: %s\n", strerror(errno));
- return ret;
+ if (all_display) {
+ for (i=0; i<drm.ndisp; i++) {
+ ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
+ &drm.connector_id[i], 1, drm.mode[i]);
+ if (ret) {
+ printf("display %d failed to set mode: %s\n", i, strerror(errno));
+ return ret;
+ }
+ }
+ } else {
+ ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
+ 0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
+ if (ret) {
+ printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
+ return ret;
+ }
}
- while (1) {
+ while (frame_count != 0) {
struct gbm_bo *next_bo;
int waiting_for_flip = 1;
* hw composition
*/
- ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id,
+ ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
if (ret) {
printf("failed to queue page flip: %s\n", strerror(errno));
printf("select timeout!\n");
return -1;
} else if (FD_ISSET(0, &fds)) {
- printf("user interrupted!\n");
- break;
+ continue;
}
drmHandleEvent(drm.fd, &evctx);
}
/* release last buffer to render on again: */
gbm_surface_release_buffer(gbm.surface, bo);
bo = next_bo;
+
+ if(frame_count >= 0)
+ frame_count--;
}
+ cleanup_kmscube();
+ printf("\n Exiting kmscube \n");
+
return ret;
}