Hello Guest

[BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)

  • 9 Replies
  • 7269 Views
While trying my hand at instanced rendering, I encountered the following crash (the full report is attached to this message):

Code: [Select]
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006926b691, pid=10056, tid=13644
#
# JRE version: 7.0-b147
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0-b17 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [atio6axx.dll+0x23b691]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# E:\Workspace\hs_err_pid10056.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

This is systematically reproducible under LWJGL 2.9.1 and 2.9.2 using the following self-contained snipped (I removed most code, including errors checking, to keep it small):

Code: [Select]
package crashtest;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL31.*;
import static org.lwjgl.opengl.GL33.*;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.Util;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;

public class CrashExample {

private static final int SCREEN_WIDTH = 640;
private static final int SCREEN_HEIGHT = 400;

private static int NB_ENTITIES = 2;
private static final int FLOAT_SIZE = 4;

private static final String vertexShader =
"#version 330 core\r\n" +
"in vec2 vertexPosition_modelspace;\r\n" +
"in mat4 modelMatrix;\r\n" +
"void main() {\r\n" +
"    gl_Position = modelMatrix * vec4(vertexPosition_modelspace, 0, 1);\r\n" +
"}\r\n";

private static final String fragmentShader =
"#version 330 core\r\n" +
"out vec3 color;\r\n" +
"void main() {\r\n" +
" color = vec3(1,1,1);\r\n" +
"}";

private static final float triangle_vertex[] = { 0, 1, 1, 0, 1, 1 };

private int vertexBuffer;
private int modelMatrixBuffer;

private int posID;
private int modelMatrixID;

public static int makeShader(int type, String code) {
int shader = glCreateShader(type);
glShaderSource(shader, code);
glCompileShader(shader);
return shader;
}

public static FloatBuffer buildFloatBuffer(float[] data) {
FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(data.length);
dataBuffer.put(data);
dataBuffer.flip();
return dataBuffer;
}

public static FloatBuffer buildFloatBuffer(Matrix4f mat) {
FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(4 * 4);
mat.store(dataBuffer);
dataBuffer.flip();
return dataBuffer;
}

private void setup() throws LWJGLException, Exception, Error {
Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
Display.create();

// Set up shaders and program
int vs = makeShader(GL_VERTEX_SHADER, vertexShader);
int fs = makeShader(GL_FRAGMENT_SHADER, fragmentShader);
int program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glUseProgram(program);

// Get program attributes
posID = glGetAttribLocation(program, "vertexPosition_modelspace");
modelMatrixID = glGetAttribLocation(program, "modelMatrix");

// Create a VAO
glBindVertexArray(glGenVertexArrays());

// Vertices for one triangle
vertexBuffer = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, buildFloatBuffer(triangle_vertex), GL_STATIC_DRAW);

// One matrix per instance; dynamic data
modelMatrixBuffer = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, modelMatrixBuffer);
glBufferData(GL_ARRAY_BUFFER, FLOAT_SIZE * 4 * 4 * NB_ENTITIES, GL_DYNAMIC_DRAW);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

Util.checkGLError();
}

private void render() {

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnableVertexAttribArray(posID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(posID, 2, GL_FLOAT, false, 0, 0);

// Build model matrices
FloatBuffer currentModelMatrices = BufferUtils.createFloatBuffer(4 * 4 * 2);
Matrix4f modelMatrix1 = new Matrix4f().scale(new Vector3f(0.5f, 0.5f, 0));
currentModelMatrices.put(buildFloatBuffer(modelMatrix1));
Matrix4f modelMatrix2 = new Matrix4f().scale(new Vector3f(0.2f, 0.2f, 0));
currentModelMatrices.put(buildFloatBuffer(modelMatrix2));
currentModelMatrices.flip();

// Upload model matrices
glEnableVertexAttribArray(modelMatrixID);
glBindBuffer(GL_ARRAY_BUFFER, modelMatrixBuffer);
glBufferData(GL_ARRAY_BUFFER, currentModelMatrices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(modelMatrixID, 16, GL_FALSE, false, 0, 0);
glVertexAttribDivisor(modelMatrixID, 1);

// Instanced draw
glDrawArraysInstanced(GL_LINE_LOOP, 0, 3, NB_ENTITIES);
}

private void start() throws Exception {
setup();

while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
render();
Display.update();
}

Display.destroy();
}

public static void main(String[] argv) throws Exception {
new CrashExample().start();
}
}

So, two questions:
  • Do you still accept bug reports filed under LWJGL 2.9, or should I port this to LWJGL 3 beforehand? :)
  • What am I doing wrong?

regards,
Olivier.

*

Kai

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #1 on: January 05, 2015, 22:16:50 »
You have a typo in your code in line 128 in the listing it says *GL_FALSE* for the value type of the vertex attribute, where it should've been *GL_FLOAT* like in line 114 of the same listing.
Instanced rendering is really bitchy also on my machine. If only a single slightest error is in the code (like forgetting to glEnableVertexAttribArray), the whole thing crashes horribly. :)
But that's not LWJGL's fault. As they say (in German): The root of the problem sits in front of the monitor. :)

As a side note: You do not need to glEnableVertexAttribArray and glVertexAttribPointer your data with every frame. This state is captured inside of the VAO. So in your setup() method you could just once do that and in your render method only bind and unbind your VAO (which of course you need to remember the handle of then).
« Last Edit: January 05, 2015, 22:34:49 by Kai »

*

Offline quew8

  • *****
  • 569
  • Because Square Eyes Look More Real
Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #2 on: January 06, 2015, 17:08:09 »
The root of the problem sits in front of the monitor.

That's a nice saying. I might steal that.

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #3 on: January 06, 2015, 20:55:47 »
You have a typo in your code in line 128 in the listing it says *GL_FALSE* for the value type of the vertex attribute, where it should've been *GL_FLOAT* like in line 114 of the same listing.

Thanks for taking the time to check my code. Now that you've hinted at it, there are actually two errors on line 128. I am specifying a "size" of 16, while it cannot be more than 4. Hence the crash.

So, contrarily to uniforms where I can happily bind a mat4, does this means that my only option to bind matrices to vertex attributes is to decompose them in 4 "vec4" (or an equivalent representation)?

Instanced rendering is really bitchy also on my machine. If only a single slightest error is in the code (like forgetting to glEnableVertexAttribArray), the whole thing crashes horribly. :)
But that's not LWJGL's fault. As they say (in German): The root of the problem sits in front of the monitor. :)

I can see your point, but I beg to differ. Up to now I've been shielded from such low-level crashes by LWJGL (and NIO buffers) checks. To avoid making this mistake in the future, I'll probably write a "glVertexAttribPointerChecked" which will throw an exception if I pass too large a size.

As a side note: You do not need to glEnableVertexAttribArray and glVertexAttribPointer your data with every frame. This state is captured inside of the VAO. So in your setup() method you could just once do that and in your render method only bind and unbind your VAO (which of course you need to remember the handle of then).

Interesting. So my "checked" version won't incur a significant overhead :)

Regards,
Olivier.

*

Kai

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #4 on: January 06, 2015, 21:04:14 »
Quote
... does this means that my only option to bind matrices to vertex attributes is to decompose them in 4 "vec4" ...
Yes, exactly. See https://www.opengl.org/discussion_boards/showthread.php/164099-how-to-specify-a-matrix-vertex-attribute. They say that too. Also, they say that a mat4 when being used as a vertex attribute would allocated 4 consecutive slots/indexes. So you would be needing to four times bind your buffer containing the matrices.
Thankfully though, you can use interleaved buffers with stride = 16*4 and 4-step-increasing offset respectively to not have 4 buffers for your 4 columns of each matrix.

Quote
I can see your point, but I beg to differ. Up to now I've been shielded from such low-level crashes by LWJGL (and NIO buffers) checks. To avoid making this mistake in the future, I'll probably write a "glVertexAttribPointerChecked" which will throw an exception if I pass too large a size.

Yeah, for vertex attributes you would be needing your own "shielding" code at both the vertex attribute specification commands AND the draw commands, since that is where the crash happens. So, the draw commands must also check that each bound vertex attribute buffer contains sufficient data!

EDIT:

So, the root cause of the problem is actually the draw command trying to source vertex attributes from an unspecified buffer, because I am certain that that glVertexAttribPointer call failed and raised a GL_INVALID_VALUE which you should check. Therefore, at that vertex attribute index there was no backing buffer and as such, the program crashed.
« Last Edit: January 06, 2015, 21:20:16 by Kai »

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #5 on: January 06, 2015, 21:37:38 »
Yes, exactly. See https://www.opengl.org/discussion_boards/showthread.php/164099-how-to-specify-a-matrix-vertex-attribute. They say that too. Also, they say that a mat4 when being used as a vertex attribute would allocated 4 consecutive slots/indexes. So you would be needing to four times bind your buffer containing the matrices.
Thankfully though, you can use interleaved buffers with stride = 16*4 and 4-step-increasing offset respectively to not have 4 buffers for your 4 columns of each matrix.
Indeed, now that I know what to search for, I've found similar confirmations.

So there's some syntactic sugar to simplify this binding, at least from the shader side. I think the java side code will get wrapped in an helper, though :)

Quote
Yeah, for vertex attributes you would be needing your own "shielding" code at both the vertex attribute specification commands AND the draw commands, since that is where the crash happens. So, the draw commands must also check that each bound vertex attribute buffer contains sufficient data!
Now that feels like overkill, at least in the render loop :) But that could be a debugging option.

Quote
So, the root cause of the problem is actually the draw command trying to source vertex attributes from an unspecified buffer, because I am certain that that glVertexAttribPointer call failed and raised a GL_INVALID_VALUE which you should check. Therefore, at that vertex attribute index there was no backing buffer and as such, the program crashed.

Very interesting, I'll investigate this. I'm surprised this did not show up in my original code, which used a debugging context, though.

*

Kai

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #6 on: January 06, 2015, 21:41:35 »
Quote
Now that feels like overkill, at least in the render loop :) But that could be a debugging option.

Agreed! That's probably the reason why the graphics driver is also not doing that, but instead just crashes the application. ;)

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #7 on: January 06, 2015, 21:55:32 »
So, the root cause of the problem is actually the draw command trying to source vertex attributes from an unspecified buffer, because I am certain that that glVertexAttribPointer call failed and raised a GL_INVALID_VALUE which you should check. Therefore, at that vertex attribute index there was no backing buffer and as such, the program crashed.

You nailed it. By calling Util.checkGLError() just after glVertexAttribPointer, I triggered the expected exception:
Code: [Select]
Exception in thread "main" org.lwjgl.opengl.OpenGLException: Invalid value (1281)
at org.lwjgl.opengl.Util.checkGLError(Util.java:59)
at crashtest.CrashExample.render(CrashExample.java:131)
at crashtest.CrashExample.start(CrashExample.java:143)
at crashtest.CrashExample.main(CrashExample.java:151)

So that's another incentive to wrap glVertexAttribPointer in a less brittle helper :)

Thanks for your time investigating this.

Regards,
Olivier.

*

Kai

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #8 on: January 06, 2015, 22:24:13 »
Oh, you gonna like this one:

Since you are using LWJGL 2.9, you can use the lwjgl-debug.jar during development, which does GL error checking after each GL call and raises a Java exception on error.
So no need to wrap anything. :)

Cheers,
Kai

Re: [BUG] EXCEPTION_ACCESS_VIOLATION (Instanced Rendering-related?)
« Reply #9 on: January 07, 2015, 06:20:25 »
If that means no low-level crashes debugging during development, I will definitely use this :) Since error checking is performed for each call, pinpointing the faulty one will be easy.

Thanks for the information!

Regards,
Olivier.