[Solved] Segfault in DrawElements; I cannot find the problem

Started by
6 comments, last by Erik Rufelt 9 years, 7 months ago

I've been trying to solve this for like 3 days and it's driving me bonkers. I've gotten my code down to the below. glDrawElements is segfaulting. I have assumed that it's from the indices but I look over it again and again and there's no problem. The segfault is happening is atio6axx.dll, which I assume means I've told OpenGL that one of my buffers is bigger than it actually is. But I check over it again and again and see no problem. I've used GLIntercept to verify that the segfault happens on the glDrawElements function.








#include <exception>
#include <iostream>
#include <fstream>
#include <sstream>
#include <list>
#include <string>
#include <algorithm>
#include <functional>

#include <utilities.hpp>

#include <GL/glew.h>
#include <SDL2/sdl.h>
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>

struct VertexData
{
GLdouble position[4];
GLfloat color[3];
GLfloat normal[3];
GLfloat tcoords[2];
};

int main(int argc, char* argv[])
{
try
{
SDL_Window* window;
SDL_GLContext context;
if(SDL_Init(SDL_INIT_VIDEO) < 0)
throw std::runtime_error("unable to initialise video");

SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);

window = SDL_CreateWindow("SpaceEngine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800, 800, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if(!window)
throw std::runtime_error("unable to create window");

context = SDL_GL_CreateContext(window);

SDL_GL_SetSwapInterval(1);

GLenum glewErr = glewInit();
if(glewErr != GLEW_OK)
{
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
throw std::runtime_error(reinterpret_cast<const char*>(glewGetErrorString(glewErr)));
}

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

std::vector<VertexData> vertices;
std::vector<GLushort> indices;
int rings = 200;
int sectors = 200;
float radius = 1.0;

if(rings < 2)
rings = 2;
if(sectors < 2)
sectors = 2;
while(rings * sectors >= std::numeric_limits<GLushort>::max())
{
rings /= 2;
sectors /= 2;
}

const GLuint polyCountXPitch = rings+1;

GLuint level = 0;

for(GLuint p1 = 0; p1 < sectors-1; ++p1)
{
for(GLuint p2 = 0; p2 < rings-1; ++p2)
{
GLuint curr = level + p2;
indices.push_back(curr + polyCountXPitch);
indices.push_back(curr);
indices.push_back(curr + 1);
indices.push_back(curr + polyCountXPitch);
indices.push_back(curr + 1);
indices.push_back(curr + 1 + polyCountXPitch);
}

indices.push_back(level + rings - 1 + polyCountXPitch);
indices.push_back(level + rings - 1);
indices.push_back(level + rings);

indices.push_back(level + rings - 1 + polyCountXPitch);
indices.push_back(level + rings);
indices.push_back(level + rings + polyCountXPitch);

level += polyCountXPitch;
}

const GLuint polyCountSq = polyCountXPitch * sectors; //top point
const GLuint polyCountSq1 = polyCountSq + 1; //bottom point
const GLuint polyCountSqM1 = (sectors - 1) * polyCountXPitch; //last rows first index

for(GLuint p2 = 0; p2 < rings - 1; ++p2)
{
indices.push_back(polyCountSq);
indices.push_back(p2 + 1);
indices.push_back(p2);

indices.push_back(polyCountSqM1 + p2);
indices.push_back(polyCountSqM1 + p2 + 1);
indices.push_back(polyCountSq1);
}

indices.push_back(polyCountSq);
indices.push_back(rings);
indices.push_back(rings - 1);

indices.push_back(polyCountSqM1 + rings - 1);
indices.push_back(polyCountSqM1);
indices.push_back(polyCountSq1);

const GLdouble angleX = 2 * pi() / rings;
const GLdouble angleY = pi() / sectors;

GLuint i = 0;
GLdouble axz;
GLdouble ay = 0;

vertices.resize(polyCountXPitch * sectors + 2);
for(GLuint y = 0; y < sectors; ++y)
{
ay += angleY;
const GLdouble sinay = std::sin(ay);
axz = 0;

for(GLuint xz = 0; xz < rings; ++xz)
{
const glm::vec3 pos((radius * std::cos(axz) * sinay),radius * std::cos(ay), radius * std::sin(axz) * sinay);
glm::vec3 normal = pos;
normal = glm::normalize(normal);

GLuint tu = 0.5f;
if(y == 0)
{
if(normal.y != -1.0f && normal.y != 1.0f)
tu = std::acos(glm::clamp<GLdouble>(normal.x/sinay, -1.0f, 1.0f)) * 0.5 * (1.0f/pi());
if(normal.z < 0.0f)
tu = 1 - tu;
}
else
tu = vertices[i-polyCountXPitch].tcoords[0];

VertexData v;
v.color[0] = 1;
v.color[1] = 1;
v.color[2] = 1;
v.position[0] = pos.x;
v.position[1] = pos.y;
v.position[2] = pos.z;
v.position[3] = 1.0f;
v.normal[0] = normal.x;
v.normal[1] = normal.y;
v.normal[2] = normal.z;
v.tcoords[0] = tu;
v.tcoords[1] = ay * (1.0f/pi());
vertices.at(i) = v;

++i;
axz += angleX;
}

vertices.at(i) = vertices.at(i - rings);
vertices.at(i).tcoords[0] = 1.0f;
++i;
}

VertexData v;
v.color[0] = 1;
v.color[1] = 1;
v.color[2] = 1;
v.position[0] = 0;
v.position[1] = radius;
v.position[2] = 0;
v.position[3] = 1.0f;
v.normal[0] = 0;
v.normal[1] = 1;
v.normal[2] = 0;
v.tcoords[0] = 0.5f;
v.tcoords[1] = 0.0f;
vertices.at(i) = v;
++i;
v.position[1] = -radius;
v.normal[1] = -1.0f;
v.tcoords[1] = 1.0f;
vertices.at(i) = v;

GLuint vao;
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(struct VertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, color));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, normal));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, tcoords));

GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), indices.data(), GL_STATIC_DRAW);

glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

GLuint shader1,shader2;
std::ifstream file("tutorial2.vert");
if(!file)
throw std::runtime_error("The file tutorial2.vert was not opened");
else
{
std::string fileContents((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());

shader1 = glCreateShader(GL_VERTEX_SHADER);
std::string fail = "glCreateShader failed using " + GL_VERTEX_SHADER;

if(!shader1)
throw std::runtime_error(fail.c_str());

const GLchar* contents[1];
contents[0] = fileContents.c_str();
glShaderSource(shader1, 1, contents, NULL);

glCompileShader(shader1);
int compiled;
glGetShaderiv(shader1, GL_COMPILE_STATUS, &compiled);
if(compiled == 0)
{
int maxLength;
glGetShaderiv(shader1, GL_INFO_LOG_LENGTH, &maxLength);
char* vertexInfoLog = new char[maxLength];
glGetShaderInfoLog(shader1, maxLength, &maxLength, vertexInfoLog);
throw std::runtime_error("Shader failed to compile:\n>\t" + std::string(vertexInfoLog));
}
}
std::ifstream file2("tutorial2.frag");
if(!file2)
throw std::runtime_error("The file tutorial2.frag was not opened");
else
{
std::string fileContents((std::istreambuf_iterator<char>(file2)),std::istreambuf_iterator<char>());

shader2 = glCreateShader(GL_FRAGMENT_SHADER);
std::string fail = "glCreateShader failed using " + GL_FRAGMENT_SHADER;
if(!shader2)
throw std::runtime_error(fail.c_str());

const GLchar* contents[1];
contents[0] = fileContents.c_str();
glShaderSource(shader2, 1, contents, NULL);

glCompileShader(shader2);
int compiled;
glGetShaderiv(shader2, GL_COMPILE_STATUS, &compiled);
if(compiled == 0)
{
int maxLength;
glGetShaderiv(shader2, GL_INFO_LOG_LENGTH, &maxLength);
char* vertexInfoLog = new char[maxLength];
glGetShaderInfoLog(shader2, maxLength, &maxLength, vertexInfoLog);
throw std::runtime_error("Shader failed to compile:\n>\t" + std::string(vertexInfoLog));
}
}

GLuint program = glCreateProgram();
if(!program)
throw std::runtime_error("glCreateProgram failed");

glAttachShader(program, shader1);
glAttachShader(program, shader2);

glBindAttribLocation(program, 0, "in_Position");
glBindAttribLocation(program, 1, "in_Color");
glBindAttribLocation(program, 2, "in_Normal");
glBindAttribLocation(program, 3, "in_UV");

glLinkProgram(program);
int IsLinked;
glGetProgramiv(program, GL_LINK_STATUS, (int *)&IsLinked);
if(IsLinked == 0)
{
int maxLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
char* shaderProgramInfoLog = new char[maxLength];
glGetProgramInfoLog(program, maxLength, &maxLength, shaderProgramInfoLog);
throw std::runtime_error("Program failed to link:\n>\t" + std::string(shaderProgramInfoLog) + "");
}

glDetachShader(program, shader1);
glDetachShader(program, shader2);

bool done = false;

while(!done)
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_WINDOWEVENT:
switch(event.window.event)
{
case SDL_WINDOWEVENT_CLOSE:
done = true;
break;
}
break;
}
}

glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(program);

glBindVertexArray(vao);

//**** SEGFAULTS HERE *********/
glDrawElements(GL_TRIANGLES,indices.size(),GL_UNSIGNED_SHORT,0);

glBindVertexArray(0);

glUseProgram(0);

SDL_GL_SwapWindow(window);
}

glUseProgram(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

glDeleteProgram(program);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);

SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();

std::cout << "all good in the hood" << std::endl;
}
catch(const std::exception& e)
{
std::cout << "ERROR:\t" << e.what() << std::endl;
}
catch(...)
{
std::cout << "ERROR" << std::endl;
}
exit(EXIT_SUCCESS);
}

My Frag and vert shaders are inconsequential.

I've also checked that the max and min values in the indices vectors are within the bounds of my vertices.

This is such a beginner program that I'm assuming I've missed something incredibly simple, but I cannot see the problem. At this point I've tried every debugging technique I know.

Advertisement

I don't see anything wrong in your code (apart from the lack of indentation :)). What happens if you rebind the index buffer before glDrawArrays? I've noticed some drivers don't keep the binding for it, even though they should.

Thanks for your reply Xycaleth. I've tried this, it as one of the first things I tried and didn't do anything.

Are you sure the GL_DOUBLE vertex format is supported by your GL driver?

Try GL_FLOAT.

I love you. GL_DOUBLE was not supported.

My god. How is it even possible to know this stuff? Only GL_UNSIGNED_INT_10F_11F_11F_REV is mentioned in the docs as having support only in 4.4+

Are you sure the GL_DOUBLE vertex format is supported by your GL driver?

Try GL_FLOAT.

Good spot :)

NeomerArcana01, for double-precision attributes you need to use glVertexAttribLPointer (notice the L before Pointer). Seems a bit odd to do this but that's how the GL spec was written :/

Thanks a lot guys, I feel like a right idiot now; but I'm glad I learned this. I'm so used to C++ function overloading that the possibility of differently named functions didn't even enter my head.

In general you have to set a minimum GL version, say for example you select GL 3.3 as your minimum platform, and then you can check the specification for what is supported for that version.

Then you can use glGet to get some implementation-defined limits if you want to use something that isn't guaranteed to be supported, like glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &number) to find out how many vertex attribs you can send to your shader. However, the reference page says that the minimum required is 16, so you only have to bother when using more than that.

https://www.opengl.org/sdk/docs/man3/

https://www.opengl.org/sdk/docs/man4/

The 4.5 specification has a table for vertex attrib support it appears, if you click the glVertexAttrib* in the menu and scroll to the bottom of the page.

This topic is closed to new replies.

Advertisement