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 :

Segfault update vbo dans thread


Sujet :

OpenGL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 274
    Par défaut Segfault update vbo dans thread
    Bonjour à tous ,
    Comme le titre du topic l'indique, j'ai un problème majeur lorsque je couple pthread avec les vbos.

    En effet, afin de ne pas perdre trop de fps, j'ai décidé de placer l'update des vbo dans un thread (avec pthread). J'utilise une classe VBO disposant d'une methode updateVertexBuffer() qui se charge de recharger les données du buffer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template <typename A, typename B, typename C>
    void OptimisedVBO<A,B,C>::updateVertexBuffer()
    {
        glBindBuffer(GL_ARRAY_BUFFER, m_numberVBO[0]);
        if(m_vertexBufferCoord2D!=NULL&&m_vertexBufferCoord2D->size())
            updateSubData(m_vertexBufferCoord2D,0,GL_ARRAY_BUFFER);
        else if(m_vertexBufferCoord3D!=NULL&&m_vertexBufferCoord3D->size())
            updateSubData(m_vertexBufferCoord3D,0,GL_ARRAY_BUFFER);
        else if(m_vertexBufferDoubleArray!=NULL&&m_vertexBufferDoubleArray->size())
            updateSubData(m_vertexBufferDoubleArray,0,GL_ARRAY_BUFFER);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    Lorsqu'un vbo est crée quelque part, il est ajouté à la classe updateThread qui met à jour les vbos crées toutes les X millisecondes (ajustables).
    Le thread est lié à la fonction update qui prend en paramètre un pointeur sur une variable correspondant au temps écoulé depuis le début du programme :
    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
    template <typename T, typename U, typename V>
    void *UpdateThread<T,U,V>::update(void *timeElapsed)
    {
        if(timeElapsed==NULL)
            m_run = false;
     
        Uint32 *time = NULL;
        if(m_run)
            time =(Uint32 *)(timeElapsed);
     
        while(m_run)
            if(timeElapsed==NULL||*time-m_lastTime>=m_timeUpdate*1000)
            {
                if(pthread_mutex_lock(&m_mutex_stock))
                    std::cout<<"Erreur !";
     
                m_lastTime = *time;
                for(unsigned int i=0;i<m_vbo.size();i++)
                    if(m_update[i])
                        m_vbo[i]->updateVertexBuffer();
     
                if(pthread_mutex_unlock(&m_mutex_stock))
                    std::cout<<"Erreur2 !";
            }
        return NULL;
    }
    Cependant, malgré les mutex, j'ai du mal à comprendre pourquoi le programme plante lorsque, après avoir ajouté 1 VBO dans le tableau par la fonction addVBO (ci-dessous). Le thread plante lorsqu'il update l'unique et premier vbo ajouté, au niveau de la fonction updateVertexBuffer du vbo, lors de l'appel à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    glBindBuffer(GL_ARRAY_BUFFER, m_numberVBO[0]);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <typename T, typename U, typename V>
    void UpdateThread<T,U,V>::addVBO(OptimisedVBO<T,U,V>* vbo, bool update)
    {
        if(vbo!=NULL)
        {
            m_vbo.push_back(vbo);
            m_update.push_back(update);
        }
    }
    Pourtant, un appel de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_vbo[m_vbo.size()-1]->updateVertexBuffer();
    lors de l'ajout du vbo ne plante pas. Cela provient donc du thread qui appelle cette même méthode du même vbo.

    Voilà, si vous avez une explication je suis preneur

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 150
    Billets dans le blog
    150
    Par défaut
    Bonjour,

    Je pense que c'est un problème de contexte. En effet, dans une application OpenGL, il y a création d'un contexte. Ce contexte est lié au thread. Du coup, les éléments OpenGL sont généralement valide que dans le thread où le contexte a été crée.
    Une solution possible est de voir du coté d'EGL et des partages de ressources OpenGL.
    Mais je vous conseille de tout faire dans un même thread, au moins, cela prouvera si c'est bien cela l'origine du problème.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 274
    Par défaut
    Merci pour ta réponse

    Je venais d'effectuer quelques recherches sur le multithreading avec openGL et effectivement il est impossible de le faire sans recréer un contexte dans le thread ce que je ne sais pas faire (comment copier le contexte actuel ou le desactiver ?)

    De plus sans le thread cela marche parfaitement mais les fps baissent extrêmement vite : au bout d'une cinquantaine de générateur de particules fonctionnant simultanément, le fps descend en dessous de 10 (des dizaines de milliers de particules sont alors affichées).

    J'ai donc pensé à 3 solutions (ou 4) :

    -faire un système assez complexe où les fonctions bindBuffer() et glMapBuffer() seraient tout d'abord appelées dans le vbo, avant que le thread update effectue un memcpy des données du buffer directement à l'adresse indiquée par le pointeur stocké correspondant à glMapBuffer(). Cependant, je ne sais pas si cela peut marcher, et surtout ce qui se passerait quand par coïncidence l'update et le dessin se chevaucheraient dans le temps, les 2 threads étant différents. Cela m'obligerait à placer un mécanisme encore plus complexe de vérification et de dessin au juste moment .

    -ajouter à chaque VBO un pointeur sur boost::thread (afin de le lancer à la demande) fonctionnant sur le même principe que précédemment : une méthode est appelée qui appelle les fonctions bind et mapbuffer depuis une classe extérieure dans le bon contexte, puis le thread lancé en fond de tâche vérifierait que l'attribut update a été modifié et lancerait le memcpy au bon endroit. Là encore, cela présente l'inconvénient de la méthode précédente, mais un avantage : chaque vbo s'auto update ce qui permet une homogénéité dans l'update de chaque vbo. Cela entraîne l'inconvénient majeur qu'il faudrait autant de threads que de vbo, ce qui serait assez problématique je pense

    -tout remodeler et optimiser afin de ne tout placer que dans un seul thread, mais là le problème est que le nombre de particules étant très important et nécessaire pour le jeu lui-même les fps sont condamnés à baisser avec l'augmentation du nombre de particules

    -trouver une méthode permettant indirectement d'utiliser le même contexte openGL ou un contexte copié dans plusieurs threads même si c'est surement impossible

    Voilà, que me conseilleriez vous ?

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 150
    Billets dans le blog
    150
    Par défaut
    Je venais d'effectuer quelques recherches sur le multithreading avec openGL et effectivement il est impossible de le faire sans recréer un contexte dans le thread ce que je ne sais pas faire (comment copier le contexte actuel ou le desactiver ?)
    Le copier, non, je ne pense pas.

    Après, ouvrir un second contexte et partagé la chose, oui peut être, mais je pense que vous avez mal calibré là où vous avez le ralentissement.
    Pour les opérations sur le contexte, elles sont souvent cachées par les bibliothèques (SDL / GLUT / ...).

    Maintenant, je pense que vous vous y prenez mal.
    Normalement, le VBO envoyé sera de taille fixe. Seul un uniform est modifié pour donner le nombre de particules à afficher.
    De plus, il se peut que seul une texture soit transférées (contenant les infos voulues), on pourra même faire en sorte que l'update soit fait par le GPU (ainsi que le dessin, mais ça, c'est habituel )

    Donc, déjà, essayez de savoir ce qui provoque les ralentissement. Il se peut aussi que d'utiliser qu'un seul VBO et non plusieurs (un par système) améliore les perfs.

    Enfin, il y a de multiples possibilités.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  5. #5
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 219
    Par défaut
    Pour pouvoir faire du multi-threading en OpenGL, il faut tout de suite oublier les libraires comme SDL et Glut. La solution est d'utiliser les API native des systèmes d'exploitation (windows, linux, mac os), pour créer le context. En effet, Glut et SDL vont simplement ajouter une couche entre ces librairies pour que cela devienne multi-platforme et simple pour ceux qui commence.

    Mais ce n'est rien de bien méchant, il appartient alors à vous de coder votre propre couche pour pouvoir ainsi crée le context OpenGL nativement par les véritables fonctions du système d'exploitation.

    Ainsi, il vous sera possible de créer ce qu'on appels des contexts partagés. Ce sont en fait des contexts mais dont l'ensemble de leurs objets sont en commun. En effet, vous allez alors créer un premier context que nous nommeront Context0, puis ensuite crée d'autre Context1, Context2 ... ContextN, mais d'on ils sont partagé avec le Context0. Alors vous pourrez crée N+1 threads dont ils auront chaqu'un leurs propre context. Attention alors à ne pas binder un même objet dans deux contexts différents, sinon il se passera des bugs. :cool:

    Attentions, l'ensemble des contexts doivent être construit à la suite. En d'autre thermes, dès lors que vous avez crée un objet dans ce mega-context partagé, vous pouvez considérer qu'il n'est plus possible de créer d'autre context partagé à celui ci. Ca peut fonctionner, mais çà dépend des drivers, et du système d'exploitation, donc instable, donc on oublie.

    Ainsi il vous sera possible de faire du multi-threading en tout tranquillité avec OpenGL.

    Constat personnel bon à savoir : s'arranger qu'un seul threads ne dessine à la foi, sinon le driver sera plus en difficulté, et au final, se sera moins rapide. Les autres treads sont utile seulement pour faire du chargement On-the-fly comme vous vous y prêtiez.

  6. #6
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 274
    Par défaut
    @ LastSpear : ton idée me semble super intéressante mais malheureusement mon niveau de programmation est assez faible et je ne vois pas du tout comment procéder ni par quel bout commencer pour faire ce que tu dis
    Si tu disposes de sites intéressants pouvant m'aiguiller je suis preneur

    @ LittleWhite : Tu as peut être raison, c'est sans doute que je m'y prends mal. Je vais expliquer ce que je fais et pourquoi je le fais, tu pourras ainsi me reprendre sur les points à améliorer ou à changer totalement

    Donc je dispose d'une classe VBO. Je l'ai créée de telle sorte que l'on puisse envoyer des pointeurs de vectors de Coord1,2ou3D templatés, qui s'ajoutent à un grand vector de pointeurs de vectors : ainsi, les données ne sont pas recopiées inutilement et sont conservées dans les classes dans lesquelles elles ont été créées. Ces vector de vector sont utilisés pour les positions des vertex, les couleurs des vertex, les positions de texture des vertex et les index.

    Lorsque je crée une classe, par exemple Joueur, et qu'un vector de coordonnées correspondant au mesh du joueur est crée, ainsi qu'un vector pour les couleurs et pour les textures (ce qui n'est pas obligatoire), j'ajoute les pointeurs de vectors au VBO du joueur. Les données sont ensuite placées dans la mémoire graphique (glBufferData et glBufferSubData) et l'affichage se fait par une classe render à qui on ajoute des vbos qui seront ou non affichés (ici celui du joueur).

    Concernant les particules, chaque particule, lorsqu'elle est créée, dispose d'un modèle de coordonnées sous forme de pointeur (chaque particule est identique au niveau de la forme pour un générateur donné). Chaque particule dispose également d'un vector de coordonnées propres qui varient au cours du temps. Lorsque le générateur de particules est en marche, les particules sont constamment mises à jour au niveau de leurs coordonnées si la particule est en cours de mouvement. A chacun de ses updates, et lorsque toutes les particules ont été mises à jour, à l'intérieur du générateur, le vbo est lui aussi mis à jour, ce qui entraîne une modification de la mémoire graphique (nouveaux appels à glBindBufferSubData) et donc beaucoup de temps (plus il y a de particules). En ce qui est de ce VBO, à chaque création de particule, un pointeur de vector correspondant à l'adresse du vector de coordonnées propre de la particule est ajouté, ce qui fait que, lors de l'update, les données sont directement chargées dans le vector de N pointeurs de vector sur les coordonnées de N particules. En ce qui concerne l'IBO, j'ai fait une erreur en en passant en paramètre à chaque ajout de particule, alors qu'il est possible de n'en n'utiliser qu'un seul pour optimiser la mémoire.

    Voilà pour ce qui est de mon raisonnement, j'espère que vous saurez trouver où les performances sont principalement perdues

Discussions similaires

  1. JProgressBar qui ne s'update pas dans un thread
    Par ionone dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 31/07/2012, 17h14
  2. [SQL SERV 2K] Problème d'update enregistrement dans procédure
    Par Tankian dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 08/06/2006, 09h42
  3. appel système opendir dans thread
    Par madimane dans le forum POSIX
    Réponses: 2
    Dernier message: 14/04/2006, 05h39
  4. update multiple dans une meme colonne
    Par debdev dans le forum Langage SQL
    Réponses: 7
    Dernier message: 29/01/2006, 21h46

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