Procédure pas à pas : objets manquants en raison de Vertex ShaderWalkthrough: Missing Objects Due to Vertex Shading

Cette procédure pas à pas montre comment utiliser les outils Graphics Diagnostics dans Visual StudioVisual Studio pour examiner un objet qui est manquant à cause d’une erreur survenue à l’étape du nuanceur de sommets.This walkthrough demonstrates how to use the Visual StudioVisual Studio Graphics Diagnostics tools to investigate an object that is missing due to an error that occurs during the vertex shader stage.

Cette procédure pas à pas décrit les tâches suivantes :This walkthrough illustrates these tasks:

  • Utilisation de la liste des événements Graphics pour rechercher les sources potentielles du problème.Using the Graphics Event List to locate potential sources of the problem.

  • Utilisation de la fenêtre Étapes de canalisation Graphics pour vérifier l’effet des appels de l’API Direct3D DrawIndexed .Using the Graphics Pipeline Stages window to check the effect of the DrawIndexed Direct3D API calls.

  • Utilisation du débogueur HLSL pour examiner le nuanceur de sommets.Using the HLSL Debugger to examine the vertex shader.

  • Utilisation de la pile des appels des événements Graphics pour trouver plus facilement la source d’une constante HLSL incorrecte.Using the Graphics Event Call Stack to help find the source of an incorrect HLSL constant.

ScénarioScenario

Une des causes courantes observées quand un objet est manquant dans une application 3D est le nuanceur de sommets qui transforme les sommets de l’objet de manière incorrecte ou inattendue. C’est le cas, par exemple, si l’objet est réduit à une très petite échelle ou s’il est transformé pour s’afficher derrière la caméra, au lieu de devant.One of the common causes of a missing object in a 3-D app occurs when the vertex shader transforms the object's vertices in an incorrect or unexpected way—for example, the object might be scaled to a very small size, or transformed such that it appears behind the camera, rather than in front of it.

Dans ce scénario, quand l’application est exécutée pour être testée, l’arrière-plan est affiché comme prévu, mais l’un des objets ne s’affiche pas.In this scenario, when the app is run to test it, the background is rendered as expected, but one of the objects does not appear. À l’aide de Graphics Diagnostics, vous capturez le problème dans un journal de graphisme pour déboguer l’application.By using Graphics Diagnostics, you capture the problem to a graphics log so that you can debug the app. Le problème se présente ainsi dans l'application :The problem looks like this in the app:

L’objet ne peut pas être visualisé. The object can not be seen.

ExamenInvestigation

À l’aide des outils Graphics Diagnostics, vous pouvez charger le fichier journal de graphisme pour examiner les frames capturés pendant le test.By using the Graphics Diagnostics tools, you can load the graphics log file to inspect the frames that were captured during the test.

Pour examiner un frame dans un journal de graphiquesTo examine a frame in a graphics log

  1. Dans Visual StudioVisual Studio, chargez un journal de graphiques qui contient un frame présentant l’objet manquant.In Visual StudioVisual Studio, load a graphics log that contains a frame that exhibits the missing object. Un nouvel onglet de journal de graphisme s’affiche dans Visual StudioVisual Studio.A new graphics log tab appears in Visual StudioVisual Studio. La partie supérieure de cet onglet contient la sortie de la cible de rendu du frame sélectionné.In the top part of this tab is the render target output of the selected frame. La partie inférieure contient la Liste de frames, qui affiche chaque frame capturé sous forme de miniature.In the bottom part is the Frame List, which displays each captured frame as a thumbnail image.

  2. Dans la Liste de frames, sélectionnez un frame qui montre que l’objet n’est pas affiché.In the Frame List, select a frame that demonstrates that the object is not displayed. La cible de rendu est mise à jour pour refléter le frame sélectionné.The render target is updated to reflect the selected frame. Dans ce scénario, l'onglet du journal de graphisme se présente comme suit :In this scenario, the graphics log tab looks like this:

    Document du journal des graphiques dans Visual StudioThe graphics log document in Visual Studio

    Une fois que vous avez sélectionné un frame qui illustre le problème, vous pouvez commencer le diagnostic dans la fenêtre Liste des événements Graphics.After you've selected a frame that demonstrates the problem, you can begin to diagnose it by using the Graphics Event List. La fenêtre 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 configurer l’état de l’appareil, créer et mettre à jour les mémoires tampons, et dessiner les objets qui apparaissent dans le frame.The Graphics Event List contains every Direct3D API call that was made to render the active frame, for example, API calls to set up device state, to create and update buffers, and to draw objects that appear in the frame. Plusieurs types d’appels sont intéressants, car il y a souvent (mais pas toujours) une modification correspondante dans la cible de rendu quand l’application fonctionne comme prévu. C’est le cas des appels de dessin, de distribution, de copie ou d’effacement, par exemple.Many kinds of calls are interesting because there is often (but not always) a corresponding change in the render target when the app is working as expected, for example Draw, Dispatch, Copy or Clear calls. Les appels de dessin sont particulièrement intéressants, car chacun d’eux représente la géométrie affichée par l’application (les appels de distribution permettent aussi cela).Draw calls are particularly interesting because each one represents geometry that the app rendered (Dispatch calls can also render geometry).

    Comme vous savez que l’objet manquant n’est pas dessiné dans la cible de rendu (dans ce cas précis), mais que le reste de la scène est dessinée de la manière attendue, vous pouvez utiliser la fenêtre Liste des événements Graphics avec l’outil Étapes de canalisation Graphics pour identifier l’appel de dessin qui correspond à la géométrie de l’objet manquant.Because you know that the missing object is not being drawn to the render target (in this case)—but that the rest of the scene is drawn as expected—you can use the Graphics Event List together with the Graphics Pipeline Stages tool to determine which draw call corresponds to the missing object's geometry. La fenêtre Étapes de canalisation Graphics affiche la géométrie qui a été envoyée à chaque appel de dessin, quel que soit son effet sur la cible de rendu.The Graphics Pipeline Stages window shows the geometry that was sent to each draw call, regardless of its effect on the render target. À mesure que vous parcourez les appels de dessin, les étapes de canalisation sont mises à jour pour afficher la géométrie qui est associée à l’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.As you move through the draw calls, the pipeline stages are updated to show the geometry that is associated with that call, and the render target output is updated to show the state of the render target after the call was completed.

