понедельник, 14 января 2019 г.

Отладка шейдеров

  До сих пор ситуация с дебагерами для шейдеров в основном печальная. В VS есть отладчик только для DirectX, не знаю точно поддерживается ли там 12, но 11 точно. В RenderDoc только DX11, для Vulkan есть декомпиляция SPIRV с помощью SPIRV-Cross. В NSight насчет DirectX не знаю, OpenGL там только просмотр шейдеров, если использовать бинарный формат, то не будет работать, для Vulkan даже просмотра дизасма SPIRV нет. Внезапно, Apple порадовал, с 31й минуты отладка шейдеров для Metal. В CUDA тоже много возможностей отладки и профилирования. Отладчиками от AMD я не пользовался из-за отсутствия видеокарты, но в расширениях GLSL есть функция timeAMD, как раз для профилирования, это можнт быть интересно. Единственный дебаггер для GLSL который я нашел не обновлялся уже 5 лет и поддержки Vulkan там точно нет.

Диаграмма из NSight смотрится красиво.


  Как я решал проблему отладки раньше: OpenCL почти сразу можно скомпилировать обычным C компилятором, надо только векторные типы объявить и некоторые операторы и функции. С GLSL уже сложнее, тут приходилось долго портировать на C++ и обратно. С появлением glslang появилась возможность сконвертировать AST в любой код, что я и сделал получив из одного GLSL шейдера сразу 4: GLSL, OpenCL program, C++, HLSL. Исходники можно посмотреть тут, пример C++ шейдера тут и тут. Версия для C++ поддерживалась только для компьют шейдеров, но обычно они как раз самые тяжелые, это позволяло отлаживать код, замерять производительность, проходиться статическим анализатором и тд, все то же что можно делать с любым C++ кодом. Но производительность особенно дебажной версии сильно проседала, к тому же если OpenCL код работает точно также как и C++, то для GLSL используются более оптимизированные математические функции и точность вычислений снижается, а конечный результат может отличатся.

  И совсем недавно появилась идея сделать запись трейса шейдера. Опять же с помощью glslang я получаю AST далее нахожу вызовы функций, модифицирующие операторы (++, =, *= и тд) и записываю их значения в storage buffer. Из AST с помощью glslang шейдер компилируется в SPIRV, обратной конвертации в GLSL нет, поэтому поддержки старых версий OpenGL нет. На прототип ушло всего около 20 часов. Далее сделал попытку встроить улучшенную версию трейса в RenderDoc, но пока работает нестабильно. Потом добавил поддержку в свой FrameGraph, теперь можно запустить отладку для конкретного DrawCall/Dispatch, а чуть позже добавлю поддержку шейдеров рейтрейсинга.
  Либа для записи трейса тут, из зависимостей только glslang, так что можно встроить куда угодно. Тесты либы и пример использования в FrameGraph.
  Такой способ отладки во много раз лучше общепринятого способа с выводом результатов в текстуру, например, я в трейсе видел такую операцию: 64.0 - 0.0 = 63.999996, без дебаггера заметить это почти невозможно.

  Дальше планирую все же доделать прототип для RenderDoc, все же иногда через него дебажить шейдеры проще. Так же в планах поддержка ассертов, чтоб обнаруживать проблемные места и при этом не сильно замедлять работу шейдера. Еще хочу дополнительный дебажный вывод - это как ассерт, но при срабатывании идет запись в текстуру, получается несколько дополнительных рендер таргетов куда выводятся промежуточные значения при выполнении шейдера. Для пройфалинга шейдеров интересно попробовать функцию timeAMD, но для этого надо будет взять видеокарту от AMD (я надеялся дождаться Navi, но посмотрим), для ветвлений хочу логировать какие потоки warp'а активны в каждой из ветвей. И хочу сделать подсчет инструкций шейдера для каждого потока/пикселя, это не сложно, но очень полезно, у меня когда-тоо была проблема, что шейдер для скайбокса крутил цикл по динамическим источникам освещения и снижал производительность всего кадра в 3 раза, потому что на мобилках я использовал лайтмапы, а для этого шейдера забыл отключить освещение вообще...

Обновление:
  Сделал прототип для RenderDoc, но особого интереса он не вызвал, а разработчик RenderDoc'а сказал, что это не тот способ которым он бы хотел сделать отладку шейдеров. Поэтому эта версия заморожена, а я продолжу развивать независимую либу для отладки шейдеров, которую можно встроить куда угодно. Также эта либа интегрирована в мой фреймграф.

Комментариев нет:

Отправить комментарий