我正在编写一个GUI,它通过OpenTK使用OpenGL和C#上的GLControl,并且我试图使用脏矩形来仅绘制需要绘制的控件。显然,仅仅为了刷新鼠标悬停按钮而重绘整个最大化形式是不明智的。
我的第一次尝试是使用glScissors,但这并不限制SwapBuffers,我怀疑(因为性能几乎完全取决于窗口大小)并不是我的平台。交换'但要将后缓冲区的完整副本复制到前缓冲区。
第二次尝试是glAddSwapHintRectWIN,理论上它会限制SwapBuffers的交换(在本例中为复制)区域,但这只是一个提示,它根本不做任何事情。
第三次尝试是glDrawBuffer将后端缓冲区的一部分复制到帧缓冲区,原因不明,即使我只复制了缓冲区的一部分,性能仍然会在窗口大小之前以同样的方式降低增加。
无论我做什么,它都会让整个区域的刷新变得无处不在。
所以我试图使用glReadPixels()并以某种方式获得一个指针直接绘制到从控件的CreateGraphics()获取的hDC像素数据。这可能吗?
修改
我认为GLControl有问题,为什么这段代码的性能取决于屏幕尺寸,我没有做任何交换缓冲或清除,只是在前端缓冲区上绘制一个恒定大小的三角形:一个驱动程序问题,也许?
GL.DrawBuffer(DrawBufferMode.Front);
Vector4 Color;
Color = new Vector4((float)R.NextDouble(), 0, 0, 0.3F);
GL.Begin(BeginMode.Triangles);
GL.Color4(Color.X, Color.Y, Color.Z, Color.W);
GL.Vertex3(50, 50, 0);
GL.Vertex3(150F, 50F, 0F);
GL.Vertex3(50F, 150F, 0F);
GL.End();
GL.Finish();
编辑2 这种解决方案不可行: 绘制到纹理上并使用glGetTexImage绘制到GDI位图上,然后将该位图绘制到窗口hDC上
使用glReadPixels从缓冲区读取缓冲区像素到GDI位图上,然后将该位图绘制到窗口hDC上。
将窗口拆分到视口网格上,并仅更新包含脏矩形的单元格
答案 0 :(得分:1)
首先,您使用的是什么平台(GPU和OS)?我们在谈论什么样的表现?
请记住,尝试在同一个hDC上组合GDI和OpenGL时存在一些限制。实际上,在大多数情况下,这将关闭硬件加速,并通过微软的软件渲染器为您提供OpenGL 1.1。
硬件加速OpenGL针对每帧重绘整个窗口进行了优化。 SwapBuffers()
使后备缓冲区的内容无效,这使得在默认帧缓冲区上进行双缓冲时无法实现脏矩形。
有两种解决方案:
SwapBuffers()
。设置GL.DrawBuffer(DrawBufferMode.Front)
并使用单缓冲来更新脏的矩形。这有严重的缺点,包括在Windows上关闭桌面组合。编辑:
单个三角形的40-60ms表示您没有获得任何硬件加速。检查GL.GetString(StringName.Renderer)
- 它是否给出了GPU的名称,还是返回"Microsoft GDI renderer"
?
如果是后者,则必须从GPU供应商的网站安装OpenGL驱动程序。这样做,性能问题就会消失。
答案 1 :(得分:0)
在使用OpenTK进行多次测试后,似乎在单缓冲或双缓冲模式下,即使启用了恒定尺寸剪刀,在控制尺寸增加时观察到的减速仍然存在。即使使用或不使用GL.Clear()也不会影响减速。 (请注意,只有高度变化才会产生重大影响。)
使用ansi c测试,我得到了相同的结果。
在linux下进行相同的测试也给出了相同的结果。
在linux下,我注意到当我从一个显示器移动到另一个显示器时,帧速率会发生变化。即使禁用了vsync。
下一步是检查directX是否具有相同的行为。如果是,则限制位于显示器和图形卡之间的总线上。
编辑:结论:此行为会导致您产生错误印象。考虑只在具有脏矩形机制的FBO上构建接口并在四边形(由三个更好)上渲染它并像往常一样交换,而不考虑通过剪切某些操作可以改善给定窗口大小的交换。