0

今天我摆脱了对 OpenTK 的依赖;我的应用程序不再依赖 OpenTK 来创建 OpenGL 上下文。但是,在 Mesa 3D(OpenGL 的软件渲染实现)中运行时,我的代码不再能够正常运行;我的代码运行,但 FPS 大约为 0.001 FPS(相比之下,使用 OpenTK 的上下文创建大约为 16+FPS)并且通常绘制到 FBO 的内容显示在窗口上,因为它是由组成的。尽管在没有 Mesa 3D 的情况下运行我的代码会产生正常的性能(在 Windows 7 上),但我担心它运行良好可能只是巧合。glGetError检查显示没有错误,这让我觉得我在创建上下文时可能做错了什么?

m_controlHandle = m_winForm.Handle; /* HWND */
m_controlDC = Win32.GetDC(m_controlHandle); /* HWND's DC*/
Win32.PixelFormatDescriptor pixelFormat = new Win32.PixelFormatDescriptor();
pixelFormat.Size = (short)Marshal.SizeOf(typeof(Win32.PixelFormatDescriptor));
pixelFormat.Version = 1;
pixelFormat.Flags =
    Win32.PixelFormatDescriptorFlags.DRAW_TO_WINDOW |
    Win32.PixelFormatDescriptorFlags.SUPPORT_OPENGL |
    Win32.PixelFormatDescriptorFlags.DOUBLEBUFFER;
pixelFormat.PixelType = Win32.PixelType.RGBA;
pixelFormat.ColorBits = 32;
pixelFormat.DepthBits = 0; /* yes, I don't use a depth buffer; 2D sprite game */
pixelFormat.LayerType = Win32.PixelFormatLayerType.MAIN_PLANE;
int formatCode = Win32.ChoosePixelFormat(m_controlDC, ref pixelFormat);
if (formatCode == 0)
    throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Win32.SetPixelFormat(m_controlDC, formatCode, ref pixelFormat))
    throw new Win32Exception(Marshal.GetLastWin32Error());
m_openGLContext = Win32.wglCreateContext(m_controlDC);
if (m_openGLContext == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Win32.wglMakeCurrent(m_controlDC, m_openGLContext))
    throw new Exception("Could not wglMakeCurrent.");

这个对吗?有什么建议可以追踪可能导致 Mesa3D 突然发疯的原因吗?

4

2 回答 2

0

好的......我希望没有人必须经历我试图弄清楚这一点的事情,所以这是解决方案:

尽管 OpenTK 会尝试使用wglChoosePixelFormatARB,但它在 Mesa 3D 上失败并回退到ChoosePixelFormat. 但是,OpenTKChoosePixelFormat实际调用的函数DllImports wglChoosePixelFormat和 NOT ChoosePixelFormat

是的,有两个版本ChoosePixelFormat:一个带有前缀wgl,一个不带前缀。来自OpenGL.org 文档

在 Win32 平台上,许多平台特定的函数调用在 OpenGL ICD 机制和 GDI 中重复。这可能会导致混淆,因为它们在功能上看起来是相同的,唯一的区别是 wgl 是否在函数名的其余部分之前。为确保 OpenGL 正确运行,请使用 ChoosePixelformat、DescribePixelformat、GetPixelformat、SetPixelformat 和 SwapBuffers,而不是 wgl 等效项 wglChoosePixelformat、wglDescribePixelformat、wglGetPixelformat、wglSetPixelformat 和 wglSwapBuffers。在所有其他情况下,在可用的情况下使用 wgl 函数。使用五个 wgl 函数只对链接到 OpenGL 驱动程序的开发人员感兴趣。不使用上述功能可能会导致黑色 OpenGL 窗口,或者在 Windows 9x 中正常运行的应用程序会在 Windows NT/2000 上产生黑色 OpenGL 窗口。

当我尝试运行时链接到 OpenGL 驱动程序(Mesa 3D)时,wgl我对这五个函数很感兴趣。一旦我用 , 和 Mesa 3D 替换了我的, ,ChoosePixelFormatSetPixelformat,Mesa 3D 工作得非常好!谜团已揭开。SwapBufferswglChoosePixelFormatwglSetPixelformatwglSwapBuffers

于 2013-09-21T10:07:54.147 回答
0

如果您想避免软件实现,那么您在选择像素格式的逻辑上存在重大缺陷。回想一下(或第一次了解)WGL 使用模式匹配启发式算法来查找所有像素格式的集合,这些格式最低限度地满足您所请求的参数。您设置为 0 的请求参数越多,在解决“最佳”(最接近)匹配时留下的歧义就越大。

如果您想了解为什么 0 位深度缓冲区与 32 位颜色缓冲区相结合可能是一个坏主意,您可以枚举显示驱动程序提供的所有像素格式并检查哪些是完全硬件加速的(它们不会有标志:PFD_GENERIC_FORMATPFD_GENERIC_ACCELERATED设置)。有软件可以为你做这件事,虽然我想不出任何东西 - 如果你真的决定这样做,准备好浏览数百个像素格式的列表......

许多奇怪的参数组合是在软件 (GDI) 中实现的,而不是在硬件中实现的。为获得硬件格式而尝试的最佳位深度之一是 32 位 RGBA、24 位深度、8 位模板。在现代硬件上,这几乎总是驱动程序选择的最合理的输入参数组合的“最接近”匹配。您越接近选择精确的硬件像素格式,就越有可能阻止 Win32 / WGL 为您提供 GDI 像素格式。


根据我自己的观察:

在遥远的过去,我不得不手动枚举像素格式并覆盖ChoosePixelFormat (...)解决驱动程序错误的行为;模式匹配行为并不总是对您有利。

在 OpenTK 的情况下,我怀疑它实际上使用wglChoosePixelFormatARB (...)了 ,这是一个用于选择像素格式的更复杂的界面(并且是支持多采样抗锯齿所必需的)。wglChoosePixelFormatARB由可安装客户端驱动程序 (ICD) 实现,因此它从不尝试将输入参数与 GDI 像素格式匹配。

我怀疑 GDI 提供 32 位 RGBA + 0 位 Z 像素格式,但您的 ICD 没有。由于最接近的匹配总是获胜,并且ChoosePixelFormat会看到 GDI 像素格式,因此您可以了解为什么这是一个问题。

您应该尝试 32 位 RGBA(24 位颜色,8 位 Alpha)+ 24 位 Z + 8 位模板,看看这是否能提高您的性能...


更新:

还有另一个问题可能会绊倒一些愚蠢的司机。应该ColorBits是RGBA 像素格式中的 RGB 位数(通常为 24)。应该是A 位数(通常为 8)。许多驱动程序会看到 32 位与 0 组合并理解隐含的行为(24 位 RGB + 8 位填充),但是编写代码的方式可能会很麻烦。从技术上讲,这种像素格式将被称为(其中 X 表示未使用的位)。AlphaBitsColorBitsAlphaBitsRGBX8

24ColorBits和 8AlphaBits可能会给出更便携的结果。

于 2013-09-20T23:53:25.240 回答