Ximages, etc...


Table des matières

Introduction

La Xlib propose une structure assez proche dans son utilisation des Pixmaps, la structure XImage. Cette structure permet d'encapsuler un buffer au sens du langage C, par exemple :

char *buffer = (char *) malloc(nb_cols * nb_lignes * 
                               sizeof(char));

...dans une structure de plus haut niveau : un objet de type XImage manipulable par la Xlib.

Le principal avantage des XImages sur les Pixmaps est que la manipulation des données graphiques qu'elles contiennent se fait en attaquant directement le buffer à l'aide de fonctions C standards. Ceci permet d'optimiser les opérations graphiques. Le dessin d'un rectangle uni se fera à l'aide d'un appel à la fonction C memcopy()par exemple...

Leur principal désavantage est que l'on ne peut plus utiliser les fonctions de dessin de la Xlib. On doit tout faire à la main. La seule fonction graphique disponible est une macro qui permet de remplir un point de l'XImage avec une couleur donnée!!!

Caractéristiques des XImages

Fonctions de manipulation des Images

Exemple d'utilisation d'une XImage

Allocation d'une XImage dans une zone de mémoire partagée

Certaines implémentations de la Xlib fournissent des fonctions permettant d'allouer une XImage dans une zone de mémoire partagée par l'application client et le serveur X. Les versions Solaris, SunOS et Linux de la Xlib en font partie.

On gagne au moins un facteur deux en performances pures lors d'opérations comme XPutImage() qui interviennt très souvent sitôt que l'on fait de l'animation. Il est donc très intéressant d'utiliser la mémoire partagée lorsqu'on en a la possibilité.

Malheureusement, il n'est possible d'allouer cette mémoire partagée que lorsque l'application client tourne sur la même machine que le serveur. En d'autres termes : si vous êtes connectés sur une autre machine que celle sur laquelle vous travaillez, ne comptez pas sur une application distante pour ouvrir une mémoire partagée sur votre machine.

Conclusion : si vous voulez qu'une application fonctionnent "normalement", en local comme en remote, prévoyez le cas ou l'allocation de la mémoire partagée échoue.

L'exemple qui suit présente une fonction qui essaie d'allouer une XImage dans une zone de mémoire partagée. Si il y a echec, alors l'XImage est allouée de manière standard.

/*----------------------------------------*/
XImage* Alloc_XImage(long width, long height)
/*----------------------------------------*/
/* Alloue un buffer de de width pixels de large * height pixels
   de haut dans une XImage */
{
  /* Pour la shared memory */
  XShmSegmentInfo Shminfo;
  int CompletionType; 
  unsigned char Shm_Hard_Buffer_Flag;

  XImage *XIma=NULL;
  long Shm_OK;

  /* Allocation d'une XImahe en Shared memory si possible */
  Shm_OK=XShmQueryExtension(display);
  switch(Shm_OK) {
  case 0: 
    /* On a pas pas pu allouer de Shared memory. On alloue 
       donc le Buffer a l'aide d'un malloc */
    if (buffer=(char *) malloc(width * height *sizeof(char)) {
      perror("malloc failed \n");
      exit(0);
    }

    /* Allocation d'une XImage normale */
    XIma=XCreateImage(display, visual ,
                      8, ZPixmap , 0,(char *) buffer ,
                      width, height,8,0);

    /* Flag qui indique qu'on a pas alloue la Shared Memory */
    Shm_Hard_Buffer_Flag = False;
    break;
 
  case 1: 
    /* On a pu allouer la Shared memory. Le buffer va donc se 
       trouver dans cette zone. On ne fait de malloc() */
    XIma=XShmCreateImage(display,visual ,8,ZPixmap ,
                         NULL,&Shminfo,width,height);
 
    Shminfo.shmid = shmget(IPC_PRIVATE,width * height, 
                           IPC_CREAT | 0777);
    Shminfo.shmaddr = XIma->data = buffer = 
                            shmat(Shminfo.shmid, NULL, 0);

    if (buffer) {
      fprintf(stderr,"erreur d'allocation en Shared memory\n");
      exit(0);
    }
    

    /* Shared memory alloue */
    Shminfo.readOnly = False;
    XShmAttach(display, &Shminfo);
 
    Shm_Hard_Buffer_Flag = True;
    CompletionType = XShmGetEventBase(display) + ShmCompletion; 
    break;  
  }  

  return XIma;
}

Ouf!!!

Remarquons plusieurs choses :