Procédure pas à pas : objets manquants en raison d'un pipeline mal configuré
Ce tutoriel montre comment utiliser les outils de diagnostic de graphiques Visual Studio pour analyser un objet qui est manquant en raison d'un shader de pixelsnon défini.
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 Pipeline Graphique pour examiner l'effet des appels d'API Direct3D DrawIndexed.
Examiner le contexte de périphérique pour confirmer qu'une étape shader n'a pas été définie.
À l'aide de la fenêtre Étapes de Pipeline Graphics avec laPile des appels des événements Graphics pour vous aider à trouver la source de shader de pixels non défini.
Scénario
Lorsqu'un objet est manquant dans une application 3D, c'est parfois parce que l'une des étapes shaders n'est pas défini avant que l'objet ne soit rendu. Dans les applications qui ont des besoins simples en rendu, la source de cette erreur est généralement située quelque part dans la pile des appels des draw-call de l'objet. Toutefois, comme optimisation, certaines applications regroupent les objets, qui ont en commun des programmes shaders, des textures, ou d'autres données pour réduire la charge de changement d'état. Dans ces applications, la source de l'erreur peut être enterrée dans le système de traitement, plutôt que située dans la pile des appels des draw-calls. Le scénario de ce tutoriel montre une application qui a des besoins de rendu simples, par conséquent sa source d'erreur se trouve dans la pile des appels.
Dans ce scénario, lorsque l'application est exécutée pour la tester, l'arrière-plan 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 :
Examen
À l'aide des outils Graphics Diagnostics, vous pouvez charger le document des logs graphiques pour examiner les frames qui ont été capturées pendant le test.
Pour examiner un frame dans un journal de graphiques
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.
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 :
Après avoir sélectionné un frame illustrant le problème, vous pouvez commencer à le diagnostiquer à l'aide de la Liste des événements Graphiques. La Liste des événements Graphiques 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 draw-calls sont particulièrement intéressants car chacun représente la géométrie que l'application affiche.
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 laListe des événements Graphiques avec l'outil Étapes de Pipeline Graphiques pour déterminer à quel draw-call 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 draw-calls, les étapes de pipeline sont mises à jour pour afficher la géométrie associée à chaque appel comme ils se produisent à chaque étape permise, et la sortie de la cible de rendu est mise à jour pour afficher l'état de la cible de rendu à l'issue de chaque appel.
Pour rechercher l'appel de dessin pour la géométrie manquante
Ouvrez la fenêtre Liste des événements Graphics. Dans la barre d'outils Graphics Diagnostics, choisissez Liste des événements.
Ouvrez la fenêtre Étapes de canalisation Graphics. Dans la barre d'outils Graphics Diagnostics , choisissez Étapes de canalisation.
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 Pipeline Graphiques, 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, notez que la fenêtre Étapes dePipeline Graphiques montre les étapes Assembleur d'entrée et Vertex shader, mais pas l'étape Pixel Shader pour un des draw calls.
Notes
Si d'autres étapes de pipeline, par exemple, les étapes Hull Shader, Domain Shader ou geometry Shader, traitent l'objet, n'importe laquelle d'entre elles peut etre 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.
Arrêtez lorsque vous atteignez l'appel de dessin qui correspond à l'objet manquant. Dans ce scénario, la fenêtre Étapes de Pipeline Graphiques indique que la géométrie vient du GPU (indiquée par la présence de l'étape Assembleur d'entrée ) et transformée (indiquée par l'étape Vertex Shader ), mais n'apparaît pas dans la cible d'affichage car il ne semble pas y avoir de shader de pixel actif (indiquée par l'absence de l'étape Pixel Shader ). Dans ce cas, vous pouvez même voir la silhouette de l'objet manquant dans l'étapeFusion de sortie :
Après avoir confirmé que l'application a émis un draw call pour la geometrie de l'objet manquant et découvert que l'étape de Shader de pixel est inactive, vous pouvez examiner l'état du périphérique pour vérifier vos déductions. Vous pouvez utiliser Table des objets Graphiques pour vérifier le contexte de périphérique et d'autres données Direct3D.
Pour vérifier le contexte de périphérique
Ouvrez lecontexte du périphérique d3d11. Dans la fenêtre Étapes de Pipeline Graphiques, sélectionnez le lien ID3D11DeviceContext qui fait partie de l'appel DrawIndexed qui est affiché en haut de la fenêtre.
Examinez l'état du périphérique affiché sous l'onglet contexte du périphérique d3d11 pour vérifier qu'aucun shader de pixel n'était actif au cours du draw call. Dans ce scénario, informations générales sur le shader— affiché sous état du shader de pixels— indique que le shader est NULL:
Après avoir confirmé que le shader de pixels a été défini à zéro par votre application, l'étape suivante consiste à déterminer l'emplacement dans le code source de votre application où le shader est défini. Vous pouvez utiliser laListe des événements Graphics avec laPile des appels à des événements Graphics pour trouver cet emplacement.
Pour rechercher où le shader de pixel est défini dans le code source de votre application
Recherchez l'appel PSSetShader qui correspond à l'objet manquant. Dans la fenêtre Liste des événements Graphics, entrez « Draw;PSSetShader » 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 la liste ne contiennet que des évenements "PSSetShader", et des évènements qui ont "Draw" dans leur noms. Choisissez le premier appel PSSetShader qui apparaît avant le draw call de l'objet manquant.
Notes
PSSetShader n'apparaît pas dans la fenêtre Liste des événements Graphics si elle n'a pas été définie pendant ce frame.Habituellement cela se produit uniquement si un Shader de pixels est utilisé pour tous les objets, ou si l'appel PSSetShader a été involontairement ignoré pendant ce frame.Dans l'un et l'autre cas, nous recommandons que vous recherchiez le code source de l'application pour les appels PSSetShader, et utilisiez ensuite des techniques traditionnelles de débogage pour examiner le comportement de ces appels.
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.
Utilisez la pile des appels pour rechercher l'appel PSSetShader dans le code source de votre application. Dans la fenêtre Pile des appels des événements Graphics, choisissez l'appel le plus élevé et examinez la valeur à laquelle le shader de pixels est défini. Le nuanceur de pixels peut être définie directement à null, ou la valeur NULL peut se produire en raison d'un argument passé à la fonction ou à un autre état. Si elle n'est pas définie directement, vous pouvez identifier la source des valeurs NULL quelque part dans le haut de la pile des appels. Dans ce scénario, vous découvrez que le shader de pixel est défini directement à nullptr dans la fonction supérieure, nommée CubeRenderer::Render:
Notes
Si vous ne parvenez pas à identifier la source des valeurs NULL uniquement en examinant la pile des appels, nous vous recommandons de définir un point de rupture conditionnelle sur l'appel PSSetShader, tel que l'exécution du programme s'arrete lorsque le shader de pixels sera défini à la valeur null.Puis redémarrez l'application en mode débogage et utilisez les techniques traditionnelles de débogage pour identifier la source des valeurs NULL.
Pour résoudre ce problème, assignez le bon shader de pixels en utilisant le premier paramètre de l'appel d'API ID3D11DeviceContext::PSSetShader.
Après avoir réparé 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 :