Как процессор и графический процессор взаимодействуют при отображении компьютерной графики?

32113
JohnnyFromBF

Здесь вы можете увидеть скриншот небольшой программы на C ++ под названием Triangle.exe с вращающимся треугольником на основе OpenGL API.

enter image description here

По общему признанию очень простой пример, но я думаю, что это применимо к другим операциям с графическими картами.

Мне было просто любопытно, и я хотел узнать весь процесс от двойного щелчка по Triangle.exe под Windows XP, пока не смогу увидеть вращающийся треугольник на мониторе. Что происходит, как взаимодействуют CPU (который сначала обрабатывает .exe) и GPU (который, наконец, выводит треугольник на экран)?

Я предполагаю, что для отображения этого вращающегося треугольника в первую очередь используется следующее аппаратное / программное обеспечение:

аппаратные средства

  • жесткий диск
  • Системная память (RAM)
  • ЦПУ
  • Видеопамять
  • GPU
  • ЖК дисплей

Программного обеспечения

  • Операционная система
  • DirectX / OpenGL API
  • Nvidia Driver

Может кто-нибудь объяснить процесс, может быть, с какой-то блок-схем для иллюстрации?

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

Я уверен, что многие люди, которые даже называют себя ИТ-специалистами, не могли правильно описать этот процесс.

56
Ваша дилемма была бы закончена, если бы вы могли считать GPU расширением CPU! KawaiKx 10 лет назад 0

7 ответов на вопрос

52
Der Hochstapler

Я решил написать немного о программном аспекте и о том, как компоненты взаимодействуют друг с другом. Может быть, это поможет пролить свет на некоторые области.

Презентация

Что нужно, чтобы нарисовать на экране то единственное изображение, которое вы разместили в своем вопросе?

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

Но, прежде чем мы сможем что-то нарисовать, мы должны сначала запустить некоторые строительные леса. Мы увидим почему позже:

// Clear The Screen And The Depth Buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // Reset The Current Modelview Matrix glMatrixMode(GL_MODELVIEW);  glLoadIdentity();  // Drawing Using Triangles glBegin(GL_TRIANGLES);  // Red glColor3f(1.0f,0.0f,0.0f); // Top Of Triangle (Front) glVertex3f( 0.0f, 1.0f, 0.0f);  // Green glColor3f(0.0f,1.0f,0.0f); // Left Of Triangle (Front) glVertex3f(-1.0f,-1.0f, 1.0f);  // Blue glColor3f(0.0f,0.0f,1.0f); // Right Of Triangle (Front) glVertex3f( 1.0f,-1.0f, 1.0f);  // Done Drawing glEnd(); 

Так, что это сделало?

Когда вы пишете программу, которая хочет использовать видеокарту, вы обычно выбираете какой-то интерфейс для драйвера. Некоторые хорошо известные интерфейсы для драйвера:

  • OpenGL
  • Direct3D
  • CUDA

Для этого примера мы будем использовать OpenGL. Теперь, ваш интерфейс драйвера является то, что дает вам все инструменты, необходимые, чтобы сделать вашу программу поговорить с видеокартой (или водителем, который затем переговоры на карту).

Этот интерфейс должен дать вам определенные инструменты . Эти инструменты принимают форму API, который вы можете вызвать из своей программы.

Этот API - это то, что мы видим в примере выше. Давайте внимательнее посмотрим.

Леса

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

Но мы не будем на это смотреть. Мы просто взглянем на то, что вам придется делать в каждом кадре . Подобно:

Очистка экрана

Графический конвейер не собирается очищать экран для каждого кадра. Вы должны будете сказать это. Зачем? Вот почему:

Если вы не очистите экран, вы будете просто рисовать над ним каждый кадр. Вот почему мы звоним glClearс GL_COLOR_BUFFER_BITсетом. Другой бит ( GL_DEPTH_BUFFER_BIT) говорит OpenGL очистить буфер глубины . Этот буфер используется для определения того, какие пиксели находятся впереди (или позади) других пикселей.

преобразование


Источник изображения

Преобразование - это та часть, где мы берем все входные координаты (вершины нашего треугольника) и применяем нашу матрицу ModelView. Это матрица, которая объясняет, как наша модель (вершины) вращается, масштабируется и переводится (перемещается).

