我的目标是使用OpenGL以最高可能的帧速率在4K中传输单通道图像。这意味着我有1个纹理,我将经常使用新内容进行更新。
至于现在,我正在使用PBO来利用GPU上的异步纹理下载。代码基本上是:
// EACH TIME TEXTURE NEEDS UPDATE
const int pboSize = 4096 * 4096 * 4;
// Bind PBO to texture data source
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboHandle);
// Discard data in PBO - already sent to GPU
glBufferData(GL_PIXEL_UNPACK_BUFFER, pboSize, NULL, GL_STREAM_DRAW);
// Map buffer to client memory
float* data = static_cast<float*>(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
if (data) {
std::valarray<IMG_PRECISION>& newImageContent = myImageArray[currentImage];
// This seems too slow
std::memcpy(data, &newImageContent[0], newImageContent.size() * sizeof(IMG_PRECISION));
} else {
std::err << "Failed to map PBO to client memory";
}
// Release the mapped buffer
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
const glm::uvec3& dimensions = _texture->dimensions();
_texture->bind();
// Send async to GPU
glTexSubImage2D(
_texture->type(),
0,
0,
0,
GLsizei(dimensions.x),
GLsizei(dimensions.y),
GLint(_texture->format()),
_texture->dataType(),
nullptr
);
// Set back to normal texture data source
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
这比仅使用没有PBO的glTexSubImage()
更快,但速度不够快。瓶颈似乎是std::memcpy
,每帧约0.0211s
。我使用glTexImage2D()
作为内部格式,GL_R16F
作为格式,GL_RED
作为数据类型,使用GL_FLOAT
创建纹理。
然而,当纹理非常接近相机时,我真的只需要4K分辨率,但是在运行时生成mipmap似乎太慢了。手动预先计算它们也会非常烦人,因为我已经在系统RAM中有很多这些图像,在CPU端加载mipmap和普通图像会太慢。
我现在还能想到任何其他多分辨率方法,或者是使用某些视频编解码器(例如ffmpeg
)获得合适帧速率的唯一方法吗?当我从光盘加载它们时,我在这些图像中有很多元数据,理想情况下要避免这种情况。
修改: Target是使用OpenGL 4.5的跨平台桌面环境
答案 0 :(得分:1)
你想避免阻止。有一个线程上传,而另一个线程绘制。你应该有多个缓冲区。
这个网站上有一个很好的例子可以ping两个缓冲区。 http://www.songho.ca/opengl/gl_pbo.html
这里有一种更高级的多线程方法。
http://on-demand.gputechconf.com/gtc/2012/presentations/S0356-GTC2012-Texture-Transfers.pdf
关于Mipmap:如果您不需要它们,请不要生成它们。只上传0级。
其他建议:
答案 1 :(得分:0)
您是否尝试过使用2个或更多渲染目标?从另一个复制时渲染为一个 - 基本上是页面翻转,但相反。否则GPU将失速。另外,您在GPUView或您最喜欢的性能分析工具中看到了什么?您(通常)在渲染到同一缓冲区时无法复制到主机。
另外,re:mipmap。您可以根据相机距离切换目标,选择在适当的位置渲染到较低分辨率的版本。它与生成mips不同,因为你仍然只处理一个版本的纹理,而不是整个金字塔。
有关您的目标平台和用例的更多信息会很有帮助。有许多特定于供应商的库和扩展可专门为流式传输而设计。