优化流媒体vbo openg

Posted

技术标签:

【中文标题】优化流媒体vbo openg【英文标题】:optimization streaming vbo openg 【发布时间】:2015-08-28 08:19:53 【问题描述】:

我正在使用 opengl 3.3 和完全流式传输的 VBO 渲染一个自上而下、基于图块的世界。

在遇到一些滞后后,我做了一些基准测试,发现结果很糟糕!

让我解释一下图片。第一个标记的方块是我使用最简单的着色器运行我的游戏。没有闪电,什么都没有!我只是上传 5000 个顶点并绘制它们。我的内存负载大约是 20-30%,cpu-load 30-40%

第二个是闪电。每个灯光都作为数组上传到片段着色器,每个片段都会处理灯光。负载约 40-50%。 100% 使用 60 盏灯。

第三个是延迟着色。首先,我将法线和漫反射绘制到 FBO,然后将每个灯光渲染到默认 FB,同时读取这些灯光。负载约为 80%。基本上不受灯光数量的影响。

这些是我渲染的场景:

如您所见,没有什么花哨的。是复古风格。我的计划是增加大量的复杂性,并且仍然在低端计算机上运行流畅。我的是i7 nvidia 660M,应该没问题。

作为比较,我运行了魔兽争霸 3,它需要大约 50-60% 的负载和 20% 的内存。

我注意到的一件奇怪的事情是,如果我禁用垂直同步并且不在交换缓冲区之前调用 glFinish,负载会显着下降。然而,时钟上升并产生热量 (53C*)。

现在,首先我想知道您是否认为这很正常。如果不是,那么我的瓶颈可能是什么?会不会是我的流媒体 VBO?我试过双重缓冲和孤立,但没有。将 sprite 的数量加倍基本上会增加 5-10% 的内存负载。 gpu-load 基本保持不变。

我知道这个问题不容易回答,但我会根据您的需要提供更多详细信息。不想在这里贴我的 20000 行代码。

哦,还有一件事......它会波动。绘制调用是相同的,但负载可以从 2% 到 100% 随心所欲。

更新:

我的主循环如下所示:

交换缓冲区

renderAndDoGlCalls

更新GameAndPoll

如果还有时间就睡觉(1/60 秒)

重复。

如果没有 v-sync、glflush 或 glfinsih,这会导致使用百分比:

交换:0.16934400677376027

人:0.9929640397185616

upp:0.007698000307920012

民意调查:0.0615780024631201

睡眠:100.39487801579511

在交换缓冲区之前使用 glFinish:

交换:26.609977064399082(这通常会上升到 80%)

人:1.231584049263362

upp:0.010266000410640016

民意调查:0.07697400307896013

睡眠:74.01582296063292

使用 Vsync 启动良好,通常与使用 glFinish 相同,然后是 bam!:

交换:197.84934791397393

人:1.221324048852962

upp:0.007698000307920012

民意调查:0.05644800225792009

睡眠:0.002562000102480004

并且一直保持这种状态。

【问题讨论】:

我认为通过使用分析器可以更好地确定瓶颈在哪里。你也应该在this 有一个lokk。 负载在哪个设备上测量? CPU还是GPU?如果你能处理好事情,你通常会用一个换另一个。 VSYNC 通常会降低 GPU 负载,但可能会增加报告的 CPU 负载,具体取决于驱动程序用于等待的机制。衡量性能的最佳方法可能是完全忽略负载百分比,因为它会根据 VSYNC 和其他人为因素(例如预渲染帧)而变化很大,并寻找帧时间一致性。我在任何地方都没有看到帧时间图表。 我已经更新了。 负载在 GPU 上测量。 CPU 稳定在 ~5% 我基本上在 cpu 上做所有事情,除了在着色器中完成的光计算 【参考方案1】:

让我澄清一下...如果我在所有 opengl 调用之后立即调用 swapbuffers,我的 CPU 会在 70% 的更新时间停止,让我什么也不做。这样,在我再次调用交换之前,我会给予 GPU 尽可能长的时间来完成后备缓冲区。

你实际上是无意中导致了相反的情况。

SwapBuffers 导致调用线程停止的唯一时间是当预渲染帧队列已满并且它必须等待 VSYNC 刷新完成的帧时。在任何给定时刻,CPU 都可以轻松领先 GPU 2-3 帧,而导致等待的不是当前帧完成(在这种情况下,已经有一个完成的帧需要交换)。

发生等待是因为驱动程序无法从后到前交换后台缓冲区,直到 VBLANK 信号滚动(每 16.667 毫秒才发生一次)。驱动程序实际上会在等待向上交换时继续接受命令,直到达到队列交换的某个限制(NVIDIA 硬件上的预渲染帧/AMD 上的翻转队列大小)。一旦达到该限制,GL 命令将导致阻塞,直到后台缓冲区被交换。

您在帧结束时处于休眠状态,因此不会产生明显的 CPU/GPU 并行性;事实上,您更有可能以这种方式跳过一帧。

这就是你在这里看到的。绝对最坏的情况是当您睡 1 毫秒时太晚而无法及时为 VBLANK 交换缓冲区。然后两帧之间的时间变为 16.66667 + 15.66667 = 32.33332 毫秒。如果您不添加自己的等待时间,这将导致不会发生的口吃。驱动程序可以轻松地从后到前复制后台缓冲区,并在您添加的那 1 个额外毫秒内继续接受命令,但它会在下一帧开始时再阻塞 15 个毫秒。

为避免这种情况,您希望在发出帧的所有命令后尽快交换缓冲区。通过这种方式,您最有可能满足 VBLANK 的最后期限。由于睡眠时间减少,报告的 CPU 使用率可能会上升,但应使用帧时间而不是计划的 CPU 时间来衡量性能。

所讨论的 VSYNC 和预渲染帧限制将使您的 CPU 和 GPU 不会失控并产生问题中提到的大量热量。

【讨论】:

谢谢,非常感谢。我会消化这个。 @Jake:我的讨论缺少任何图表,但我认为您应该看看following diagram。它没有讨论预渲染帧,但是如果您想象自己在橙色气泡中添加一些睡眠时间,您基本上可以看到如果您在蓝色气泡开始的时间之后睡觉会发生什么(显示的最后一帧有这个问题)。绿色气泡将是有效的驱动因素。 那么,你是说如果前面的 gl-commands 没有完成,swapbuffers 就不会停止?如果我在“后缓冲队列”中有几个准备好的帧,这对我来说很有意义。但我不认为我这样做,因为我只对每个交换缓冲区进行一次渲染调用,让 GPU 除了等待当前帧完成之外别无选择。即使我确实设法将几帧放入队列中,那么输入和屏幕上的内容之间不会有很多延迟吗?

以上是关于优化流媒体vbo openg的主要内容,如果未能解决你的问题,请参考以下文章

sh [bash] ffmpeg针对流媒体优化mp4

Spark/Mesos 发明人教你用决策树优化视频流媒体用户体验质量

如何在spark结构化流媒体应用程序中优化执行程序实例的数量?

EasyPlayer流媒体播放器播放HLS视频,起播速度慢的技术优化

切换到使用交错 VBO - 编译但没有绘制 - opengl es 2.0

海康大华安防网络摄像头OnvifRTSP网络无插件直播流媒体服务解决方案EasyNVR表单重复提交的优化方案