RenderDoc — графический отладчик для DirectX11 от Crytek

  • Tutorial
Как вы, возможно, знаете в мире Windows для рисования графики часто используется DirectX. В последних версиях (10, 11.x) библиотека серьёзно шагнула вперёд и именно на них построены движки многих современных игр. Кроме того, DirectX используется не только в играх — сам интерфейс ОС Windows тоже с непомню-какой версии (Vista?) рисуется через него, да и казалось-бы не сильно связанные с графикой программы, желая увеличить производительность и плавность зума\скрола переходят на последние версии DirectX. Так некоторое время назад на DirectX11 перешел рендер Google Chrome (вроде бы с версии 36).

Когда-то во времена Windows 95 и Pentium II была такая шутка, что чем медленнее компьютер — тем лучше можно понять работу операционной системы — невооруженным глазом видно в каком порядке прорисовываются элементы окон, обрабатываются события. Сегодня для подобных целей относительно DirectX есть отдельные инструменты — графические отладчики, позволяющие понять, как именно рисуется каждый пиксель каждого кадра, какие операции выполняет движок DirectX, какие ресурсы он использует, насколько быстро и правильно всё работает. Один из таких инструментов — RenderDoc от компании Crytek мы сегодня и рассмотрим. А в качестве примера разберём уже упомянутый выше новый рендер Google Chrome.




Прежде всего — почему я говорю о RenderDoc? Есть немало аналогичных инструментов:


Все они — очень хороши. Но:
  • PIX — уже устарел, не развивается и не работает на последних ОС
  • инструменты от Intel\AMD\Nvidia — сделаны в духе «вот этими утилитами можно посмотреть, как офигительно классно и быстро работает DirectX на наших видеокартах», при этом некоторые прикладные, рутинные задачи отладки в них делать не очень удобно
  • Visual Studio — заточена именно под разработку своего софта, а не анализ чужого


Что касается RenderDoc, то это:
  • opensource, активно развивается
  • заточен на последние версии Windows и DirectX11
  • продукт от профессионалов 3D-разработки — компании, создавшей движок CryEngine со всей сопутствующей обвязкой
  • пропитан практическим подходом к разработке и отладке — не знаю, как это лучше объяснить, но вот к примеру когда только задумываешься о том, что «хм, было бы неплохо в этом вызове увидеть вот эту информацию в вот такой-вот форме» внезапно оказывается, что RenderDoc показывает именно эту информацию, именно в этом вызове и именно в нужной форме. Видно, что инструмент живёт и полируется в руках Crytek.
  • вообще единственный продукт, который понял от меня, что я хочу отлаживать отрисовку графики в дочернем процессе Chrome, запущенного из родительского, в котором никакой графики нет вообще. Казалось бы, лаунчер — простейшая вещь, используется во многих играх, но вот только RenderDoc дошел до необходимости его поддержки в отладчике.


Итак, качаем RenderDoc, устанавливаем. Запускаем, видим главное окно. Открываем в меню Tools->Options и указываем папку, в которую будут складываться временные файлы (дампы).



Теперь нам нужно запустить под отладчиком RenderDoc приложение, которое мы хотим отлаживать. Для этого на вкладке "Capture Executable" вводим путь к Chrome, его рабочую папку. Здесь есть несколько интересных моментов. Графика в Хроме рисуется в отдельном дочернем процессе, его можно определить запустив Process Hacker и найдя среди всех запущенных процессов chrome.exe тот, у которого среди параметров командной строки имеется флаг --type=gpu-process.



Мы не можем запустить этот процесс напрямую, поэтому мы должны запустить главный процесс Chrome, указав в RenderDoc, что хотим отслеживать вызовы DirectX-функций в том числе среди дочерних процессов (галочка Hook Into Children)

