]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/kmscube.git/blobdiff - kmscube.c
kmscube: Add : argument for connector support
[glsdk/kmscube.git] / kmscube.c
index 20516155b908ddf58edc103b194f4891f797027d..df2731d528971b5b8cd634bf737522d693173c80 100644 (file)
--- a/kmscube.c
+++ b/kmscube.c
@@ -1,6 +1,7 @@
 /*
  * 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 <stdbool.h>
+#include <unistd.h>
 #include <errno.h>
+#include <signal.h>
 
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#include <drm_fourcc.h>
 #include <gbm.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;
+char* device = "/dev/dri/card0";
 
 static struct {
        EGLDisplay display;
@@ -49,6 +58,9 @@ static struct {
        EGLSurface surface;
        GLuint program;
        GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
+       GLuint vbo;
+       GLuint positionsoffset, colorsoffset, normalsoffset;
+       GLuint vertex_shader, fragment_shader;
 } gl;
 
 static struct {
@@ -58,9 +70,14 @@ 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];
+       uint32_t format[MAX_DISPLAYS];
+       drmModeModeInfo *mode[MAX_DISPLAYS];
+       drmModeConnector *connectors[MAX_DISPLAYS];
 } drm;
 
 struct drm_fb {
@@ -68,29 +85,155 @@ struct drm_fb {
        uint32_t fb_id;
 };
 
+static uint32_t drm_fmt_to_gbm_fmt(uint32_t fmt)
+{
+       switch (fmt) {
+               case DRM_FORMAT_XRGB8888:
+                       return GBM_FORMAT_XRGB8888;
+               case DRM_FORMAT_ARGB8888:
+                       return GBM_FORMAT_ARGB8888;
+               case DRM_FORMAT_RGB565:
+                       return GBM_FORMAT_RGB565;
+               default:
+                       printf("Unsupported DRM format: 0x%x", fmt);
+                       return GBM_FORMAT_XRGB8888;
+       }
+}
+
+static bool search_plane_format(uint32_t desired_format, int formats_count, uint32_t* formats)
+{
+       int i;
+
+       for ( i = 0; i < formats_count; i++)
+       {
+               if (desired_format == formats[i])
+                       return true;
+       }
+
+       return false;
+}
+
+int get_drm_prop_val(int fd, drmModeObjectPropertiesPtr props,
+                        const char *name, unsigned int *p_val) {
+       drmModePropertyPtr p;
+       unsigned int i, prop_id = 0; /* Property ID should always be > 0 */
+
+       for (i = 0; !prop_id && i < props->count_props; i++) {
+               p = drmModeGetProperty(fd, props->props[i]);
+               if (!strcmp(p->name, name)){
+                       prop_id = p->prop_id;
+                       break;
+               }
+               drmModeFreeProperty(p);
+       }
+
+       if (!prop_id) {
+               printf("Could not find %s property\n", name);
+               return(-1);
+       }
+
+       drmModeFreeProperty(p);
+       *p_val = props->prop_values[i];
+       return 0;
+}
+
+static bool set_drm_format(void)
+{
+       /* desired DRM format in order */
+       static const uint32_t drm_formats[] = {DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565};
+       drmModePlaneRes *plane_res;
+       bool found = false;
+       int i,k;
+
+       drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+
+       plane_res  = drmModeGetPlaneResources(drm.fd);
+
+       if (!plane_res) {
+               printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
+               drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+               return false;
+       }
+
+       /*
+        * find the plane connected to crtc_id (the primary plane) and then find the desired pixel format
+        * from the plane format list
+        */
+       for (i = 0; i < plane_res->count_planes; i++)
+       {
+               drmModePlane *plane = drmModeGetPlane(drm.fd, plane_res->planes[i]);
+               drmModeObjectProperties *props;
+               unsigned int plane_type;
+
+               if(plane == NULL)
+                       continue;
+
+               props = drmModeObjectGetProperties(drm.fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
+
+               if(props == NULL){
+                       printf("plane (%d) properties not found\n",  plane->plane_id);
+                       drmModeFreePlane(plane);
+                       continue;
+               }
+
+               if(get_drm_prop_val(drm.fd, props, "type",  &plane_type) < 0)
+               {
+                       printf("plane (%d) type value not found\n",  plane->plane_id);
+                       drmModeFreeObjectProperties(props);
+                       drmModeFreePlane(plane);
+                       continue;
+               }
+
+               if (plane_type != DRM_PLANE_TYPE_PRIMARY)
+               {
+                       drmModeFreeObjectProperties(props);
+                       drmModeFreePlane(plane);
+                       continue;
+               }
+               else if (!plane->crtc_id)
+               {
+                       plane->crtc_id = drm.crtc_id[drm.ndisp];
+               }
+
+               drmModeFreeObjectProperties(props);
+
+               if (plane->crtc_id == drm.crtc_id[drm.ndisp])
+               {
+                       for (k = 0; k < ARRAY_SIZE(drm_formats); k++)
+                       {
+                               if (search_plane_format(drm_formats[k], plane->count_formats, plane->formats))
+                               {
+                                       drm.format[drm.ndisp] = drm_formats[k];
+                                       drmModeFreePlane(plane);
+                                       drmModeFreePlaneResources(plane_res);
+                                       drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+                                       return true;
+                               }
+                       }
+               }
+
+               drmModeFreePlane(plane);
+       }
+
+       drmModeFreePlaneResources(plane_res);
+       drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+       return false;
+}
+
 static int init_drm(void)
 {
-       static const char *modules[] = {
-                       "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos"
-       };
        drmModeRes *resources;
        drmModeConnector *connector = NULL;
        drmModeEncoder *encoder = NULL;
-       int i, area;
+       drmModeCrtc *crtc = NULL;
 
-       for (i = 0; i < ARRAY_SIZE(modules); i++) {
-               printf("trying to load module %s...", modules[i]);
-               drm.fd = drmOpen(modules[i], NULL);
-               if (drm.fd < 0) {
-                       printf("failed.\n");
-               } else {
-                       printf("success.\n");
-                       break;
-               }
-       }
+       int i, j, k;
+       uint32_t maxRes, curRes;
 
+       /* Open default dri device */
+       drm.fd = open(device, O_RDWR | O_CLOEXEC);
        if (drm.fd < 0) {
-               printf("could not open drm device\n");
+               printf("could not open drm device %s\n", device);
                return -1;
        }
 
@@ -99,19 +242,125 @@ static int init_drm(void)
                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;
+
+                       /* find the matched encoders */
+                       for (j=0; j<connector->count_encoders; j++) {
+                               encoder = drmModeGetEncoder(drm.fd, connector->encoders[j]);
+
+                               /* Take the fisrt one, if none is assigned */
+                               if (!connector->encoder_id)
+                               {
+                                       connector->encoder_id = encoder->encoder_id;
+                               }
+
+                               if (encoder->encoder_id == connector->encoder_id)
+                               {
+                                       /* find the first valid CRTC if not assigned */
+                                       if (!encoder->crtc_id)
+                                       {
+                                               for (k = 0; k < resources->count_crtcs; ++k) {
+                                                       /* check whether this CRTC works with the encoder */
+                                                       if (!(encoder->possible_crtcs & (1 << k)))
+                                                               continue;
+
+                                                       encoder->crtc_id = resources->crtcs[k];
+                                                       break;
+                                               }
+
+                                               if (!encoder->crtc_id)
+                                               {
+                                                       printf("Encoder(%d): no CRTC find!\n", encoder->encoder_id);
+                                                       drmModeFreeEncoder(encoder);
+                                                       encoder = NULL;
+                                                       continue;
+                                               }
+                                       }
+
+                                       break;
+                               }
+
+                               drmModeFreeEncoder(encoder);
+                               encoder = NULL;
+                       }
+
+                       if (!encoder) {
+                               printf("Connector (%d): no encoder!\n", connector->connector_id);
+                               drmModeFreeConnector(connector);
+                               continue;
+                       }
+
+                       /* choose the current or first supported mode */
+                       crtc = drmModeGetCrtc(drm.fd, encoder->crtc_id);
+                       for (j = 0; j < connector->count_modes; j++)
+                       {
+                               if (crtc->mode_valid)
+                               {
+                                       if ((connector->modes[j].hdisplay == crtc->width) &&
+                                       (connector->modes[j].vdisplay == crtc->height))
+                                       {
+                                               drm.mode[drm.ndisp] = &connector->modes[j];
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       if ((connector->modes[j].hdisplay == crtc->x) &&
+                                          (connector->modes[j].vdisplay == crtc->y))
+                                       {
+                                               drm.mode[drm.ndisp] = &connector->modes[j];
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if(j >= connector->count_modes)
+                               drm.mode[drm.ndisp] = &connector->modes[0];
+
+                       drm.connector_id[drm.ndisp] = connector->connector_id;
+
+                       drm.encoder[drm.ndisp]  = (uint32_t) encoder;
+                       drm.crtc_id[drm.ndisp] = encoder->crtc_id;
+                       drm.connectors[drm.ndisp] = connector;
+
+                       if (!set_drm_format())
+                       {
+                               // Error handling
+                               printf("No desired pixel format found!\n");
+                               return -1;
+                       }
+
+                       printf("### Display [%d]: CRTC = %d, Connector = %d, format = 0x%x\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp], drm.format[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..
                 */
@@ -119,38 +368,6 @@ static int init_drm(void)
                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;
 }
 
@@ -159,8 +376,8 @@ static int init_gbm(void)
        gbm.dev = gbm_create_device(drm.fd);
 
        gbm.surface = gbm_surface_create(gbm.dev,
-                       drm.mode->hdisplay, drm.mode->vdisplay,
-                       GBM_FORMAT_XRGB8888,
+                       drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
+                       drm_fmt_to_gbm_fmt(drm.format[DISP_ID]),
                        GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
        if (!gbm.surface) {
                printf("failed to create gbm surface\n");
@@ -173,9 +390,107 @@ static int init_gbm(void)
 static int init_gl(void)
 {
        EGLint major, minor, n;
-       GLuint vertex_shader, fragment_shader;
        GLint ret;
 
+       static const GLfloat vVertices[] = {
+                       // front
+                       -1.0f, -1.0f, +1.0f, // point blue
+                       +1.0f, -1.0f, +1.0f, // point magenta
+                       -1.0f, +1.0f, +1.0f, // point cyan
+                       +1.0f, +1.0f, +1.0f, // point white
+                       // back
+                       +1.0f, -1.0f, -1.0f, // point red
+                       -1.0f, -1.0f, -1.0f, // point black
+                       +1.0f, +1.0f, -1.0f, // point yellow
+                       -1.0f, +1.0f, -1.0f, // point green
+                       // right
+                       +1.0f, -1.0f, +1.0f, // point magenta
+                       +1.0f, -1.0f, -1.0f, // point red
+                       +1.0f, +1.0f, +1.0f, // point white
+                       +1.0f, +1.0f, -1.0f, // point yellow
+                       // left
+                       -1.0f, -1.0f, -1.0f, // point black
+                       -1.0f, -1.0f, +1.0f, // point blue
+                       -1.0f, +1.0f, -1.0f, // point green
+                       -1.0f, +1.0f, +1.0f, // point cyan
+                       // top
+                       -1.0f, +1.0f, +1.0f, // point cyan
+                       +1.0f, +1.0f, +1.0f, // point white
+                       -1.0f, +1.0f, -1.0f, // point green
+                       +1.0f, +1.0f, -1.0f, // point yellow
+                       // bottom
+                       -1.0f, -1.0f, -1.0f, // point black
+                       +1.0f, -1.0f, -1.0f, // point red
+                       -1.0f, -1.0f, +1.0f, // point blue
+                       +1.0f, -1.0f, +1.0f  // point magenta
+       };
+
+       static const GLfloat vColors[] = {
+                       // front
+                       0.0f,  0.0f,  1.0f, // blue
+                       1.0f,  0.0f,  1.0f, // magenta
+                       0.0f,  1.0f,  1.0f, // cyan
+                       1.0f,  1.0f,  1.0f, // white
+                       // back
+                       1.0f,  0.0f,  0.0f, // red
+                       0.0f,  0.0f,  0.0f, // black
+                       1.0f,  1.0f,  0.0f, // yellow
+                       0.0f,  1.0f,  0.0f, // green
+                       // right
+                       1.0f,  0.0f,  1.0f, // magenta
+                       1.0f,  0.0f,  0.0f, // red
+                       1.0f,  1.0f,  1.0f, // white
+                       1.0f,  1.0f,  0.0f, // yellow
+                       // left
+                       0.0f,  0.0f,  0.0f, // black
+                       0.0f,  0.0f,  1.0f, // blue
+                       0.0f,  1.0f,  0.0f, // green
+                       0.0f,  1.0f,  1.0f, // cyan
+                       // top
+                       0.0f,  1.0f,  1.0f, // cyan
+                       1.0f,  1.0f,  1.0f, // white
+                       0.0f,  1.0f,  0.0f, // green
+                       1.0f,  1.0f,  0.0f, // yellow
+                       // bottom
+                       0.0f,  0.0f,  0.0f, // black
+                       1.0f,  0.0f,  0.0f, // red
+                       0.0f,  0.0f,  1.0f, // blue
+                       1.0f,  0.0f,  1.0f  // magenta
+       };
+
+       static const GLfloat vNormals[] = {
+                       // front
+                       +0.0f, +0.0f, +1.0f, // forward
+                       +0.0f, +0.0f, +1.0f, // forward
+                       +0.0f, +0.0f, +1.0f, // forward
+                       +0.0f, +0.0f, +1.0f, // forward
+                       // back
+                       +0.0f, +0.0f, -1.0f, // backbard
+                       +0.0f, +0.0f, -1.0f, // backbard
+                       +0.0f, +0.0f, -1.0f, // backbard
+                       +0.0f, +0.0f, -1.0f, // backbard
+                       // right
+                       +1.0f, +0.0f, +0.0f, // right
+                       +1.0f, +0.0f, +0.0f, // right
+                       +1.0f, +0.0f, +0.0f, // right
+                       +1.0f, +0.0f, +0.0f, // right
+                       // left
+                       -1.0f, +0.0f, +0.0f, // left
+                       -1.0f, +0.0f, +0.0f, // left
+                       -1.0f, +0.0f, +0.0f, // left
+                       -1.0f, +0.0f, +0.0f, // left
+                       // top
+                       +0.0f, +1.0f, +0.0f, // up
+                       +0.0f, +1.0f, +0.0f, // up
+                       +0.0f, +1.0f, +0.0f, // up
+                       +0.0f, +1.0f, +0.0f, // up
+                       // bottom
+                       +0.0f, -1.0f, +0.0f, // down
+                       +0.0f, -1.0f, +0.0f, // down
+                       +0.0f, -1.0f, +0.0f, // down
+                       +0.0f, -1.0f, +0.0f  // down
+       };
+
        static const EGLint context_attribs[] = {
                EGL_CONTEXT_CLIENT_VERSION, 2,
                EGL_NONE
@@ -266,41 +581,41 @@ static int init_gl(void)
        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);
                }
 
@@ -309,8 +624,8 @@ static int init_gl(void)
 
        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");
@@ -340,125 +655,79 @@ static int init_gl(void)
        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;
+       gl.colorsoffset = sizeof(vVertices);
+       gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
+       glGenBuffers(1, &gl.vbo);
+       glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
+       glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
+       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
+       glEnableVertexAttribArray(1);
+       glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
+       glEnableVertexAttribArray(2);
 
        return 0;
 }
 
-static void draw(uint32_t i)
+static void exit_gbm(void)
 {
-       ESMatrix modelview;
-       static const GLfloat vVertices[] = {
-                       // front
-                       -1.0f, -1.0f, +1.0f, // point blue
-                       +1.0f, -1.0f, +1.0f, // point magenta
-                       -1.0f, +1.0f, +1.0f, // point cyan
-                       +1.0f, +1.0f, +1.0f, // point white
-                       // back
-                       +1.0f, -1.0f, -1.0f, // point red
-                       -1.0f, -1.0f, -1.0f, // point black
-                       +1.0f, +1.0f, -1.0f, // point yellow
-                       -1.0f, +1.0f, -1.0f, // point green
-                       // right
-                       +1.0f, -1.0f, +1.0f, // point magenta
-                       +1.0f, -1.0f, -1.0f, // point red
-                       +1.0f, +1.0f, +1.0f, // point white
-                       +1.0f, +1.0f, -1.0f, // point yellow
-                       // left
-                       -1.0f, -1.0f, -1.0f, // point black
-                       -1.0f, -1.0f, +1.0f, // point blue
-                       -1.0f, +1.0f, -1.0f, // point green
-                       -1.0f, +1.0f, +1.0f, // point cyan
-                       // top
-                       -1.0f, +1.0f, +1.0f, // point cyan
-                       +1.0f, +1.0f, +1.0f, // point white
-                       -1.0f, +1.0f, -1.0f, // point green
-                       +1.0f, +1.0f, -1.0f, // point yellow
-                       // bottom
-                       -1.0f, -1.0f, -1.0f, // point black
-                       +1.0f, -1.0f, -1.0f, // point red
-                       -1.0f, -1.0f, +1.0f, // point blue
-                       +1.0f, -1.0f, +1.0f  // point magenta
-       };
+        gbm_surface_destroy(gbm.surface);
+        gbm_device_destroy(gbm.dev);
+        return;
+}
 
-       static const GLfloat vColors[] = {
-                       // front
-                       0.0f,  0.0f,  1.0f, // blue
-                       1.0f,  0.0f,  1.0f, // magenta
-                       0.0f,  1.0f,  1.0f, // cyan
-                       1.0f,  1.0f,  1.0f, // white
-                       // back
-                       1.0f,  0.0f,  0.0f, // red
-                       0.0f,  0.0f,  0.0f, // black
-                       1.0f,  1.0f,  0.0f, // yellow
-                       0.0f,  1.0f,  0.0f, // green
-                       // right
-                       1.0f,  0.0f,  1.0f, // magenta
-                       1.0f,  0.0f,  0.0f, // red
-                       1.0f,  1.0f,  1.0f, // white
-                       1.0f,  1.0f,  0.0f, // yellow
-                       // left
-                       0.0f,  0.0f,  0.0f, // black
-                       0.0f,  0.0f,  1.0f, // blue
-                       0.0f,  1.0f,  0.0f, // green
-                       0.0f,  1.0f,  1.0f, // cyan
-                       // top
-                       0.0f,  1.0f,  1.0f, // cyan
-                       1.0f,  1.0f,  1.0f, // white
-                       0.0f,  1.0f,  0.0f, // green
-                       1.0f,  1.0f,  0.0f, // yellow
-                       // bottom
-                       0.0f,  0.0f,  0.0f, // black
-                       1.0f,  0.0f,  0.0f, // red
-                       0.0f,  0.0f,  1.0f, // blue
-                       1.0f,  0.0f,  1.0f  // magenta
-       };
+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 const GLfloat vNormals[] = {
-                       // front
-                       +0.0f, +0.0f, +1.0f, // forward
-                       +0.0f, +0.0f, +1.0f, // forward
-                       +0.0f, +0.0f, +1.0f, // forward
-                       +0.0f, +0.0f, +1.0f, // forward
-                       // back
-                       +0.0f, +0.0f, -1.0f, // backbard
-                       +0.0f, +0.0f, -1.0f, // backbard
-                       +0.0f, +0.0f, -1.0f, // backbard
-                       +0.0f, +0.0f, -1.0f, // backbard
-                       // right
-                       +1.0f, +0.0f, +0.0f, // right
-                       +1.0f, +0.0f, +0.0f, // right
-                       +1.0f, +0.0f, +0.0f, // right
-                       +1.0f, +0.0f, +0.0f, // right
-                       // left
-                       -1.0f, +0.0f, +0.0f, // left
-                       -1.0f, +0.0f, +0.0f, // left
-                       -1.0f, +0.0f, +0.0f, // left
-                       -1.0f, +0.0f, +0.0f, // left
-                       // top
-                       +0.0f, +1.0f, +0.0f, // up
-                       +0.0f, +1.0f, +0.0f, // up
-                       +0.0f, +1.0f, +0.0f, // up
-                       +0.0f, +1.0f, +0.0f, // up
-                       // bottom
-                       +0.0f, -1.0f, +0.0f, // down
-                       +0.0f, -1.0f, +0.0f, // down
-                       +0.0f, -1.0f, +0.0f, // down
-                       +0.0f, -1.0f, +0.0f  // down
-       };
+static void exit_drm(void)
+{
 
-       /* clear the color buffer */
-       glClearColor(0.5, 0.5, 0.5, 1.0);
-       glClear(GL_COLOR_BUFFER_BIT);
+        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);
+        close(drm.fd);
+        return;
+}
 
-       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
-       glEnableVertexAttribArray(0);
+void cleanup_kmscube(void)
+{
+       exit_gl();
+       exit_gbm();
+       exit_drm();
+       printf("Cleanup of GL, GBM and DRM completed\n");
+       return;
+}
 
-       glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, vNormals);
-       glEnableVertexAttribArray(1);
+static void draw(uint32_t i)
+{
+       ESMatrix modelview;
 
-       glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, vColors);
-       glEnableVertexAttribArray(2);
+       /* clear the color buffer */
+       glClearColor(0.5, 0.5, 0.5, 1.0);
+       glClear(GL_COLOR_BUFFER_BIT);
 
        esMatrixLoadIdentity(&modelview);
        esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
@@ -466,7 +735,7 @@ static void draw(uint32_t i)
        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);
@@ -491,8 +760,6 @@ static void draw(uint32_t i)
        glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
        glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
 
-       glEnable(GL_CULL_FACE);
-
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
        glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
@@ -516,7 +783,8 @@ drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
 static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
 {
        struct drm_fb *fb = gbm_bo_get_user_data(bo);
-       uint32_t width, height, stride, handle;
+       uint32_t width, height, format;
+       uint32_t bo_handles[4] = {0}, offsets[4] = {0}, pitches[4] = {0};
        int ret;
 
        if (fb)
@@ -527,10 +795,11 @@ static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
 
        width = gbm_bo_get_width(bo);
        height = gbm_bo_get_height(bo);
-       stride = gbm_bo_get_stride(bo);
-       handle = gbm_bo_get_handle(bo).u32;
+       pitches[0] = gbm_bo_get_stride(bo);
+       bo_handles[0] = gbm_bo_get_handle(bo).u32;
+       format = gbm_bo_get_format(bo);
 
-       ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
+       ret = drmModeAddFB2(drm.fd, width, height, format, bo_handles, pitches, offsets, &fb->fb_id, 0);
        if (ret) {
                printf("failed to create fb: %s\n", strerror(errno));
                free(fb);
@@ -546,7 +815,35 @@ static void page_flip_handler(int fd, unsigned int frame,
                  unsigned int sec, unsigned int usec, void *data)
 {
        int *waiting_for_flip = data;
-       *waiting_for_flip = 0;
+       *waiting_for_flip = *waiting_for_flip - 1;
+}
+
+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-d /dev/dri/cardX : DRM device to be used. [If not specified, use /dev/dri/card0]\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[])
@@ -560,15 +857,55 @@ int main(int argc, char *argv[])
        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:d:n:")) != -1) {
+               switch(opt) {
+               case 'a':
+                       all_display = 1;
+                       break;
+
+               case 'h':
+                       print_usage();
+                       return 0;
+
+               case 'c':
+                       connector_id = atoi(optarg);
+                       break;
+               case 'd':
+                       device = 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();
@@ -591,16 +928,28 @@ int main(int argc, char *argv[])
        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;
+               int waiting_for_flip;
+               int cc;
 
                draw(i++);
 
@@ -613,11 +962,24 @@ int main(int argc, char *argv[])
                 * hw composition
                 */
 
-               ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id,
-                               DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
-               if (ret) {
-                       printf("failed to queue page flip: %s\n", strerror(errno));
-                       return -1;
+               if (all_display) {
+                       for (cc=0;cc<drm.ndisp; cc++) {
+                               ret = drmModePageFlip(drm.fd, drm.crtc_id[cc], fb->fb_id,
+                                       DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
+                               if (ret) {
+                                       printf("failed to queue page flip: %s\n", strerror(errno));
+                                       return -1;
+                               }
+                       }
+                       waiting_for_flip = drm.ndisp;
+               } else {
+                       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));
+                               return -1;
+                       }
+                       waiting_for_flip = 1;
                }
 
                while (waiting_for_flip) {
@@ -629,8 +991,7 @@ int main(int argc, char *argv[])
                                printf("select timeout!\n");
                                return -1;
                        } else if (FD_ISSET(0, &fds)) {
-                               printf("user interrupted!\n");
-                               break;
+                               continue;
                        }
                        drmHandleEvent(drm.fd, &evctx);
                }
@@ -638,7 +999,13 @@ int main(int argc, char *argv[])
                /* 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;
 }