Pour rechercher l’appel de dessin correspondant à la géométrie manquanteTo find the draw call for the missing geometry

  1. Ouvrez la fenêtre Liste des événements Graphics .Open the Graphics Event List window. Dans la barre d’outils Graphics Diagnostics , choisissez Liste des événements.On the Graphics Diagnostics toolbar, choose Event List.

  2. Ouvrez la fenêtre Étapes de canalisation Graphics .Open the Graphics Pipeline Stages window. Dans la barre d’outils Graphics Diagnostics , choisissez Étapes de canalisation.On the Graphics Diagnostics toolbar, choose Pipeline Stages.

  3. À mesure que vous parcourez chaque appel de dessin dans la fenêtre Liste des événements Graphics , recherchez l’objet manquant dans la fenêtre Étapes de canalisation Graphics .As you move through each draw call in the Graphics Event List window, watch the Graphics Pipeline Stages window for the missing object. Pour rendre la tâche plus simple, entrez “Draw” dans la zone Rechercher , en haut à droite de la fenêtre Liste des événements Graphics .To make this easier, enter "Draw" in the Search box in the upper-right corner of the Graphics Event List window. Cela permet de filtrer la liste pour retenir uniquement les événements qui contiennent « Draw » dans leur titre.This filters the list so that it only contains events that have "Draw" in their titles.

    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 tandis que l’étape Nuanceur de sommets montre le même objet après sa transformation.In the Graphics Pipeline Stages window, the Input Assembler stage shows the object's geometry before its transformed, and the Vertex Shader stage shows the same object after it's transformed. Dans ce scénario, vous avez trouvé l’objet manquant quand il s’affiche à l’étape Assembleur d’entrée , mais pas à l’étape Nuanceur de sommets .In this scenario, you know that you've found the missing object when it is displayed in the Input Assembler stage and nothing is displayed in the Vertex Shader stage.

    Note

    Si d’autres étapes de géométrie (par exemple, Nuanceur de coque, Nuanceur de domaine ou Nuanceur de géométrie) traitent l’objet, elles peuvent être la cause du problème.If other geometry stages—for example, the Hull Shader, Domain Shader, or Geometry Shader stages—process the object, they might be the cause of the problem. En règle générale, le problème est lié à la première étape durant laquelle le résultat n’est pas affiché ou est affiché de manière inattendue.Typically, the problem is related to the earliest stage in which the result is not displayed or is displayed in an unexpected way.

  4. Arrêtez quand vous atteignez l’appel de dessin qui correspond à l’objet manquant.Stop when you reach the draw call that corresponds to the missing object. Dans ce scénario, la fenêtre Étapes de canalisation Graphics indique que la géométrie a été émise vers le GPU (indiqué par la présence de l’aperçu Assembleur d’entrée), mais elle n’apparaît pas dans la cible de rendu à cause d’une erreur survenue à l’étape du nuanceur de sommets (indiquée par l’aperçu Nuanceur de sommets) :In this scenario, the Graphics Pipeline Stages window indicates that the geometry was issued to the GPU (indicated by the Input Assembler thumbnail), but doesn't appear in the render target because something went wrong during the vertex shader stage (indicated by the Vertex Shader thumbnail):

    Événement DrawIndexed et son effet sur le pipelineA DrawIndexed event and its effect on the pipeline

    Une fois que vous avez constaté que l’application a effectué un appel de dessin pour la géométrie de l’objet manquant et que vous avez découvert que le problème se produit à l’étape du nuanceur de sommets, vous pouvez utiliser le débogueur HLSL pour examiner le nuanceur de sommets et comprendre ce qui s’est passé avec la géométrie de l’objet.After you confirm that the app issued a draw call for the missing object's geometry and discover that the problem happens during the vertex shader stage, you can use the HLSL Debugger to examine the vertex shader and find out what happened to the object's geometry. Le débogueur HLSL vous permet d’examiner l’état des variables HLSL pendant l’exécution, d’exécuter pas à pas le code HLSL et de définir des points d’arrêt pour vous aider à diagnostiquer le problème.You can use the HLSL Debugger to examine the state of HLSL variables during execution, step through the HLSL code, and set breakpoints to help you diagnose the problem.

Pour examiner le nuanceur de sommetsTo examine the vertex shader

  1. Démarrez le débogage du nuanceur de sommets.Start debugging the vertex shader stage. Dans la fenêtre Étapes de canalisation Graphics , sous l’étape Nuanceur de sommets , choisissez le bouton Démarrer le débogage .In the Graphics Pipeline Stages window, under the Vertex Shader stage, choose the Start Debugging button.

  2. Vous avez constaté que l’étape Assembleur d’entrée fournit des données correctes au nuanceur de sommets et que l’étape Nuanceur de sommets ne produit aucune sortie. Vous souhaitez donc examiner la structure de la sortie du nuanceur de sommets, output.Because the Input Assembler stage appears to provide good data to the vertex shader and the Vertex Shader stage appears to produce no output, you want to examine the vertex shader output structure, output. Vous exécutez le code HLSL pas à pas pour déterminer plus en détail à quels moments output est modifié.As you step through the HLSL code, you take a closer look when output is modified.

  3. La première modification apportée à output est l’écriture du membre worldPos .The first time that output is modified, the member worldPos is written to.

    La valeur « Output.worldpos » semble raisonnableThe value of "output.worldPos" appears reasonable

    Comme sa valeur vous semble correcte, vous continuez l’exécution du code pas à pas jusqu’à la ligne suivante qui modifie output.Because its value appears to be reasonable, you continue stepping through code until the next line that modifies output.

  4. La modification suivante apportée à output est l’écriture du membre pos .The next time that output is modified, the member pos is written to.

    La valeur de « output.pos » a été remis à zéroThe value of "output.pos" has been zeroed out

    Cette fois, la valeur du membre pos , composée uniquement de zéros, vous semble douteuse.This time, the value of the pos member—all zeros—seems suspicious. Vous voulez alors essayer de comprendre pourquoi output.pos a cette valeur composée de zéros.Next, you want to determine how output.pos came to have a value of all zeros.

  5. Vous remarquez que output.pos prend sa valeur d’une variable nommée temp.You notice that output.pos takes its value from a variable that's named 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.On the previous line, you see that the value of temp is the result of multiplying its previous value by a constant that's named projection. Vous supposez que la valeur douteuse de tempest le résultat de cette multiplication.You suspect that temp's suspicious value is the result of this multiplication. Quand vous placez le pointeur sur projection, vous voyez que sa valeur n’est composée que de zéros, elle aussi.When you rest the pointer on projection, you notice that its value is also all zeros.

    La matrice de projection contient une transformation incorrecteThe projection matrix contains a bad transform

    Dans ce scénario, l’examen révèle que la valeur douteuse de tempest probablement le résultat de la multiplication par projection. De plus, comme projection est une constante censée contenir une matrice de projection, vous savez qu’elle ne doit pas contenir que des zéros.In this scenario, the examination reveals that temp's suspicious value is most likely caused by its multiplication by projection, and because projection is a constant that's meant to contain a projection matrix, you know that it should not contain all zeros.

    Après avoir déterminé que la constante HLSL projection, passée au nuanceur par votre application, est la source probable du problème, vous devez maintenant rechercher à quel endroit, dans le code source de votre application, la mémoire tampon constante est remplie.After you determine that the HLSL constant projection—passed into the shader by your app—is the likely source of the problem, the next step is to find the location in your app's source code where the constant buffer is filled. Vous pouvez faire cette recherche dans la fenêtre Liste des événements Graphics .You can use the Graphics Event Call Stack to find this location.

