IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Seg fault de gluBuild2DMipmaps dans pthread


Sujet :

OpenGL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 29
    Points : 17
    Points
    17
    Par défaut Seg fault de gluBuild2DMipmaps dans pthread
    Bonjour tout le monde, :]

    J'ai un petit souci avec la fonction gluBuild2DMipmaps (OpenGL) en environnement multi-thread. Je m'explique : ...

    J'ai créé une classe Texture comportant une méthode publique "load()". Cette fonction charge un fichier image et le transforme en texture OpenGL. Voici son code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    int Texture::load() {
     
    	// Loading the image file
    	SDL_Surface * surfaceImage = IMG_Load("/home/test/image_file.png");
    	if (surfaceImage == NULL) {
    		return ERROR;
    	}
     
    	// Mask
    	Uint32 rmask, gmask, bmask, amask;
    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
    	rmask = 0xff000000;
    	gmask = 0x00ff0000;
    	bmask = 0x0000ff00;
    	amask = 0x000000ff;
    #else
    	rmask = 0x000000ff;
    	gmask = 0x0000ff00;
    	bmask = 0x00ff0000;
    	amask = 0xff000000;
    #endif
     
    	// Format
    	SDL_PixelFormat format = *(surfaceImage->format);
    	format.BitsPerPixel = 32;
    	format.BytesPerPixel = 4;
    	format.Rmask = rmask;
    	format.Gmask = gmask;
    	format.Bmask = bmask;
    	format.Amask = amask;
    	SDL_Surface * surfaceGL = SDL_ConvertSurface(surfaceImage, &format, SDL_SWSURFACE);
     
    	// Flipping the surface
    	SDL_Surface * flipedSurfaceGL = SDL_CreateRGBSurface(SDL_SWSURFACE, surfaceGL->w, surfaceGL->h, surfaceGL->format->BitsPerPixel, surfaceGL->format->Rmask, surfaceGL->format->Gmask, surfaceGL->format->Bmask, surfaceGL->format->Amask);
    	SDL_LockSurface(surfaceGL);
    	SDL_LockSurface(flipedSurfaceGL);
    	int pitch = surfaceGL->pitch;
    	for (int i = 0; i < surfaceGL->h; i++) {
    		memcpy(&((unsigned char* )flipedSurfaceGL->pixels)[i*pitch], &((unsigned char* )surfaceGL->pixels)[(surfaceGL->h - 1 - i)*pitch], pitch);
    	}
    	SDL_UnlockSurface(flipedSurfaceGL);
    	SDL_UnlockSurface(surfaceGL);
     
    	// Building the texture
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glBindTexture(GL_TEXTURE_2D, textureId);
    	gluBuild2DMipmaps(GL_TEXTURE_2D, 4, flipedSurfaceGL->w, flipedSurfaceGL->h, GL_RGBA,GL_UNSIGNED_BYTE, flipedSurfaceGL->pixels);
     
    	// Anti-aliasing
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     
    	SDL_FreeSurface(flipedSurfaceGL);
    	SDL_FreeSurface(surfaceGL);
    	SDL_FreeSurface(surfaceImage);
     
    	return OK;
    }
    J'appelle cette méthode de la façon la plus simple qui soit, à savoir que dans ma fonction main() j'ai ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ...
    Texture * maTexture = listeLecture.at(j);
    maTexture->load();
    refreshDisplay();
    ...
    La fonction "refreshDisplay()" ne sert ici qu'à mettre à jour mon VBO. Elle n'est pas l'objet de ce topique car, a priori, elle fonctionne bien et le problème ne se situe pas là.

    D'ailleurs tout ce que j'ai donné jusque là fonctionne à merveille. Avec ce code j'arrive à afficher en texture le fichier image indiqué dans la méthode "load()".

    Le problème vient du fait que je veux appeler cette fonction dans un autre thread que le principal. J'ai donc fait le choix d'utiliser la bibliothèque pthread pour cela.
    Concrètement j'ai transformé mon code d'appel en ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ...
    Texture * maTexture = listeLecture.at(j);
    maTexture->startThread();
    ...
    La fonction "startThread()" comporte juste une ligne et lance une fonction "actionThread()" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pthread_create(&thread, NULL, &actionThread, NULL);
    Enfin, cette fonction "actionThread()" comporte les 2 lignes déjà citées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    load();
    refreshDisplay();
    Et c'est là que le bât blesse! En effet : le thread se lance bien, le programme rentre dans la fonction "load()", arrive jusqu'à la fonction "gluBuild2DMipmaps()" et ... plante! J'ai un magnifique seg fault en plein dans cette fonction. Je ne sais pas d'où il vient et je sollicite votre aide pour en déterminer la cause.

    S'il s'agit d'une incompatibilité entre OpenGL et pthread quelqu'un en connaitrait-il l'explication ? Je sais qu'OpenGL est une machine à états, néanmoins je ne pense pas avoir modifié l'ordre des appels. D'autant que je bloque (avec un sémaphore) le thread principal en attendant que le nouveau thread se termine...

    Merci et bon week-end.


    PS : Au cas où cela servirait : j'ai initialisé SDL et OpenGL dans mon thread principal avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // Init SDL
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTTHREAD) == -1) {
    	return ERROR;
    }
    SDL_SetVideoMode(1600, 600, 16, SDL_ANYFORMAT | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_OPENGL);
    glewInit();
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Il faut que tu aies un contexte OpenGL valide dans le thread, dès lors que tu appelles une fonction OpenGL (ou GLU).

    J'imagine que si tu charges tes textures dans un thread c'est que tu fais autre chose dans le thread principal, et qu'il te faudrait donc un nouveau contexte OpenGL, autre que celui qui existe dans le thread principal. Et ça je ne sais pas si c'est possible avec SDL.

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 994
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 994
    Points : 222 449
    Points
    222 449
    Billets dans le blog
    133
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    Il faut que tu aies un contexte OpenGL valide dans le thread, dès lors que tu appelles une fonction OpenGL (ou GLU).

    J'imagine que si tu charges tes textures dans un thread c'est que tu fais autre chose dans le thread principal, et qu'il te faudrait donc un nouveau contexte OpenGL, autre que celui qui existe dans le thread principal. Et ça je ne sais pas si c'est possible avec SDL.
    Dans SDL, on ne peut avoir qu'un seul contexte (comme on ne peut avoir qu'une seule fenêtre) (bien souvent les deux sont liés)
    Sinon, je suis entièrement d'accord avec la réponse donné par Laurent Gomila, les contextes sont spécifiques aux threads et du coup, cela cause des erreurs (c'est marqué surtout dans les spécifications d'OpenGL (et de EGL))

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 29
    Points : 17
    Points
    17
    Par défaut
    Effectivement j'ignorais cela. Dommage cela m'aurait été utile, j'ai dû me débrouiller autrement. Algorithmiquement c'est moins joli mais bon... ça fonctionne. =)

    Néanmoins après quelques recherches j'ai vu qu'il était éventuellement possible de transmettre le contexte à un autre thread dans la prochaine version de la SDL (la 1.3). Cela se ferait avec une subtile succession d'appels à SDL_CreateWindow, SDL_GL_CreateContext, et SDL_GL_MakeCurrent si je ne m'abuse. Moi je tourne avec la v1.2 et je n'ai accès qu'à SDL_SetVideoMode donc tant pis je verrai cela plus tard.

    Merci.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Tu peux tout à fait utiliser un même contexte dans plusieurs threads, par contre un seul d'entre eux peut l'avoir "actif" à un moment donné.

    Deux solutions: soit synchroniser l'accès à ce thread (avec un mutex par exemple), soit avoir deux contextes qui se partagent les textures.

Discussions similaires

  1. Réponses: 2
    Dernier message: 21/12/2010, 15h10
  2. Réponses: 6
    Dernier message: 12/09/2007, 08h55
  3. Réponses: 1
    Dernier message: 11/09/2007, 13h16
  4. [fclose] erreur de fermeture (seg fault)
    Par Goundy dans le forum C
    Réponses: 17
    Dernier message: 06/04/2006, 14h16
  5. probleme de valeur retournée et seg fault
    Par florent_de_brest dans le forum C
    Réponses: 5
    Dernier message: 04/12/2005, 17h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo