Qt:vsync - 缺少渲染帧
Qt: vsync - missing rendered frames
对于科学任务,屏幕上应显示频率稳定(最大 60 Hz)的闪烁区域。我尝试使用 Qt 5.6 实现稳定的刺激可视化。
根据这个blog entry和许多其他在线建议,我实现了三种不同的方法:继承自QWindow Class、QOpenGLWindow Class 和QRasterWindow Class。我想获得 vsync 的优势并避免使用 QTimer。
可以显示闪烁区域。帧之间的稳定时间段也被测量为 16 到 17 毫秒。
但是每隔几秒就会发现一些丢失的帧。可以很清楚地看到,没有刺激的稳定可视化。所有三种方法都会产生相同的效果。
我是否正确执行了我的代码,或者是否存在更好的解决方案?如果代码足以满足其目的,我是否必须假设这是硬件问题?显示一个简单的闪烁区域有那么难吗?
非常感谢您对我的帮助!
例如,您可以在此处查看我的 QWindow Class 代码:
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));}
我得到了 qt-forum 一些专家的帮助。您可以关注整个讨论 here。结果是这样的:
”
垂直同步很难 ;) 基本上它是在与系统固有的噪音作斗争。如果输出显示 16-17 毫秒,那就是问题所在。 17 毫秒太多了。这就是你看到的跳过。
有几件事可以减少噪音:
- 不要在渲染循环中执行 I/O! qDebug() 是 I/O,它可以阻止各种缓冲恶作剧。
- 在调试器下测试垂直同步是没有用的。调试会将各种噪音引入您的应用程序。您应该在没有附加调试器的情况下在发布模式下测试垂直同步。
- 如果可以的话尽量不要使用signals/slots/events。它们可能很嘈杂,即在 paintGL 结束时手动调用 update()。您可以通过这种方式跳过一些开销(不多但每一位都很重要)。
- 如果您只需要闪烁的屏幕,请避免使用 QPainter。它并不完全慢,但进入它的 begin() 方法并查看它实际做了多少。 OpenGL 有快速、专用的工具来用颜色填充缓冲区。你不妨用一下。
没有直接关系,但它会使您的代码更清晰:
- 使用 QElapsedTimer 而不是手动计算时间间隔。为什么要重新发明轮子。
应用这些位,我能够从您的示例中删除跳过。请注意,跳过 会 在某些情况下发生,例如当您 move/resize window 或 OS/other 应用忙于做某事时。你无法控制它。
“
对于科学任务,屏幕上应显示频率稳定(最大 60 Hz)的闪烁区域。我尝试使用 Qt 5.6 实现稳定的刺激可视化。
根据这个blog entry和许多其他在线建议,我实现了三种不同的方法:继承自QWindow Class、QOpenGLWindow Class 和QRasterWindow Class。我想获得 vsync 的优势并避免使用 QTimer。
可以显示闪烁区域。帧之间的稳定时间段也被测量为 16 到 17 毫秒。 但是每隔几秒就会发现一些丢失的帧。可以很清楚地看到,没有刺激的稳定可视化。所有三种方法都会产生相同的效果。
我是否正确执行了我的代码,或者是否存在更好的解决方案?如果代码足以满足其目的,我是否必须假设这是硬件问题?显示一个简单的闪烁区域有那么难吗?
非常感谢您对我的帮助!
例如,您可以在此处查看我的 QWindow Class 代码:
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));}
我得到了 qt-forum 一些专家的帮助。您可以关注整个讨论 here。结果是这样的:
” 垂直同步很难 ;) 基本上它是在与系统固有的噪音作斗争。如果输出显示 16-17 毫秒,那就是问题所在。 17 毫秒太多了。这就是你看到的跳过。
有几件事可以减少噪音:
- 不要在渲染循环中执行 I/O! qDebug() 是 I/O,它可以阻止各种缓冲恶作剧。
- 在调试器下测试垂直同步是没有用的。调试会将各种噪音引入您的应用程序。您应该在没有附加调试器的情况下在发布模式下测试垂直同步。
- 如果可以的话尽量不要使用signals/slots/events。它们可能很嘈杂,即在 paintGL 结束时手动调用 update()。您可以通过这种方式跳过一些开销(不多但每一位都很重要)。
- 如果您只需要闪烁的屏幕,请避免使用 QPainter。它并不完全慢,但进入它的 begin() 方法并查看它实际做了多少。 OpenGL 有快速、专用的工具来用颜色填充缓冲区。你不妨用一下。
没有直接关系,但它会使您的代码更清晰:
- 使用 QElapsedTimer 而不是手动计算时间间隔。为什么要重新发明轮子。
应用这些位,我能够从您的示例中删除跳过。请注意,跳过 会 在某些情况下发生,例如当您 move/resize window 或 OS/other 应用忙于做某事时。你无法控制它。 “