当前位置: 首页 > 知识库问答 >
问题:

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

方宏才
2023-03-14

我正在编写一个GUI,它通过OpenTK和C#上的GLControl使用OpenGL,我试图使用脏矩形来绘制需要绘制的控件。显然,仅仅为了刷新鼠标悬停按钮而重新绘制整个最大化表单是不明智的。

我的第一次尝试是使用glScissors,但这并不限制SwapBuffers,在我的平台中,我怀疑(因为性能几乎完全取决于窗口大小)不会“交换”,而是将后缓冲区的完整副本复制到前缓冲区。

第二次尝试是glAddSwapHintRectWIN,理论上它会限制交换缓冲区的交换(在本例中是复制的)区域,但这只是一个提示,它没有任何作用。

第三次尝试是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个答案

艾敏学
2023-03-14

在用OpenTK进行了几次测试后,似乎在单缓冲或双缓冲模式下,随着控件大小的增加而观察到的速度减慢仍然存在,即使启用了恒定大小的剪刀。甚至是GL的使用与否。Clear()不影响减速。(请注意,只有高度变化有显著影响。)

用ansi c示例进行测试,得到了相同的结果。

linux下做同样的几个测试也给出了同样的结果。

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

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

编辑:结论:

这种行为会导致错误的印象。考虑只在带有脏矩形机制的FBO上构建您的界面,并将其呈现在四边形(由tri制成更好)上,然后像往常一样交换,而不考虑您可以通过剪切一些操作来改进给定窗口大小的交换。

梁存
2023-03-14

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

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

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

有两种解决方案:

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

编辑:

单个三角形的40-60ms表示您没有获得任何硬件加速。检查<code>GL.GetString(StringName.Renderer)-它是给出GPU的名称还是返回<code>“Microsoft GDI渲染器”?

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

 类似资料:
  • 我的要求是将字节流转换为具有预定义数据长度的结构类型。在下面的示例中,我可以将字节转换为“Test”对象并读取数据(func-buffertoStruct演示了这一点), 但问题是 我需要根据字符串或整数长度转换为数据类型。现在没有发生。 我有很多不同的结构,比如“类型测试”,每个结构都有大量的数据变量。因此,根据大小逐个将字节复制到结构测试变量中是行不通的。 我在考虑解决方案: 我正在考虑保留所

  • 问题内容: 在编写用于OpenGL库的Matrix类时,我遇到了一个问题,即使用Java数组还是使用Buffer策略存储数据(JOGL为Matrix操作提供直接缓冲区复制)。为了对此进行分析,我编写了一个小型性能测试程序,该程序比较了Arrays vs Buffers和Direct Buffers上循环和批量操作的相对速度。 我想在这里与您分享我的结果(因为我发现它们很有趣)。请随时发表评论和/或

  • 我做了一个在上面渲染天空盒和粒子的应用程序。我想添加一些效果,我需要使用帧缓冲区来渲染天空盒、粒子颜色、深度和位置以分离纹理。然后我想使用简单的着色器来使用这些纹理中的值并以适当的方式混合它们。我为纹理、帧缓冲区和屏幕四边形(渲染简单的矩形)编写了辅助类,但不幸的是——当我尝试使用它时没有任何渲染。 当绑定帧缓冲区被注释掉时,我的场景如下所示: 修改着色器表明深度和位置值计算正确。因此问题在于纹理

  • 在DirectX中,您可以有单独的渲染目标和深度缓冲区,因此可以绑定渲染目标和一个深度缓冲区、执行一些渲染、移除深度缓冲区然后使用旧的深度缓冲区作为纹理进行更多渲染。 你会如何在opengl中做到这一点?根据我的理解,您有一个帧缓冲区对象,其中包含颜色缓冲区和可选的深度缓冲区。我不认为我可以同时绑定多个帧缓冲器对象,我是否必须在每次更改时(可能一帧几次)重新创建帧缓冲器对象?普通的 opengl

  • 我有一个正在开发的OpenGL应用程序。正在渲染的地形似乎没有遵循深度缓冲规则,所以我猜我在某个地方搞砸了 我的代码中有GL11.glEnable(GL11.GL_CULL_FACE) 这是飞机在没有四边形在另一个后面的情况下的样子,所以即使没有z缓冲区,事情看起来也很正常。请注意,这是从“自上而下”的视图中,其中“相机”在飞机上方 而现在,从不同的角度看 离场景最远的四边形正在更靠近计算机的四边

  • 问题内容: 我有一些二进制数据的缓冲区: 我想追加。 如何追加更多二进制数据?我正在搜索文档,但是要附加数据,它必须是字符串,否则,将发生错误( TypeError:Argument必须是string ): 然后,我在这里看到的唯一解决方案是为每个附加的二进制数据创建一个新缓冲区,并将其复制到具有正确偏移量的主缓冲区中: 但这似乎效率不高,因为我必须为每个追加实例化一个新的缓冲区。 您知道附加二进