2013-02-12 23 views
7

Tôi dường như không nhận được Qt5 để cập nhật cảnh của mình ở một tốc độ có ý nghĩa. Cảnh của tôi là hình chữ nhật có kích thước 512x512. Tỷ lệ tôi nhận được là khoảng 1 khung hình/giây (!).Cập nhật Qt OpenGL Unusably Slow

Trong constructor của tôi

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(); 
} 

Có cách nào để thiết lập ưu tiên? Tôi đang làm điều gì đó hoàn toàn, sai? Có một số loại giới hạn cập nhật nội tại trong Qt, và chắc chắn nó không phải theo thứ tự 1 FPS? Lý thuyết của tôi là Qt bỏ qua các cuộc gọi của tôi để thực sự cập nhật màn hình.

Tôi đã thử

  1. để chèn một QCoreApplication::processEvents(); nhưng điều này không giúp
  2. Gọi cập nhật trên widget phụ huynh, và chạy bộ đếm thời gian từ cha mẹ
  3. Tạo một hàm gọi là animate() đã chạy forever{} và cập nhật cuộc gọi từ trong số đó
  4. Ví dụ wigglywidget dường như hoạt động, điều này gợi ý cho tôi rằng QT OpenGL đang thu hẹp khung hình, bỏ qua các cuộc gọi của tôi để cập nhật. Có một heuristic rằng điều khiển này?

Mã tối thiểu để Tái

(Phiên bản là một chút khác nhau, được mô hình hóa sau khi lớp wigglywidget, nhưng có vấn đề chính xác cùng)

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 += 
+0

bạn đã thử gọi QGLWidget :: update() sau khi updateGL()? Liên quan: http://stackoverflow.com/questions/4468846/qglwidget-updategl-doest-update-with-qtimer. – kfunk

+0

Tôi rất thích nhìn thấy một [Ngắn, tự chứa, chính xác (Compilable), Ví dụ] (http://sscce.org/) để giúp bạn ra ngoài. – karlphillip

+0

@karlphillip Tôi đã đăng một cái gì đó, tôi nghĩ rằng tôi sẽ cố gắng chỉnh sửa nó xuống, nhưng như bạn có thể hiểu mã OpenGL có thể khá lớn. Tôi nghĩ rằng tôi đăng một repo hit hoặc một cái gì đó để chuẩn bị cho việc gửi một báo cáo lỗi? – Mikhail

Trả lời

9

tôi nhân bản kho và thực hiện một vài thay đổi mã để giúp bạn gỡ rối vấn đề. Thứ nhất, in một thông báo vào đầu paintGL() với std :: cout:

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

và một thông báo vào cuối paintGL.Sau đó, tăng biến cập:

program1.release(); 

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

Cách tiếp cận này rõ ràng cho thấy rằng paintGL() được gọi là gần 30 lần mỗi giây do số lượng tin nhắn được in ra cửa sổ Console trong 2 giây:

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

Vì vậy, lý thuyết rằng có một vấn đề với bộ đếm thời gian có thể được loại bỏ. Bộ đếm thời gian là tốt, và bạn thực sự vẽ cửa sổ 30 bộ đếm thời gian mỗi giây hoặc lâu hơn.

Sự cố có thể là một nơi khác trong mã của bạn. Vì bạn chỉ chia sẻ một phần của ứng dụng trong kho lưu trữ, tôi sợ rằng tôi sẽ không thể giúp bạn thêm nữa.

EDIT:

tôi nhận thấy rằng bên trong addNoise() bạn có một bộ tạo số ngẫu nhiên. Nếu bạn đang mong đợi bản vẽ thay đổi ở mọi cuộc gọi paintGL() dựa trên số được tạo bởi phương thức khác, bạn sẽ thất vọng.

Cơ chế tạo số hiện tại được triển khai không nhạy cảm với các thay đổi mili giây, vì vậy tất cả các cuộc gọi đến addNoise() trong cùng một giây sẽ tạo ra cùng một số, do đó sẽ vẽ cùng một thứ trên cửa sổ của bạn trong toàn bộ giây . Điều đó giải thích tại sao bản vẽ chỉ thay đổi một lần mỗi giây.

Để khắc phục vấn đề này, tôi khuyên bạn nên xem tại địa chỉ:

+0

Cảm ơn bạn đã xem xét điều này. Khi tôi chạy mã trên máy Xeon Windows 7 của tôi, tôi thấy thay đổi hình ảnh có thể nhìn thấy chậm hơn dưới 30 khung hình mỗi giây. Tôi mong đợi mã để flash một hình ảnh, nhưng nó chỉ dường như cập nhật khoảng một lần mỗi giây? Bạn có thấy một cái gì đó như thế này? Đó là sự hiểu biết của tôi rằng một công cụ đồ họa sẽ kết hợp (thu gọn) các chức năng repaint để bạn không thể kích hoạt thêm repaints sau đó là có thể, tôi tự hỏi nếu đây là vấn đề, bởi vì mã tương tự hoạt động tốt mà không có các widget OpenGL. – Mikhail

+0

@Mikhail Gọi 'glFinish()' trước 'std :: cout' cuối cùng.Chức năng này chặn cho đến khi tất cả các thao tác hoàn tất, vì vậy bạn biết chắc chắn rằng cửa sổ sẽ sơn lại sau mỗi 30ms. Tôi quên nói rằng tôi đã xóa 'CONFIG + = C++ 11' khỏi tệp **. Pro ** và kết quả là tôi phải thay thế: ' std :: default_random_engine e ((unsigned int) (thời gian (0))); GLubyte c = e()% 256; ' theo kiểu truyền thống: ' srand ((không dấu int) thời gian (0)); GLubyte c = rand()% 256; ' – karlphillip

Các vấn đề liên quan