Поделиться через


Пошаговое руководство. Отсутствие объектов вследствие неправильной настройки конвейера

В данном пошаговом руководстве показано, как использовать средства диагностики графики Visual Studio, чтобы исследовать объект, который отсутствует из-за неустановленного пиксельного шейдера.

В данном пошаговом руководстве рассмотрены следующие задачи:

  • Использование Список событий графики, чтобы обнаружить потенциальные источники проблемы.

  • Использование окна Graphics Pipeline Stages для проверки эффекта вызовов API Direct3D DrawIndexed.

  • Проверка контекста устройства, чтобы убедиться, что этап шейдера не установлен.

  • Использование окна Graphics Pipeline Stages вместе с Graphics Event Call Stack для поиска источника неустановленного пиксельного шейдера.

Скрипт

Иногда объект отсутствует в трехмерном приложении из-за того, что один из этапов шейдеров не установлен до рендеринга объекта. В приложениях, которые имеют простые требования рендеринга, источник этой ошибки обычно находится в стеке вызовов для рисования объекта. Однако в целях оптимизации некоторые приложения группируют объекты с общими программами шейдеров, текстурами или другими данными, чтобы минимизировать расходы на смену состояний. В этих приложениях источник ошибки может быть похоронен в системе пакетной обработки, а не находиться в стеке вызовов рисования. Сценарий в этом пошаговом руководстве демонстрирует приложение, которое имеет простые требования рендеринга, поэтому источник ошибки можно найти в стеке вызовов.

В этом сценарии при запуске приложения для тестирования фон отображён как ожидалось, но один из объектов не появляется. Используя диагностику графики, вы записываете проблему в журнал графики, позволяя отлаживать приложение. В приложении проблема выглядит следующим образом:

Объект не виден

Расследование

С помощью инструментов диагностики графики можно загрузить документ журнала графики для проверки кадров, зарегистрированных во время теста.

Как Просмотреть кадр в журнале графики

  1. В Visual Studio загрузите документ журнала графики, содержащий кадр, который указывает на отсутствующий объект. Новая вкладка журнала графики отображается в Visual Studio. В верхней части этой вкладки находится отображенный целевой вывод выбранного кадра. В нижней части раздела Список кадров, которая отображает каждый схваченный кадр как эскиз.

  2. В поле Список кадров выберите кадр, который демонстрирует, что объект не отображается. целевой объект прорисовки обновляется, отражая выбранный кадр. В этом сценарии вкладка журнала графики выглядит следующим образом:

    Документ журнала графики в Visual Studio

После выбора кадра, который демонстрирует проблему, можно начать диагностику с использованием Graphics Event List. Graphics Event List содержит все вызовы API Direct3D, которое были выполнены для отрисовки активного кадра, например, вызовы API для настройки состояния устройства, создания и обновления буферов и рисования объектов, которые присутствуют в кадре. Существует много типов вызовов, которые интересны, поскольку часто (но не всегда) происходит соответствующее изменение в целевом объекте отрисовки, когда приложение работает, как ожидалось. Например, вызовы Draw, Dispatch, Copy или Clear. Вызовы рисования особенно интересны, поскольку каждое из них представляет геометрический объект, который приложение обработало.

Так как известно, что отсутствующий объект не рисуется в целевом объекте прорисовки, но другие ошибки отсутствуют, можно использовать Graphics Event List совместно с средством Graphics Pipeline Stages, чтобы определить, какой вызов рисования соответствует геометрии отсутствующего объекта. В окне Этапы графического конвейера отображается геометрия, отправляемая каждому вызову рисования, независимо от оказываемого им воздействия на целевой буфер отрисовки. По мере продвижения через вызовы рисования этапы конвейера обновляются для указания геометрии, связанной с каждым вызовом при его проходе через каждый включенный этап, и целевой результат отрисовки обновляется для отображения состояния целевого объекта отрисовки после выполнения вызова.