Далее мы применяем нашу матрицу проекции. Это перемещает все координаты так, чтобы они правильно смотрели на нашу камеру.

Теперь мы снова преобразуем нашу матрицу Viewport. Мы делаем это, чтобы масштабировать нашу модель до размеров нашего монитора. Теперь у нас есть набор вершин, которые готовы к визуализации!

Мы вернемся к преобразованию чуть позже.

Рисование

Чтобы нарисовать треугольник, мы можем просто сказать OpenGL начать новый список треугольников, вызвав glBeginэту GL_TRIANGLESконстанту.
Есть и другие формы, которые вы можете нарисовать. Как треугольная полоса или треугольный веер . Это прежде всего оптимизация, так как они требуют меньше связи между процессором и графическим процессором, чтобы нарисовать одинаковое количество треугольников.

После этого мы можем предоставить список наборов из 3 вершин, которые должны составлять каждый треугольник. Каждый треугольник использует 3 координаты (как в 3D-пространстве). Кроме того, я также предоставляю цвет для каждой вершины, вызывая glColor3f перед вызовом glVertex3f.

Тень между 3 вершинами (3 угла треугольника) рассчитывается OpenGL автоматически . Он будет интерполировать цвет по всей поверхности многоугольника.

взаимодействие

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

Это становится намного сложнее, когда вы хотите начать взаимодействовать с 3D-сценой.

Сначала вы должны четко знать, в каком пикселе пользователь щелкнул окно. Затем, принимая во внимание вашу перспективу, вы можете рассчитать направление луча от точки щелчка мыши до вашей сцены. Затем вы можете рассчитать, пересекается ли какой-либо объект в вашей сцене с этим лучом . Теперь вы знаете, нажал ли пользователь на объект.

Итак, как вы делаете это вращаться?

преобразование

Мне известны два типа преобразований, которые обычно применяются:

  • Матричное преобразование
  • Костная трансформация

Разница в том, что кости влияют на отдельные вершины . Матрицы всегда влияют на все нарисованные вершины одинаково. Давайте посмотрим на пример.

пример

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

Если я хочу, чтобы повернуть его сейчас, я мог либо сделать математику сам (на CPU) и просто звонить glVertex3fс другими координатами (которые вращаются). Или я мог бы позволить GPU сделать всю работу, позвонив glRotatefперед рисованием:

// Rotate The Triangle On The Y axis glRotatef(amount,0.0f,1.0f,0.0f);  

amountэто, конечно, просто фиксированное значение. Если вы хотите анимировать, вам придется отслеживать amountи увеличивать его каждый кадр.

Итак, подождите, что случилось со всеми матричными разговорами ранее?

В этом простом примере нам не нужно заботиться о матрицах. Мы просто звоним glRotatefи обо всем этом позаботимся.

glRotateпроизводит вращение angleградусов вокруг вектора xyz. Текущая матрица (см. GlMatrixMode ) умножается на матрицу вращения с продуктом, заменяющим текущую матрицу, как если бы glMultMatrix вызывался со следующей матрицей в качестве аргумента:

x 2 ⁡ 1 - c + cx ⁢ y z 1 - c - z ⁢ sx ⁢ z ⁡ 1 - c + y ⁢ s 0 y ⁢ x ⁡ 1 - c + z ⁢ sy 2 ⁡ 1 - c + cy ⁢ z ⁡ 1 - c - x ⁢ s 0 x ⁢ z ⁡ 1 - c - y ⁢ sy ⁢ z ⁡ 1 - c + x ⁢ sz 2 ⁡ 1 - c + c 0 0 0 0 1

Ну, спасибо за это!

Заключение

Становится очевидным, что с OpenGL много говорят . Но это ничего не говорит нам . Где связь?

Единственное, что OpenGL говорит нам в этом примере, это когда это будет сделано . Каждая операция займет определенное количество времени. Некоторые операции занимают невероятно много времени, другие - невероятно быстро.

Отправка вершины в GPU будет настолько быстрой, что я даже не знаю, как это выразить. Отправка тысяч вершин из ЦП в ГП, каждый кадр, скорее всего, не проблема.

Очистка экрана может занять миллисекунду или даже хуже (имейте в виду, что у вас обычно есть только около 16 миллисекунд времени для прорисовки каждого кадра), в зависимости от размера вашего окна просмотра. Чтобы очистить его, OpenGL должен нарисовать каждый пиксель в цвет, который вы хотите очистить, это может быть миллионы пикселей.

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

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

Затем мы можем «визуализировать» результат нашего вычисления (в виде новых цветов) в новую текстуру.

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

Мы действительно лишь слегка коснулись всей темы. Программирование трехмерной графики - адское чудовище.


Источник изображения

Отличный ответ! Должен был иметь больше голосов, но, возможно, присутствие в бюллетене поможет этому. Linuxios 11 лет назад 2
36
David Schwartz

Трудно понять, что именно ты не понимаешь.

Графический процессор имеет ряд регистров, которые отображаются в BIOS. Они позволяют ЦПУ получать доступ к памяти графического процессора и инструктируют графический процессор выполнять операции. Процессор вставляет значения в эти регистры, чтобы отобразить часть памяти графического процессора, чтобы процессор мог получить к ней доступ. Затем он загружает инструкции в эту память. Затем он записывает значение в регистр, который указывает графическому процессору выполнять инструкции, загруженные ЦПУ в его память.

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

Затем драйвер управляет серией «окон» в памяти графического процессора, из которого ЦП может читать и записывать. Как правило, шаблон доступа включает в себя инструкции или информацию ЦП о записи в отображенную память ГП, а затем команду ГП через регистр выполнить эти инструкции или обработать эту информацию. Информация включает в себя шейдерную логику, текстуры и так далее.

Спасибо за ваше объяснение. По сути, я не понял, как набор команд процессора взаимодействует с набором команд графического процессора, но, очевидно, именно этот драйвер выполняет эту функцию. Вот что я имел в виду со слоями абстракции. JohnnyFromBF 11 лет назад 1
Там не задействован набор команд процессора. Драйвер и среда выполнения компилируют ваши CUDA, OpenGL, Direct3D и т. Д. В собственные программы / ядра GPU, которые затем также загружаются в память устройства. Буфер команд тогда относится к тем же ресурсам, что и любой другой. Axel Gneiting 11 лет назад 2
Я не уверен, на какие программы вы ссылаетесь (которые работают на GPU и включены в драйверы). GPU - это в основном аппаратное обеспечение с фиксированными функциями, и единственные программы, которые он будет запускать, это шейдеры, которые предоставляются приложением, а не драйвером. Драйвер только компилирует эти программы, а затем загружает их в память графического процессора. Ben Richards 11 лет назад 2
@ sidran32: Например, в архитектуре nVidia Kepler ядра, потоки и события создаются программным обеспечением, работающим на графическом процессоре, а не (обычно) процессором. Программное обеспечение на стороне GPU также управляет RDMA. Все это программное обеспечение загружается драйвером в память графического процессора и работает как «мини-ОС» на графическом процессоре, который обрабатывает сторону GPU взаимодействующей пары CPU / GPU. David Schwartz 11 лет назад 1
@DavidSchwartz Я забыл про задачи вычислений на GPU. Тем не менее, они все равно ведут себя как шейдеры в реализации. Я бы не назвал это «мини-ОС», так как она не обладает той же функциональностью, которая обычно ассоциируется с ОС. Это все еще очень специализированное программное обеспечение, поскольку графический процессор не спроектирован как процессор (по уважительной причине). Ben Richards 11 лет назад 0
12
Tom Wijsman

Мне было просто любопытно, и я хотел узнать весь процесс от двойного щелчка по Triangle.exe под Windows XP, пока не смогу увидеть вращающийся треугольник на мониторе. Что происходит, как взаимодействуют CPU (который сначала обрабатывает .exe) и GPU (который, наконец, выводит треугольник на экран)?

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

Каков интерфейс между процессором и графическим процессором?

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

Но вы не можете прямо говорить с аппаратным обеспечением или драйвером из кода; поэтому это должно происходить через такие API, как OpenGL, Direct3D, CUDA, HLSL, Cg. В то время как первый запускает инструкции GPU и / или обновляет память GPU, последний фактически выполняет код на GPU, поскольку они являются языками физики / шейдеров.

Зачем запускать код на GPU, а не на CPU?

