2012-09-25 52 views
0

我正在尝试使用QGLWidget实现CoverFlow效果,问题在于纹理加载过程。Qt4/Opengl bindTexture在分离线程中

我有一个工作(QThread)从磁盘加载图像,主线程检查新加载的图像,如果它发现任何然后使用bindTexture将它们加载到QGLContext中。当纹理被绑定时,主线程被阻塞,所以我有一个fps的下降。

这样做的正确方法是什么?

回答

0

在主线程(单QGLWidget溶液)的结合:

  1. 决定最大纹理大小。例如,您可以根据最大可能的小部件大小来决定它。假设您知道该窗口小部件最多可以(大约)800x600像素,并且最大的可见屏幕上下可以看到30像素的边距,并且纵横比为1:2 - > 600-2 * 30 = 540 - >封面的最大尺寸为270x540,例如存储在m_maxCoverSize

  2. 在加载程序线程中将传入图像缩放到该大小。绑定较大的纹理并没有意义,并且它越大,上传到显卡所需的时间就越长。使用QImage::scaled(m_maxCoverSize, Qt::KeepAspectRatio)来缩放加载的图像并将其传递给主线程。

  3. 限制纹理的数量或更好地花费每帧绑定它们的时间。即记住你开始绑定纹理的时间(例如QTime bindStartTime;),并绑定每个纹理之后:

    if(bindStartTime.elapsed()> BIND_TIME_LIMIT) break;

BIND_TIME_LIMIT将取决于你想保留的帧频。但是,当然,如果绑定每一个纹理需要比BIND_TIME_LIMIT长得多的时间,你还没有解决任何问题。

尽管在较慢的机器/图形卡上加载图像,但您仍然可能会遇到帧率下降。其余的代码应该准备好与它一起生活(例如,使用实际的时间来驱动动画)。


替代溶液是在单独的线程绑定(使用第二隐形QGLWidget,见):在一个线程

2.纹理上传。

在处理大量需要显示的图像的应用程序中执行纹理上传可能非常有用,例如照片库应用程序。 Qt通过现有的bindTexture()API支持这一点。一个简单的方法是创建两个共享的QGLWidgets。一个是在主GUI线程中创建的,另一个是在纹理上传线程中创建的。上传线程中的小部件从不显示,它仅用于与主线程共享纹理。对于通过bindTexture()绑定的每个纹理,请通知主线程,以便它可以开始使用纹理。

+0

问题是纹理大小,我使用480x700图像(或多或少),但每个封面都有自己的大小(480x741,480x744,640x437),以保持封面的高宽比。我已经缩小了工作线程上的覆盖范围,但取决于显卡,封面尺寸必须缩放太多。 – louissmr

+0

为什么会出现这种问题? – artm

+0

对不起,我的评论不完整。 – louissmr

2

我发现bindTexture在Qt4的默认行为是extremelly慢:

bindTexture(image,target,format,LinearFilteringBindOption | InvertedYBindOption | MipmapBindOption) 

仅使用绑定选项LinearFilteringBindOption加快了很多东西,这是我当前的呼叫:

bindTexture(image, GL_TEXTURE_2D,GL_RGBA,QGLContext::LinearFilteringBindOption); 

的详细信息here:加载时间为3800x2850 bmp文件2秒降低到34毫秒

当然,如果你需要mipmapping,这不是解决方案。在这种情况下,我认为要走的路是像素缓冲区对象。

+0

因此,生成两个大小的纹理的非大功率的mipmap很慢,为什么您认为Pixel Buffers会有所作为? – artm

+0

PBO可以使用DMA将像素数据传输到图形卡,而不涉及CPU周期,不是吗?因此,在分离线程中使用PBO可以解决问题。 – louissmr

+0

任何图形驱动程序都可以优化上传PBO,以优化上传纹理。对这种尺寸的图片进行mipmap处理的问题不仅仅是转移,而是它将扩展到4096x4096并缩小12倍以形成mipmap。这些操作不会通过切换到PBO加快,事实上我不明白PBO如何与mipmapping完全相关。 – artm