Как обновление буфера глубины работает в GPU?

10

Прямо сейчас я пытаюсь реализовать некоторый буфер глубины в программном обеспечении, и у меня возникает огромная проблема, когда я пишу в него. Наличие одного мьютекса - это абсолютное излишество. Поэтому я создал количество мьютексов, равное количеству потоков. Я блокирую мьютекс на основе текущего пикселя (pixel_index% mutexes_number), и это работает лучше, но все еще очень и очень медленно. И мне интересно, как это делается в реальном графическом процессоре? Есть ли умный алгоритм или аппаратное обеспечение?

nikitablack
источник

Ответы:

9

Это узкоспециализированное оборудование. Типичной стратегией для графического процессора является растеризация мозаики и сохранение информации о глубине в сжатых форматах (например, уравнение z, когда многоугольник полностью покрывает плитку). Это позволяет одновременно тестировать всю плитку; Другие интересные трюки HW включают тестирование глубины перед запуском пиксельного шейдера (при условии, что условия позволяют - шейдер не может записать значение глубины). Вы могли бы рассмотреть что-то похожее в программном обеспечении, например, иметь каждый поток «своим» подмножеством плиток и обходить каждый примитив независимо, или имитировать стратегии нескольких GPU, такие как альтернативные кадры или альтернативные растровые линии.

Даниэль М Гессель
источник
11

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

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

На этапе геометрии каждое ядро ​​может обрабатывать кусок входных примитивов; затем для каждого примитива он может быстро определить, к каким плиткам прикоснется примитив (это называется «грубая растеризация»), и добавить примитив в очередь для каждого ядра, которому принадлежит одна из затронутых плиток.

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

Натан Рид
источник