2

对于科学任务,应在屏幕上显示具有稳定频率(最大 60 Hz)的闪烁区域。我尝试使用 Qt 5.6 实现稳定的刺激可视化。

根据这篇文和许多其他在线建议,我实现了三种不同的方法:继承自 QWindow 类、QOpenGLWindow 类和 QRasterWindow 类。我想获得 vsync 的优势并避免使用 QTimer。

可以显示闪烁区域。帧之间的稳定时间段也被测量为 16 到 17 毫秒。但是每隔几秒钟就会发现一些丢失的帧。可以非常清楚地看到,刺激没有稳定的可视化。相同的效果出现在所有三种方法上。

我是否正确地执行了我的代码或是否存在更好的解决方案?如果代码足以满足其目的,我是否必须假设这是硬件问题?那么,显示一个简单的闪烁区域有那么难吗?

非常感谢你帮助我!

作为示例,您可以在此处查看我的 QWindow 类代码:

Window::Window(QWindow *parent)
: m_context(0)
, m_paintDevice(0)
, m_bFlickerState(true){
setSurfaceType(QSurface::OpenGLSurface);

QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setSwapInterval(1);
this->setFormat(format);

m_context.setFormat(format);
m_context.create();}

被覆盖的事件函数调用的render()函数是:

void Window::render(){

//calculating exposed time between frames
m_t1 = QTime::currentTime();
int curDelta = m_t0.msecsTo(m_t1);
m_t0 = m_t1;
qDebug()<< curDelta;

m_context.makeCurrent(this);

if (!m_paintDevice)
    m_paintDevice = new QOpenGLPaintDevice;
if (m_paintDevice->size() != size())
    m_paintDevice->setSize(size());

QPainter p(m_paintDevice);
// draw using QPainter
if(m_bFlickerState){
    p.setBrush(Qt::white);
    p.drawRect(0,0,this->width(),this->height());
}
p.end();
m_bFlickerState = !m_bFlickerState;
m_context.swapBuffers(this);

// animate continuously: schedule an update
QCoreApplication::postEvent( this, new QEvent(QEvent::UpdateRequest));}
4

1 回答 1

3

我从 qt-forum 得到了一些专家的帮助。您可以在此处关注整个讨论。最后,结果是这样的:

“垂直同步很难 ;) 基本上它与系统固有的噪音作斗争。如果输出显示 16-17 毫秒,那就是问题所在。17 毫秒太多了。这就是你看到的跳过。

减少噪音的几件事:

  • 不要在渲染循环中进行 I/O!qDebug() 是 I/O,它可以阻止各种缓冲恶作剧。
  • 在调试器下测试 V-sync 是没有用的。调试会在您的应用程序中引入各种噪音。您应该在没有附加调试器的情况下在发布模式下测试 v-sync。
  • 如果可以的话,尽量不要使用信号/插槽/事件。它们可能很吵,即在paintGL 结束时手动调用update()。您以这种方式跳过了一些开销(不多,但每一位都很重要)。
  • 如果您只需要一个闪烁的屏幕,请避免使用 QPainter。它并不是很慢,但是进入它的 begin() 方法,看看它实际上做了多少。OpenGL 具有快速、专用的工具来用颜色填充缓冲区。你也可以使用它。

没有直接关系,但它会让你的代码更干净:

  • 使用 QElapsedTimer 而不是手动计算时间间隔。为什么要重新发明轮子。

应用这些位,我能够从您的示例中删除跳过。请注意,在某些情况下发生跳过,例如当您移动/调整窗口大小或操作系统/其他应用程序忙于做某事时。你无法控制它。"

于 2016-05-17T19:19:31.150 回答