Почему функции дублируются между opengl32.dll и gdi32.dll?

Следующие функции дублируются между opengl32.dll и gdi32.dll:

[opengl32.dll]         / [gdi32.dll]
wglChoosePixelFormat   / ChoosePixelFormat
wglDescribePixelFormat / DescribePixelFormat
wglGetPixelFormat      / GetPixelFormat
wglSetPixelFormat      / SetPixelFormat
wglSwapBuffers         / SwapBuffers

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

FAQ по OpenGL, раздел 5.190, предполагает, что эти функции не являются функционально идентичными:

Чтобы обеспечить правильную работу OpenGL, используйте ChoosePixelformat, DescribePixelformat, GetPixelformat, SetPixelformat и SwapBuffers вместо wgl-эквивалентов, wglChoosePixelformat, wglDescribePixelformat, wglGetPixelformat и wg. Forfors, wg. Во всех остальных случаях используйте функцию wgl, если она доступна. Использование пяти функций wgl представляет интерес только для разработчиков, устанавливающих связь с драйвером OpenGL.

Означает ли "связывание во время выполнения с драйвером OpenGL" обходом opengl32.dll и прямой загрузкой ICD?

Поток stackru с именем "Mesa3D не любит мой код создания контекста", кажется, подтверждает это.

Другой поток stackru, названный wglCreateContext в C#, терпит неудачу, но не в управляемом C++, предлагает, чтобы opengl32.dll должен был быть загружен перед gdi32.dll при использовании функций GDI, или риск сбоя во время выполнения (ошибка: 2000).

Мои собственные тесты показывают, что "ошибка: 2000" возникает внекоторых системах (Nvidia, но не Intel или Parallels VM), если вызывается версия этих функций opengl32/wgl. Переход на версию GDI устраняет эту проблему, но использование LoadLibrary("opengl32.dll"), похоже, ничего не меняет.

Кто-нибудь когда-нибудь исследовал разницу между этими функциями WGL и GDI? Ясно, что естькакая-то форма различий, и я пытаюсь понять, какую версию следует использовать, при каких обстоятельствах и каковы потенциальные ловушки, если используется неправильная версия.

Edit: wayback machine открывает веб-страницу, которая описывает, как работает прямая загрузка ICD. Это, по-видимому, требовалось еще в дни Voodoo 1/2, когда 2-й и 3-й ускорители представляли собой два разных устройства с отдельными ICD (с которыми не справлялся обычный механизм opengl32.dll+ICD). Quake 1 и 2, по-видимому, загружались МКБ напрямую из-за этого.

Тем не менее, пост ниже показывает, что AMD ICD не экспортирует варианты wgl, что противоречит этой идее.

Должен быть кто-то или какое-то место, где хранятся ключи к этим знаниям.

Изменить 2: с веб-страницы выше приходит самое ясное предложение:

"Поэтому, если вы используете драйвер OpenGL с именем opengl32.dll, вы должны вызывать функции GDI, а если вы не используете драйвер с именем opengl32.dll, вы НЕ должны вызывать функции GDI".

Но как это согласуется с тем фактом, что AMD ICD не экспортирует функции wgl?

Редактировать 2: очевидно, что Mesa3d экспортирует символы WGL, как можно увидеть здесь: http://cgit.freedesktop.org/mesa/mesa/tree/src/mesa/drivers/windows/gdi

Это имеет смысл, поскольку Mesa3d не предполагается использовать в качестве ICD. Это соответствует шаблону в потоке Mesa3d, связанном выше: их вызовы не маршрутизируются через opengl32.dll от Microsoft, поэтому функции gdi не выполняются, но Mesa3d экспортирует функции wgl *, поэтому они по-прежнему работают. Однако, это специфично для Mesa3d - этот метод потерпит неудачу, если вы попытаетесь использовать AMD ICD напрямую.

1 ответ

Решение

Существует огромная разница, а именно, что прототипы для функций WGL не определены ни в каких системных заголовках. opengl32.dll экспортирует символы, но если вы не импортируете функции вручную, вы никогда не узнаете этого.

