Почему рекурсия запрещена в OpenCL?

19

Я бы хотел использовать OpenCL для ускорения рендеринга изображений с трассировкой лучей, но я заметил, что на странице Википедии утверждается, что рекурсия запрещена в Open CL. Это правда? Поскольку я широко использую рекурсию при трассировке лучей, для ее ускорения потребуется значительное количество редизайна. Какое основное ограничение препятствует рекурсии? Есть ли способ обойти это?

Trichoplax
источник
2
Графические процессоры работают по-другому. (Некоторые архитектуры) не имеют понятия глобального "стека программ", поэтому рекурсивные вызовы функций в них невозможны. OpenCL, вероятно, использует наименьший общий знаменатель, что полностью не позволяет ему оставаться переносимым между графическими процессорами. Более новое оборудование CUDA, похоже, в какой-то момент внедрило поддержку рекурсии: stackoverflow.com/q/3644809/1198654
glampert

Ответы:

27

Это в основном потому, что не все графические процессоры могут поддерживать вызовы функций - и даже если они могут, вызовы функций могут быть довольно медленными или иметь ограничения, такие как очень малая глубина стека.

Код шейдера и код вычислений на GPU могут иметь повсеместные вызовы функций, но при нормальных обстоятельствах все они на 100% встроены компилятором. Машинный код, выполняемый графическим процессором, содержит ветви и циклы, но не вызывает функции. Однако рекурсивные вызовы функций не могут быть встроены по очевидным причинам. (Если только некоторые аргументы не являются константами времени компиляции, таким образом, что компилятор может сложить их и встроить все дерево вызовов.)

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

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

Что касается трассировки лучей, то люди обычно обрабатывают подобные вещи, создавая очереди лучей, которые находятся в процессе отслеживания. Вместо повторения вы добавляете луч в очередь, и где-то на высоком уровне у вас есть цикл, который продолжает обрабатываться до тех пор, пока все очереди не станут пустыми. Это требует значительной реорганизации вашего кода рендеринга, если вы начинаете с классического рекурсивного raytracer. Для получения дополнительной информации, хорошая статья, чтобы прочитать об этом, является Wavefront Path Tracing .

Натан Рид
источник
6
Я не хочу делиться этим секретным соусом, но мне очень повезло, у меня фиксированный максимальный счетчик отказов и стек с фиксированным размером (и цикл с фиксированным числом итераций), чтобы справиться с этим. Кроме того (и это настоящий секретный соус для меня!), Мои материалы должны быть отражающими или преломляющими, но никогда не то и другое, что делает их так, чтобы лучи не расщеплялись при отражении. Конечным результатом всего этого является рекурсивный рендеринг с трассировкой лучей, но с помощью итерации фиксированного размера, а не рекурсии.
Алан Вулф
Как рекурсия хвоста?
Танмай Патил
Вам не понадобится стек для выполнения хвостовой рекурсии, поскольку хвостовые рекурсивные функции могут быть преобразованы в итеративные функции. Разве компилятор OpenCL не делает это автоматически?
Андерсон Грин