Partager via


Procédure pas à pas : objets manquants en raison de Vertex Shader

Cette procédure pas à pas montre comment utiliser les outils Graphics Diagnostics Visual Studio pour examiner un objet qui manque en raison d'une erreur qui se produit à l'étape de vertex shader.

Cette procédure pas à pas décrit les tâches suivantes :

  • Utilisation de la Liste des événements Graphics pour identifier les sources possibles du problème.

  • Utilisation de la fenêtre Étapes de canalisation Graphics pour contrôler l'effet des appels d'API Direct3D DrawIndexed.

  • Utilisation du Débogueur HLSL pour tester le vertex shader.

  • Utilisation de la Pile des appels des événements Graphics pour rechercher plus facilement la source d'une constante HLSL non valide.

Scénario

Une des causes courantes d'un objet manquant dans une application 3D se produit lorsque le vertex shader transforme les vertex de l'objet de manière incorrecte ou inattendue, par exemple l'objet peut être mis à une échelle très petite ou transformé de telle sorte qu'il apparaisse derrière la caméra et non devant elle.

Dans ce scénario, lorsque l'application est exécutée pour tester l'arrière-plan, celui-ci est restitué comme prévu, mais l'un des objets ne s'affiche pas. À l'aide de l'outil Graphics Diagnostics, capturez le problème dans un journal graphique afin de déboguer l'application. Dans l'application, le problème ressemble à cela :

L'objet ne peut être visualisé.

Examen

À l'aide des outils Graphics Diagnostics, vous pouvez charger le fichier journal de graphiques pour examiner les frames qui ont été capturés pendant le test.

Pour examiner un frame dans un journal de graphiques

  1. Dans Visual Studio, chargez un journal de graphiques qui contient un frame qui affiche l'objet manquant. Un nouvel onglet Journal de graphiques apparaît dans Visual Studio. La partie supérieure de cet onglet contient la sortie de cible de rendu du frame sélectionné. Dans la partie inférieure figure la Liste de frames, qui affiche chaque frame capturé sous forme d'une image miniature.

  2. Dans Liste de frames, sélectionnez un frame qui indique que l'objet n'est pas affiché. La cible de rendu est mise à jour pour refléter le frame sélectionné. Dans ce scénario, l'onglet du journal des graphiques se présente comme suit :

    Document du journal des graphiques dans Visual Studio

Après avoir sélectionné un frame illustrant le problème, vous pouvez commencer à le diagnostiquer à l'aide de la Liste des événements Graphics. La Liste des événements Graphics contient chaque appel d'API Direct3D qui a été effectué pour afficher le frame actif, par exemple, les appels API pour installer l'état du périphérique, créer et mettre à jour des mémoires tampons, et pour dessiner des objets qui apparaissent dans le frame. De nombreux genres d'appels sont intéressants car il y a généralement (mais pas toujours) une modification correspondante dans la cible de rendu lorsque l'application s'exécute comme prévu. Par exemple, les appels Draw, Dispatch, Copy ou Clear. Les appels de dessin sont particulièrement intéressants car chacun représente la géométrie que l'application affiche (les appels d'expédition peuvent également afficher la géométrie).

Comme vous savez que l'objet manquant n'est pas tracé sur la cible de rendu (dans ce cas), mais que le reste de la scène est dessiné comme prévu, vous pouvez utiliser Liste des événements Graphics avec l'outil Étapes de canalisation Graphics pour déterminer l'appel de dessin qui correspond à la géométrie de l'objet manquant. La fenêtre Étapes de canalisation Graphics montre la géométrie qui a été envoyée à chaque appel de dessin, quel que soit son effet sur la cible de rendu. Lorsque vous naviguez dans les appels de dessin, les étapes de pipeline sont mises à jour pour afficher la géométrie associée à cet appel, et la sortie de la cible de rendu est mise à jour pour afficher l'état de la cible de rendu à l'issue de l'appel.