Поиск вызова рисования для отсутствующей геометрии

  1. При необходимости откройте окно Список событий графики. На панели инструментов Диагностика графики выберите Список событий.

  2. Откройте окно Этапы графического конвейера. На панели инструментов Диагностика графики выберите Этапы конвейера.

  3. По мере движения через каждый вызов рисования в окне Список событий графики, следите за отсутствующим объектом в окне Этапы графического конвейера. Чтобы сделать это проще, введите «Рисование» в окне Поиск в правом верхнем углу окна Список событий графики. Это фильтрует список, чтобы он будет содержать только события с «Draw» в своих именах.

    В окне Graphics Pipeline Stages этап Input Assembler показывает геометрию объекта перед тем, как он будет преобразован, а этап Vertex Shader показывает тот же объект после преобразования. Обратите внимание, что в этом сценарии в поле Graphics Pipeline Stages отображаются этапы Input Assembler и Vertex Shader, но не этап Pixel Shader для одного из вызовов рисования.

    Примечание

    Если другие стадии конвейера — например стадии шейдера поверхности, шейдера доменов или шейдера геометрии — обрабатывают объект, любая из них быть причиной проблемы.Как правило, проблема связана с самой ранней стадией, в которой результат не отображается или отображается непредвиденным образом.

  4. Дойдя до вызова рисования, соответствующего отсутствующему объекту, остановитесь. В этом сценарии окно Graphics Pipeline Stages показывает, что геометрический объект был передан в GPU (показано наличием этапа Input Assembler) и преобразован (показано этапом Vertex Shader), но не отображается в целевом объекте рендеринга, поскольку нет активного пиксельного шейдера (показано отсутствием этапа Pixel Shader). В этом сценарии можно увидеть даже силуэт отсутствующего объекта на этапе Output Merger:

    Событие DrawIndexed и его результат в конвейере

После того, как вы убедитесь, что приложение выполнило вызов средств рисования для отсутствующей геометрии объекта и обнаружите, что этап пиксельного шейдера не был активен, можно проверить состояние устройства для подтверждения выводов. Можно использовать Graphics Object Table для просмотра контекста устройства и других данных объекта Direct3D.

Для проверки контекста устройства

  1. Откройте d3d11 device context. В окне Graphics Pipeline Stages выберите ссылку ID3D11DeviceContext, являющуюся частью вызова DrawIndexed, который отображается в верхней части окна.

  2. Просмотрите состояние устройства, которое отображается на вкладке d3d11 device context, чтобы подтвердить, что пиксельный шейдер не был активным во время вызова рисования. В этом сценарии shader general information — отображаемое под pixel shader state— указывает, что шейдер NULL:

    Контекст устройства D3D 11 показывает состояние шейдера пикселей

После того, как вы убедитесь, что пиксельный шейдер был установлен равным NULL в приложении, на следующем этапе необходимо найти место в исходном коде приложения, где устанавливается пиксельный шейдер. Graphics Event List можно использовать вместе с Graphics Event Call Stack для поиска этого расположения.

Поиск, где пиксельный шейдер устанавливается в исходном коде приложения

  1. Найдите вызов PSSetShader, соответствующий отсутствующему объекту. В окне Graphics Event List введите "Draw;PSSetShader" в поле Search в правом верхнем углу окна Graphics Event List. Это фильтрует список, чтобы он содержал только события с «Draw» в своих именах и события "PSSetShader". Выберите первый вызов PSSetShader, который отображается до вызова рисования отсутствующего объекта.

    Примечание

    PSSetShader не отобразится в окне Graphics Event List, если оно не задано в процессе выполнения этого кадра.Обычно это происходит только если только один пиксельный шейдер используется для всех объектов или если вызов PSSetShader непреднамеренно был пропущен в ходе этого кадра.В любом случае рекомендуется выполнять поиск вызова PSSetShader в исходном коде приложения и использовать традиционные методы отладки, чтобы проанализировать поведение этих вызовов.

  2. При необходимости откройте окно Стек вызовов событий графики. На панели инструментов Диагностика графики выберите Стек вызовов событий графики.

  3. Используйте стек вызова, чтобы найти вызов PSSetShader в исходном коде приложения. В окне Graphics Event Call Stack выберите вызов на самом верхнем уровне и просмотрите значение, задаваемое пиксельному шейдеру. Пиксельный шейдер может быть напрямую установлен в NULL, или значение NULL, может возникнуть из-за аргумента, который передается в функцию или другому состоянию. Если он не установлен напрямую, можно обнаружить источник значения NULL в другом месте вверх по стеку вызовов. В этом сценарии будет обнаружено, что пиксельный шейдер устанавливается непосредственно в nullptr в функции на самом верхнем уровне, которая называется CubeRenderer::Render:

    Код, который не инициализирует шейдер пикселей

    Примечание

    Если не удается обнаружить источник значения NULL только проанализировав стек вызова, рекомендуется установить условную точку останова в вызове PSSetShader, чтобы приостановить выполнение программы при установке пиксельного шейдера в NULL.Перезапустите приложение в режиме отладки и используйте традиционные методы отладки, чтобы обнаружить источник значения NULL.

Чтобы устранить проблему, присвойте правильный пиксельный шейдер с помощью первого параметра вызова API ID3D11DeviceContext::PSSetShader.

Исправленный исходный код C++

После фиксирования кода можно перестроить его и снова запустите приложение, чтобы убедиться, что проблема отрисовки разрешена:

Теперь объект появился