7

I can't seem to get Qt5 to update my scene at a meaningful rate. My scene is a 512x512 textured rectangle. The rate I am getting is about 1 frame per second (!).

In my constructor

   aTimer.setSingleShot(false);
   aTimer->setTimerType(Qt::PreciseTimer);
   connect(&aTimer,SIGNAL(timeout()),this,SLOT(animate()));
   aTimer.start(50);
   setAutoFillBackground(false);

and

void GLWidget::animate()
{
//Logic for every time step
updateGL();
}

Is there a way to set priority? Am I doing something totally, wrong? Is there some sort of intrinsic update limitation in Qt, and its certainly not on the order of 1 FPS? My theory is that Qt is ignoring my calls to actually update the screen.

I have tried

  1. to insert a QCoreApplication::processEvents(); but this doesn't help
  2. Call update on the parent widget, and run the timer from the parent
  3. Create a function called animate() that ran forever{} and call update from within it
  4. The wigglywidget example seems to work, which hints to me that QT OpenGL is somehow collapsing frames, ignoring my calls to update. Is there a heuristic that controls this?

Minimal Code to Recreate

(The version is a bit different, being modeled after the wigglywidget class, but has the exact same problem)

git clone https://bitbucket.org/FunFarm/qtcapturesoftware.git

glwidget.h

/****************************************************************************/

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>
#include <QtOpenGL/qglshaderprogram.h>
#include <QTimer>
#include <math.h>
#include "time.h"
#include <assert.h>
#include <random>

class GLWidget : public QGLWidget
{
    Q_OBJECT

public:
    GLWidget(QWidget *parent = 0);
    ~GLWidget();
    void addNoise();
protected:
    void initializeGL();
    void paintGL();
    void timerEvent(QTimerEvent *event);
    void resizeGL(int width, int height);
private:
    QBasicTimer timer;
    QPoint lastPos;
    GLuint textures[6];
    QVector<QVector2D> vertices;
    QVector<QVector2D> texCoords;
    QGLShaderProgram program1;
    int vertexAttr1;
    int vertexTexr1;
    //
    int heightGL;
    int widthGL;
    //
    GLubyte* noise;
    //
    QTimer* aTimer;
    //
};
#endif

glwidget.cpp

#include <QtWidgets>
#include <QtOpenGL>
#include "glwidget.h"


#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
    setAutoFillBackground(false);
    aTimer = new QTimer();
    timer.start(30, this); // 30 fps?
}
void GLWidget::timerEvent(QTimerEvent *event)
{
    addNoise();
    update();// Doesn't matter which update function I call, this is the one from the wigglywidget example
}
 GLWidget::~GLWidget(){}
void GLWidget::initializeGL()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_MULTISAMPLE);
    static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
    QGLShader *vshader1 = new QGLShader(QGLShader::Vertex, this);
    const char *vsrc1 =
            "attribute vec2 coord2d;   \n"
            "attribute mediump vec4 texCoord;\n"
            "varying mediump vec4 texc;\n"
            "void main()                  \n"
            "{                            \n"
            "   gl_Position = vec4(coord2d, 0.0, 1.0); \n"
            "   texc = texCoord;\n"
            "}                          \n";
    vshader1->compileSourceCode(vsrc1);

    QGLShader *fshader1 = new QGLShader(QGLShader::Fragment, this);
    const char *fsrc1 =
            "uniform sampler2D texture;\n"
            "varying mediump vec4 texc;\n"
            "void main(void)\n"
            "{\n"
            "    gl_FragColor = texture2D(texture, texc.st);\n"
            "}\n"                                                  ;
    fshader1->compileSourceCode(fsrc1);

    program1.addShader(vshader1);
    program1.addShader(fshader1);
    program1.link();
    vertexAttr1 = program1.attributeLocation( "coord2d");
    vertexTexr1 = program1.attributeLocation( "texCoord");

    // Create the vertex buffer.
    vertices.clear();
    float u=1;
#define AVEC -u,u
#define BVEC -u,-u
#define CVEC u,u
#define DVEC u,-u
    vertices << QVector2D(AVEC);
    vertices << QVector2D(BVEC);
    vertices << QVector2D(CVEC);
    vertices << QVector2D(BVEC);
    vertices << QVector2D(DVEC);
    vertices << QVector2D(CVEC);
    // Create the texture vertex buffer
#define TAVEC 0,1
#define TBVEC 0,0
#define TCVEC 1,1
#define TDVEC 1,0
    texCoords << QVector2D(TAVEC);
    texCoords << QVector2D(TBVEC);
    texCoords << QVector2D(TCVEC);
    texCoords << QVector2D(TBVEC);
    texCoords << QVector2D(TDVEC);
    texCoords << QVector2D(TCVEC);
    QPixmap aMap(":/images/testmap.jpg");
    assert(aMap.width());
    heightGL = aMap.height();
    widthGL = aMap.width();
    textures[0] =bindTexture(aMap,GL_TEXTURE_2D,GL_LUMINANCE);
    noise = (GLubyte*) calloc(1*widthGL*heightGL,sizeof(GLubyte));//GL_RGB8
    memset(noise,100,1*widthGL*heightGL);
    //
}
void GLWidget::addNoise()
{
    std::default_random_engine e((unsigned int)(time(0)));
    GLubyte c = e()%256;
    assert(noise);
    for (int i = 0; i<heightGL;i++)
    {
        for(int j =0;j<widthGL;j++)
            noise[i*widthGL+j]= c;
    }
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    //
    //

    program1.bind();
    program1.setUniformValue("texture", 0);
    program1.enableAttributeArray(vertexAttr1);
    program1.enableAttributeArray(vertexTexr1);
    program1.setAttributeArray(vertexAttr1, vertices.constData());
    program1.setAttributeArray(vertexTexr1, texCoords.constData());
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,
                    widthGL,heightGL,GL_LUMINANCE,GL_UNSIGNED_BYTE, //lets hope these are correct
                    noise);
    glDrawArrays(GL_TRIANGLES, 0, vertices.size());
    program1.disableAttributeArray(vertexTexr1);
    program1.disableAttributeArray(vertexAttr1);
    program1.release();
}

void GLWidget::resizeGL(int width, int height)
{
    int side = qMin(width, height);
    glViewport((width - side) / 2, (height - side) / 2, side, side);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
    glMatrixMode(GL_MODELVIEW);

}

main.cpp

/****************************************************************************/
#include <QApplication>
#include <QDesktopWidget>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //cameraView cV;
    //cV.show();
    GLWidget mW;
    mW.show();
    return a.exec();
}

test.pro

HEADERS       = glwidget.h \
    cameraview.h
SOURCES       = glwidget.cpp \
                main.cpp \
    cameraview.cpp
QT           += opengl widgets

CONFIG += console
CONFIG += c++11

# install
target.path = $$[QT_INSTALL_EXAMPLES]/qt_OpenGL_3x/02_First_Triangle
sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS 02-first-triangle.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/qt_OpenGL_3x/02_First_Triangle
INSTALLS += target sources


simulator: warning(This example might not fully work on Simulator platform)

FORMS += \
    cameraview.ui

RESOURCES += \
    images.qrc

OTHER_FILES +=
4

1 回答 1

10

我克隆了存储库并对代码进行了一些更改以帮助您调试问题。首先,在std::coutpaintGL()开头打印一条消息:

void GLWidget::paintGL()
{
   static int xyz = 0;
   std::cout << "PaintGL begin " << xyz << std::endl;

和末尾的另一条消息paintGL。之后,增加计数器变量:

   program1.release();

   std::cout << "PaintGL end " << xyz << std::endl;
   xyz++;
}

这种方法清楚地表明,paintGL()由于在 2 秒内打印到控制台的消息量,每秒调用近 30 次:

PaintGL begin 0
PaintGL end 0
PaintGL begin 1
PaintGL end 1
...
...
PaintGL begin 60
PaintGL end 60
PaintGL begin 61
PaintGL end 61

所以可以放弃定时器有问题的理论。计时器很好,您确实在每秒绘制 30 个计时器左右的窗口。

问题可能出在代码中的其他地方。由于您仅在存储库中共享了应用程序的一部分,因此恐怕我无法为您提供任何进一步的帮助。

编辑

我注意到里面addNoise()有一个随机数生成器。如果您期望绘图在每次paintGL()调用时根据其他方法生成的数字而改变,您会感到失望。

当前实现的数字生成机制对毫秒变化不敏感,因此addNoise()在同一秒内的所有调用都将生成相同的数字,这反过来又会在您的窗口上绘制相同的东西一整秒。这就解释了为什么绘图每秒只更改一次。

为了解决这个问题,我建议看看:

于 2013-02-14T00:46:10.297 回答