0

How to bufferswap between two textures, to achieve drawing on the next VBL?

Currently I'm using two QPixmap which I set to a QLabel. This results in a unstable delay between 18ms and 45ms measured against parallelport, using a 85Hz CRT monitor (no buffers there which add any delays).

My goal would be to issue a flip command which leads to bufferswap on the next VBL (Vertical Blanking Interrupt).

What I have tried now: I setup a full screen window in the main.cpp (different problem: can't open a window at runtime) and initialize there two QPixmaps.

With a signal created by a timer I trigger the change:

myVisualStimuli = new VisualStimuli(0);
    //Start Timer for Stimulus Presenation
    StimulusThread = new QThread(this);
    StimulusTimer = new QTimer(0);
    StimulusTimer->setInterval(500);
    StimulusTimer->moveToThread(StimulusThread);
    myVisualStimuli->moveToThread(StimulusThread);

    myVisualStimuli->connect(StimulusTimer, SIGNAL(timeout()), SLOT(SetStimulus()), Qt::DirectConnection);
    this->connect(StimulusTimer, SIGNAL(timeout()), SLOT(SetStimulus()), Qt::DirectConnection);

    // Make sure the timer gets started from m_thread.
    StimulusTimer->connect(StimulusThread, SIGNAL(started()), SLOT(start()));
    StimulusThread->start();

And the Drawing: Header / Code

#ifndef VISUALSTIMULI_H
#define VISUALSTIMULI_H

#include <QtCore>
#include <QObject>
#include <QThread>
#include <QLabel>

class VisualStimuli: public QThread
{
    Q_OBJECT
public:
    explicit  VisualStimuli(QObject *parent = 0);
    int Setup();
    bool StimulusToggle = true;

    QRect *screenres;
    QLabel* StimulusWindow;

    QPixmap *pix1;
    QPixmap *pix2;
public slots:
    void SetStimulus();
private:
protected:
    void run();

};

#endif // VISUALSTIMULI_H


#include "visualstimuli.h"
VisualStimuli::VisualStimuli(QObject *parent) : QThread(parent)
{

}

int VisualStimuli::Setup()
{
    return 0;
}

void VisualStimuli::SetStimulus()
{
    start();

}

void VisualStimuli::run()
{
    if(StimulusToggle){
        this->StimulusWindow->setPixmap(*pix1);
        StimulusToggle=false;
    }else{
        this->StimulusWindow->setPixmap(*pix2);
        StimulusToggle=true;
    }
}

Due to Hardware I'm bound to Windows 10 64Bit, so I 'don’t mind to use any platform dependent code/library for the stimulus presentation.

dbrue
  • 81
  • 7
  • 1
    I'm not sure whether Qt is the best choice for your specific task. This library is very portable and customizable but definitely not the fastest concerning refresh rates. (I don't want to blame Qt - for a usual GUI, this is fully acceptable considering that human perception rate is round about 100 ms (and the average patience of users even longer)). For high-performance rendering, I would recommend OpenGL. The synchronization with vertical blank is an OpenGL extension for which you have good chances for support in your OpenGL driver. (I know that NVidia supports this.) – Scheff's Cat Mar 07 '18 at 15:29
  • 2
    Actually, Qt has OpenGL support built-in. Thus, this could be a possible option to use [`QOpenGLWidget`](http://doc.qt.io/qt-5/qopenglwidget.html) with [`QOpenGLFunctions`](http://doc.qt.io/qt-5/qopenglfunctions.html) instead of `QLabel`s with `QPixmap`s. However, I'm not quite sure whether the `QLabel`/`QPixmap` rendering is the bottleneck. I'm afraid the general event processing of Qt could be a problem as well. Nevertheless, the OpenGL VSync ext. to solve the VBL issue is probably solvable with `QOpenGL...`. May be, it even can be activated/forced in the Windows Graphics Driver settings. – Scheff's Cat Mar 07 '18 at 15:35
  • I only need very basic textures, and the are almost anytime constant therefore the rendering should not be the problem. If I'm switching to OpenGL which is completly new to me should I use QOpenGLWidget, GLFW or what else? – dbrue Mar 07 '18 at 16:03
  • If I use OpenGL and let the NVidia driver handle the synchronization to the vertical blank, can you get back a timestamp when the actual swap occured? – dbrue Mar 07 '18 at 16:07
  • `QOpenGLWidget` for the widget and `QOpenGLFunctions` for the OpenGL binding. GLFW is not needed (except you decide to skip Qt at all). There should be many simple examples to find with google, some in the Qt doc., (a few published by me in SO). – Scheff's Cat Mar 07 '18 at 16:09
  • Timestamp of last VBL? Phew... never thought about this... I recently researched/read about time measurement of OpenGL rendering (which is usually done in the GPU and not easily retrieved on CPU side). This might be worth a research... – Scheff's Cat Mar 07 '18 at 16:12
  • For my luck, the resp. browser tabs are still open: [SO: OpenGL, measuring rendering time on gpuOpenGL, measuring rendering time on gpu](https://stackoverflow.com/q/30104982/7478597) and [Khronos: How to measure timing in OpenGL?](https://www.opengl.org/discussion_boards/showthread.php/171554-How-to-measure-timing-in-OpenGL). My google search terms were 'get opengl rendering time' and there were a lot more hits... – Scheff's Cat Mar 07 '18 at 16:17
  • I mentioned the OpenGL rendering time measurement because it is usually connected to the issue, to detect done rendering on CPU side (this is probably related to back/front buffer swap which in turn should be synchronized to the VBL if VSync is enabled). This said with a grain of salt, as I do not have personal experiences about this... – Scheff's Cat Mar 07 '18 at 16:23

0 Answers0