Garbage written to end of SSBO depending on buffer size

I’m trying to figure out why my compute shader is writing garbage into the end of my SSBO - but only for some buffer sizes.

I’m working on a marching cubes shader which I want to examine an input 3D texture and output a set of points coresponding to the vertices of the final mesh. Since the number of vertices can be anywhere between 0 and (volume_of_image * 3 * 5), I can’t predetermine the address each vertex with be written do and instead am doing some on-thy-fly memory management by using an atomicAdd so each invocation and ‘allocate’ a chunk of the output buffer once it knows how many vertices it is writing. While this works fine some of the time, other times the end of the buffer seems to be filled with what seems to be random values.

Adjusting the size of the buffer will change whether or not the end of the buffer is written to correctly. Strangely, larger buffer sizes will sometimes produce garbage where smaller ones do not. In one of my test cases, I set it up so that each invocation will write 3 vec4 to the buffer. This allowed me to precalculate a buffer size. Oddly, this minimal buffer was written to with no errors while a second buffer more than three times its size had the end of the data written to it corrupted. I am calling sync() which ought to cause the compute shader program to finish, but perhaps it isn’t? I also tried calling barrier() with the compute shader flag but this didn’t help. (I’m writing this in GDScript for Godot, so I have to work with the API commands they provide me).

I don’t understand what could be happening here. Why does using an oversized buffer cause corruption (but not always - an even bigger buffer was not corrupted)? How can I choose the size of my buffer if I don’t know the number of vertices being output in advance?

#[compute]
#version 450

layout(set = 0, binding = 1, std430) restrict buffer ParamBufferRW {
	int num_vertices;
}
params_rw;

layout(rgba32f, set = 0, binding = 4) writeonly restrict uniform image1D result_points;
layout(rgba32f, set = 0, binding = 5) writeonly restrict uniform image1D result_normals;

...
    main{

        ...

	int read_pos = tessellation_offsets[cube_index];
	int num_points = tessellation_offsets[cube_index + 1] - read_pos;
	int write_pos = atomicAdd(params_rw.num_vertices, num_points);
	
	for (int i = 0; i < num_points; ++i) {
		imageStore(result_points, write_pos + i, vec4(5, 6, 7, 1));
		
	}
}

You’re not writing to an SSBO; you’re writing to an image. Hence the command imageStore. SSBOs and images aren’t the same thing.

1D images have a fixed, maximum size. And that size is generally not large.

1 Like