Несмотря на то, что процессор хорошо справляется с нашими ежедневными программами для рабочих станций и серверов, о всей этой блестящей графике, которую вы видите в играх наших дней, особо не задумывались. Когда-то были рендеры программного обеспечения, которые добились цели из некоторых 2D и 3D вещей, но они были очень ограничены. Итак, вот где GPU вступил в игру.

Графический процессор оптимизирован для одного из самых важных вычислений в графике, Matrix Manipulation . В то время как ЦП должен вычислять каждое умножение в матричной манипуляции один за другим (позже, такие вещи, как 3DNow! И SSE перехватили), GPU может выполнять все эти умножения одновременно! Параллельность.

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

Как эти инструкции / память / код графического процессора показывают графику?

Есть одна недостающая часть, чтобы заставить это все работать, нам нужно что-то, что мы можем написать, что мы можем затем прочитать и отправить на экран. Мы можем сделать это, создав кадровый буфер . Какую бы операцию вы ни делали, вы в конечном итоге обновите пиксели в кадровом буфере; которые помимо местоположения также содержат информацию о цвете и глубине.

Давайте приведем пример, где вы хотели нарисовать спрайт крови (изображение) где-нибудь; во-первых, сама текстура дерева загружается в память графического процессора, что позволяет легко перерисовывать ее по желанию. Затем, чтобы действительно нарисовать спрайт где-нибудь, мы можем перевести спрайт, используя вершины (расположив его в правильном положении), растеризовав его (превратив его из трехмерного объекта в пиксели), и обновив буфер кадров. Чтобы получить лучшее представление, вот схема конвейера OpenGL из Википедии:

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

7
AZ.

To keep things simple we can describe it like this. Some memory addresses are reserved (by BIOS and/or operating system) not for RAM but for the video card. Any data written at those values (pointers) goes to the card. So in theory any program can write directly to the videocard just by knowing the address range and this is exactly how it was done back in the old days. In practice with modern OSes this is managed by the video driver and/or the graphics library on top (DirectX, OpenGL etc.).

-1 он спрашивает, как вызов API DirectX от ЦПУ может взаимодействовать с графическим процессором, и ваш ответ * «он управляется драйвером и / или DirectX» *? Это также не объясняет, как можно запускать пользовательский код (ala CUDA). BlueRaja - Danny Pflughoeft 11 лет назад 1
Пожалуйста, научитесь читать. Я сказал, записав конкретные адреса памяти, которые зарезервированы для графического процессора вместо оперативной памяти. И это объясняет, как вы можете запустить все. Диапазон памяти зарегистрирован для карты. Все, что вы пишете в этом диапазоне, поступает в графический процессор, на котором выполняется обработка вершин, CUDA, что угодно. AZ. 11 лет назад 3
4
Axel Gneiting

GPUs are usually driven by DMA buffers. That is, the driver compiles the commands it receives from the user space program into a stream of instructions (switch state, draw this in that way, switch contexts, etc.), that are then copied to device memory. It then instructs the GPU to execute this command buffer via a PCI register or similar methods.

So on every draw call etc. what happens is that the user space driver will compile the command, which then calls the kernel space driver via an interrupt and that one finally submits the command buffer to device memory and instructs the GPU to start rendering.

On consoles you even can have the fun to do all of that yourself, especially on PS3.

0
user583641

I think the CPU sends video data to GPU through the bus and then GPU displays it. So faster GPU can handle more data from the CPU. In this way some of the processing of cpuoffload to GPU. Therefore you get faster speed in games.

It's kind of like the RAM where CPU stores stuff so it can load and process quickly. Both make games faster.

Or sound card or net card work on same principle, that is get data and offload some work of CPU.

Это дублирует другой ответ и не добавляет новый контент. Пожалуйста, не публикуйте ответ, если у вас нет чего-то нового. DavidPostill 8 лет назад 0
0
dave

Я думаю, что op не уверен, что именно процессор говорит графической карте, и почему команды, связанные с графикой (например, команды opengl или direct3d), не отправляются напрямую в графический процессор.

Процессор просто говорит графическому процессору, что визуализировать. Все инструкции сначала проходят через процессор, где они настраиваются / инициализируются для графического процессора, чтобы фактически сделать рендеринг.

Похожие вопросы