По-умолчанию дочерние процессы Chrome «живут» в песочнице — имеют низкий Integrity Level, который препятствует их взаимодействию с файловой системой, другими процессами и общими ресурсами ОС. Таким образом, если мы просто запустим Chrome, то RenderDoc не будет в состоянии взаимодействовать с процессом, в котором рисуется графика. Для этого есть хак — Chrome нужно запускать со специальным флагом --no-sandbox, который отключает «песочницу» Chrome.

Поскольку нам интересно вообще всё, что будет происходить по ходу рисования графики — включаем побольше разных полезных галочек. Также мы можем сразу указать, какой по счету фрейм мы хотим захватить (для этого есть галочка Queue Capture Of Frame #), а можем уже в приложении нажать кнопку PrintScreen, чтобы создать дамп для текущего кадра

В итоге вкладка Capture Executable у нас будет выглядеть вот так:


Жмём кнопку Capture, запускается Chrome.


В верхней части окна мы видим некую отладочную информацию, которая говорит нам как-минимум о нескольких вещах:
  • Chrome действительно использует DirectX11 для рисования своего окна (причём целого окна: заголовка, тулбаров и контента страницы)
  • RenderDoc успешно «прицепился» к Chrome


Теперь можно открыть в Chrome что-нибудь и нажать PrintScreen. В верхней части окна Chrome появится надпись о созданном скриншоте. Всё, Chrome можно закрывать, а в папке, которую вы указали в настройках должен появиться файл с расширением rdc. Это и есть наш дамп. Открываем его через "File->Open Log" и видим примерно вот такую картину:


В верхней части окна находится «таймлайн» — временная линия, на которой отмечены этапы рисования данного кадра. Их может быть до нескольких десятков (если вы их не видите — кликните по плюсику в левом верхнем углу окна «Timeline»). Те же этапы отмечены в панели "Event Browser" в левой части окна. Кликая по таймлайну или по событиям в «Event Browser» мы можем переходить к разным моментам по ходу рисования кадра.

Корневой узел дерева событий называется "Frame #N" и показывает, какой это кадр от момента инициализации DirectX в приложении. Далее следует мета-узел "Frame start" указывающий на момент начала рисования данного кадра (никаких реальных вызовов DirectX-методов к нему не привязано). Далее мы видим три узла: "Colour Pass #1 (1 Targets)", "Draw(4)" и "Present()". Из этого мы можем понять, что всё рисование контента окна хрома проходит в несколько этапов:
  • Сначала всё рисуется в некую промежуточную текстуру (этап "Colour Pass #1 (1 Targets)")
  • Затем вызов метода "Draw(4)" переносит содержание этой текстуры в Swap Chain Backbuffer
  • И наконец метод Present вызывает отображение бэкбуфера на экран


Как видите, этап рисование в промежуточную текстуру в дереве можно раскрыть и мы увидим моменты рисования отдельных элементов окна Хрома.


Первым делом текстура очищается (вызов ClearRenderTargetView). Затем следует много этапов под названием "DrawIndexed(6)". 6 — это количество точек, ограничивающих область, рисуемую на данном этапе. То, что их 6, наталкивает на мысль, что это 2 треугольника, составляющих прямоугольник. Давайте выберем один их этапов "DrawIndexed(6)" (не первый, но и не последний) и рассмотрим его повнимательнее.

Начнём с вкладки "Pipeline State"


Как вы, возможно, знаете, в DirectX11 используется понятие "Pipeline" — это набор из нескольких последовательных операций, предназначенных для формирования окончательного кадра. Начинается пайплайн с этапа Input Assembler — здесь мы предоставляем все необходимые входные данные по вершинным, индексным и константным буферам, которые могут в дальнейшем понадобиться для рассчёта что и куда нужно будет рисовать. Далее следуют этапы обработки входных данных различными типами шейдеров и последняя фаза — Output Merger, в которой графика компонуется и выводится туда, куда должна быть выведена.

В окне Pipeline State мы можем кликнуть по любой стадии пайплайна и увидеть:
  • Что пришло на вход стадии (буфер, шейдер, текстура), общую информацию об этом объекте
  • Кликнув по зелёной стрелочке справа от входного параметра мы можем открыть окно с более полной информацией. Для буфера это его полное содержание, для текстуры — её картинка, для шейдера — его скомпилированный байткод.
  • Для стадии Input Assembler мы также можем кликнуть по большой кнопке "Mesh" и посмотреть координаты точек, образующих рисуемую на данном этапе область. Здесь ещё раз можно убедиться, что рисуем мы именно прямоугольник.


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


В тулбаре "PS Resources" мы видим текстуру(ы), которая будет рисоваться на данном этапе, а в тулбаре "OM Targets" — текстуру, куда будет происходить отрисовка. Оставаясь в окне текстур, можно покликать по этапам отрисовке сверху или слева — и мы увидим, что Хром рисует своё окно текстурами размером 256х256 пикселей. Начинает он с нижней части окна, потом рисует боковые края и затем — заголовок окна с тулбарами. После этого Хром приступает к рисованию контента вкладки (опять-таки кусочками по 256х256 пикселей). Потом рисуются лежащие «поверх» контента объекты — видео, флеш-баннеры, всплывающие подсказки. На последних этапах рисуются скроллбар и его ползунок. Теперь текстура готова к рисованию в бэкбуфер.

Что ещё интересного умеет RenderDoc


Показывать API вызываемых DirectX-методов для каждого этапа отрисовки

Невероятно полезная вещь. А учитывая, что видны не только названия методов, но и их параметры — это вообще красота.

Показывать колстек (откуда в коде был вызван тот или иной DirectX-метод)
Правда, для этого нужно подсунуть программе pdb-файл (который у вас есть только если вы сами — автор отлаживаемого кода). Весьма полезно для отладки своих программ, полностью бесполезно для анализа чужих.

Дебажить шейдеры
Для вершинных шейдеров отладка начинается в окне Mesh Output с клика правой кнопкой мыши по интересующей вершине.


Для пикселей — в окне текстур, где на интересующем пикселе нужно кликнуть правой кнопкой мыши и кликнуть в тулбаре "Pixel Content" кнопку "Debug this Pixel"


Вот такой полезный инструмент RenderDoc.
Удачной вам отладки графики.
Инфопульс Украина
96.91
Creating Value, Delivering Excellence
Share post

Comments 21

    +2
    В новой(2013) Visual Studio MS утверждали, что сильно улучшили диагностику графики. И те возможности RenderDoc, которые вы описали в этой статье, там появились. Сам не пробовал, но судя по презентации — в том числе отладка сторонних приложений. Впрочем, на счет дочерних процессов и корректной обработки ланчеров ничего не знаю, как и на счет реального удобства отладки сторонних приложений.
      +5
      Студия — отличный инструмент для разработки и отладки своего DirectX-кода, если у вас есть код — ничего кроме VS 2013 и не надо. А вот как отлаживать чужие программы — я так и не понял. Если кто-то может показать\рассказать как отладить хоть что-нибудь без кода и pdb-файлов — буду очень благодарен.
        +1
        В студии очень просто работать с Graphics Debugger'ом. Создаем пустой native проект (С++), или открываем абсолютно любой существующий. В настройках проекта, в разделе Debugging в поле Command вписываем полный путь к исследуемому exe. По необходимости также заполняем поля Command Arguments и Working Directory. Закрываем настройки. Графический дебаггинг запускаем в меню Debug->Graphics->Start Diagnostics. Никаких PDB и «своего DirectX-кода» при этом не надо. Возможность дебагать child процессы была в PIX. Я когда игры реверсил постоянно ею пользовался. Сейчас в студийном дебаггере такой возможности найти не могу, возможно ее и нету. Зато в NSight есть. В настройках проекта надо поставить галочку «Application is a launcher». После запуска появится список child процессов среди которых надо выбрать нужный. Я не буду сравнивать различные дебаггеры (хотя бы потому что не работал с RenderDoc). Мне с лихвой хватало возможностей PIX/Visual Studio Graphics Debugger, PerfHUD/NSight, GPA, но весь тот функционал, что описан в статье есть во всех этих утилитах. Могу лишь только сказать, что все тезисы в разделе «Но:» кроме «PIX — уже устарел, не развивается и не работает на последних ОС» не соответсвуют действительности.
          +1
          Вообще не надо никаких проектов создавать, просто открываем *.exe-шник ;)
            +1
            Век живи, век учись. Все оказалось еще проще. Спасибо.
            0
            Могу лишь только сказать, что все тезисы в разделе «Но:» кроме «PIX — уже устарел, не развивается и не работает на последних ОС» не соответсвуют действительности.

            Забьёмся на что-нибудь, что ни PIX'ом, ни студией Вы не разберёте отрисовку кадра интерфейса Хрома так, как показано в статье с использованием RenderDoc? PIX тупо валит Хром на коннекте к дочернему процессу, а Студия просто не умеет.
            0
            Никаких проблем.
            Project -> Open solution
            открываем *.exe файл (дада, именно экзешник который будем отлаживать, как не покажется это странным)
            Далее в меню Debug->Graphics->Run diagnostic.
            Собственно все.
              +1
              Не решает проблему лаунчеров\дочерних процессов.
                0
                Но в статье черным по белому:
                Visual Studio — заточена именно под разработку своего софта, а не анализ чужого
                И комментарием выше вы говорите:
                Студия — отличный инструмент для разработки и отладки своего DirectX-кода, если у вас есть код — ничего кроме VS 2013 и не надо. А вот как отлаживать чужие программы — я так и не понял. Если кто-то может показать\рассказать как отладить хоть что-нибудь без кода и pdb-файлов — буду очень благодарен.
                Но вот последний ваш коммент на благодарность ну никак не похож. :)
                  0
                  Потому что до «открыть студией экзешник и нажать Run diagnostic» я и сам додумался, вот только это не помогает ни разу для того же Хрома. Хотелось узнать что-то новое.
                    0
                    А вот как отлаживать чужие программы и как отладить хоть что-нибудь без кода и pdb-файлов != Отладка дочерних процессов
                      0
                      Да, неверно выразился.
          0
          Классно, а для OpenGL что-нибудь такое есть?
          0
          В статью, помимо ссылки на скачивание, неплохо бы добавить ещё эти:
          Домашняя страница RenderDoc
          Страница RenderDoc на GitHub
            0
            Кстати, да
            +1
            Я попробовал RenderDoc — мне кажется, GPA сейчас удобнее. Во-первых, нормально показывает меши. Но самое главное — умеет аттачиться к процессу, запускаемому откуда-то еще. Когда редактор и игра живут в разных процессах и хочется подебажить рендер в редакторе — особенно удобно. Ну и как маленький бонус — каунтеры для интеловских железок.

            Еще с Интелом охуенно работать — посылаешь им frame capture, на котором что-то не работает — в ответку получаешь оперативно внутренний билд с фиксом.
              0
              А что значит «нормально показывает меши»? RenderDoc тоже показывает, и в таблицах и графически.
              image
                0
                ок, был не прав, значит
                А как рендердок работает с компут шейдерами, тесселяцией, hdr-текстурами и depth-buffer'ами?
                  0
                  Компут шейдеры есть на вкладке пайплайна (хотя им там и не место)…
                  На счёт тесселяции — можно посмотреть вход и выход hull-шейдеров и domain-шейдеров, и на этом всё. Отлаживать их пока нельзя.
                  hdr-текстуры и depth-буффера в документации упоминались как поддерживаемые, но сам я не пробовал.
              0
              RenderDoc — достойная замена PIX. Но им пользуюсь только для дебага шейдеров, все остальное делаю в Intel GPA для профайлинга Stage3D приложений(Flash). Два года назад писал про Intel GPA для флешеров, может кому будет интересно.
              Спасибо за статью! С интересом слежу за развитием RenderDoc.

              Only users with full accounts can post comments. Log in, please.