Как OpenGL работает на самом низком уровне? [закрытый]
Я понимаю, как писать программы OpenGL/DirectX, и я знаю математику и концептуальные вещи за ней, но мне любопытно, как связь GPU-CPU работает на низком уровне.
скажем, у меня есть программа OpenGL, написанная на C, которая отображает треугольник и поворачивает камеру на 45 градусов. Когда я скомпилирую эту программу, она будет превращена в серию ioctl-вызовов, а затем драйвер gpu отправляет соответствующие команды на gpu, где вся логика вращения треугольник и установка соответствующих пикселей в соответствующем цвете подключены? Или программа будет скомпилирована в" программу gpu", которая загружается на gpu и вычисляет вращение и т. д.? Или что-то совсем другое?
Edit:
Через несколько дней я нашел эту серию статей, которая в основном отвечает на вопрос:
http://fgiesen.wordpress.com/2011/07/01/a-trip-through-the-graphics-pipeline-2011-part-1/
4 ответов:
на этот вопрос почти невозможно ответить, потому что OpenGL сам по себе является только интерфейсным API, и до тех пор, пока реализация придерживается спецификации и результат соответствует этому, это можно сделать любым способом.
вопрос, возможно, был: как работает драйвер OpenGL на самом низком уровне. Теперь это снова невозможно ответить в целом, так как драйвер тесно связан с какой-то аппаратной частью, которая может снова делать вещи, однако разработчик разработал оно.
поэтому вопрос должен был быть: "как это выглядит в среднем за кулисами OpenGL и графической системы?". Давайте посмотрим на это снизу вверх:
на самом низком уровне есть некоторые графические устройства. В настоящее время это графические процессоры, которые обеспечивают набор регистров, контролирующих их работу (какие именно регистры зависят от устройства), имеют некоторую программную память для шейдеров, объемную память для входных данных (вершины, текстуры и т. д.) и I / O канал к остальной части системы, по которой он получает / отправляет потоки данных и команд.
графический драйвер отслеживает состояние графических процессоров и все прикладные программы ресурсов, которые используют графический процессор. Также он отвечает за преобразование или любую другую обработку данных, отправляемых приложениями (преобразование текстур в пиксельформат, поддерживаемый графическим процессором, компиляция шейдеров в машинный код графического процессора). Кроме того, он предоставляет некоторые абстрактные, зависимые от драйвера интерфейс к прикладным программам.
тогда есть зависимая от драйвера клиентская библиотека OpenGL / драйвер. На Windows это получает загружается по прокси через opengl32.dll, в системах Unix это находится в двух местах:
- Х11 комплектации GLX модуль и драйвер зависит от водителя ГБО
- и /usr / lib / libGL. so может содержать некоторые зависимые от драйвера вещи для прямого рендеринга
на MacOS X это бывает " OpenGL Рамки."
именно эта часть переводит вызовы OpenGL, как вы это делаете, в вызовы определенных функций драйвера в части драйвера, описанной в (2).
наконец, фактическая библиотека API OpenGL, opengl32.dll в Windows, и на Unix /usr/lib/libGL.so; это в основном просто передает команды к реализации OpenGL собственно.
Как происходит фактическое общение не может быть обобщенный:
в Unix соединение 34 может происходить либо через сокеты (да, это может быть и происходит по сети, Если вы хотите), либо через общую память. В Windows библиотека интерфейса и клиент драйвера загружаются в адресное пространство процесса, так что это не так много общения, но простые вызовы функций и передача переменных/указателей. В MacOS X это похоже на Windows, только что нет разделения между интерфейсом OpenGL и клиентом драйвера (вот почему почему MacOS X так медленно идет в ногу с новыми версиями OpenGL, он всегда требует полного обновления операционной системы для доставки новой платформы).
связь между 3 2 может проходить через ioctl, чтение/запись или через отображение некоторой памяти в адресное пространство процесса и настройку MMU для запуска некоторого кода драйвера при каждом изменении этой памяти. Это очень похоже на любую операционную систему, так как вам всегда нужно пересекать границу ядра/пользователя: в конечном итоге вы идете через некоторые операции.
связь между системой и GPU происходит через периферийную шину и методы доступа, которые она определяет, поэтому PCI, AGP, PCI-E и т. д., которые работают через порт-I/O, память, отображенную I/O, DMA, IRQs.
когда я скомпилирую эту программу, она будет превращена в серию ioctl-вызовов, а затем драйвер gpu отправляет соответствующие команды на gpu, где вся логика вращения треугольника и установки соответствующих пикселей в соответствующем цвете подключена? Или программа будет скомпилирована в" программу gpu", которая загружается на gpu и вычисляет вращение и т. д.?
вы не за горами. Ваша программа вызывает устанавливаемый драйвер клиента (который на самом деле не является драйвером, это общая библиотека пользовательского пространства). Это будет использовать ioctl или аналогичный механизм для передачи данных в драйвер ядра.
для следующей части, это зависит от аппаратного обеспечения. Старые видеокарты имели то, что называется "конвейер с фиксированной функцией". В видеокарте были выделенные пространства памяти для матриц и выделенное оборудование для поиска текстур, смешивания и т. д. Видеодрайвер загрузит правильные данные и флаги для каждого из этих блоков, а затем настроит DMA для передачи данных о вершинах (положение, цвет, координаты текстуры и т. д.).
новое оборудование имеет процессорные ядра ("шейдеры") внутри видеокарты, которые отличаются от вашего процессора тем, что каждый из них работает намного медленнее, но есть еще много из них, работающих параллельно. Для этих видеокарт драйвер подготавливает двоичные файлы программы для запуска на шейдерах GPU.
ваша программа не компилируется для какого-либо конкретного GPU; она просто динамически связана с библиотекой, которая будет реализовывать OpenGL. Фактическая реализация может включать отправку команд OpenGL на GPU, запуск резервных копий программного обеспечения, компиляцию шейдеров и отправку их на GPU или даже использование резервных копий шейдеров для команд OpenGL. Графический ландшафт довольно сложный. К счастью, связывание изолирует вас от большей части сложности драйверов, оставляя разработчиков драйверов свободными в использовании какие бы методы они считают нужным.
компиляторы/компоновщики C/C++ делают ровно одно: они преобразуют текстовые файлы в серию машинных опкодов, которые выполняются на ЦП. OpenGL и Direct3D - это просто API C/C++; они не могут волшебным образом преобразовать ваш компилятор/компоновщик C/C++ в компилятор/компоновщик для GPU.
каждая строка кода C/C++, который вы пишете, будет выполняться на ЦП. Вызовы OpenGL / Direct3D будут вызывать библиотеки C/C++, статические или динамические, в зависимости от случая.
единственное место, когда a программа "ГПУ" вступит в игру, если ваш код явно создает шейдеры. То есть, если вы делаете вызовы API в OpenGL/D3D, которые вызывают компиляцию и связывание шейдеров. Для этого вы (во время выполнения, а не во время компиляции C/C++) либо создаете, либо загружаете строки, представляющие шейдеры на некотором языке шейдеров. Затем вы проталкиваете их через компилятор шейдера и возвращаете объект в этом API, который представляет этот шейдер. Затем вы применяете один или несколько шейдеров к определенной команде отрисовки. Каждый из этих шагов происходит явно в направлении вашего кода C/C++, который, как было указано ранее, работает на ЦП.
многие языки шейдеров используют C/C++-подобный синтаксис. Но это не делает их эквивалентными C/C++.
Comments