-1

首先让我稍微解释一下应用程序。这是一款视频安全软件,可以同时显示多达 48 个摄像头。每个视频流都有自己的 Windows HDC,但它们都使用共享的 OpenGL 上下文。我使用 OpenGL 获得了相当不错的性能,它可以在 Windows/Linux/Mac 上运行。在后台,上下文是使用 wxWidgets 2.8 wxGLCanvas 创建的,但我认为这与问题无关。

现在问题来了。假设我使用同一个相机并将其显示在我的所有 48 个窗口中。这基本上意味着我只解码 30fps(无论如何都是在不同的线程上完成的)但显示高达 1440fps 以从图片中提取解码。我正在使用 PBO 来传输图像,这取决于是否支持像素着色器和多纹理,我可以使用它们在 GPU 上进行 YUV->RGB 转换。然后我使用四边形来定位纹理并调用 SwapBuffers。所有的 OpenGL 调用都来自 UI 线程。此外,我尝试在 CPU 上进行 YUV->RGB 转换,并搞砸了使用 GL_RGBA 和 GL_BGRA 纹理,但所有格式仍然产生大致相同的性能。现在的问题是我只能从可能的 1440fps 中得到大约 1000fps(我知道我不应该以 fps 来衡量,但在这种情况下更容易)。上述场景使用 320x240 (YUV420) 视频,大约只有 110MB/秒。如果我使用 1280x720 相机,那么我得到的帧速率大致相同,接近 1.3GB/秒。这告诉我,这肯定不是纹理上传速度。如果我在 CPU 上进行 YUV->RGB 转换和缩放并使用 Windows DC 进行绘画,那么我可以轻松获得完整的 1440fps。

另一件要提到的事情是,我已经在我的视频卡上和通过 OpenGL 使用 wglSwapIntervalEXT 禁用了 vsync。也没有报告 OpenGL 错误。但是,使用 very sleepy 来分析应用程序似乎大部分时间都花在了 SwapBuffers 中。我假设这个问题与我在某处使用多个 HDC 或 SwapBuffers 有某种关系,但是,我不确定我正在做的其他事情。

我不是 OpenGL 方面的专家,所以如果有人有任何建议或任何我想听听的意见。如果我正在做的任何事情听起来是错误的,或者我可以更有效地实现同样的事情,我很想听听。

以下是 glIntercept 日志的一些链接,以便更好地了解所有正在进行的 OpenGL 调用:

简单 RGB:https ://docs.google.com/open?id=0BzGMib6CGH4TdUdlcTBYMHNTRnM

着色器 YUV:https ://docs.google.com/open?id=0BzGMib6CGH4TSDJTZGxDanBwS2M

分析信息:所以在分析之后报告了几个冗余的状态变化,我对此并不感到惊讶。我消除了所有这些,并没有看到我预期的明显性能差异。每个渲染循环有 34 个状态更改,并且我使用了几个不推荐使用的函数。我将研究使用可以解决这些问题的顶点数组。但是,我每个渲染循环只做一个四边形,所以我真的不期望这会对性能产生太大影响。另外请记住,我不想把所有东西都撕掉并全部使用 VBO,因为我仍然需要支持一些我认为只有 OpenGL 1.4 的相当老的英特尔芯片组驱动程序。

真正让我感兴趣并且之前没有想到的事情是每个上下文都有自己的前后缓冲区。由于我只使用一个上下文,因此之前的 HDC 渲染调用必须在交换发生之前完成对后台缓冲区的写入,然后下一个可以再次开始写入后台缓冲区。使用多个上下文真的会更有效吗?或者我应该考虑渲染到纹理(我认为是 FBO)并继续使用一个上下文?

编辑:使用多个 OpenGL 上下文提到的原始描述,但我错了,我只使用一个 OpenGL 上下文和多个 HDC。EDIT2:在使用 gDEBugger 进行分析后添加了一些信息。

4

1 回答 1

0

我试图让您的应用程序更快。我创建了一个 OpenGL 渲染线程(如果您有 2 个或更多显卡,则创建更多)。显卡无法一次处理多个上下文,您的多个 OpenGL 上下文正在等待其中一个上下文。这个线程只会让 OpenGL 工作,比如 YUV->RGB 转换(使用 FBO 渲染到纹理)。Camere 的线程将图像发送到该线程,UI 线程可以将其拾取并显示在窗口上。您可以在 OpenGL 上下文中处理查询,并且可以将多个帧组合到一个纹理中以通过一次转换来转换它。它可能很有用,因为您最多有 48 个摄像头。作为另一个变体,如果 OpenGL 线程现在很忙,您可以在 CPU 上转换一些帧。

从日志中我看到您经常调用相同的方法:

glEnable(GL_TEXTURE_2D)
glMatrixMode(GL_TEXTURE)
glLoadIdentity()
glColor4f(1.000000,1.000000,1.000000,1.000000)

您可以在每个上下文中调用一次,而不是为每个渲染调用一次。

如果我理解正确,您对 YUV 的每个平面使用 3 个纹理

glTexSubImage2D(GL_TEXTURE_2D,0,0,0,352,240,GL_LUMINANCE,GL_UNSIGNED_BYTE,00000000)
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,176,120,GL_LUMINANCE,GL_UNSIGNED_BYTE,000000)
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,176,120,GL_LUMINANCE,GL_UNSIGNED_BYTE,00000000)

尝试使用一种纹理并在着色器中使用计算来为像素获取正确的 YUV 值。有可能,我在我的应用程序中做到了。

于 2015-09-10T11:25:09.417 回答