Почему функции OpenGL загружаются во время выполнения, а не динамически связаны?
Пользователи API OpenGL обычно используют такие библиотеки, как GLEW, или рады загружать функции OpenGL во время выполнения. Почему динамическая загрузка является предпочтительным методом связывания?
Статическое связывание явно не подходит, поскольку программы, использующие OpenGL, как правило, компилируются автором и распространяются среди пользователей, которые имеют разные библиотеки OpenGL для своих конкретных видеокарт.
Это оставляет динамическое связывание и динамическую загрузку. Кажется, что динамическое связывание может работать, так как мы знаем имена всех функций, к которым мы хотим получить доступ.
Является ли динамическое связывание жизнеспособным вариантом? Если нет, то почему? Если да, то почему динамическая загрузка предпочтительнее?
2 ответа
То, что вы хотите, возможно. Вы можете создать загрузчик, который является DLL/SO со статическим интерфейсом, который будет загружать указатели на функции из-за кулис реализации. Он будет передавать вызовы функций в реализацию, в зависимости от текущего контекста. Действительно, именно так работают современные дистрибутивы Linux.
Это также, как WGL работает в Windows... по крайней мере, в OpenGL версии 1.1.
Причина, по которой он не является "предпочтительным", заключается в том, что он требует усилий. Кто-то должен создать и поддерживать эту промежуточную библиотеку, которая находится между приложением и драйвером. Всякий раз, когда выходит новое расширение, библиотека должна быть обновлена. Всякий раз, когда выходит новая версия, библиотека должна быть обновлена. И тогда вы должны убедиться, что ссылка на нужную версию этой библиотеки.
Эта дополнительная зависимость работала нормально в Linux, потому что она поддерживалась в актуальном состоянии. Однако OpenGL32.dll в Windows не было. WinNT некоторое время принимал OpenGL, но Microsoft также ушла и создала свой собственный графический API для Win9x. Поэтому они никогда не обновляли OpenGL32.dll для более поздних версий OpenGL или новых расширений. И если бы они хотели быть обратно-совместимыми, я думаю, они бы полностью исключили OpenGL32.dll из своих ОС.
Поскольку для работы в Windows нужен загрузчик времени выполнения, проще заставить все платформы работать с использованием одного и того же загрузчика времени выполнения (хотя, очевидно, с другой функцией, извлекающей указатели функций). И хотя вы могли бы создать тот тип DLL, о котором вы говорите, это была бы просто еще одна библиотека загрузки OpenGL, еще одна зависимость, которую вы должны поддерживать. Без централизации, которую приносит Linux/MESA, нет никакого смысла беспокоиться.
Я думал, что приложение может быть динамически связано непосредственно с самим драйвером без промежуточной библиотеки
Вы можете сделать это. Тем не менее, вы будете ссылаться на библиотеку этого конкретного драйвера с помощью статической библиотеки импорта. Это означает, что если вы ссылаетесь на реализацию NVIDIA, ваше приложение не сможет работать на внедрении AMD.
И вы не можете статически связать импорт библиотеки для обеих DLL. Причина в том, что если одна статическая библиотека импорта не может быть загружена, ваше приложение завершается. Таким образом, если у вас на компьютере нет реализаций AMD и NVIDIA, вы не сможете работать ни на одном из них.
Также:
поскольку библиотека драйверов не может быть доступна во время компиляции, мы все еще знаем имена функций OpenGL
Это предполагает, что их драйверы напрямую экспортируют эти имена. Это вряд ли гарантировано.
В конце концов, интерфейс WGL/GLX должен использовать wgl/glXGetProcAddress
чтобы получить указатели на функции. Если интерфейс между WGL/GLX и драйвером просто передает строку в функцию драйвера, то драйверу не нужно напрямую экспортировать какие-либо функции. Он предоставляет свой API через единую точку входа, форсируя загрузку указателя функции времени выполнения, а не разрешая статическое связывание.
Насколько я понимаю, OpenGL загружает библиотеки LoadLibrary/dlopen из библиотеки dll/dylib/so, которые сами являются драйверами графической карты, и эти библиотеки драйверов имеют таблицы символов с функциями OpenGL. Какие части этого не так?
Все части этого неверны. Вы ссылаетесь на базовый интерфейс API (например, WGL или GLX). Библиотека загрузки использует этот интерфейс для загрузки указателей на функции. Как интерфейс API переводит загрузку указателя функции в DLL-драйвер, зависит от платформы. В Windows wglGetProcAddress
вызывает функцию в драйвере, передавая строковое имя функции и возвращая указатель на функцию.
В Linux GLX стремится производить функции внутри, используя методы позднего связывания для последующей загрузки фактической функции драйвера. То есть можно позвонить glXGetProcAddress
с некоторым поддельным именем, и он возвратит указатель функции shim, который при вызове загрузит функцию для текущего контекста из драйвера.
Вики OpenGL дает некоторое представление о процессе загрузки функций OpenGL. Не то, чтобы с помощью GetProcAddress
функции составляют форму динамического связывания, выполняемого вне самой операционной системы. Из Википедии:
В вычислениях динамический компоновщик - это часть операционной системы, которая загружает и связывает разделяемые библиотеки, необходимые исполняемому файлу при его выполнении (во время выполнения), путем копирования содержимого библиотек из постоянного хранилища в ОЗУ и заполнения таблицы переходов и перемещения указателей.
Расширения для OpenGL выходят постоянно и могут быть доступны или не зависеть от поставщиков и платформ драйверов. Вики OpenGL утверждает, что в MacOSX:
Функции GL в OSX слабо связаны с OSX 10.2; это означает, что вы можете вызывать их напрямую, и нереализованные расширения преобразуются в NULL. Обратите внимание, что это означает, что вы должны проанализировать строку расширения, чтобы определить, является ли функция действительной или нет, или ваша программа потерпит крах.
Таким образом, даже если Apple поддерживает библиотеку для динамической связи, вам все равно нужно добавить слой, чтобы проверить, доступна ли данная функция или нет, в зависимости от поддерживаемой версии OpenGL и расширений.