OpenGL中快速绘制直线

12

我正在开展一个项目,需要在ADC获得数据时绘制大量数据。例如,在1600像素宽的监视器上每帧50,000行。这个项目在2007年左右的Quadro FX 570系统上运行良好,但是在Intel HD 4000级别芯片的机器上无法跟上数据速度。数据负载为32个通道的200Hz数据,每个通道以5个样本的批次40次/秒接收。因此,换句话说,该卡只需要实现40帧/秒或更好的效果。

我使用单个VBO来处理所有32个通道,每个通道具有10,000个顶点的空间。 VBO基本上被视为每个通道的环形缓冲区序列。当数据到达时,我根据所使用的时间尺度对其进行降采样。所以,基本上,它跟踪每个通道的最小值/最大值。当足够的数据已经接收到了单个像素列时,它会为每个通道设置下两个顶点,并呈现新的一帧。

我使用glMapBuffer()一次性访问数据,更新所有通道,然后使用glUnmapBuffer,再根据需要进行渲染。

我提前手动计算变换矩阵(使用非通用方式计算的正交变换,以减少乘法),顶点着色器如下:

#version 120

varying vec4 _outColor;

uniform vec4 _lBound=vec4(-1.0);
uniform vec4 _uBound=vec4(1.0);
uniform mat4 _xform=mat4(1.0);

attribute vec2 _inPos;
attribute vec4 _inColor;

void main()
{
    gl_Position=clamp(_xform*vec4(_inPos, 0.0, 1.0), _lBound, _uBound);
    _outColor=_inColor;
}

_lBound_uBound_xform 统一变量每个通道更新一次。 所以,每帧会更新32次。 clamp 用于将特定通道限制在屏幕上的一定范围内。

片段着色器简单地为:

#version 120

varying vec4 _outColor;

void main()
{
    gl_FragColor=_outColor;
}

屏幕上还有其他东西要渲染;例如,使用四边形和纹理集的通道标签;但是在gDEBugger中进行性能分析似乎表明,每帧占用时间最多的是线条渲染。

然而,对我来说,50000条线条似乎并不是一个可怕的数量。

所以,经过所有这些之后,问题是:有没有什么技巧可以加快画线的速度?我尝试将它们渲染到模板缓冲区,然后剪裁一个单独的四边形,但这样会更慢。我想过将线条绘制到纹理中,然后用纹理绘制一个四边形。但是,这似乎不具可扩展性,因为需要不断上传大型纹理,也不一定更快。我看到了一种将y值存储在单行纹理中的技术,但那似乎更像是内存优化而不是速度优化。


3
关闭此问题的任何人:这个问题完全符合在OpenGL标签下的StackOverflow的主题。 - datenwolf
1
啊。最大纹理尺寸是个问题。 - slakr007
1
不确定这是否有效,但我将尝试使用多个帧缓冲和glBlitFramebuffer()进行实验。基本上,将Framebuffer A中的渲染数据复制到Framebuffer B中,向右移动一个像素,渲染新行,并输出Framebuffer B。有点像FBO中的纹理想法,但可以避免纹理大小限制。 - slakr007
1
你发出了多少个OpenGL绘制调用来渲染所有的线条?加速OpenGL性能的好方法是在一个非常大的顶点缓冲区中构建线条几何体,然后将其全部提交到图形卡中进行一次绘制调用。你可以轻松预测所需的顶点缓冲区大小,因此这不应该是一个问题。通常的限制确实是绘制调用的数量,而不是实际的数据带宽。 - Jorma Rebane
1
我理解你的意思是基本上想要呈现像这样,只不过有32个轨道?如果是这样的话,就不要画线,而是为每个通道绘制一个四边形,并使用像素着色器。 - Damon
显示剩余15条评论
3个回答

2

映射VBO可能会使您的速度变慢,因为驱动程序可能需要将GPU与CPU同步。更高效的方法是将数据直接传输到GPU,这样CPU和GPU就可以更独立地运行。

  • 每次重新创建VBO时,请使用STATIC_DRAW进行创建
  • 如果需要映射数据,请勿将其映射为可读取状态(GL_WRITE_ONLY)

1
感谢大家。我最终选择在由渲染缓冲区支持的帧缓冲区之间进行位块传送。这种方法足够有效。许多人建议使用纹理,如果将来需要在数据后面绘制,我可能会采用这种方法。

0

如果你只是在滚动一条线图(GDI风格),只需在CPU上绘制新列并使用glTexSubImage2D更新纹理中的单个列。将其绘制为一对四边形,并更新st坐标以处理滚动/换行。

如果您需要始终更新所有行,请使用使用GL_DYNAMIC_DRAW创建的VBO,并使用glBufferSubData更新缓冲区。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接