Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. vsync: missing rendered frames
Forum Updated to NodeBB v4.3 + New Features

vsync: missing rendered frames

Scheduled Pinned Locked Moved Solved General and Desktop
framebuffervsync
12 Posts 3 Posters 6.2k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    kshegunov
    Moderators
    wrote on 16 May 2016, 11:58 last edited by kshegunov
    #2

    Hello,

    this->setFormat(format);
    

    this is the same as:

    setFormat(format)
    

    the context (this) is resolved automatically. This is not an error by any means, only a note.

    if (!m_paintDevice)
        m_paintDevice = new QOpenGLPaintDevice;
    

    this part I don't understand. Your QWindow (if Window is derived fromQWindow) is already a paint device, so why do you need another? Could you provide the class declaration as well? This also goes to Window::render, why do that. I'd derive from QOpenGLWindow and do the painting in a QOpenGLWindow::paintGL and implement the other needed protected methods as well - initializing the GL context and resize at least.

    QCoreApplication::postEvent( this, new QEvent(QEvent::UpdateRequest));
    

    This is the same as calling requestUpdate().

    Kind regards.

    Read and abide by the Qt Code of Conduct

    G 1 Reply Last reply 16 May 2016, 12:37
    0
    • K kshegunov
      16 May 2016, 11:58

      Hello,

      this->setFormat(format);
      

      this is the same as:

      setFormat(format)
      

      the context (this) is resolved automatically. This is not an error by any means, only a note.

      if (!m_paintDevice)
          m_paintDevice = new QOpenGLPaintDevice;
      

      this part I don't understand. Your QWindow (if Window is derived fromQWindow) is already a paint device, so why do you need another? Could you provide the class declaration as well? This also goes to Window::render, why do that. I'd derive from QOpenGLWindow and do the painting in a QOpenGLWindow::paintGL and implement the other needed protected methods as well - initializing the GL context and resize at least.

      QCoreApplication::postEvent( this, new QEvent(QEvent::UpdateRequest));
      

      This is the same as calling requestUpdate().

      Kind regards.

      G Offline
      G Offline
      geissenpeter
      wrote on 16 May 2016, 12:37 last edited by geissenpeter
      #3

      @kshegunov
      (I looked it up but I couldn't see the QWindow is a paint device but QOpenGLWindow does inherit from QPaintDeviceWindow class!)

      Thank you very much for the fast response!

      If you would choose QOpenGLWIndow, I provide you with the declaration and Implementation of my QOpenGLWindow approach. Like I said, I have the same problem here: frames are clearly missing!
      Also I can't display this class in Fullscreen-mode on another screen: This error message then is generated:

      QPainter::begin(): QOpenGLPaintDevice's context needs to be current
      QPainter::begin(): Returned false
      QPainter::end: Painter not active, aborted
      

      Here is now my full code:
      mainwindow.cpp:

      #include "mainwindow.h"
      #include "QPainter"
      
      #include <QOpenGLWindow>
      
      
      MainWindow::MainWindow(QOpenGLWindow *parent)
          : m_bFlickerState(true)
      {
          QSurfaceFormat format;
          format.setDepthBufferSize(24);
          format.setStencilBufferSize(8);
          format.setSwapInterval(1);
          setFormat(format);
          //continous update when frame was displayed
          connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
      }
      
      void MainWindow::resizeGL(int w, int h) {
      
      }
      
      void MainWindow::paintGL() {
          //calculating FPS
          m_t1 = QTime::currentTime();
          int curDelta = m_t0.msecsTo(m_t1);
          m_t0 = m_t1;
          qDebug()<< curDelta;
      //    QOpenGLFunctions *f = context()->functions();
      //    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      // issue some native OpenGL commands
          QPainter p(this);
          // draw using QPainter
          if(m_bFlickerState){
                  //f->glClearColor(1,1,1,1);
              p.fillRect(0,0,100,100,Qt::white);
          }
          else{
              //f->glClearColor(0,0,0,0);
              p.fillRect(0,0,100,100,Qt::black);
      
          }
          p.end();
          m_bFlickerState = !m_bFlickerState;
      }
      
      

      mainwindow.h:

      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      
      #include <QtCore>
      #include <QOpenGLPaintDevice>
      #include <QOpenGLFunctions>
      #include <QOpenGLWindow>
      
      class MainWindow : public QOpenGLWindow, protected QOpenGLFunctions
      {
          Q_OBJECT
      
      public:
          explicit MainWindow(QOpenGLWindow *parent = 0 );
          ~MainWindow();
      
      protected:
          void resizeGL(int w, int h);
          void paintGL();
      
      private:
          QTime   m_t0;
          QTime   m_t1;
          bool m_bFlickerState;
          QOpenGLPaintDevice *m_paintDevice;
          QTimer  timer;
      };
      
      #endif // MAINWINDOW_H
      

      main.cpp:

      #include "mainwindow.h"
      #include <QApplication>
      #include <QScreen>
      #include <QVBoxLayout>
      #include <QLayout>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          QScreen *screen = QGuiApplication::screens()[1];
      
          //setup the window
          MainWindow w;
          w.setScreen(screen);
          w.showFullScreen();
      
          return a.exec();
      }
      
      K 1 Reply Last reply 16 May 2016, 17:16
      0
      • G geissenpeter
        16 May 2016, 12:37

        @kshegunov
        (I looked it up but I couldn't see the QWindow is a paint device but QOpenGLWindow does inherit from QPaintDeviceWindow class!)

        Thank you very much for the fast response!

        If you would choose QOpenGLWIndow, I provide you with the declaration and Implementation of my QOpenGLWindow approach. Like I said, I have the same problem here: frames are clearly missing!
        Also I can't display this class in Fullscreen-mode on another screen: This error message then is generated:

        QPainter::begin(): QOpenGLPaintDevice's context needs to be current
        QPainter::begin(): Returned false
        QPainter::end: Painter not active, aborted
        

        Here is now my full code:
        mainwindow.cpp:

        #include "mainwindow.h"
        #include "QPainter"
        
        #include <QOpenGLWindow>
        
        
        MainWindow::MainWindow(QOpenGLWindow *parent)
            : m_bFlickerState(true)
        {
            QSurfaceFormat format;
            format.setDepthBufferSize(24);
            format.setStencilBufferSize(8);
            format.setSwapInterval(1);
            setFormat(format);
            //continous update when frame was displayed
            connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
        }
        
        void MainWindow::resizeGL(int w, int h) {
        
        }
        
        void MainWindow::paintGL() {
            //calculating FPS
            m_t1 = QTime::currentTime();
            int curDelta = m_t0.msecsTo(m_t1);
            m_t0 = m_t1;
            qDebug()<< curDelta;
        //    QOpenGLFunctions *f = context()->functions();
        //    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // issue some native OpenGL commands
            QPainter p(this);
            // draw using QPainter
            if(m_bFlickerState){
                    //f->glClearColor(1,1,1,1);
                p.fillRect(0,0,100,100,Qt::white);
            }
            else{
                //f->glClearColor(0,0,0,0);
                p.fillRect(0,0,100,100,Qt::black);
        
            }
            p.end();
            m_bFlickerState = !m_bFlickerState;
        }
        
        

        mainwindow.h:

        #ifndef MAINWINDOW_H
        #define MAINWINDOW_H
        
        #include <QtCore>
        #include <QOpenGLPaintDevice>
        #include <QOpenGLFunctions>
        #include <QOpenGLWindow>
        
        class MainWindow : public QOpenGLWindow, protected QOpenGLFunctions
        {
            Q_OBJECT
        
        public:
            explicit MainWindow(QOpenGLWindow *parent = 0 );
            ~MainWindow();
        
        protected:
            void resizeGL(int w, int h);
            void paintGL();
        
        private:
            QTime   m_t0;
            QTime   m_t1;
            bool m_bFlickerState;
            QOpenGLPaintDevice *m_paintDevice;
            QTimer  timer;
        };
        
        #endif // MAINWINDOW_H
        

        main.cpp:

        #include "mainwindow.h"
        #include <QApplication>
        #include <QScreen>
        #include <QVBoxLayout>
        #include <QLayout>
        
        int main(int argc, char *argv[])
        {
            QApplication a(argc, argv);
        
            QScreen *screen = QGuiApplication::screens()[1];
        
            //setup the window
            MainWindow w;
            w.setScreen(screen);
            w.showFullScreen();
        
            return a.exec();
        }
        
        K Offline
        K Offline
        kshegunov
        Moderators
        wrote on 16 May 2016, 17:16 last edited by
        #4

        @geissenpeter said:

        I looked it up but I couldn't see the QWindow is a paint device but QOpenGLWindow does inherit from QPaintDeviceWindow class!

        Yes indeed, that's a mistake on my part.

        I provide you with the declaration and Implementation of my QOpenGLWindow approach

        It looks good to me.

        Like I said, I have the same problem here: frames are clearly missing!

        The only thing I could think of is that the paint events might be getting compressed and some of the updates are skipped. Perhaps you could attach an additional receiver for the frameSwapped signal and see if that's the case - you'd expect to see update request and then a repaint and then another update request etc. If that's not the case, then this might very well be the reason.

        Kind regards.

        Read and abide by the Qt Code of Conduct

        G 1 Reply Last reply 16 May 2016, 20:26
        0
        • K kshegunov
          16 May 2016, 17:16

          @geissenpeter said:

          I looked it up but I couldn't see the QWindow is a paint device but QOpenGLWindow does inherit from QPaintDeviceWindow class!

          Yes indeed, that's a mistake on my part.

          I provide you with the declaration and Implementation of my QOpenGLWindow approach

          It looks good to me.

          Like I said, I have the same problem here: frames are clearly missing!

          The only thing I could think of is that the paint events might be getting compressed and some of the updates are skipped. Perhaps you could attach an additional receiver for the frameSwapped signal and see if that's the case - you'd expect to see update request and then a repaint and then another update request etc. If that's not the case, then this might very well be the reason.

          Kind regards.

          G Offline
          G Offline
          geissenpeter
          wrote on 16 May 2016, 20:26 last edited by
          #5

          @kshegunov said:

          some of the updates are skipped

          I think this can't be, because the time measured between the update calls is always about 16 to 18 ms. Could a problem with the frame buffer occur instead?

          Also I have a problem with the QPainter: When my class is displayed in Fullscreen mode (like shown in the code above) then this error is generated. I have looked it up, but haven't found a solution yet

          QPainter::begin(): QOpenGLPaintDevice's context needs to be current
          QPainter::begin(): Returned false
          QPainter::end: Painter not active, aborted
          

          thank you for your fast response!

          K 1 Reply Last reply 16 May 2016, 22:23
          0
          • G geissenpeter
            16 May 2016, 20:26

            @kshegunov said:

            some of the updates are skipped

            I think this can't be, because the time measured between the update calls is always about 16 to 18 ms. Could a problem with the frame buffer occur instead?

            Also I have a problem with the QPainter: When my class is displayed in Fullscreen mode (like shown in the code above) then this error is generated. I have looked it up, but haven't found a solution yet

            QPainter::begin(): QOpenGLPaintDevice's context needs to be current
            QPainter::begin(): Returned false
            QPainter::end: Painter not active, aborted
            

            thank you for your fast response!

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 16 May 2016, 22:23 last edited by
            #6

            @geissenpeter

            I think this can't be, because the time measured between the update calls is always about 16 to 18 ms.

            This is of no consequence. Look here: http://doc.qt.io/qt-5/eventsandfilters.html#sending-events
            update() posts an event on the queue for later processing and this event is subject to being compressed on occasion. I don't know if you can force the repaint however.

            Could a problem with the frame buffer occur instead?

            I'm by no means an expert, but it seems doubtful.

            Also I have a problem with the QPainter: When my class is displayed in Fullscreen mode (like shown in the code above) then this error is generated. I have looked it up, but haven't found a solution yet

            Possibly you're getting a paint event when the windows is not exposed. But I'm just guessing here.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            1
            • G Offline
              G Offline
              geissenpeter
              wrote on 17 May 2016, 10:53 last edited by geissenpeter
              #7

              @kshegunov
              I realized your approach: Every frameSwapped() signal is following an update request. So this code seems to do its job. I don't know what possible errors I could look for anymore...
              Could other solutions exist for this (in my opinion) quite simple task?

              K 1 Reply Last reply 17 May 2016, 10:59
              0
              • G geissenpeter
                17 May 2016, 10:53

                @kshegunov
                I realized your approach: Every frameSwapped() signal is following an update request. So this code seems to do its job. I don't know what possible errors I could look for anymore...
                Could other solutions exist for this (in my opinion) quite simple task?

                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 17 May 2016, 10:59 last edited by
                #8

                @geissenpeter

                I don't know what possible errors I could look for anymore...

                Sadly, I don't know either.

                Could other solutions exist for this (in my opinion) quite simple task?

                I'm sure there are other solutions, but I don't know of any better way. Perhaps one of our more GL-versed members, like @Chris-Kawa, might take a look and suggest something.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                0
                • C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 17 May 2016, 18:19 last edited by Chris Kawa
                  #9

                  V-sync is hard ;) Basically it's fighting with the inherent noisiness of the system. If the output shows 16-17 ms then that's the problem. 17 ms is too much. That's the skipping you see.

                  Couple of things to reduce that noise:

                  • Don't do I/O in the render loop! qDebug()is I/O and it can block on all kinds of buffering shenanigans.
                  • Testing V-sync under a debugger is useless. Debugging introduces all kinds of noise into your app. You should be testing v-sync in Release mode without debugger attached.
                  • try not to use signals/slots/events if you can help it. They can be noisy i.e. call update() manually at the end of paintGL. You skip some overhead this way (not much but every bit counts).
                  • If all you need is a flickering screen avoid QPainter. It's not exactly slow, but drop into the begin() method of it and see how much it actually does. OpenGL has fast, dedicated facilities to fill the buffer with a color. You might as well use it.

                  Not directly related, but it will make your code cleaner:

                  • Use QElapsedTimer instead of manually calculating time intervals. Why re-invent the wheel.

                  Applying these bits I was able to remove the skipping from your example. Note that the skipping will occur in some circumstances, e.g. when you move/resize the window or when OS/other apps are busy doing something . You have no control over that.

                  Here are the modified code bits:

                  //mainwindow.h
                      ...
                      QElapsedTimer  m_timer;
                  };
                  
                  //mainwindow.cpp
                  MainWindow::MainWindow(QOpenGLWindow *parent) : m_bFlickerState(true)
                  {
                      QSurfaceFormat format;
                      format.setDepthBufferSize(24);
                      format.setStencilBufferSize(8);
                      format.setSwapInterval(1);
                      setFormat(format);
                      m_timer.start(); //note that it doesn't really start any timers, just records current time
                  }
                  
                  void MainWindow::paintGL()
                  {
                      int ms_elapsed = timer.restart(); //you can store it somewhere to analyze later 
                  
                      auto f = context()->functions();
                      if(m_bFlickerState)
                          f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
                      else
                          f->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
                  
                      f->glClear(GL_COLOR_BUFFER_BIT);
                  
                      m_bFlickerState = !m_bFlickerState;
                      update(); //schedules next update directly, without going through signal dispatching
                  }
                  
                  K 1 Reply Last reply 17 May 2016, 18:31
                  1
                  • C Chris Kawa
                    17 May 2016, 18:19

                    V-sync is hard ;) Basically it's fighting with the inherent noisiness of the system. If the output shows 16-17 ms then that's the problem. 17 ms is too much. That's the skipping you see.

                    Couple of things to reduce that noise:

                    • Don't do I/O in the render loop! qDebug()is I/O and it can block on all kinds of buffering shenanigans.
                    • Testing V-sync under a debugger is useless. Debugging introduces all kinds of noise into your app. You should be testing v-sync in Release mode without debugger attached.
                    • try not to use signals/slots/events if you can help it. They can be noisy i.e. call update() manually at the end of paintGL. You skip some overhead this way (not much but every bit counts).
                    • If all you need is a flickering screen avoid QPainter. It's not exactly slow, but drop into the begin() method of it and see how much it actually does. OpenGL has fast, dedicated facilities to fill the buffer with a color. You might as well use it.

                    Not directly related, but it will make your code cleaner:

                    • Use QElapsedTimer instead of manually calculating time intervals. Why re-invent the wheel.

                    Applying these bits I was able to remove the skipping from your example. Note that the skipping will occur in some circumstances, e.g. when you move/resize the window or when OS/other apps are busy doing something . You have no control over that.

                    Here are the modified code bits:

                    //mainwindow.h
                        ...
                        QElapsedTimer  m_timer;
                    };
                    
                    //mainwindow.cpp
                    MainWindow::MainWindow(QOpenGLWindow *parent) : m_bFlickerState(true)
                    {
                        QSurfaceFormat format;
                        format.setDepthBufferSize(24);
                        format.setStencilBufferSize(8);
                        format.setSwapInterval(1);
                        setFormat(format);
                        m_timer.start(); //note that it doesn't really start any timers, just records current time
                    }
                    
                    void MainWindow::paintGL()
                    {
                        int ms_elapsed = timer.restart(); //you can store it somewhere to analyze later 
                    
                        auto f = context()->functions();
                        if(m_bFlickerState)
                            f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
                        else
                            f->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
                    
                        f->glClear(GL_COLOR_BUFFER_BIT);
                    
                        m_bFlickerState = !m_bFlickerState;
                        update(); //schedules next update directly, without going through signal dispatching
                    }
                    
                    K Offline
                    K Offline
                    kshegunov
                    Moderators
                    wrote on 17 May 2016, 18:31 last edited by
                    #10

                    @Chris-Kawa
                    Chris, would running the rendering in a dedicated thread without event loop that forces rendering on a regular interval (for example a QThread subclass) be beneficial in this case? Or are the waiting routines (i.e. QThread::msleep/QThread::usleep/QSemaphore::tryAcquire) not precise enough for such things?

                    Again I'm just curious, so don't answer if you don't have the time. :)

                    Read and abide by the Qt Code of Conduct

                    1 Reply Last reply
                    1
                    • C Offline
                      C Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on 17 May 2016, 18:45 last edited by
                      #11

                      @kshegunov
                      Any kind of sleeping/timer is no good for frame-perfect rendering. It doesn't matter in which thread you do it. There's just no solid way to synchronize these with the refresh rate.
                      You can't for example calculate "oh I rendered in 7ms so I have ~9.66ms left till the v-sync so I'll sleep for 9ms". That will miss most of the time. If any of these primitives is late even a microsecond for the v-sync it's all lost.
                      The only way to have any control over it is start drawing as soon as the v-sync is done and wait for the next one. Basically QOpenGLContext::swapBuffers is your only tool for that (done implicitly when you exit paintGL).

                      K 1 Reply Last reply 17 May 2016, 18:47
                      1
                      • C Chris Kawa
                        17 May 2016, 18:45

                        @kshegunov
                        Any kind of sleeping/timer is no good for frame-perfect rendering. It doesn't matter in which thread you do it. There's just no solid way to synchronize these with the refresh rate.
                        You can't for example calculate "oh I rendered in 7ms so I have ~9.66ms left till the v-sync so I'll sleep for 9ms". That will miss most of the time. If any of these primitives is late even a microsecond for the v-sync it's all lost.
                        The only way to have any control over it is start drawing as soon as the v-sync is done and wait for the next one. Basically QOpenGLContext::swapBuffers is your only tool for that (done implicitly when you exit paintGL).

                        K Offline
                        K Offline
                        kshegunov
                        Moderators
                        wrote on 17 May 2016, 18:47 last edited by
                        #12

                        @Chris-Kawa
                        Fair enough. Thanks for taking the time.

                        Cheers!

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        0

                        11/12

                        17 May 2016, 18:45

                        • Login

                        • Login or register to search.
                        11 out of 12
                        • First post
                          11/12
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved