Unsolved Seg Faults with OpenGLWindow
-
Hi wonderful people of this forum,
I'm working on a graphics application. Right now it's pretty simple; all I want to do is render a primitive triangle and cubes in an OpenGL context coupled with a Qt GUI. I got the triangle rendering scheme working just fine, but when I try to compile the cube, I get random seg faults. That is to say, the program seg faults about 1/2 the time. Sometimes it runs fine, and other times it won't start at all. I've tried and tried to diagnose the error, but to no avail. So I'm turning to this forum for help.
The basic idea was to work from the Qt OpenGLWindow example: https://doc.qt.io/qt-5/qtgui-openglwindow-example.html. I kept the abstract OpenGLWindow, and defined a GeometryWindow class that inherits from the OpenGLWindow. The geometry window class can be specialized to work with a Triangle or a Cube class, which both inherit from an abstract Geometry class. Finally, the GeometryWindow is contained in an OpenGLDocker Widget that controls the display of the triangle/cube.
I'm pretty sure the problem is somewhere in the GeometryWindow rendering scheme when it tries to render a cube. I suspect that the problem lies somewhere in memory management and allocation of the buffers, but I'm not sure where. Again, the triangle class works just fine, it's only the cube class that gives me a problem.
GeometryWindow Header
#ifndef GEOMETRYWINDOW_H #define GEOMETRYWINDOW_H #include <QtOpenGL> #include "openglwindow.h" #include "geometry.h" namespace Geo { class GeometryWindow : public OpenGLWindow { public: GeometryWindow(Geometry *geo, QWindow* parent = nullptr); ~GeometryWindow() override; using OpenGLWindow::OpenGLWindow; void initialize() override; void render() override; void rotate(const QMatrix4x4& rotMat); void resetRotState(); void scale(float scale) { m_sFactor = scale; } QMatrix4x4 getRotMatrix() const { return m_rotationState; } void setBuffers(); protected: Geometry *p_geo; void allocTriBuffers(); void allocCubeBuffers(); void setTriangleBuffers(); void setCubeBuffers(); void deleteBuffers(); void renderTriangle(); void renderCube(); private: float m_sFactor; GLint m_posAttr = 0; GLint m_colAttr = 0; GLint m_matrixUniform = 0; Geo::gType m_gType; QMatrix4x4 m_rotationState; QMatrix4x4 m_translationState; GLfloat *mp_pointBuffer; GLfloat *mp_colorBuffer; vector<GLfloat*> mvp_lineBuffers; QOpenGLShaderProgram *m_program = nullptr; }; } #endif // GEOMETRYWINDOW_H
GeometryWindow source
#include "geometrywindow.h" using namespace Geo; GeometryWindow::GeometryWindow(Geometry *geo, QWindow* parent) :OpenGLWindow(parent) { m_rotationState = QMatrix4x4(); p_geo = geo; m_gType = geo->Type(); m_sFactor = 1.0; switch (m_gType) { case Geo::gType::Triangle: allocTriBuffers(); break; case Geo::gType::Cube: allocCubeBuffers(); break; case Geo::gType::Tetrahedron: break; } } GeometryWindow::~GeometryWindow() { deleteBuffers(); } void GeometryWindow::initialize() { m_program = new QOpenGLShaderProgram(this); m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource); m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource); m_program->link(); m_posAttr = m_program->attributeLocation("posAttr"); Q_ASSERT(m_posAttr != -1); m_colAttr = m_program->attributeLocation("colAttr"); Q_ASSERT(m_colAttr != -1); m_matrixUniform = m_program->uniformLocation("matrix"); Q_ASSERT(m_matrixUniform != -1); initializeOpenGLFunctions(); } void GeometryWindow::setBuffers() { switch (m_gType) { case Geo::gType::Triangle: setTriangleBuffers(); break; case Geo::gType::Cube: setCubeBuffers(); break; case Geo::gType::Tetrahedron: break; } } void GeometryWindow::allocTriBuffers() { mp_pointBuffer = new float [21]; mp_colorBuffer = new float [21]; mvp_lineBuffers.resize(7); for(int l = 0; l < 7; l++){ mvp_lineBuffers[l] = new float[9]; } } void GeometryWindow::allocCubeBuffers() { mp_pointBuffer = new float [45]; mp_colorBuffer = new float [45]; mvp_lineBuffers.resize(28); for(int l = 0; l < 28; l++){ mvp_lineBuffers[l] = new float[9]; } } void GeometryWindow::deleteBuffers() { if(mp_pointBuffer != nullptr) delete mp_pointBuffer; if(mp_colorBuffer != nullptr) delete mp_colorBuffer; if(mvp_lineBuffers.size() > 0){ for(int i = 0; i < mvp_lineBuffers.size(); i++){ delete mvp_lineBuffers[i]; } } } void GeometryWindow::setTriangleBuffers() { for(int i = 0; i < 21; i++){ mp_pointBuffer[i] = m_sFactor*(*p_geo)(i/3, i%3); } for(int i = 0; i < 7; i++){ mp_colorBuffer[3*i] = p_geo->C(i).redF(); mp_colorBuffer[3*i+1] = p_geo->C(i).greenF(); mp_colorBuffer[3*i+2] = p_geo->C(i).blueF(); } int idx; for(int l = 0; l < 7; l++){ for(int i = 0; i < 9; i++){ idx = (*p_geo)[l][i/3]; mvp_lineBuffers[l][i] = m_sFactor*(*p_geo)(idx, i%3); } } } void GeometryWindow::setCubeBuffers() { for(int i = 0; i < 45; i++){ mp_pointBuffer[i] = m_sFactor*(*p_geo)(i/3, i%3); } for(int i = 0; i < 45; i++){ mp_colorBuffer[3*i] = p_geo->C(i).redF(); mp_colorBuffer[3*i+1] = p_geo->C(i).greenF(); mp_colorBuffer[3*i+2] = p_geo->C(i).blueF(); } // int idx; // for(int l = 0; l < 7; l++){ // for(int i = 0; i < 9; i++){ // idx = (*p_geo)[l][i/3]; // mvp_lineBuffers[l][i] = m_sFactor*(*p_geo)(idx, i%3); // } // } } void GeometryWindow::resetRotState() { m_rotationState = QMatrix4x4(); } void GeometryWindow::rotate(const QMatrix4x4& rotMat) { m_rotationState *= rotMat; } void GeometryWindow::render() { //const qreal retinaScale = devicePixelRatio(); switch (m_gType) { case Geo::gType::Triangle: setTriangleBuffers(); renderTriangle(); break; case Geo::gType::Cube: setCubeBuffers(); renderCube(); break; } } void GeometryWindow::renderTriangle() { glViewport(0, 0, width(), height()); glClear(GL_COLOR_BUFFER_BIT); m_program->bind(); QMatrix4x4 matrix; matrix.ortho(0, 0, width(), height(), 0.1f, 1.f); matrix *= m_rotationState; m_program->setUniformValue(m_matrixUniform, matrix); glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, mp_pointBuffer); glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, mp_colorBuffer); glEnableVertexAttribArray(m_posAttr); glEnableVertexAttribArray(m_colAttr); glPointSize(10); glDrawArrays(GL_POINTS, 0, 7); glDisableVertexAttribArray(m_colAttr); glDisableVertexAttribArray(m_posAttr); GLfloat lineColors[] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; for(int l = 1; l < p_geo->LineNumber(); l++){ glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, mvp_lineBuffers[l]); glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, lineColors); glEnableVertexAttribArray(m_posAttr); glEnableVertexAttribArray(m_colAttr); glDrawArrays(GL_LINES, 0, 2); glDisableVertexAttribArray(m_colAttr); glDisableVertexAttribArray(m_posAttr); } m_program->release(); } void GeometryWindow::renderCube() { glViewport(0, 0, width(), height()); glClear(GL_COLOR_BUFFER_BIT); m_program->bind(); QMatrix4x4 matrix; matrix.ortho(0, 0, width(), height(), 0.1f, 1.f); //matrix.rotate(45, 1, 1, 0); matrix *= m_rotationState; m_program->setUniformValue(m_matrixUniform, matrix); glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, mp_pointBuffer); glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, mp_colorBuffer); glEnableVertexAttribArray(m_posAttr); glEnableVertexAttribArray(m_colAttr); glPointSize(10); glDrawArrays(GL_POINTS, 0, 15); glDisableVertexAttribArray(m_colAttr); glDisableVertexAttribArray(m_posAttr); // GLfloat lineColors[] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; // for(int l = 1; l < p_geo->LineNumber(); l++){ // glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, mvp_lineBuffers[l]); // glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, lineColors); // glEnableVertexAttribArray(m_posAttr); // glEnableVertexAttribArray(m_colAttr); // glDrawArrays(GL_LINES, 0, 2); // glDisableVertexAttribArray(m_colAttr); // glDisableVertexAttribArray(m_posAttr); // } m_program->release(); }
Cube Header and source
#ifndef CUBE_H #define CUBE_H #include "geometry.h" class Cube : public Geometry { public: Cube(); ~Cube(); Geo::gType Type() const { return Geo::gType::Cube; } void NatCmap(); }; #endif // CUBE_H #include "cube.h" Cube::Cube() : Geometry(15, 28, 3) { // Point Map m_points[0][0] = 0.0f; m_points[0][1] = 0.0f; m_points[0][2] = 0.0f; // 0 m_points[1][0] = 1.0f; m_points[1][1] = 1.0f; m_points[1][2] = 0.0f; // 1 m_points[2][0] = 1.0f; m_points[2][1] = 0.0f; m_points[2][2] = 1.0f; // 2 m_points[3][0] = 1.0f; m_points[3][1] = 0.0f; m_points[3][2] = 0.0f; // 3 m_points[4][0] = 0.0f; m_points[4][1] = 1.0f; m_points[4][2] = 1.0f; // 4 m_points[5][0] = 0.0f; m_points[5][1] = 1.0f; m_points[5][2] = 0.0f; // 5 m_points[6][0] = 0.0f; m_points[6][1] = 0.0f; m_points[6][2] = 1.0f; // 6 m_points[7][0] = 1.0f; m_points[7][1] = 1.0f; m_points[7][2] = 1.0f; // 7 m_points[8][0] = 1.0f; m_points[8][1] = 1.0f; m_points[8][2] = -1.0f; // 8 m_points[9][0] = 1.0f; m_points[9][1] = -1.0f; m_points[9][2] = 1.0f; // 9 m_points[10][0] = 1.0f; m_points[10][1] = -1.0f; m_points[10][2] = -1.0f; // 10 m_points[11][0] = -1.0f; m_points[11][1] = 1.0f; m_points[11][2] = 1.0f; // 11 m_points[12][0] = -1.0f; m_points[12][1] = 1.0f; m_points[12][2] = -1.0f; // 12 m_points[13][0] = -1.0f; m_points[13][1] = -1.0f; m_points[13][2] = 1.0f; // 13 m_points[14][0] = -1.0f; m_points[14][1] = -1.0f; m_points[14][2] = -1.0f; // 14 NatCmap(); } Cube::~Cube() { } void Cube::NatCmap() { m_colors[0] = QColor::fromRgbF(1.0, 1.0, 1.0); m_colors[1] = QColor::fromRgbF(0.0, 0.0, 1.0); m_colors[2] = QColor::fromRgbF(0.0, 1.0, 0.0); m_colors[3] = QColor::fromRgbF(0.0, 1.0, 1.0); m_colors[4] = QColor::fromRgbF(1.0, 0.0, 0.0); m_colors[5] = QColor::fromRgbF(1.0, 0.0, 1.0); m_colors[6] = QColor::fromRgbF(1.0, 1.0, 0.0); m_colors[7] = QColor::fromRgbF(0.5, 0.5, 0.5); m_colors[8] = QColor::fromRgbF(0.5, 0.5, 0.5); m_colors[9] = QColor::fromRgbF(0.0, 0.0, 0.5); m_colors[10] = QColor::fromRgbF(0.0, 0.5, 0.0); m_colors[11] = QColor::fromRgbF(0.0, 0.5, 0.5); m_colors[12] = QColor::fromRgbF(0.5, 0.0, 0.0); m_colors[13] = QColor::fromRgbF(0.5, 0.0, 0.5); m_colors[14] = QColor::fromRgbF(0.5, 0.5, 0.0); }
Triangle Header and Source
#ifndef TRIANGLE_H #define TRIANGLE_H #include "geometry.h" class Triangle : public Geometry { public: Triangle(); ~Triangle(); Geo::gType Type() const { return Geo::gType::Triangle; } void NatCmap(); // natural color map }; #endif // TRIANGLE_H #include "triangle.h" using namespace Geo; /* Point Labels * 1 * 5 0 3 * 4 6 2 * * Line Labels * 0: (356) * 1: (160) * 2: (340) * 3: (250) * 4: (123) * 5: (145) * 6: (246) */ Triangle::Triangle() : Geometry(7, 7, 3) { // Point Maps m_points[0][0] = 0.0f; m_points[0][1] = 0.0f; m_points[0][2] = 0.0f; // 0 m_points[1][0] = 0.0f; m_points[1][1] = 1.0f; m_points[1][2] = 0.0f; // 1 m_points[2][0] = 0.866f; m_points[2][1] = -0.5; m_points[2][2] = 0.0f; // 2 m_points[3][0] = 0.433f; m_points[3][1] = 0.25f; m_points[2][2] = 0.0f; // 2 m_points[4][0] = -0.866f; m_points[4][1] = -0.5; m_points[3][2] = 0.0f; // 3 m_points[5][0] = -0.433f; m_points[5][1] = 0.25f; m_points[5][2] = 0.0f; // 5 m_points[6][0] = 0.0f; m_points[6][1] = -0.5f; m_points[6][2] = 0.0f; // 6 // Line Maps m_lines[0][0] = 3; m_lines[0][1] = 5; m_lines[0][2] = 6; m_lines[1][0] = 1; m_lines[1][1] = 6; m_lines[1][2] = 0; m_lines[2][0] = 3; m_lines[2][1] = 4; m_lines[2][2] = 0; m_lines[3][0] = 2; m_lines[3][1] = 5; m_lines[3][2] = 0; m_lines[4][0] = 1; m_lines[4][1] = 2; m_lines[4][2] = 3; m_lines[5][0] = 1; m_lines[5][1] = 4; m_lines[5][2] = 5; m_lines[6][0] = 2; m_lines[6][1] = 4; m_lines[6][2] = 6; // Color Maps NatCmap(); } Triangle::~Triangle() { } void Triangle::NatCmap() { /* Natural Point Colors * B * M W C * R Y G */ m_colors[0] = QColor::fromRgbF(1.0, 1.0, 1.0); m_colors[1] = QColor::fromRgbF(0.0, 0.0, 1.0); m_colors[2] = QColor::fromRgbF(0.0, 1.0, 0.0); m_colors[3] = QColor::fromRgbF(0.0, 1.0, 1.0); m_colors[4] = QColor::fromRgbF(1.0, 0.0, 0.0); m_colors[5] = QColor::fromRgbF(1.0, 0.0, 1.0); m_colors[6] = QColor::fromRgbF(1.0, 1.0, 0.0); }
Geometry Header and Source
#include <QColor> using std::vector; using std::array; namespace Geo { enum gType{ Triangle, Cube, Tetrahedron }; } class Geometry { public: Geometry(int Points, int Lines, int LineLength=3); virtual ~Geometry(); // Geometry( Algebra *algebra ); // add pure virtual to prevent instantation of an abstract geometry class virtual Geo::gType Type() const =0; virtual void NatCmap()=0; //// Get a point coordinate float operator()(int point, int basis) const { return m_points[point][basis]; } //// Get a line's point contents vector<int> operator[](int line) const { return m_lines[line]; } //// Get a color QColor C(int point) const { return m_colors[point]; } void setNumPoints(int points) { m_NumPoints = points; } void setNumLines(int lines) { m_NumLines = lines; } void setLength(int Length) { m_Length = Length; } int PointNumber() const { return m_NumPoints; } int LineNumber() const { return m_NumLines; } int LineLength() const { return m_Length; } protected: int m_Length; // number of points in a line int m_NumPoints; // number of points in the geometry int m_NumLines; // number of lines vector<array<float,3>> m_points; vector<vector<int>> m_lines; vector<QColor> m_colors; }; #endif // GEOMETRY_H #include "geometry.h" using namespace Geo; Geometry::Geometry(int Points, int Lines, int LineLength) { m_points.resize(Points); m_lines.resize(Lines); for(int l = 0; l < Lines; l++){ m_lines[l].resize(LineLength); } m_colors.resize(Points); m_Length = LineLength; m_NumLines = Lines; m_NumPoints = Points; } Geometry::~Geometry() { }
If someone could spot the problem, I'd be most grateful.
-
add debugging code to your program to see where it is segfaulting. assert() is your friend. Also, I note that you are doing absolutely no error checking. The GL state machine should be checked, as well as the existence of the heap allocated objects you create to compile your shader programs.
-
Hi
And welcome to the forums.
As you say its mostly a buffer overrun or dangling pointer.
Since it sometimes works and sometimes not, using the debugger/ qDebug()
to know where it crashes is the way to go.Is the code complete so if i combine it with the
https://doc.qt.io/QtOPCUA/qtopcua-opcuaviewer-example.html: https://doc.qt.io/qt-5/qtgui-openglwindow-example.html.
i can run it ? -
@Kent-Dorfman Thanks, so you just mean that I should be placing a bunch of lines like
Q_ASSERT(glGetError() == 0)
after each time I an OpenGL function? What should I be checking about the heap allocated objects?
-
@mrjj Thanks for the response. The code is complete and runs about 1/2 the time or so. I could upload the code source.
I'm not sure what that QtOPCUA is. I've tried a few different approaches, from C++ pointers, to std::vector with the data() function, and now classic C malloc(). The problem definitely lies in the GL drawing routine, around
m_program->setUniformValue(m_matrixUniform, matrix); glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, mp_pointBuffer); glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, mp_colorBuffer); glEnableVertexAttribArray(m_posAttr); glEnableVertexAttribArray(m_colAttr); glPointSize(10); glDrawArrays(GL_POINTS, 0, 15); glDisableVertexAttribArray(m_colAttr); glDisableVertexAttribArray(m_posAttr); m_program->release();