Pour rechercher où la constante est définie dans le code source de votre applicationTo find where the constant is set in your app's source code

  1. Ouvrez la fenêtre Pile des appels des événements Graphics .Open the Graphics Event Call Stack window. Dans la barre d’outils Graphics Diagnostics , choisissez Pile des appels des événements Graphics.On the Graphics Diagnostics toolbar, choose Graphics Event Call Stack.

  2. Remontez la pile des appels dans le code source de votre application.Navigate up the call stack into your app's source code. Dans la fenêtre Pile des appels des événements Graphics , choisissez le premier appel en haut pour voir si la mémoire tampon constante est remplie à cet endroit.In the Graphics Event Call Stack window, choose the top-most call to see if the constant buffer is being filled there. Si ce n’est pas le cas, continuez de remonter la pile des appels jusqu’à ce que vous trouviez l’endroit où elle est remplie.If it is not, continue up the call stack until you find where it is being filled. Dans ce scénario, vous découvrez que la mémoire tampon constante est remplie, via l’API Direct3D UpdateSubresource , plus haut dans la pile des appels dans une fonction nommée MarbleMaze::Render, et que sa valeur provient d’un objet mémoire tampon constante nommé m_marbleConstantBufferData:In this scenario, you discover that the constant buffer is being filled—by using the UpdateSubresource Direct3D API—further up the call stack in a function that's named MarbleMaze::Render, and that its value comes from a constant buffer object that's named m_marbleConstantBufferData:

    Le code qui définit la mémoire tampon constante de l’objetThe code that sets the object's constant buffer

    Conseil

    Si vous déboguez simultanément votre application, vous pouvez définir un point d’arrêt à cet emplacement, qui sera atteint lorsque le frame suivant sera affiché.If you are simultaneously debugging your app, you can set a breakpoint at this location and it will be hit when the next frame is rendered. En examinant ensuite les membres de m_marbleConstantBufferData , vous constatez que le membre projection a une valeur composée uniquement de zéros quand la mémoire tampon constante est remplie.You can then inspect the members of m_marbleConstantBufferData to confirm that the value of the projection member is set to all zeros when the constant buffer is filled.

    Vous avez trouvé l’endroit où la mémoire tampon constante est remplie et découvert que ses valeurs proviennent de la variable m_marbleConstantBufferData. Vous devez maintenant trouver l’endroit où le membre m_marbleConstantBufferData.projection a une valeur composée de zéros.After you find the location where the constant buffer is being filled and discover that that its values come from the variable m_marbleConstantBufferData, the next step is to find out where the m_marbleConstantBufferData.projection member is set to all zeros. Vous pouvez utiliser Rechercher toutes les références pour rechercher rapidement le code qui modifie la valeur de m_marbleConstantBufferData.projection.You can use Find All References to quickly scan for code that changes the value of m_marbleConstantBufferData.projection.

Pour rechercher où le membre projection est défini dans le code source de votre applicationTo find where the projection member is set in your app's source code

  1. Recherchez les références à m_marbleConstantBufferData.projection.Find references to m_marbleConstantBufferData.projection. Ouvrez le menu contextuel de la variable m_marbleConstantBufferData, puis choisissez Rechercher toutes les références.Open the shortcut menu for the variable m_marbleConstantBufferData, and then choose Find All References.

  2. Pour accéder à la ligne dans le code source de votre application où le membre projection est modifié, sélectionnez cette ligne dans la fenêtre Résultats de la recherche de symbole .To navigate to the location of the line in your app's source code where the projection member is modified, choose that line in the Find Symbol Results window. Comme le premier résultat qui modifie le membre projection ne peut pas être la cause du problème, vous allez devoir examiner plusieurs parties du code source de votre application.Because the first result that modifies the projection member might not be the cause of the problem, you might have to examine several areas of your app's source code.

    Après avoir trouvé où m_marbleConstantBufferData.projection est défini, vous pouvez examiner le code source environnant pour déterminer l’origine de la valeur incorrecte.After you find the location where m_marbleConstantBufferData.projection is set, you can examine the surrounding source code to determine the origin of the incorrect value. Dans ce scénario, vous constatez que la valeur de m_marbleConstantBufferData.projection est définie sur une variable locale nommée projection avant son initialisation sur une valeur fournie par le code m_camera->GetProjection(&projection); sur la ligne suivante.In this scenario, you discover that the value of m_marbleConstantBufferData.projection is set to a local variable that's named projection before it has been initialized to a value that's given by the code m_camera->GetProjection(&projection); on the next line.

    La projection marble est définie avant l’initialisationThe marble projection is set before initialization

    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.To fix the problem, you move the line of code that sets the value of m_marbleConstantBufferData.projection after the line that initializes the value of the local variable projection.

    La correction C+ + code sourceThe corrected C++ source code

    Après avoir corrigé le code, vous pouvez le régénérer, puis réexécuter l’application pour vérifier que le problème d’affichage est résolu :After you fix the code, you can rebuild it and run the app again to discover that the rendering issue is solved:

    L’objet est désormais affiché. The object in now displayed.