opengl32.dll和gdi32.dll之间重复以下功能:
[opengl32.dll] / [gdi32.dll]
wglChoosePixelFormat / ChoosePixelFormat
wglDescribePixelFormat / DescribePixelFormat
wglGetPixelFormat / GetPixelFormat
wglSetPixelFormat / SetPixelFormat
wglSwapBuffers / SwapBuffers
Run Code Online (Sandbox Code Playgroud)
我一直在寻找一个答案很长一段时间,但似乎没有任何具体的信息,为什么会这样,他们的确切区别是什么.
在OpenGL的常见问题,节5.190,表明这些功能都没有功能上相同的:
为确保OpenGL的正确操作,请使用ChoosePixelformat,DescribePixelformat,GetPixelformat,SetPixelformat和SwapBuffers,而不是wgl等效项,wglChoosePixelformat,wglDescribePixelformat,wglGetPixelformat,wglSetPixelformat和wglSwapBuffers.在所有其他情况下,使用可用的wgl函数.使用五个wgl函数只是开发人员运行时链接到OpenGL驱动程序的兴趣.
"运行时链接到OpenGL驱动程序"是否意味着绕过opengl32.dll并直接加载ICD?
名为"Mesa3D不喜欢我的上下文创建代码"的stackoverflow线程似乎强化了这一点.
另一个在C#中名为wglCreateContext但不在托管C++中的 stackoverflow线程表明,在使用GDI函数时,必须在gdi32.dll之前加载opengl32.dll,否则可能会导致运行时失败(错误:2000).
我自己的测试表明,如果调用这些函数的opengl32/wgl版本,某些系统(Nvidia,但不是Intel或Parallels VM)会出现"error:2000" .更改为GDI版本会清除此问题,但使用LoadLibrary("opengl32.dll")似乎不会更改任何内容.
有没有人研究过这些WGL和GDI函数之间的区别?显然存在某种形式的差异,我试图了解在哪种情况下应该使用哪个版本以及如果使用错误版本会有什么潜在的缺陷.
编辑:wayback机器打开一个网页,描述ICD的直接加载如何工作.这显然需要在Voodoo 1/2天内,当2d和3d加速器是具有单独ICD的两个不同硬件(正常的opengl32.dll + ICD机制无法处理时).地震1和2显然会加载ICD直接因此而产生.
但是,下面的帖子显示AMD ICD不会导出wgl变体,这与此想法相矛盾.
有有是某个人或某个地方,在那里,持有的钥匙,这方面的知识.
编辑2:从上面的网页上得到了最清晰的建议:
"因此,如果您使用的是名为OPENGL32.DLL你一个OpenGL驱动程序 必须调用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线程中的模式:它们的调用没有通过Microsoft的opengl32.dll路由,因此gdi函数失败,但是Mesa3d正在导出wgl*函数,所以这些仍然有效.但是,这是特定于Mesa3d的 - 如果您尝试直接使用AMD的ICD,该方法将失败.
如何使用最少量的代码初始化无窗口OpenGL上下文?
我在这里读到你可以wglCreateContextAttribsARB用来创建无窗口的上下文,但它没有解释如何?
似乎某些特定于API的调用设置了返回的错误GetLastError()。例如,wglCreateContextAttribsARB(...)可以返回(来自规范的信息):
ERROR_INVALID_VERSION_ARB == 0x2095
ERROR_INVALID_PROFILE_ARB == 0x2096
Run Code Online (Sandbox Code Playgroud)
但是,调试时会得到不同的结果。例如,尝试用于wglCreateContextAttribsARB(...)设置GL 4.5上下文(我的GPU不支持该上下文)会导致错误值0xC0072095。低16位与无效版本错误相匹配(之所以有意义是因为这是版本问题),但是高16位对我而言没有意义。
我浏览了GetLastError文档,该文档说应该为应用程序错误代码设置第29位。但是,我找不到关于为什么要设置其他位的任何理由,无论如何,这与ARB规范(即返回某某值)相冲突。
这是怎么回事?
我通常使用wglChoosePixelFormatARB()这些参数(以及其他参数)创建像素格式:
WGL_DOUBLE_BUFFER_ARB = GL_TRUE
WGL_SAMPLE_BUFFERS_ARB = GL_TRUE
WGL_SAMPLES_ARB = 4
Run Code Online (Sandbox Code Playgroud)
即双缓冲和x4多重采样.这很好用.
但是当我尝试转换双缓冲时:
WGL_DOUBLE_BUFFER_ARB = GL_FALSE
WGL_SAMPLE_BUFFERS_ARB = GL_TRUE
WGL_SAMPLES_ARB = 4
Run Code Online (Sandbox Code Playgroud)
调用wglChoosePixelFormatARB()失败(或者说它没有创建任何东西)
当我有效地关闭多重采样时:
WGL_DOUBLE_BUFFER_ARB = GL_FALSE
WGL_SAMPLE_BUFFERS_ARB = GL_TRUE
WGL_SAMPLES_ARB = 1
Run Code Online (Sandbox Code Playgroud)
我再次正常工作.
有没有固有的东西阻止非双缓冲像素格式与多重采样一起使用?
我正在关闭双缓冲的原因是为了实现无约束的帧速率.使用双缓冲,我得到的帧速率仅高达60 FPS(这款笔记本电脑液晶显示器的工作频率为60Hz).但是通过双缓冲关闭,我可以达到1500 FPS.有没有办法通过双缓冲来实现这一目标?
我试图使用WGL_ARB_pbuffer进行OpenGL的屏幕外渲染,
但我在初始化期间失败了. 这是我的代码.wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB");
if(!wglGetExtensionsStringARB) return;
const GLubyte* extensions = (const GLubyte*) wglGetExtensionsStringARB(wglGetCurrentDC());
Run Code Online (Sandbox Code Playgroud)
实际上这结束于第二行,因为wglGetExtensionsStringARB得到NULL.
我不知道为什么wglGetProcAddress不起作用. 我包括"wglext.h",我也在标题中定义如下.PFNWGLGETEXTENSIONSSTRINGARBPROC pwglGetExtensionsStringARB = 0;
#define wglGetExtensionsStringARB pwglGetExtensionsStringARB
Run Code Online (Sandbox Code Playgroud)
为什么我不能像我想的那样使用wglGetProcAddress? 我正在开发一个应用程序,通过逐渐禁用某些功能和优化,可以使用从 4.6 到 2.0 的任何 OpenGL 版本。这意味着它可以使用 2.0,但更喜欢最新支持的版本,以便能够使用 OpenGL 3.x-4.x 中的所有可用功能。此外,它还处理核心和兼容性上下文之间的所有差异,因此它应该适用于任何配置文件。
看来在 Windows 上不会有问题,因为我可以省略版本和配置文件,并自动获取最新支持版本的兼容性上下文。
但 macOS 和 Mesa 上的工作方式有所不同。在那里,我必须请求某个特定版本的核心前向兼容上下文,即使我不想要特定版本,我想要最新的版本。
我该如何处理这个问题?我是否必须循环尝试所有版本 4.6、4.5、4.4、4.3、4.2、4.1、4.0、3.3、3.2、3.1、3.0、2.1、2.0,直到成功创建上下文?或者有更好的解决方案吗?
如果没有更好的通用解决方案,我想知道它在不同平台上的不同驱动程序的实践中如何工作。
wglMakeCurrent 是否应该只调用一次,还是需要在每次缓冲区交换之前调用?当前的 opengl 上下文可以通过其他外部事物重置,然后通过 wglMakeCurrent 设置吗?
我来这里只是为了缩小可能出现的问题。我无法在这里发布相关代码,因为我不知道哪一部分是相关的。
目前我有一个循环执行 makeCurrent ->clear ->render。它渲染正确。我尝试在初始化时使上下文成为当前上下文,而不是每次绘制时都将其设为当前上下文,但它呈现为空屏幕。仅当我退出窗口时,正确的渲染才会闪烁一帧。我发现使用 nvidia 的图形调试器有问题。调试器的覆盖层奇怪地闪烁。其他应用程序不会这样做。
需要明确的是,我已经广泛测试了这段代码,发现问题出在 WGL 代码之前编写的代码中。正是在 WIN32 代码中。现在我认为这可能部分是由调用 gluOrth2D 引起的,但即便如此,据我所知,这不应该是主要原因。我可能会自己通过搞乱东西来解决这个问题,但考虑到这个问题(发生在一个更大的项目中)已经占用了我很多时间,我认为值得发布这个,以防其他人遇到同样的问题。我希望得到解释以及修复/更正。
#include <GL/glew.h>
#include <glfw3.h>
#define GLFW_EXPOSE_NATIVE_WGL
#define GLFW_EXPOSE_NATIVE_WIN32
#include <glfw3native.h>
constexpr int width = 1000, height = 1000;
bool running = true;
LRESULT CALLBACK WIN32_processMessage(HWND hwnd, UINT msg,
WPARAM wparam, LPARAM lparam)
{
return DefWindowProcA(hwnd, msg, wparam, lparam);
}
int main()
{
HINSTANCE hinst = GetModuleHandleA(NULL);
HICON icon = LoadIcon(hinst, IDI_APPLICATION);
WNDCLASSA* wc = (WNDCLASSA*)memset(malloc(sizeof(WNDCLASSA)), 0, sizeof(WNDCLASSA));
if (wc == NULL)
{
return -1;
}
wc->style = CS_DBLCLKS;
wc->lpfnWndProc = WIN32_processMessage;
wc->cbClsExtra = …Run Code Online (Sandbox Code Playgroud) 我正在使用wlgGetProcAddress使用创建的上下文来获取函数wglCreateContext.我已经设置了上下文wglMakeCurrent.我得到一个有效的函数指针glGetStringi,但我得到NULL了glGetString.我认为glGetString并且glGetStringi是在相同版本的OpenGL(1.0)中引入的.任何想法为什么我得到这个NULL?
const GLubyte* (*glGetString)(GLenum);
const GLubyte* (*glGetStringi)(GLenum, GLuint);
glGetString = reinterpret_cast<decltype(glGetString)>(wglGetProcAddress("glGetString"));
glGetStringi = reinterpret_cast<decltype(glGetStringi)>(wglGetProcAddress("glGetStringi"));
Run Code Online (Sandbox Code Playgroud)
如果它很重要,我有一个驱动程序版本13.251.0.0的Radeon HD 7950.