]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/kmscube.git/blobdiff - kmscube.c
kmscube.c: init_drm(): handle usecase where display is disabled
[glsdk/kmscube.git] / kmscube.c
index 6b1dd8b8c0da57e040ad74a71ed6fded180d67e2..9dbefa346b6e8f0ce44e95ca9314c73d8ddc0887 100644 (file)
--- a/kmscube.c
+++ b/kmscube.c
@@ -31,7 +31,9 @@
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <errno.h>
+#include <signal.h>
 
 #include <xf86drm.h>
 #include <xf86drmMode.h>
@@ -44,6 +46,7 @@
 #define MAX_DISPLAYS   (4)
 uint8_t DISP_ID = 0;
 uint8_t all_display = 0;
+int8_t connector_id = -1;
 
 static struct {
        EGLDisplay display;
@@ -54,6 +57,7 @@ static struct {
        GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
        GLuint vbo;
        GLuint positionsoffset, colorsoffset, normalsoffset;
+       GLuint vertex_shader, fragment_shader;
 } gl;
 
 static struct {
@@ -66,6 +70,8 @@ static struct {
        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;
@@ -78,12 +84,15 @@ struct drm_fb {
 static int init_drm(void)
 {
        static const char *modules[] = {
-                       "omapdrm", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
+                       "omapdrm", "tilcdc", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
        };
        drmModeRes *resources;
        drmModeConnector *connector = NULL;
        drmModeEncoder *encoder = NULL;
-       int i, j;
+       drmModeCrtc *crtc = NULL;
+
+       int i, j, k;
+       uint32_t maxRes, curRes;
 
        for (i = 0; i < ARRAY_SIZE(modules); i++) {
                printf("trying to load module %s...", modules[i]);
@@ -106,29 +115,89 @@ 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) {
-                       /* choose the last supported mode */
-                       drm.mode[drm.ndisp] = &connector->modes[connector->count_modes-1];
-                       drm.connector_id[drm.ndisp] = connector->connector_id;
 
-                       for (j=0; j<resources->count_encoders; j++) {
-                               encoder = drmModeGetEncoder(drm.fd, resources->encoders[j]);
+                       /* 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("no encoder!\n");
-                               return -1;
+                               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;
 
@@ -137,6 +206,20 @@ static int init_drm(void)
                        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);
@@ -173,7 +256,6 @@ 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[] = {
@@ -365,41 +447,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);
                }
 
@@ -408,8 +490,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");
@@ -461,6 +543,50 @@ static int init_gl(void)
        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;
@@ -556,6 +682,33 @@ static void page_flip_handler(int fd, unsigned int frame,
        *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;
@@ -567,27 +720,52 @@ 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);
 
-       if (argc > 1) {
-               if (strcmp(argv[1], "--all") == 0) 
+       while ((opt = getopt(argc, argv, "ahc:n:")) != -1) {
+               switch(opt) {
+               case 'a':
                        all_display = 1;
-               else if (strcmp(argv[1], "-h") == 0)
-                       printf("Usage: %s [ --all | <0|1|..> ] \n", argv[0]);
-               else
-                       DISP_ID = atoi(argv[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) 
+       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();
@@ -628,7 +806,7 @@ int main(int argc, char *argv[])
                }
        }
 
-       while (1) {
+       while (frame_count != 0) {
                struct gbm_bo *next_bo;
                int waiting_for_flip = 1;
 
@@ -659,8 +837,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);
                }
@@ -668,7 +845,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;
 }