Pour rechercher l'appel de dessin pour la géométrie manquante

  1. Ouvrez la fenêtre Liste des événements Graphics. Dans la barre d'outils Graphics Diagnostics, choisissez Liste des événements.

  2. Ouvrez la fenêtre Étapes de canalisation Graphics. Dans la barre d'outils Graphics Diagnostics , choisissez Étapes de canalisation.

  3. Comme vous vous déplacez dans chaque appel de dessin dans la fenêtre Liste des événements Graphics, examinez la fenêtre Étapes de canalisation Graphics pour l'objet manquant. Pour simplifier ce processus, entrez « Draw » dans la zone Rechercher dans l'angle supérieur droit de la fenêtre Liste des événements Graphics. La liste est filtrée, afin que les événements contenus comportent « draw » dans leurs titres.

    Dans la fenêtre Étapes de canalisation Graphics, l'étape Assembleur d'entrée montre la géométrie de l'objet avant sa transformation, et l'étape Vertex Shader montre le même objet après sa transformation. Dans ce scénario, vous savez que vous avez trouvé l'objet manquant lorsqu'il est affiché dans l'étape Assembleur d'entrée et que rien n'est affiché dans l'étape Vertex Shader.

    Notes

    Si d'autres étapes géométriques existent, par exemple, les étapes Nuanceur Hull Shader, Nuanceur de domaine ou Nuanceur de géométrie, traitez l'objet, car elles peuvent être la cause du problème.En général, le problème est lié à la première étape, au cours de laquelle le résultat n'est pas affiché ou est restitué de manière inattendue.

  4. Arrêtez lorsque vous atteignez l'appel de dessin qui correspond à l'objet manquant. Dans ce scénario, la fenêtre Étapes de canalisation Graphics indique que la géométrie a été fournie au GPU (ce qui est indiqué par la miniature Assembleur d'entrée), mais n'apparaît pas dans la cible de rendu suite à un problème durant l'étape de vertex shader (indiqué par la miniature Vertex Shader) :

    Événement DrawIndexed et son effet sur le pipeline

Après avoir confirmé que l'application a émis un appel de dessin pour la géométrie de l'objet manquant et identifié que le problème se produit pendant l'étape de vertex shader, vous pouvez utiliser le débogueur HLSL pour examiner le vertex shader et déterminer ce qui est arrivé à la géométrie de l'objet. Vous pouvez utiliser le débogueur HLSL pour examiner l'état des variables HLSL pendant l'exécution, parcourir le code HLSL, et définir des points d'arrêt de positionnement pour vous aider à diagnostiquer le problème.

Pour consulter le nuanceur de sommets

  1. Commencez à déboguer l'étape de vertex shader. Dans la fenêtre Étapes de canalisation Graphics, sous l'étape Vertex Shader, choisissez le bouton Démarrer le débogage.

  2. Comme l'étape Assembleur d'entrée apparaît pour fournir de bonnes données au nuanceur de sommets et que l'étape Nuanceur de sommets apparaît sans produire de sortie, vous devez examiner la structure de sortie du nuanceur de sommets, output. Lorsque vous parcourez le code HLSL, l'examen est plus détaillé lorsque output est modifié.

  3. La première fois que output est modifié, le worldPos du membre est écrit.

    La valeur « output.worldPos » semble raisonnable

    Comme sa valeur semble raisonnable, continuez à parcourir le code jusqu'à la ligne suivante qui modifie output.

  4. La prochaine fois que output est modifié, le pos du membre est écrit.

    La valeur « output.pos » a été remise à zéro

    Cette fois, la valeur du membre pos, composée uniquement de zéros, semble douteuse. Ensuite, vous voulez déterminer comment output.pos a pu avoir une valeur composée de zéros.

  5. Vous remarquez que output.pos prend sa valeur d'une variable nommée temp. Sur la ligne précédente, vous constatez que la valeur de temp est le résultat de la multiplication de sa valeur précédente par une constante nommée projection. Vous pensez que la valeur suspecte temp est le résultat de cette multiplication. Lorsque vous placez le pointeur sur projection, vous remarquez que sa valeur n'est composée elle aussi que de zéros.

    La matrice de projection contient une transformation incorrecte

    Dans ce scénario, l'examen révèle que la valeur douteuse de temp est probablement due à sa multiplication par projection, et comme projection est une constante censée contenir une matrice de projection, vous savez qu'elle ne doit pas contenir que des zéros.

Après avoir déterminé que la constante HLSL projection passée dans le nuanceur par votre application est la source probable du problème, l'étape suivante consiste à rechercher l'emplacement dans le code source de votre application où la mémoire tampon de la constante est remplie. Vous pouvez utiliser Pile des appels des événements Graphics pour rechercher cet emplacement.

Pour rechercher où la constante est définie dans le code source de votre application

  1. Ouvrez la fenêtre Pile des appels des événements Graphics. Dans la barre d'outils Graphics Diagnostics, choisissez Pile des appels des événements Graphics.

  2. Accédez au code source de votre application en haut de la pile des appels. Dans la fenêtre Pile des appels des événements Graphics , choisissez l'appel de niveau supérieur pour voir si la mémoire tampon constante est alimentée à cet endroit. Si ce n'est pas le cas, passez en haut de la pile des appels jusqu'à ce que vous trouviez l'emplacement où elle est remplie. Dans ce scénario, vous découvrez que la mémoire tampon constante est en cours de remplissage via l'API Direct3D UpdateSubresource jusqu'en haut de la pile des appels dans une fonction nommée MarbleMaze::Render, et que sa valeur provient d'un objet de mémoire tampon constante nommé m_marbleConstantBufferData

    Code qui définit la mémoire tampon constante de l'objet

    Conseil

    Si vous déboguez simultanément votre application, vous pouvez définir un point d'arrêt à cet emplacement et il sera atteint lorsque le prochain frame s'affichera.Vous pouvez ensuite examiner les membres de m_marbleConstantBufferData pour confirmer que la valeur du membre projection est définie sur tous les zéros lorsque la mémoire tampon constante est remplie.

Après avoir trouvé l'emplacement où la mémoire tampon de la constante est remplie et constaté que ses valeurs proviennent de la variable m_marbleConstantBufferData, l'étape suivante consiste à déterminer l'emplacement où le membre m_marbleConstantBufferData.projection a une valeur composée de zéros. Vous pouvez utiliser Rechercher toutes les références pour rechercher rapidement du code qui modifie la valeur de m_marbleConstantBufferData.projection.

Pour rechercher où le membre de projection est défini dans le code source de votre application

  1. Recherchez les références à m_marbleConstantBufferData.projection. Ouvrez le menu contextuel de la variable m_marbleConstantBufferData, puis choisissez Rechercher toutes les références.

  2. Pour accéder à l'emplacement de la ligne dans le code source de votre application où le membre projection est modifié, choisissez cette ligne dans la fenêtre Résultats de la recherche de symbole. Comme le premier résultat qui modifie le membre de projection ne peut pas être la cause du problème, vous pouvez être amené à examiner plusieurs zones du code source de votre application.

Après avoir trouvé l'emplacement où m_marbleConstantBufferData.projection est défini, vous pouvez examiner le code source environnant pour déterminer l'origine de la valeur incorrecte. Dans ce scénario, vous constatez que la valeur de m_marbleConstantBufferData.projection correspond à une variable locale nommée projection avant son initialisation sur une valeur spécifiée par le code m_camera->GetProjection(&projection); sur la ligne suivante.

La projection marble est définie avant l'initialisation

Pour résoudre le problème, déplacez la ligne de code qui définit la valeur de m_marbleConstantBufferData.projection après la ligne qui initialise la valeur de la variable locale projection.

Code source C++ corrigé

Après avoir résolu le code, vous pouvez le régénérer et réexécuter l'application pour vérifier que le problème de rendu est résolu :

L'objet est désormais affiché.