将OpenGL后缓冲区直接复制到GDI DC像素数据上

时间:2014-03-18 02:01:40

标签: c# opengl gdi opentk hdc

我正在编写一个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上。

将窗口拆分到视口网格上,并仅更新包含脏矩形的单元格

2 个答案:

答案 0 :(得分:1)

首先,您使用的是什么平台(GPU和OS)?我们在谈论什么样的表现?

请记住,尝试在同一个hDC上组合GDI和OpenGL时存在一些限制。实际上,在大多数情况下,这将关闭硬件加速,并通过微软的软件渲染器为您提供OpenGL 1.1。

硬件加速OpenGL针对每帧重绘整个窗口进行了优化。 SwapBuffers()使后备缓冲区的内容无效,这使得在默认帧缓冲区上进行双缓冲时无法实现脏矩形。

有两种解决方案:

  1. 不要致电SwapBuffers()。设置GL.DrawBuffer(DrawBufferMode.Front)并使用单缓冲来更新脏的矩形。这有严重的缺点,包括在Windows上关闭桌面组合。
  2. 不直接渲染到默认的帧缓冲区。而是分配并渲染到帧缓冲对象中。这样,您只能更新已修改的FBO区域。 (您仍然需要将FBO复制到屏幕的每一帧,因此根据您的GUI复杂性,它可能会或可能不会取得性能。)
  3. 编辑:

    单个三角形的40-60ms表示您没有获得任何硬件加速。检查GL.GetString(StringName.Renderer) - 它是否给出了GPU的名称,还是返回"Microsoft GDI renderer"

    如果是后者,则必须从GPU供应商的网站安装OpenGL驱动程序。这样做,性能问题就会消失。

答案 1 :(得分:0)

在使用OpenTK进行多次测试后,似乎在单缓冲或双缓冲模式下,即使启用了恒定尺寸剪刀,在控制尺寸增加时观察到的减速仍然存在。即使使用或不使用GL.Clear()也不会影响减速。 (请注意,只有高度变化才会产生重大影响。)

使用ansi c测试,我得到了相同的结果。

在linux下进行相同的测试也给出了相同的结果。

在linux下,我注意到当我从一个显示器移动到另一个显示器时,帧速率会发生变化。即使禁用了vsync。

下一步是检查directX是否具有相同的行为。如果是,则限制位于显示器和图形卡之间的总线上。

编辑:结论:

此行为会导致您产生错误印象。考虑只在具有脏矩形机制的FBO上构建接口并在四边形(由三个更好)上渲染它并像往常一样交换,而不考虑通过剪切某些操作可以改善给定窗口大小的交换。