Когда вычислительный шейдер более эффективен, чем пиксельный шейдер для фильтрации изображений?


37

Операции фильтрации изображений, такие как размытие, SSAO, bloom и т. Д., Обычно выполняются с использованием пиксельных шейдеров и операций «сбора», где каждый вызов пиксельного шейдера выдает несколько выборок текстуры для доступа к значениям соседних пикселей и вычисляет ценность одного пикселя. результат. Этот подход имеет теоретическую неэффективность в том, что выполняется много избыточных выборок: соседние вызовы шейдеров будут повторно извлекать многие из тех же текселей.

Еще один способ сделать это с помощью вычислительных шейдеров. У них есть потенциальное преимущество в том, что они могут совместно использовать небольшой объем памяти для группы вызовов шейдеров. Например, вы можете заставить каждый вызов извлекать один тексель и сохранять его в общей памяти, а затем вычислять результаты оттуда. Это может или не может быть быстрее.

Вопрос в том, при каких обстоятельствах (если вообще когда-либо) метод compute-shader на самом деле быстрее, чем метод pixel-shader? Зависит ли это от размера ядра, какой это операции фильтрации и т. Д.? Ясно, что ответ будет варьироваться от одной модели графического процессора к другой, но мне интересно услышать, есть ли какие-либо общие тенденции.


Я думаю, что ответ «всегда», если вычислительный шейдер сделан правильно. Это не тривиально для достижения. Вычислительный шейдер также лучше подходит для алгоритмов обработки изображений, чем пиксельный шейдер. Однако пиксельный шейдер обеспечивает меньшую свободу действий при написании неэффективных фильтров.
Берни

@bernie Можете ли вы уточнить, что нужно для того, чтобы вычислительный шейдер был «сделан правильно»? Может написать ответ? Всегда хорошо, чтобы получить больше точек зрения на эту тему. :)
Натан Рид

2
Теперь посмотри, что ты заставил меня сделать! :)
Берни

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

Ответы:


23

Архитектурное преимущество вычислительных шейдеров для обработки изображений состоит в том, что они пропускают этап ROP . Весьма вероятно, что записи с пиксельных шейдеров проходят через все обычные аппаратные средства смешивания, даже если вы их не используете. Вообще говоря, вычислительные шейдеры проходят другой (и часто более прямой) путь к памяти, поэтому вы можете избежать узкого места, которое в противном случае было бы. Я слышал о довольно значительных выигрышах в производительности, связанных с этим.

Архитектурный недостаток вычислительных шейдеров заключается в том, что графический процессор больше не знает, какие рабочие элементы удаляются в какие пиксели. Если вы используете конвейер затенения пикселей, у графического процессора есть возможность упаковать работу в деформацию / волновой фронт, который записывает в область цели рендеринга, которая является непрерывной в памяти (которая может быть мозаичной по Z-порядку или что-то подобное для производительности причины). Если вы используете вычислительный конвейер, графический процессор может перестать работать в оптимальных пакетах, что приведет к большему использованию полосы пропускания.

Возможно, вы сможете снова превратить эту измененную упаковку деформации / волнового фронта в преимущество, если знаете, что ваша конкретная операция имеет подструктуру, которую вы можете использовать, упаковывая связанные работы в одну группу потоков. Как вы сказали, теоретически вы можете дать аппаратному обеспечению выборки перерыв, выбрав одно значение для каждой полосы и поместив результат в групповую память для доступа к другим линиям без выборки. Является ли это победой, зависит от того, насколько дорогой является ваша общая групповая память: если она дешевле, чем текстурный кеш самого низкого уровня, то это может быть победой, но это не гарантируется. Графические процессоры уже хорошо справляются с выборками текстур с высокой степенью локальности (по необходимости).

Если у вас есть промежуточные этапы в операции, где вы хотите поделиться результатами, может иметь смысл использовать групповую память (так как вы не можете использовать аппаратное обеспечение выборки текстур, не записав свой промежуточный результат в память). К сожалению, вы также не можете зависеть от получения результатов от какой-либо другой группы потоков, поэтому второй этап должен ограничиваться только тем, что доступно в той же плитке. Я думаю, что каноническим примером здесь является вычисление средней яркости экрана для автоэкспозиции. Я мог бы также представить комбинирование сглаживания текстур с какой-либо другой операцией (поскольку повышение сэмплирования, в отличие от сглаживания и размытия, не зависит от каких-либо значений за пределами данного тайла).


Я серьезно сомневаюсь, что ROP добавляет какие-либо потери производительности, если смешивание отключено.
GroverManheim

@GroverManheim Зависит от архитектуры! Этап выходного слияния / ROP также должен иметь дело с гарантиями упорядочения, даже если смешивание отключено. С полноэкранным треугольником нет никаких реальных опасностей при заказе, но аппаратные средства могут этого не знать. Могут быть специальные быстрые пути в оборудовании, но мы точно
знаем,

10

