2013-02-12 64 views
7

मुझे लगता है कि मुझे अपने दृश्य को सार्थक दर पर अपडेट करने के लिए Qt5 नहीं मिल रहा है। मेरा दृश्य 512x512 बना हुआ आयताकार है। मुझे जो दर मिल रही है वह लगभग 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(); 
} 

में प्राथमिकता सेट करने के लिए कोई तरीका है? क्या मैं कुछ पूरी तरह गलत कर रहा हूँ? क्या क्यूटी में कुछ प्रकार की आंतरिक अद्यतन सीमा है, और यह निश्चित रूप से 1 एफपीएस के आदेश पर नहीं है? मेरा सिद्धांत यह है कि क्यूटी स्क्रीन को वास्तव में अपडेट करने के लिए मेरी कॉल को अनदेखा कर रही है।

मैं

  1. की कोशिश की है एक QCoreApplication::processEvents(); सम्मिलित करने के लिए, लेकिन यह माता पिता विजेट पर
  2. कॉल अद्यतन मदद नहीं करता है, और माता पिता के
  3. से टाइमर चलाने के एक समारोह चेतन बनाएं जिसका नाम() 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 sources 


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

FORMS += \ 
    cameraview.ui 

RESOURCES += \ 
    images.qrc 

OTHER_FILES += 
+0

आप() QGLWidget :: updateGL के बाद अद्यतन() कॉल का प्रयास किया:

इस समस्या को मैं पर एक नज़र पूरे करने की सलाह ठीक करने के लिए? संबंधित: http://stackoverflow.com/questions/4468846/qglwidget-updategl-doest-update-with-qtimer। – kfunk

+0

मुझे आपकी मदद करने के लिए एक [लघु, स्वयं युक्त, सही (संकलित), उदाहरण] (http://sscce.org/) देखना अच्छा लगेगा। – karlphillip

+0

@karlphillip मैंने कुछ पोस्ट किया है, मुझे लगता है कि मैं इसे संपादित करने की कोशिश करूंगा, लेकिन जैसा कि आप समझ सकते हैं कि ओपनजीएल कोड काफी बड़ा हो सकता है। मुझे लगता है कि मैं एक बग रिपोर्ट जमा करने के लिए तैयारी में हिट रेपो या कुछ पोस्ट करता हूं? – Mikhail

उत्तर

9

मैं भंडार क्लोन और कोड के लिए कुछ बदलाव किए हैं मदद करने के लिए आप समस्या को डीबग करते हैं। सबसे पहले, एसटीडी के साथ 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() संदेशों के राशि है कि 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() पर सभी कॉल एक ही संख्या उत्पन्न करेंगे, जो बदले में आपकी खिड़की पर एक ही चीज़ को पूरे सेकेंड के लिए पेंट करेगा । यह बताता है कि चित्र प्रति सेकंड केवल एक बार क्यों बदलता है।

+0

इस पर ध्यान देने के लिए धन्यवाद। जब मैं अपने विंडोज 7 ज़ीऑन मशीन पर कोड चलाता हूं तो मुझे लगता है कि छवि परिवर्तन प्रति सेकंड 30 फ्रेम से कम धीमे दिखाई देता है। मैं कोड को एक छवि फ्लैश करने की उम्मीद करता हूं, लेकिन यह केवल हर सेकेंड में लगभग एक बार अपडेट होने लगता है? क्या तुमने ऐसा कुछ देखा? यह मेरी समझ है कि एक ग्राफिक्स इंजन पेंट फ़ंक्शन को गठबंधन करेगा (पतन) और अधिक पश्चाताप को ट्रिगर नहीं कर सकता है, तो मुझे आश्चर्य है कि यह समस्या है, क्योंकि समान कोड ओपनजीएल विजेट के बिना ठीक काम करता है। – Mikhail

+0

@ मिखाइल कॉल 'glfinish() 'पिछले' std :: cout' से पहले।यह कार्य तब तक अवरुद्ध हो जाता है जब तक कि सभी परिचालन पूर्ण नहीं होते हैं, इसलिए आप निश्चित रूप से जानते हैं कि खिड़की प्रत्येक 30ms को पेंट करेगी। मैं यह कहना भूल गया कि मैंने **। प्रो ** फ़ाइल से 'CONFIG + = C++ 11' हटा दिया है, और परिणामस्वरूप मुझे प्रतिस्थापित करना पड़ा: 'std :: default_random_engine e ((unsigned int) (time (0))); ग्लूबेट सी = ई()% 256; ' पारंपरिक द्वारा: ' srand ((हस्ताक्षरित int) समय (0)); GLubyte सी = रैंड()% 256; ' – karlphillip