[Перевод] Ад визуализации 1.1 — Книга 1: Обзор
Недостаток знаний иногда может оказаться достоинством, потому что вы наивно говорите себе: «Пфф… разве это сложно?» и просто погружаетесь в проблему с головой. Я начал эту статью с размышления: «Хм… Что же такое Draw Call?». За время »5-ти минутного» исследования я так и не нашел удовлетворяющего меня объяснения. Я проверил часы и, так как до сна оставалось еще 30 минут, сказал…
Пфф… Разве это сложно написать самостоятельно?
… и просто начал. Это было два месяца назад и с тех пор я непрерывно читал, писал и задавал много вопросов.Это было самое сложное и низкоуровневое исследование, которое я когда-либо делал, и для меня непрограммиста это был кошмар состоящий из «да, но в этом особом случае…» и «зависит от реализации API…». Это был мой личный ад визуализации, но я прошел через него и принес нечто с собой: Четыре книги, каждая из которых представляет собой попытку объяснить одну из частей визуализации с точки зрения художника. Я надеюсь, что вам понравится.
Сегодня художники должны быть хорошо подкованными: С точки зрения компьютера ваши игровые ресурсы — это всего лишь наборы вершин и данных текстур. Преобразование этих сырых данных в изображение уровня «следующего поколения» преимущественно делается вашим центральным процессором (CPU) и графическим процессором (GPU).
1. Копирование данных в оперативную память для быстрого доступаСперва все необходимые данные загружаются с вашего жесткого диска (HDD) в оперативную память (RAM) для быстрого доступа. После этого нужные полигональные сетки и текстуры загружаются в память графической карты (VRAM). Это делается потому, что графическая карта имеет значительно более быстрый доступ к VRAM и в большинстве случаев не имеет доступа к RAM.[embedded content]
До того как сторона визуализации может приступить к работе, CPU задает некоторые глобальные значения, которые описывают то, как полигональная сетка должна быть отображена. Этот набор значений называется Render State.
2. Установка Render State значений Render State — это некоторое глобальное определение того, как полигональная сетка должна быть визуализирована. Она содержит в себе информацию о: «вершинных и пиксельных шейдерах, текстурах, материалах, освещении, прозрачности итп. […]» [Real-Time Rendering: стр. 711]
Важно, что каждая полигональная сетка, которую CPU передает в GPU для отрисовки, будет отображена с этими условиями! Вы можете рисовать камень, стул или меч — все они будут использовать одинаковые параметры визуализации (такие как материал), если вы не измените Render State до отображения следующей сетки.[embedded content]
После того, как подготовка будет окончена, CPU наконец-то может обратиться к GPU и сказать, что следует рисовать. Эта команда известна как Draw Call.
3. Draw Call Draw Call — это команда отображения одной полигональной сетки. Она отдается центральным процессором. Ее получает графический процессор. Команда указывает только на полигональную сетку, которую надо отобразить, и не содержит никакой информации о материале, так как она уже определена через установку Render State. В этот момент полигональная сетка находится в памяти графической карты (VRAM).[embedded content]
После того, как команда отдана, GPU берет параметры Render State’а (материал, текстуру, шейдер, …) и все данные о вершинах и преобразует эту информацию с помощью некоторой магии в прекрасные (надеюсь) пиксели на вашем экране. Этот процесс преобразования называется Pipeline’ом.
4. Pipeline Как я говорил выше, игровые ресурсы — это, в некотором роде, просто наборы вершин и данных текстур. Чтобы преобразовать их в сногсшибательную картинку, графической карте надо создать треугольники из вершин, вычислить их освещенность, отобразить на них пиксели текстуры и много чего еще. Эти действия называются состояниями. Состояниями Pipeline’а.В зависимости от того, какие материалы вы читаете, вы обнаружите, что практически все делается графическим процессором. Но иногда говорится, что, например, создание треугольников и фрагментов делается другими частями графической карты.
Данный пример Pipeline’а крайне упрощен и должен трактоваться только как дающий общее представление. Я попытался изобразить его настолько хорошо, насколько смог, но, как у непрограммиста, у меня есть проблемы с пониманием, когда пример становится таким простым, что уводит вас в неправильном направлении. Поэтому, пожалуйста, не принимайте его всерьез и посмотрите все другие замечательные источники, которые я привел в конце статьи. Или не стесняйтесь написать мне письмо, твит или сообщение в фейсбуке, чтобы улучшить анимацию/объяснение. :)
Вот пример с единственным ядром GPU:[embedded content]
Визуализация — это просто выполнение огромного числа маленьких задач, таких как вычисление чего-либо для тысяч вершин или рисование миллионов пикселей на экране. Как минимум (хорошо бы) в 30 кадрах в секунду.
Важно иметь возможность вычислять эти вещи одновременно, а не каждую вершину/пиксель одну за другой. В старые добрые времена, процессоры имели только одно ядро и не было графического ускорения — они могли делать только одну вещь в один момент времени. Игры выглядели как… ретро. Современные CPU имеют 6–8 ядер, тогда как GPU содержат несколько тысяч (они не настолько сложны как CPU-ядра, но они идеальны для пропускания через себя огромного кол-ва вершинных и пиксельных данных).
Когда данные (например куча вершин) попадают на этап Pipeline’а, работа по трансформации точек/пикселей разделяется между несколькими ядрами так, чтобы большинство этих маленьких элементов формировалось параллельно в большую картину:
[embedded content]
Теперь мы знаем о том, что GPU может обрабатывать все параллельно. Но как насчет коммуникации между CPU и GPU? Ждет ли CPU того момента, когда GPU закончит свою работу и сможет получать новые команды?
К счастью, нет! Причина заключается в том, что такая коммуникация будет образовывать «бутылочные горлышки» (например, когда CPU не может доставлять команды достаточно быстро) и сделает параллельную работу невозможной. Решение — это список, в который команды могут добавляться CPU и читаться GPU независимо друг от друга! Такой список называется буфером команд.5. Буфер команд Буфер команд позволяет CPU и GPU работать независимо друг от друга. Если CPU хочет что-либо отобразить, он помещает команду в очередь, а когда у GPU появляются освободившиеся ресурсы, он берет команду из списка и выполняет ее (но, так как список устроен как FIFO, GPU может взять только самую старую команду из списка (которая была добавлена первой) и выполнить ее).[embedded content]
Тем не менее команды могут быть разными. Один из примеров — Draw Call, другим может быть изменение Render State’а.
На этом первая книга заканчивается. Теперь вы должны иметь общее представление о данных игровых ресурсов, Draw Call’ах, Render State’ах и взаимодействии между CPU и GPU.
Конец