Джон уже написал отличный ответ, поэтому считайте этот ответ продолжением своего.

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

После того, как вы поймете, как работают вычислительные шейдеры, во многих случаях они приобретают гораздо больший смысл. Использование пиксельных шейдеров для фильтрации изображения требует настройки буфера кадров, отправки вершин, использования нескольких этапов шейдера и т. Д. Почему это необходимо для фильтрации изображения? На мой взгляд, использование для отображения полноэкранных четырехугольников для обработки изображений, безусловно, является единственной «действительной» причиной для их дальнейшего использования. Я убежден, что новичок в области вычислительной графики найдет вычислительные шейдеры гораздо более естественными для обработки изображений, чем рендеринг в текстуры.

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

При использовании вычислительных шейдеров для выполнения реальной работы можно использовать больше кремния на графическом процессоре. Все эти дополнительные шаги необходимы при использовании маршрута пиксельного шейдера:

  • Сборка вершин (чтение атрибутов вершин, делителей вершин, преобразование типов, расширение их до vec4 и т. Д.)
  • Вершинный шейдер должен быть запланирован независимо от того, насколько он минимален
  • Растеризатор должен вычислить список пикселей для затенения и интерполировать выходные данные вершин (возможно, только текстурные координаты для обработки изображений)
  • Все различные состояния (тест глубины, альфа-тест, ножницы, смешивание) должны быть установлены и управляться

Можно утверждать, что все вышеупомянутые преимущества в производительности могут быть сведены на нет умным драйвером. Вы были бы правы. Такой драйвер может определить, что вы рендеринге полноэкранного четырехугольника без глубинного тестирования и т. Д., И настроить «быстрый путь», который пропускает всю бесполезную работу, выполненную для поддержки пиксельных шейдеров. Я не удивлюсь, если некоторые драйверы сделают это для ускорения проходов постобработки в некоторых играх AAA для своих конкретных графических процессоров. Конечно, вы можете забыть о любом таком лечении, если вы не работаете над игрой ААА.

Однако драйвер не может найти лучшие возможности параллелизма, предлагаемые конвейером вычислительных шейдеров. Возьмите классический пример гауссовского фильтра. Используя вычислительные шейдеры, вы можете сделать что-то вроде этого (разделить фильтр или нет):

  1. Для каждой рабочей группы разделите выборку исходного изображения по размеру рабочей группы и сохраните результаты в общей разделяемой памяти.
  2. Вычислите выходные данные фильтра, используя результаты выборки, хранящиеся в общей памяти.
  3. Написать в выходную текстуру

Шаг 1 является ключевым здесь. В версии пиксельного шейдера исходное изображение дискретизируется несколько раз на пиксель. В версии вычислительного шейдера каждый исходный тексель читается только один раз внутри рабочей группы. Чтение текстур обычно использует кэш на основе плитки, но этот кеш все еще намного медленнее, чем разделяемая память.

Гауссов фильтр является одним из простых примеров. Другие алгоритмы фильтрации предлагают другие возможности для обмена промежуточными результатами внутри рабочих групп, использующих общую память.

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

Ссылки


Улучшенный параллелизм сэмплирования, который вы описываете, интригует - у меня есть гибкий симулятор, который уже реализован с помощью вычислительных шейдеров с множеством экземпляров по нескольким выборкам на пиксель. Использование групповой памяти для одиночной выборки с барьером памяти, как вы описываете, кажется отличным, но я одержим одну мысль - как получить доступ к соседним пикселям, если они попадают в другую рабочую группу? например, если у меня есть область моделирования 64x64, распределенная по отправке (2,2,1) из numthreads (16,16,1), как пиксель с id.xy == [15,15] получит соседние пиксели ?
Тоссрок

В этом случае я вижу 2 основных варианта. 1) увеличить размер группы более 64 и записывать результаты только для 64x64 пикселей. 2) сначала сэмплируйте 64 + nX64 + n, разделенных каким-либо образом в вашей рабочей группе 64x64, а затем используйте эту большую «входную» сетку для вычислений. Лучшее решение, конечно, зависит от ваших конкретных условий, и я предлагаю вам написать еще один вопрос для получения дополнительной информации, так как комментарии плохо подходят для этого.
Берни

3

Я наткнулся на этот блог: вычислить оптимизацию шейдеров для AMD

Учитывая, какие приемы можно сделать в вычислительных шейдерах (которые характерны только для вычислительных шейдеров), мне было любопытно, было ли параллельное сокращение в вычислительных шейдерах быстрее, чем в пиксельных шейдерах. Я отправил электронное письмо автору Вольфу Энгелю, чтобы он спросил, пробовал ли он пиксельный шейдер. Он ответил, что да, и когда он писал в блоге, версия вычислительного шейдера была значительно быстрее, чем версия пиксельного шейдера. Он также добавил, что сегодня различия еще больше. Таким образом, по-видимому, существуют случаи, когда использование вычислительного шейдера может иметь большое преимущество.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.