Как OpenGL работает на самом низком уровне? [закрыто]

85

Я понимаю, как писать программы OpenGL / DirectX, и я знаю математику и концептуальный материал, лежащий в основе этого, но мне любопытно, как связь GPU-CPU работает на низком уровне.

Скажем, у меня есть программа OpenGL, написанная на C, которая отображает треугольник и поворачивает камеру на 45 градусов. Когда я компилирую эту программу, будет ли она преобразована в серию ioctl-вызовов, и драйвер графического процессора затем отправит соответствующие команды на графический процессор, где вся логика поворота треугольника и установки соответствующих пикселей в соответствующий цвет подключена в? Или программа будет скомпилирована в «программу для графического процессора», которая загружается в графический процессор и вычисляет вращение и т. Д.? Или что-то совсем другое?

Изменить : несколько дней спустя я нашел эту серию статей, которая в основном отвечает на вопрос: http://fgiesen.wordpress.com/2011/07/01/a-trip-through-the-graphics-pipeline-2011-part- 1 /

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

Ответы:

87

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

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

Поэтому вопрос должен был быть таким: «Как это в среднем выглядит за кулисами OpenGL и графической системы?». Давайте посмотрим на это снизу вверх:

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

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

  3. Затем существует клиентская библиотека / драйвер OpenGL, зависящая от драйвера. В Windows он загружается через прокси-сервер через opengl32.dll, в системах Unix он находится в двух местах:

    • Модуль X11 GLX и драйвер GLX, зависящий от драйвера
    • и /usr/lib/libGL.so может содержать некоторые зависящие от драйвера вещи для прямого рендеринга

    В MacOS X это «OpenGL Framework».

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

  4. Наконец, собственно библиотека API OpenGL, opengl32.dll в Windows и в Unix /usr/lib/libGL.so; в основном это просто передает команды самой реализации OpenGL.

Невозможно обобщить, как происходит реальное общение:

В Unix соединение 3 <-> 4 может происходить либо через сокеты (да, может, и действительно идет по сети, если хотите), либо через общую память. В Windows интерфейсная библиотека и клиент-драйвер загружаются в адресное пространство процесса, так что не столько общение, сколько простые вызовы функций и передача переменных / указателей. В MacOS X это похоже на Windows, за исключением того, что нет разделения между интерфейсом OpenGL и клиентским драйвером (вот почему MacOS X так медленно успевает за новыми версиями OpenGL, он всегда требует полного обновления операционной системы для предоставления новых фреймворк).

Связь между 3 <-> 2 может происходить через ioctl, чтение / запись или через отображение некоторой памяти в адресное пространство процесса и конфигурирование MMU для запуска некоторого кода драйвера при каждом изменении этой памяти. Это очень похоже на любую операционную систему, поскольку вам всегда нужно пересекать границу ядра / пользовательского пространства: в конечном итоге вы выполняете некоторый системный вызов.

Связь между системой и графическим процессором осуществляется через периферийную шину и методы доступа, которые она определяет, например, PCI, AGP, PCI-E и т. Д., Которые работают через порт ввода-вывода, ввод-вывод с отображением памяти, DMA, IRQ.

свидание
источник
1
Это описание, вероятно, слишком низкоуровневое и общее с очень небольшими особенностями OpenGL. Это примерно применимо к любому компоненту оборудования, присутствующему в компьютере.
v.shashenko
1
@ в.шащенко: Ну конечно. Независимо от того, о каком аппаратном компоненте вы говорите, он следует этой общей схеме. Но OpenGL - это не конкретная программа, это просто спецификация, и все, что соответствует спецификации, является действительной реализацией. И поскольку в конечном итоге реализация OpenGL обращается к графическому процессору, она будет примерно следовать тому же сценарию, по которому реализуются аппаратные API. Невозможно стать более конкретным, потому что не существует " ЕДИНОЙ " реализации OpenGL. И каждая реализация немного отличается.
datenwolf
1
@ v.shashenko: Если вам нужны подробности, вам нужно спросить о конкретной реализации. Например, скажем, X11 + GLX + DRI → Mesa / AMDGPU → Linux-KMS + DRM (Direct Rendering Manager). И каждый из этих компонентов - довольно сложный зверь с таким количеством деталей, что вы можете заполнить книги подробностями о том, как каждый компонент работает. Но это описало бы реализацию Linux-AMDGPU. Но Linux + NVidia - совсем другой зверь. И в Windows снова все по-другому.
datenwolf
Вы помните, как мы болтали несколько дней назад, я просто хотел знать, как с вами связаться, если я хочу что-то узнать?
Сурадж Джайн
То, чему вы учили в тот день, развеяло многие мои сомнения, сделало и кое-что новое, но в целом сейчас я не считаю магией рисование окон и значков на экране.
Сурадж Джайн
23

