Ircam - Centre Georges-Pompidou Équipe Analyse/Synthèse

Bilan de la tentative d'utilisation de openGL / X


  • Introduction
  • OpenGL et XSpect
  • Conclusion

    Introduction

    OpenGL, GLX, GLU

    OpenGL est une interface logicielle destinee a la manipulation de graphismes, permettant le dessin 2Dou 3D. A partir de vertices (coordonees ou ensemble de coordonnees), ainsi que d'informations sur le rendu specifies par l'utilisateur, openGL calcule l'image resultante et l'affiche.

    GLX est une bibliotheque permettant l'utilisation de openGL a travers un serveur X. Cette bibliotheque permet d'effectuer l'affichage a l'interieur de drawables X comme les pixmaps, mais elle offre egalement un mode de connexion direct, qui n'utilise pas le serveur X, dans le but d'accelerer l'affichage.

    Enfin, GLU (GL Utilities) est une bibliotheque de haut niveau, reposant sur GL, qui permet par exemple le trace de NURBS et de tous types d'objet complexes, la gestion de la perspective de facon simplifiee.

    Dans le Makefile, les directives -lGL et -lGLU doivent etre ajoutees a la ligne de compilation. Les lignes ajoutees pour permettre l'utilisation de GLX, openGL et GLU sont:

    #ifdef openGL
    #include <GL/glx.h>
    #include <GL/gl.h>
    #include <GL/glu.h>
    #endif
    

    Pertinence de l'utilisation de openGL pour Xspect

    L'utilisation d'openGL a ete decidee dans un premier temps pour plusieurs raisons.
  • cette bibliotheque existe pour un grand nombre de systemes, ce qui devait permettre a terme un portage plus facile de Xspect vers d'autre platformes sans retoucher a la partie d'affichage des signaux et des analyses. (Bien que l'on puisse objecter a cela que openGl n'est pas disponible pour stations alpha)
  • l'affichage devait permettre l'utilisation de degrades de couleurs et de la transparence, afin de pouvoir superposer plusieurs representations differentes (comme c'est le cas dans SpeX), ainsi qu'une eventuelle representation en 3 dimensions, trois fonctionnalites aisement utilisables de openGL.
  • enfin, openGL semblait etre extrement rapide.

    Fonctionnement general d'openGL / X

    Dans notre cas, il n'est pas possible d'utiliser le mode de rendu direct, puisque tout l'affichage est effectue en X dans des drawables. On doit passer par la couche X qui les gere, a moins de reprogrammer toute la partie graphique de XSpect afin de n'utiliser qu'openGL.

  • La premiere etape consiste a choisir un Visual (ensemble d'attributs comme la profondeur de l'affichage, de chacune des couleurs, la representation des couleurs en RGBA (red, green, blue, alpha) ou en mode indexe, la profondeur de chacune des couleurs, etc.). La fonction
    glXChooseVisual(Display* display, int screen, int* attributeList)
    renvoie le visual qui correpond le mieux aux specifications de la liste d'attributs attributeList. Cette fonction est le pendant GLX a la fonction X XMatchVisualInfo.

  • Comme X, openGL utilise la notion de contexte. Un contexte contient la valeur de toutes les variables d'etat de openGL, mais rien sur l'endroit ou doit etre effectue le rendu. La seconde etape consiste donc a creer un contexte GLX par la fonction
    glXCreateContext(Display* display,XVisualInfo *vis,GLXContext shareList,Bool direct);
    

  • Il faut ensuite creer un pixmap utilisable par GLX par la fonction
    glXCreateGLXPixmap(Display* display,XVisualInfo *vis,Pixmap pixmap)
    pixmap est le pixmap X qui existe deja dans les structures de View et de Frame

  • L'ensemble du drawables et du contexte GL peuvent ensuite etre specifies comme courants pour que les modifications s'appliquent a eux. C'est ce que fait la fonction
    glXMakeCurrent(Display* display, GLXDrawable draw, GLXContext ctx)

    Dessiner avec openGL

    Primitives de dessin

    Le dessin sous openGL consiste a donner a GL toutes les informations necessaires pour effectuer un trace, puis de demander l'affichage. Ces informations sont passees sous la forme de primitives telles que des definitions de coordonnees. De telles informations sont delimitees par des primitives de debut et de fin. L'exemple suivant trace un triangle dans l'espace et une droite dans le plan (O,i,j)(le repere de openGL doit etre specifie auparavant).
     
    glBegin(GL_TRIANGLE);
      glVertex3f(0.0,0.0,0.0); /* 3 signifie 3 dimensions, f pour float */ 
      glVertex3f(1.0,0.0,0.0);
      glVertex3f(0.0,1.0,1.0);
    glEnd();
    glBegin(GL_LINES);
      glVertex2i(1,1);         /* 2 signifie 2 dimensions, i pour int */ 
      glVertex2i(0,0);
    glEnd();
    glFlush();                 /* affiche le resultat */
    

    Listes d'affichage (Display List)

    OpenGL utilise egalement la notion de Display List, qui est une liste de primitives d'affichage delimitees par des primitives de debut et de fin compilees avant l'affichage pour optimiser la vitesse du rendu. Ces listes peuvent encapsuler la quasi totalite des primitives openGL, et donc comporter des modifications du contexte courant.

    Une liste possede un nom (sous forme d'entier), afin de pouvoir etre reutilisee. OpenGl propose un jeu complet de primitives de reservation/creation/affichage/destruction de Display List. Celles ci sont la pour en faciliter la gestion, mais leur utilisation n'est pas obligatoire. L'exemple suivant illustre l'utilisation de telles listes.

    GLUint nomListe1;
    nomListe = glGenList(2);           /* reservation de 2 listes */
    
    glNewList(nomListe,GL_COMPILE)     /* debut de definition de la premiere liste*/
      glBegin(GL_TRIANGLE);
        ...
      glEnd();
      glBegin(GL_LINES);
        ...
      glEnd();  
      glFlush();
    glEndList();
    
    glNewList(nomListe+1,GL_COMPILE_AND_EXECUTE) /* la liste est executee directement */
      glDoAnUnknownOperationOnTheGLContext();
      ...
      glDoAnotherOperation();
    glEndList();
    
    glCallList(nomListe);              /* execution des listes */
    glCallList(nomListe+1);
            
    

    OpenGL et XSpect

    Structures de donnees

    Plusieurs modifications ont du etre faites dans les strucures de donnees.

    Nous avons vu plus haut que les zones d'affichage ne peuvent pas etre directement les drawables X, mais des GLXPixmaps. Chaque View est suceptible de recevoir un affichage en openGL. C'est pourquoi nous avons ajoute a cette strucure un pixmap GLX. De meme, pour des raisons de rapidite et d'homogeneite avec les traces en X (il est plus commode de stocker le contexte GLX dans cette meme structure et de l'appeler lorsque l'on en a besoin que de le changer les attributs du contexte courant avant chaque affichage). La strucure view devient donc:

    typedef struct _View
    {
      ...
      Pixmap             pixmap;                   /* Xwindow pixmap */
      GC                 gc;                       /* Xwindow Graphic Context to copy view in frame */
      Pixmap             clipMask;                 /* Xwindow clipMask, added to gc */
    #ifdef openGL
      GLXPixmap          glxPixmap;                /* (modif 03/08/98) pixmap used by openGL */
      GLXContext         glxContext;               /* (modif 14/08/98) glx context used by openGL */
    #endif
      ...
    }
    Meme si, en pratique, l'affichage doit se faire, dans XSpect, dans les pixmaps des View, X ou GLX, et etre copies par la suite dans les pixmaps des Frames avant d'etre affiches, en prevision d'une extension de l'utilisation de openGL a tous les traces, il a ete bon de creer l'equivalent GLX du pixmap X des frames. On obtient donc la strucure suivante.
    typedef struct _Frame
    {
      ...
      Pixmap             pixmap;                   /* global Xwindow pixmap */
    #ifdef openGL
      GLXPixmap          glxPixmap;                /* pixmap for openGL (modif 03/08/98) */
      GLXContext         glxContext;               /* (modif 14/08/98) glx context used by openGL */
    #endif  
      ...
    }
    Enfin, l'utilisation des display Lists dans une optique de rapidite a impose l'ajout de la reference de la display List dans la structure View.
    typedef struct _View
    {
      ...
    #ifdef openGL
      GLuint             glListName;               /* name of the view's openGl display list */
    #endif       
      ...
    }

    Gestion des couleurs (indexe / RGBA)

    OpenGL permet l'utilisation d'un contexte RGBA, alors meme que le pixmap dans lequel va etre effectue l'affichage (c'est a dire le pixmap X a partir duquel est cree le pixmap GLX) utilise les couleurs. De plus, le mode indexe ne permet pas de specifier le parametre alpha dans la definition de la couleur.

    Ceci est visible sur les fonctions de choix de la couleur appliquee au contexte courant, qui sont, pour le mode RGB et le mode indexe respectivement

    glColor4x(red,green,blue,alpha) et glIndex(index)

    Pour obtenir la couleur finale dans le cas d'une specification RGBA dans un pixmap en mode indexe, openGL calcule les composantes RGB de chaque pixel, puis recherche dans la Colormap (palette de couleur associee a l'application ou a l'ecran) la couleur ayant les composantes RGB les plus proches. Le resultat est donc assez aleatoire, et dans les cas ou peu de couleurs sont alouees, ce qui est le cas de Xspect, franchement mauvais.

    De plus, ce choix ne permet pas d'utiliser l'overlay (technique de bas niveau, qui consite a ne modifier qu'un plan de couleur de l'ecran) utilisee dans XSpect pour les surlignements dans les selections.

    On est donc contraint, si l'on ne veut pas remettre en cause la globalite de la partie graphique d'XSpect, de choisir le mode de couleur indexe, ce qui empeche l'utilisation de la transparence (les resultats etant trop mauvais), er une utilisation intuitive des couleurs.

    Passage des donnees du sonagramme a openGL

    Listes d'affichages (display list)

    L'objectif de l'utilisation d'openGl a ete en premier lieu le trace du sonagrame. L'analyse est faite avant l'affichage par le Super Vocdeur de Phase, et les resultats doivent etre lus dans un fichier qui contient toutes les amplitudes.
    Une methode naturelle de trace est donc le passage de tous les points a openGL, sous forme de triangles ou de quadrilateres en trois dimensions dont la couleur est fonction de l'amplitude, afin qu'openGL gere seul la perspective, le zoom, dans une certaine mesure, donc, toute la partie affichage.
    On a par consequent utilise un algorithme du type
    glNewList(nomListe,GL_COMPILE);    
      Pour tous les points du fichier 
        obtenir son amplitude(z)
        fixer la couleur
        obtenir le temps(x) et la frequence(y) correspondants
        tracer un polygone avec les points environnants
      Fin pour      
    glEndList();
    

    Problemes de lenteurs et modification de l'utilisation d'openGL

    L'utilisation de l'algorithme precedent s'est toutefois revele impossible: d'une part la compilation de la liste etait beaucoup trop longue (de l'ordre de 5 secondes), d'autre part son execution etait loin d'etre instantanee (de l'ordre de 2 a 3 secondes).

    En effet, le nombre de points contenus dans un fichier, meme s'il est tres variable, atteint courament plusieurs centaines de milliers de donnees. L'examen attentif de l'execution a revele que dans l'algorithme, le temps d'execution de toutes les commandes non openGL reunnies etait negligeable devant celui des primitives openGL utilisees a savoir

  • la selection de la couleur par glColor, mais aussi par glIndex
  • l'entree des vertex dans openGL.

    Entrer dans openGL toutes les donnees etant impossible, il est donc logique de chercher a ne rentrer que les donnees indispensables pour reduire le temps de calcul, c'est a dire les donnees qui vont etre affichees.

    A partir de la, il devient inutile de rentrer les coordonnees en 3 dimensions, puisque l'on ne sait pas a l'avance quelles donnees sont necessaires ou non en fonction de l'affichage desire (puisque c'est justement le role meme de openGL). La seule part de openGL se reduit donc a l'affichage de points de couleur dans un pixmap. Cette couche supplementaire est donc inutile.

    Conclusion

    L'utilisation de openGL s'est donc progressivement restreinte au trace de points ou de rectangles dans un pixmap GL en utilisant une palette de couleurs par indices, pour des raisons de rapidite et de qualite de rendu, openGL/X n'apportant aucune garantie quand a l'utilisation des couleurs en mode RGBA pour une application utilisant le mode indexe.

    Meme avec ces restrictions, l'affichage est reste tres lent: l'utilisation faite d'openGL n'a manifestement pas ete la bonne. La solution openGL ne presentait donc plus aucun avantage, c'est pourquoi le sonagramme a finalement ete realise en X pur.


    Derniere modification : 15/09/98 - Vivien Guillet