使用 OpenGL 和 Gdi+ 的 GetDC、ReleaseDC、CS_OWNDC
Posted
技术标签:
【中文标题】使用 OpenGL 和 Gdi+ 的 GetDC、ReleaseDC、CS_OWNDC【英文标题】:GetDC, ReleaseDC, CS_OWNDC with OpenGL and Gdi+ 【发布时间】:2018-02-07 12:27:33 【问题描述】:阅读 GetDC/ReleaseDC 我应该总是做后者,并且窗口上的 CS_OWNDC 被认为是邪恶的:
https://blogs.msdn.microsoft.com/oldnewthing/20060601-06/?p=31003
查看我的代码,我发现我持有从 GetDC 检索到的 DC,我已将其发送到 wglCreateContextAttribARB。我假设上下文是在该 DC 上创建的,因此随后从驱动程序下释放它是不礼貌的。我的假设正确吗?目前,当我销毁其他 OpenGL 资源时,我正在调用 ReleaseDC。
另外,在我的库的其他地方,我调用 GetDC 来实例化一个 GDI+ 图形对象,然后在我完成绘图后再次释放它。我认为出于性能原因在绘图调用之间保留 DC 和 Graphics 对象会很好,仅在 WM_DISPLAYCHANGE 等上重新创建它。
那么,是否有该领域最佳实践的权威指南?我努力释放 GDI+ DC 但坚持使用 OpenGL DC 的方式似乎有些不一致。
【问题讨论】:
【参考方案1】:OpenGL 和 GDI+ 的行为不同。
在 OpenGL 中,您需要一个上下文,它附加与DC
。这意味着DC
必须在上下文存在时存在。因此,OpenGL 绘制的窗口确实需要CS_OWNDC
样式。
删除上下文后致电ReleaseDC
。
GDI+ 像任何常见的DC
一样在 MS Windows 中使用:检索 DC,绘制到它,释放该 DC。在这种情况下,CS_OWNDC
的使用可能是邪恶的,正如您发布的link 中所指出的那样。
MS GDI+ 使用图形硬件的方式(即创建上下文或其他)与您无关。
编辑由于 Chris Becke 的评论:
不需要使用 CS_OWNDC
引用https://msdn.microsoft.com/es-es/library/windows/desktop/dd374387(v=vs.85).aspx:
hdc 参数必须引用 OpenGL 支持的绘图表面。 它不必与传递给 wglCreateContext 时相同的 hdc hglrc 已创建,但它必须在同一设备上并且具有相同的 像素格式。
建议使用 CS_OWNDC。
在过去的 Windows 9x 中,获取和发布设备上下文既昂贵又缓慢。拥有一个固定直流会更有效。在窗口注册时使用CS_OWNDC
标志是获得固定直流的方法。
CS_OWNDC
用法提供了一个私有设备上下文(参见https://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx#class_styles)。
引用 MS 文档 (https://msdn.microsoft.com/en-us/library/windows/desktop/dd162872(v=vs.85).aspx):
虽然私有设备上下文使用起来很方便,但它是 在系统资源方面内存密集,需要800或更多 要存储的字节。建议使用私有设备上下文 性能考虑大于存储成本。
您必须注意,您必须避免使用私有设备上下文的ReleaseDC
:
应用程序可以通过以下方式检索私有设备上下文的句柄 在创建窗口后随时使用 GetDC 函数。这 应用程序必须只检索一次句柄。此后,可以 保持和使用手柄任意次数。因为是私人设备 上下文不是显示设备上下文缓存的一部分,一个 应用程序永远不需要通过使用释放设备上下文 释放DC函数。
在通过检索DC
、设置当前上下文、绘制、交换缓冲区和释放DC
来绘制到唯一窗口的常见场景中,使用 CS_OWNDC 而不是 GetDC&ReleaseDC 是很自然的。
无论您的 GetDC/ReleaseDC 代码如何,都可能使用 wglGetCurrentDC()
(例如通过外部库)。通常不会发生任何问题。但如果当前 gl-context 为 NULL(就像您在 ReleaseDC 之后立即做的那样),那么 wglGetCurrentDC()
将失败。
没有 CS_OWNDC 的代码 在两个窗口中使用像素格式相同如下所示:
myGLContext = wglCreateContext(...)
//Draw to window A
HDC hdcA = GetDC(hWndA)
wglMakeCurrent(hdcA, myGLContext)
... render...
SwapBuffers(hdcA)
ReleaseDC(hWndA, hdcA)
//Draw to window B
HDC hdcB = GetDC(hWndB)
wglMakeCurrent(hdcB, myGLContext)
... render...
SwapBuffers(hdcB)
ReleaseDC(hWndA, hdcA)
wglMakeCurrent(hdcB, NULL)
【讨论】:
好吧,在我看来,这听起来像是一个很好的一般规则。 CS_OWNDC 在 GDI 的上下文中是不好的,GDI+。在所有情况下都不是一概而论。 这是垃圾。像素格式在 window 上设置,为该窗口检索到的所有窗口 DC 都将使用 gl 上下文。甚至 OpenGL 也不需要使用 CS_OWNDC。 @ChrisBecke 但是在官方的 Khronos wiki (khronos.org/opengl/wiki/Creating_an_OpenGL_Context_(WGL)) 中我们可以读到应该使用 CS_OWNDC 标志:“当你创建你的 HWND 时,你需要确保它设置了 CS_OWNDC它的风格。” 是的——我也读过。但那是一个质量可疑的维基页面。我在任何官方标准文档中都找不到任何对这种奇怪说法的佐证。它确实与 wgl* 和 SetPixelFormat* 函数的 MSDN 文档隐含冲突,至少对我而言,这些函数的措辞暗示任何表示窗口的 HDC 都是等效的。 @ChrisBecke MSDN 说:“GetDC 函数根据指定窗口的类样式检索公共、类或私有 DC。”因此,当未指定 CS_OWNDC 标志时,我们会得到常见的 DC 类。所以对于这样的DC,像素格式只能设置一次。如果我们创建一个“假”窗口来检索扩展和函数以更好地创建 OpenGL 上下文,并且如果我们想创建另一个具有另一个上下文的窗口,我们不能选择其他像素格式(例如支持多重采样的像素格式)。为此,我们需要一个与给定窗口关联的 DC,因此需要 CS_OWNDC 标志。以上是关于使用 OpenGL 和 Gdi+ 的 GetDC、ReleaseDC、CS_OWNDC的主要内容,如果未能解决你的问题,请参考以下文章