Однако функции, которые реализуют устанавливаемые клиентские драйверы WGL (ICD), на самом деле имеют префикс: DrvSwapBuffers (...), DrvSetPixelFormat (...), DrvGetProcAddress (...)и т. д. Итак, вы определенно не будете связываться напрямую с ICD, если позвоните wglChoosePixelFormat (...) вместо ChoosePixelFormat (...),

opengl32.dll - это GDI-реализация Microsoft OpenGL и оболочка для ICD. Вы даже можете увидеть, как выглядит реализация ICD, если вы посмотрите на Mesa; обратите внимание, что ни одна из функций не имеет префикса wgl? ICD не экспортируют символы с префиксом wgl, все функции WGL, которые они реализуют, являются расширениями (например, wglSwapIntervalEXT (...), wglChoosePixelFormatARB (...)и т. д.) и может быть загружен только с помощью wglGetProcAddress (...) или же DrvGetProcAddress (...),


Взгляните на AMD OpenGL ICD:

ICD Exports

Вы заметите, что AMD фактически полностью реализует API EGL в своих ICD (и вы можете получить необходимые заголовки для использования EGL на оборудовании AMD здесь), но символы WGL не экспортируются.


Обновить:

Как объяснено в комментариях, gdi32.dll фактически вызывает wglChoosePixelFormat (...) когда ты звонишь ChoosePixelFormat (...), Самое первое, что делает функция, это пытается загрузить opengl32.dll и вызвать wglChoosePixelFormat (...):

.text:4D579CAC ; int __stdcall ChoosePixelFormat(HDC,const PIXELFORMATDESCRIPTOR *)
.text:4D579CAC                 public _ChoosePixelFormat@8
.text:4D579CAC _ChoosePixelFormat@8 proc near
.text:4D579CAC
.text:4D579CAC hLibModule      = dword ptr -4
.text:4D579CAC arg_0           = dword ptr  8
.text:4D579CAC arg_4           = dword ptr  0Ch
.text:4D579CAC
.text:4D579CAC                 mov     edi, edi
.text:4D579CAE                 push    ebp
.text:4D579CAF                 mov     ebp, esp
.text:4D579CB1                 push    ecx
.text:4D579CB2                 push    esi
.text:4D579CB3                 lea     eax, [ebp+hLibModule]
.text:4D579CB6                 push    eax             ; int
.text:4D579CB7                 push    offset aWglchoosepixel ; "wglChoosePixelFormat"
.text:4D579CBC                 call    _GetAPI@12      ; GetAPI(x,x,x)
.text:4D579CC1                 xor     esi, esi
.text:4D579CC3                 test    eax, eax
.text:4D579CC5                 jz      short loc_4D579CD1
.text:4D579CC7                 push    [ebp+arg_4]
.text:4D579CCA                 push    [ebp+arg_0]
.text:4D579CCD                 call    eax
.text:4D579CCF                 mov     esi, eax

Вот GetAPI (все, что он делает, это загружает opengl32.dll и импортирует из него именованную функцию):

GetAPI - gdi32.dll

Теперь, ICD фактически не реализуют ChoosePixelFormat (...), поскольку он функционально идентичен во всех реализациях. Это простая функция сопоставления с образцом. Если вы хотите посмотреть, как opengl32.dll отправляет один из своих wgl... функции ICD во время выполнения, взгляните на поток управления для wglSwapBuffers:

wglSwapBuffers - opengl32.dll

Красная левая ветвь - это то, что происходит, когда установлена ​​ICD, а зеленая правая ветвь является реализацией GDI по умолчанию. wglSwapBuffers, Интересно, что вы можете видеть, что реализация GDI требует полного glFinish (...), Большинство драйверов аппаратного обеспечения склонны сбрасывать очередь команд, а не завершать их при замене буферов, это обеспечивает лучшую параллельность между процессором и графическим процессором.

Другие вопросы по тегам