PDA

View Full Version : using GL_LINEAR_MIPMAP_LINEAR filter cause crash



jianliang79
09-08-2011, 07:52 PM
I have recently encountered an annoying crash problem when using GL_LINEAR_MIPMAP_LINEAR filter to sample texture image(only with my ATI card, my nVidia card works fine), to demonstrate this problem I wrote a sample program to reproduce it, the code snippet is listed below:


static char *g_vertexShader =
"#version 150\n"
"uniform mat4 mvp;\n"
"in vec2 vertex;\n"
"in vec2 texCoord;\n"
"out vec2 fragTexCoord;\n"
"void main()\n"
"{\n"
"fragTexCoord = texCoord;\n"
"gl_Position = mvp * vec4(vertex, 0, 1);\n"
"}\n";

static char *g_fragmentShader =
"#version 150\n"
"uniform sampler2D texSampler;\n"
"in vec2 fragTexCoord;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
"fragColor = texture(texSampler, fragTexCoord);\n"
"}\n";

struct SVertex {
GLfloat x, y;
GLfloat s, t;
};

static void crash()
{
//
// prepare shader program
//
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLint shaderLen = -1;
glShaderSource(vertexShader, 1, (const GLchar **)&g_vertexShader, &shaderLen);
glCompileShader(vertexShader);

GLint compileStatus = GL_FALSE;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &compileStatus);

GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, (const GLchar **)&g_fragmentShader, &shaderLen);
glCompileShader(fragmentShader);

glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &compileStatus);

GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

GLint linkStatus = GL_FALSE;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &linkStatus);

//
// create VAO
//
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

//
// create VBO
//
GLuint vbo = 0;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

SVertex vtx[4];
vtx[0].x = 0;
vtx[0].y = 1;
vtx[0].s = 0;
vtx[0].t = 1;
vtx[1].x = 0;
vtx[1].y = 0;
vtx[1].s = 0;
vtx[1].t = 0;
vtx[2].x = 1;
vtx[2].y = 1;
vtx[2].s = 1;
vtx[2].t = 1;
vtx[3].x = 1;
vtx[3].y = 0;
vtx[3].s = 1;
vtx[3].t = 0;

glBufferData(GL_ARRAY_BUFFER, sizeof(SVertex) * 4, vtx, GL_STATIC_DRAW);

GLint attribIdx;
attribIdx = glGetAttribLocation(shaderProgram, "vertex");
glEnableVertexAttribArray(attribIdx);
glVertexAttribPointer(attribIdx, 2, GL_FLOAT, GL_TRUE, sizeof(GLfloat) * 4, (const GLvoid *)0);

attribIdx = glGetAttribLocation(shaderProgram, "texCoord");
glEnableVertexAttribArray(attribIdx);
glVertexAttribPointer(attribIdx, 2, GL_FLOAT, GL_TRUE, sizeof(GLfloat) * 4, (const GLvoid *)(sizeof(GLfloat) * 2));

glBindBuffer(GL_ARRAY_BUFFER, 0);

//
// create FBO
//
GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);

//
// create textures
//
GLuint tex[2] = {0, 0};
glGenTextures(2, tex);

glBindTexture(GL_TEXTURE_2D, tex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1920, 1080, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);

glBindTexture(GL_TEXTURE_2D, tex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1920, 1080, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);

glViewport(0, 0, 1920, 1080);

glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[0], 0);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

glUseProgram(shaderProgram);

//
// setup uniform
//
GLint uniformLoc = glGetUniformLocation(shaderProgram, "mvp");
// model/view/projection matrix
GLfloat matUniform[16] = {2, 0, 0, 0, 0, 2, 0, 0, 0, 0, -1, 0, -1, -1, 0, 1};
glUniformMatrix4fv(uniformLoc, 1, GL_FALSE, matUniform);

uniformLoc = glGetUniformLocation(shaderProgram, "texSampler");
glUniform1i(uniformLoc, 0);

glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[1], 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // crash in this line!
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);

glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);

glDeleteTextures(2, tex);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);

glDeleteBuffers(1, &vbo);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);

glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteProgram(shaderProgram);
}