Когда я компилирую эту программу, будет ли она преобразована в серию ioctl-вызовов, и драйвер графического процессора затем отправит соответствующие команды на графический процессор, где вся логика поворота треугольника и установки соответствующих пикселей в соответствующий цвет подключена в? Или программа будет скомпилирована в «программу для графического процессора», которая загружается в графический процессор и вычисляет вращение и т. Д.?

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

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

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

Бен Фойгт
источник
20

Ваша программа не скомпилирована для какого-либо конкретного графического процессора; он просто динамически связан с библиотекой, которая будет реализовывать OpenGL. Фактическая реализация может включать отправку команд OpenGL на графический процессор, запуск резервных программных приложений, компиляцию шейдеров и их отправку на графический процессор или даже использование резервных вариантов шейдеров для команд OpenGL. Графический ландшафт довольно сложен. К счастью, связывание изолирует вас от большей части сложности драйверов, позволяя разработчикам драйверов использовать любые методы, которые они сочтут нужными.

Тобу
источник
18

Компиляторы / компоновщики C / C ++ делают только одно: они преобразуют текстовые файлы в серию машинно-зависимых кодов операций, которые запускаются на ЦП. OpenGL и Direct3D - это просто API C / C ++; они не могут волшебным образом преобразовать ваш компилятор / компоновщик C / C ++ в компилятор / компоновщик для графического процессора.

Каждая строка кода C / C ++, которую вы пишете, будет выполняться на ЦП. Вызов OpenGL / Direct3D будет вызывать библиотеки C / C ++, статические или динамические, в зависимости от обстоятельств.

Единственное место, где может вступить в игру «программа с графическим процессором», - это если ваш код явно создает шейдеры. То есть, если вы делаете вызовы API в OpenGL / D3D, которые вызывают компиляцию и связывание шейдеров. Для этого вы (во время выполнения, а не во время компиляции C / C ++) либо генерируете, либо загружаете строки, представляющие шейдеры на каком-либо языке шейдеров. Затем вы пропускаете их через компилятор шейдера и возвращаете объект в этом API, который представляет этот шейдер. Затем вы применяете один или несколько шейдеров к конкретной команде рендеринга. Каждый из этих шагов выполняется явно по указанию вашего кода C / C ++, который, как было сказано ранее, выполняется на ЦП.

Многие языки шейдеров используют синтаксис, подобный C / C ++. Но это не делает их эквивалентными C / C ++.

Никол Болас
источник
В последнее время я изучаю opengl и удивляюсь, почему я вижу все эти «шейдерные программы» в коде, который я смотрю, написанном как отдельные строки. Как вы сказали, они компилируются во время выполнения. Я видел несколько примеров в коде opengl es для Android. Затем я увидел код для iphone. По-видимому, в iPhone есть четыре векторных процессора, которые могут выполнять вычисления с плавающей запятой намного быстрее, чем ЦП iPhone, поэтому вы можете записать ASM в виде буквальных строк для компиляции во время выполнения для использования этих процессоров вместо основного процессора.
eggie5
1
Большая часть «конвейера фиксированных функций» теперь реализована набором шейдерных программ по умолчанию. Вам не нужно явно запрашивать шейдер, чтобы его получить.
Ben Voigt
1
@Ben Voigt: Верно, но если бы вам никто не сказал, вы бы не заметили разницы.
Никол Болас
1
Что могло бы быть разумным подходом, если бы этот вопрос не касался скрытых деталей.
Ben Voigt