2

I have no experience in writing a game and this week I'm trying writing a player of a music game's map (finally may become a game?) in QT; met problem and I think I need some help.

I want to show animation in 60 FPS on QOpenGLWidget. It's just some circles move in the widget, and CPU usage is low. But it looks laggy.

I enabled VSync by set the default surface format's swap behavior to doublebuffer/triplebuffer and has an interval of 1 which I think it means 60 FPS.
I implement the paintGL() method and draw the content by QPainter which QT's 2D drawing example does.
The step to compute the positions of each circle is placed outsides the paintGL method, and will run before paintGL is called.

This is the flow of the program runs:

  1. read the script
  2. start a timer
  3. post a event to call "tick" procedure
  4. "tick" procedure runs, and request update the window.
  5. paintGL runs, draw the frame
  6. before exit the paintGL method, a event to call "tick" is posted
  7. I think now it waits for VSync and swap buffer
  8. "tick" is called, go to step 4

the code:

class CgssFumenPlayer : public QOpenGLWidget
{
    Q_OBJECT

    ...
    bool Load();

public slots:
    void onTick();

protected:
    ....
    void paintGL() override;
    QElapsedTimer elapsedTimer;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QSurfaceFormat fmt;
    fmt.setSwapBehavior(QSurfaceFormat::TripleBuffer);
    fmt.setSwapInterval(1);
    QSurfaceFormat::setDefaultFormat(fmt);

    CgssFumenPlayer w;
    w.Load();
    w.setFixedSize(704, 396);
    w.show();

    return a.exec();
}

bool CgssFumenPlayer::Load()
{
    ....
    elapsedTimer.start();
    QMetaObject::invokeMethod(this, "onTick", Qt::QueuedConnection);
}

void CgssFumenPlayer::onTick()
{
    playerContext.currentTime = elapsedTimer.elapsed() / 1000.0;
    double f = playerContext.currentTime / (1.0 / 60);
    playerContext.currentTime = (int)f * (1.0 / 60);

    fumen->Compute(&playerContext);

    update();
}


void CgssFumenPlayer::paintGL()
{
    QPainter painter;
    painter.begin(this);

    painter.setRenderHint(QPainter::Antialiasing);

    painter.setWindow(0, 0, windowWidth, windowHeight);
    painter.fillRect(QRectF(0, 0, windowWidth, windowHeight), QColor().black());
    DrawButtons(painter);
    DrawIcons(painter, &playerContext);

    painter.end();

    QMetaObject::invokeMethod(this, "onTick", Qt::QueuedConnection);
}

I tried these ways to get more information:

  1. print current time by qDebug() each time entering the paintGL method.
    It seems sometimes frame is dropped; it looks very obvious, and he interval to last time it's called is more than 30ms.
  2. move the mouse in/out the window duration animation. It became laggy in higher possibility.
  3. collect the time cost in compute position, seems only a very short time.
  4. run this program in android, just the same or even more laggy.
  5. game which are much more complex runs fluently on my computer. I think the hardware is fast enough. ( i7-4800M, GTX 765M )
  6. restart the program again and again. it's now fluent (less or no frame-dropping happened), now laggy... I can't find the pattern.

Also, adjust the animation to 30 FPS cause it always looks laggy.

How can I deal with the problem?
(p.s. I hope it can run on android as well)

this is the full source code

https://github.com/sorayuki/CGSSPlayer/releases (cgssplayer.zip, not the source code)
(cgss-fumen.cpp makes no difference in this problem I think)

It can build in QTCreator (5.6) with no other dependency.

(for QT 5.5, it require to add

CONFIG += c++11

into the .pro file)

Sorayuki
  • 256
  • 2
  • 7
  • How did you draw buttons? Is there widgets? – Mykola Apr 09 '16 at 19:31
  • @Mykola No, both buttons and icons are basic shapes like circles, rectangles and triangles – Sorayuki Apr 10 '16 at 00:41
  • Strange, it must not cause that perormance downgrade? I suspect that, your performance problems may be caused by different reason than painting. In which way did you renew your OpenGL surface? – Mykola Apr 10 '16 at 08:39
  • @Mykola all contents are drawn via QPainter, and the details of swap buffers, etc. are down by QT. I don't know how it have down. I decide to have a try on SDL to see if the same problem happened. – Sorayuki Apr 10 '16 at 11:16
  • you can also try to connect your repaint slot to signal of QTimer timeout() for repaint your OpenGL surface for continuous time periods – Mykola Apr 10 '16 at 12:24
  • you can do like `connect(&m_Timer, SIGNAL(timeout()), this, SLOT(repaint())); m_Timer.start(1);` to repaint your surface every milisecond – Mykola Apr 10 '16 at 12:32

0 Answers0