I run this code in windows 7 x64 and I have an ATI radeon 5770 card with catalyst 11.8 driver installed in my system, It will crash in
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); But this code works fine in my nVidia card. This crash will NOT happen if I don't use a FBO to draw to the first texture which I will sample later or if I don't set its filter mode to GL_LINEAR_MIPMAP_LINEAR. Is anything wrong with my code ?

strattonbrazil
09-08-2011, 10:53 PM
This may help you.

http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=251072

jianliang79
09-09-2011, 01:10 AM
I have read that post, but I think that case is not very similar to my case.
1) In that post, that program crashed when generating mipmap for texutre, but in my case the crash is happened when I was issuing GL draw command.
2) In that post, that program didn't draw something to the texture through FBO before generating mipmap for it; In my case I clear the texture through FBO before generating mipmap for it, and then use it as an input texture for the next drawing command.
3) In that post they used some tricks to workaround the crash, for example, call glEnable(GL_TEXTURE_2D); or glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); before generating mipmap, but that thing has been deprecated in opengl 3 (I used a opengl 3.2 core profile context)

nsdev
09-09-2011, 03:58 AM
Could you try a quick workarround: before calling glGenerateMipmap() function set first the mipmap filtering mode for the texture to LINEAR_MIPMAP_LINEAR.

So instead of:


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);


you will have:


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);

jianliang79
09-09-2011, 07:53 AM
hi, nsdev:
In fact when I wrote this sample program for the first time I call glTexParameteri(GL_TEXTURE_2D, L_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); before generating mipmap for the texture, in this case the program will crash in glGenerateMipmap(GL_TEXTURE_2D); To avoid this crash I place the GL_LINEAR_MIPMAP_LINEAR mode setting code after mipmap generating deliberately, but this time the crash happens in glDrawArrays();

I think the point of this issue is that: render something to a texture through FBO before generating mipmap to this texture and use it as an input texture to draw something later will always lead to crash in ATI card (sometimes when generating mipmap and sometimes when issue draw command)

nsdev
09-09-2011, 08:10 AM
If it's like you say it means that this bug I already raised a few months before is not yet fixed at ATI side: post (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Main=52814&Number=2735 38#Post273538)
Check that post. There is a workaround suggested for this.

I was under the impression that they fixed it already.

Alfonse Reinheart
09-09-2011, 02:31 PM
I don't know why it is that you constantly feel the need to flip the filtering mode. Just set it to GL_LINEAR_MIPMAP_LINEAR when you create it and be done with it. The filtering mode has no effect on how rendering to the image via FBOs work. You do need to set a proper filtering mode to make the texture complete.

Yes, setting GL_LINEAR_MIPMAP_LINEAR on a texture with no mipmaps can make the texture incomplete. But the easiest way to do that is to generate the mipmap pyramid by hand beforehand. There's a reason why we just got new functions to allocate a mipmap pyramid all in one shot: because drivers like it that way.

The first thing you should always do when creating a texture is to allocate the mipmaps for it. You don't need data; you can pass NULL for those mipmaps. But you should always generate storage for them with glTexImage* if you intend to use mipmaps.

After that, the next thing you should do is set the GL_TEXTURE_BASE/MAX_LEVEL correctly. Note that it is not a half-open range; it is an inclusive range. So if you have 10 mipmaps, then the base level is 0 and the max level is 9. Never leave these at the default settings.

Note: this doesn't excuse the crash. But you're more likely to not get a crash if you're as up-front with the driver as possible.

nsdev
09-10-2011, 01:58 AM
Alfonse, from where did you deduce that I "constantly feel the need to flip the filtering mode"? Please read carefully before jumping to conclusions.

I've just said that after an year I would have expected that bug to be fixed. Especially by such an important provider like AMD. Or maybe you consider this kind of driver problems not important? It is in small details where a software's quality lies.

jianliang79
09-12-2011, 10:07 PM
Hi, Alfonse, by allocating mipmap storage before calling glGenerateMipmap() to generate mipmap for texture I have successfully avoid the crash. Thank you!

But this behaviour of AMD driver is a bug, where can I report bug to AMD openGL driver?