Обновление Qt OpenGL неоправданно медленное

Кажется, я не могу заставить Qt5 обновлять мою сцену со значительной скоростью. Моя сцена представляет собой текстурированный прямоугольник 512×512. Скорость, которую я получаю, составляет около 1 кадра в секунду (!).

В моем конструкторе

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

а также

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

Есть ли способ установить приоритет? Я делаю что-то полностью, не так? Есть ли какое-то внутреннее ограничение обновления в Qt, и оно определенно не порядка 1 FPS? Моя теория состоит в том, что Qt игнорирует мои звонки, чтобы фактически обновить экран.

я пытался

  1. вставить QCoreApplication::processEvents();
    но это не помогает
  2. Вызовите update для родительского виджета и запустите таймер из родительского виджета.
  3. Создайте функцию с именем animate (), которая запустилась forever{} и вызвать обновление изнутри
  4. wigglywidget пример работает, что намекает мне на то, что QT OpenGL как-то сворачивает фреймы, игнорируя мои призывы к обновлению. Есть ли эвристика, которая контролирует это?

Минимальный код для воссоздания

(Версия немного отличается, моделируется после класса wigglywidget, но имеет точно такую ​​же проблему)

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 sourcessimulator: warning(This example might not fully work on Simulator platform)

FORMS += \
cameraview.ui

RESOURCES += \
images.qrc

OTHER_FILES +=

7

Решение

Я клонировал репозиторий и внес несколько изменений в код, чтобы помочь вам отладить проблему. Сначала распечатайте сообщение в начале paintGL() с станд :: соиЬ:

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() вызывается почти 30 раз в секунду из-за количества сообщений, которые выводятся на консоль за 2 секунды:

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() в течение одной секунды будет сгенерировано то же число, которое, в свою очередь, нарисует одно и то же на вашем окне в течение всей секунды. Это объясняет, почему рисунок меняется только один раз в секунду.

Чтобы решить эту проблему, я предлагаю взглянуть на:

9

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector