OpenGL crashes without error message

Started by bene_2808, March 06, 2020, 09:25:39

Previous topic - Next topic

bene_2808

Hey forum,

I'm trying to execute a compute shader with relatively big workload (e.g. 128m invocations in sum). I checked the limits for thread group size and counts along the axes and the limit for the sum group count. None is exceeded. Nevertheless when querying the results from a buffer via glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY) after running the compute shader, my Java application just terminates without an error message or anything. This error seems only to happen if the work group count is somewhat too high.
Has anybody stumbled across sth similar and can tell me how to solve it? Or is there a log file with additional information somewhere? Could it be a driver bug (RTX 2070)? Or is there sth I must have done terribly wrong to produce that result? ???

Thanks in advance! :D

spasi

How big is the buffer? Note that ByteBuffers in Java cannot index more than Integer.MAX_VALUE bytes.

bene_2808

The buffers are very small compared to the count of work groups. Just a few kilobytes, maximal megabytes...

spasi

First step is making sure you're not doing something obviously wrong. The simplest approach is running your application with LWJGLX/debug.

bene_2808

Hey this tool really seems to be great. Haven't known about it before. Thanks!

But I think, the output is "inconspicuous". The only messages I get seem to be notifications (e.g. for performance) with at most medium severity, e.g.:

[warn ][1] OpenGL debug message
  ID: 0x20072
  Source: API
  Type: PERFORMANCE
  Severity: MEDIUM
  Message: Buffer performance warning: Buffer object 3 (bound to GL_ATOMIC_COUNTER_BUFFER, and GL_ATOMIC_COUNTER_BUFFER (0), usage hint is GL_DYNAMIC_COPY) is being copied/moved from VIDEO memory to HOST memory.
  Stacktrace: org.lwjgl.system.JNI.callPPPV(Native Method)


Or:

[info ][1] OpenGL debug message
  ID: 0x20071
  Source: API
  Type: OTHER
  Severity: NOTIFICATION
  Message: Buffer detailed info: Buffer object 3 (bound to GL_ATOMIC_COUNTER_BUFFER, and GL_ATOMIC_COUNTER_BUFFER (0), usage hint is GL_DYNAMIC_COPY) will use VIDEO memory as the source for buffer object operations.
  Stacktrace: org.lwjgl.opengl.GL11C.glDrawArrays(Native Method)


Of course I get these messages not only for atomic counter buffers, but for all kinds of my buffers.

So have you got any further idea? :-\

spasi

Would need more details about your program (are you using threads? could it be bad synchronization somewhere?). Or an MCVE.

Also, when the JVM crashes, there's usually a hs_err_pid*.log file written to the application folder. Is there one that you could share?

bene_2808

Nope it's singlethreaded. So no bad synchronization. Of course I can't exclude bad synchronization between threads on the GPU, even if I'm quite sure that the problem isn't there.

Thanks for linking the MCVE ;D. Unfortunately it seems to be very hard in this case to break down the code to an example which reproduces the error. I already tried switching to my integrated graphics chip. There it worked. Way slower of course, but it didn't crash.

Sometimes behaviour is really weird for this application. For example the program crashes for a certain problem size. But if I insert glFinish() at some points it crashes way earlier. Is this expectable behaviour? I thought glFinish() would just cause the calling CPU thread to pause until all pending requests have been finished.

And unfortunately there's no hs_err_pid.log file, too. That's why I am so confused right now. I'm used to at least get one of these, too... :-X

bene_2808

Ok, i've managed to find some bugs I admittedly caused myself... ::)

And here's the minimal crashing example. It's just supposed to atomically increase a buffer and print the resulting value.

private static final int size = 976191488;

public static void main(String[] args) {
	// GL initialisieren
	GLFW.glfwInit();
	final long window = GLFW.glfwCreateWindow(1, 1, "Test", 0L, 0L);
	GLFW.glfwMakeContextCurrent(window);
	GL.createCapabilities();
	// Shader initialisieren
	final int shader = GL46.glCreateShader(GL46.GL_COMPUTE_SHADER);
	GL46.glShaderSource(shader, loadShaderCode());
	GL46.glCompileShader(shader);
	final String info = GL46.glGetShaderInfoLog(shader);
	if (info != null && info.length() > 0) {
		throw new RuntimeException("Fehler beim Kompilieren:\n" + info);
	}
	// Program initialisieren
	final int program = GL46.glCreateProgram();
	GL46.glAttachShader(program, shader);
	GL46.glLinkProgram(program);
	if (GL20.glGetProgrami(program, GL20.GL_LINK_STATUS) != GL11.GL_TRUE) {
		throw new RuntimeException("Fehler beim Initialisieren des Programs:\n" + GL46.glGetProgramInfoLog(program));
	}
	// Buffer erzeugen
	int buffer = GL46.glGenBuffers();
	GL46.glBindBuffer(GL46.GL_SHADER_STORAGE_BUFFER, buffer);
	GL46.glNamedBufferData(buffer, 4, GL46.GL_DYNAMIC_COPY);
	// Shader ausführen
	final int[] groupSize = new int[3];
	GL46.glGetProgramiv(program, GL43.GL_COMPUTE_WORK_GROUP_SIZE, groupSize);
	final int groupCount = ceil(size, groupSize[0]);
	GL46.glUseProgram(program);
	GL46.glUniform1ui(GL46.glGetUniformLocation(program, "size"), size);
	dispatch(program, groupCount, buffer);
	dispatch(program, groupCount, buffer);
}
	
private static void dispatch(int program, int groupCount, int buffer) {
	ByteBuffer bytes;
	// Buffer auf 0 setzen
	bytes = GL46.glMapNamedBuffer(buffer, GL46.GL_WRITE_ONLY);
	bytes.putInt(0);
	GL46.glUnmapNamedBuffer(buffer);
	// Program ausführen
	final int binding = 0;
	GL46.glShaderStorageBlockBinding(program, GL46.glGetProgramResourceIndex(program, GL46.GL_SHADER_STORAGE_BLOCK, "numberBuffer"), binding);
	GL46.glBindBufferBase(GL46.GL_SHADER_STORAGE_BUFFER, binding, buffer);
	GL46.glDispatchCompute(groupCount, 1, 1);
	// Ergebnisse lesen
	bytes = GL46.glMapNamedBuffer(buffer, GL46.GL_READ_ONLY);
	final int result = bytes.getInt();
	GL46.glUnmapNamedBuffer(buffer);
	System.out.printf("result: %d\n", result);
}
	
private static int ceil(int dividend, int divisor) {
	return (dividend + divisor - 1) / divisor;
}


And here's the shader:

#version 430

uniform uint size;

layout (std430) buffer numberBuffer {
	uint number;
};

layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

void main() {
	if (gl_GlobalInvocationID.x >= size) {
		return;
	}
	atomicAdd(number, 1);
}


For me the program doesn't manage to do the second print. To be more precise it crashes while trying to map the buffer for reading. I tried out some synchronization here, too, but it didn't work either and actually I never experienced that it's necessary. If I use glGetBufferSubData it works.