【发布时间】:2012-09-25 09:07:53
【问题描述】:
我正在尝试使用 QGLWidget 实现类似 CoverFlow 的效果,问题是纹理加载过程。
我有一个工作线程(QThread)用于从磁盘加载图像,主线程检查新加载的图像,如果找到,则使用 bindTexture 将它们加载到 QGLContext 中。在绑定纹理时,主线程被阻塞,所以我有一个 fps 下降。
这样做的正确方法是什么?
【问题讨论】:
我正在尝试使用 QGLWidget 实现类似 CoverFlow 的效果,问题是纹理加载过程。
我有一个工作线程(QThread)用于从磁盘加载图像,主线程检查新加载的图像,如果找到,则使用 bindTexture 将它们加载到 QGLContext 中。在绑定纹理时,主线程被阻塞,所以我有一个 fps 下降。
这样做的正确方法是什么?
【问题讨论】:
我发现Qt4中bindTexture的默认行为非常慢:
bindTexture(image,target,format,LinearFilteringBindOption | InvertedYBindOption | MipmapBindOption)
在绑定选项中仅使用 LinearFilteringBindOption 可以大大加快速度,这是我当前的调用:
bindTexture(image, GL_TEXTURE_2D,GL_RGBA,QGLContext::LinearFilteringBindOption);
更多信息here:3800x2850 bmp 文件的加载时间从 2 秒减少到 34 毫秒
当然,如果您需要 mipmapping,这不是解决方案。在这种情况下,我认为要走的路是 Pixel Buffer Objects。
【讨论】:
在主线程中绑定(单QGLWidget解决方案):
决定最大纹理大小。例如,您可以根据最大可能的小部件大小来决定它。假设您知道小部件最多(大约)800x600 像素,并且可见的最大封面具有上下 30 像素的边距和 1:2 纵横比 -> 600-2*30 = 540 -> 封面的最大尺寸是270x540,例如存储在m_maxCoverSize。
在加载器线程中将传入的图像缩放到该大小。绑定更大的贴图是没有意义的,越大的贴图上传到显卡的时间就越长。使用QImage::scaled(m_maxCoverSize, Qt::KeepAspectRatio) 缩放加载的图像并将其传递给主线程。
限制纹理的数量或花费在每帧绑定它们的更好时间。 IE。记住你开始绑定纹理的时间(例如QTime bindStartTime;)和绑定每个纹理之后:
if (bindStartTime.elapsed() > BIND_TIME_LIMIT) 休息;
BIND_TIME_LIMIT 取决于您要保持的帧速率。但是当然,如果绑定每个纹理比BIND_TIME_LIMIT 花费的时间要长得多,那么您还没有解决任何问题。
尽管在速度较慢的机器/显卡上加载图像,您仍可能会遇到帧率下降的情况。其余的代码应该准备好接受它(例如,使用实际时间来驱动动画)。
替代解决方案是在单独的线程中绑定(使用第二个不可见的QGLWidget,参见documentation):
2.纹理在线程中上传。在线程中上传纹理对于处理需要显示的大量图像的应用程序(例如照片库应用程序)可能非常有用。这在 Qt 中通过现有的 bindTexture() API 得到支持。一个简单的方法是创建两个共享的 QGLWidgets。一个在主 GUI 线程中成为当前线程,而另一个在纹理上传线程中成为当前线程。上传线程中的小部件从不显示,它仅用于与主线程共享纹理。对于通过 bindTexture() 绑定的每个纹理,通知主线程以便它可以开始使用该纹理。
【讨论】: