Need help with geometry shader

Tried to switch to geometry shaders for my square & triangle faces but ran into an issue with input, the example I followed didn’t specify an array limit for gl_in[] but when I try to compile my glsl it complains it needs a limit, yet this would defy the purpose of the geometry shader (at least the way I’m trying to use it), someone mind taking a look at telling me if there’s a way to go about doing it how I’ve tried:

#version 430

uint	vertices = 3;
uint	uquarter = ~0u / 4;
double	dquarter = double(uquarter);

void emit_vertex( vec4 PosPoint, uint x, uint y )
{
	vec4 point = { 0.0, 0.0, 0.0, 0.0 };
	point.x = float(double(x) / dquarter);
	point.y = float(double(y) / dquarter);
	point.w = 1.0;
	point.xy += PosPoint.xy;
	gl_Position = point;
	EmitVertex();
}

void main()
{
	for ( int i = 0; i < gl_in.length(); ++i )
	{
		vec4 PosPoint = gl_in[i].gl_Position;
		uint v, qtr = ~0u / 4, oct = ~0u / 8;
		double aim;
		double cap = double(~0u);
		double max = double(3);

		for ( v = 0, aim = 0.0; v < 3; ++v, ++aim )
		{
			uint rotate = uint((aim / max) * cap);
			uint linear = rotate % qtr;
			uint curved = linear + (linear / 3);

			/* Normal vertex */
			emit_vertex( PosPoint, linear, uquarter - linear );

			/* Curve vertex */
			if ( linear < oct )
				emit_vertex( PosPoint, curved, uquarter - linear );
			else
				emit_vertex( PosPoint, linear, uquarter - curved );
		}
	}
}

Making a working GS requires that you specify certain things. Among them is what primitive type the GS is made for. That means that every GS is specific to a particular primitive, so the array size of the input is specific to that primitive size. You don’t have to explicitly write this size in your shader anywhere, but you do have to specify the input primitive which defines the input size.

Is there a way to declare that it be used for any primitive? I’m designing my shader around that, I REALLY do not want to waste bytes on duplicate shaders for different types that do the exact same thing, it’s really wasteful and error prone.

No. That’s why I said “requires”.

Well that’s silly, there’s absolutely no reason it should require that, vertex & color shaders can work without knowing if they’re working with triangles, lines or points, there’s no reason the geometry shader needs to know either, it should only deal with the buffer (which also seems weird to me, isn’t the point to generate a shape around a point? why does it need to access the buffer of points when it’s only dealing with one point per usage anyways?), oh well, I’ve set it to points for now but I still see it as shooting devs in both feet for no good reason.

Also having another strange issue with a uniform being “inactive” despite being used, originally was used in vertex shader by I’ve just switched that to geometry shader as it made more sense there.

#version 430

layout(points) in;

uint	vertices = 3;
uint	uquarter = ~0u / 4;
double	dquarter = double(uquarter);

uniform ivec2	WinLimit;
uniform vec2	WinScale;

void emit_vertex( vec4 PosPoint, uint x, uint y )
{
	vec4 point = { 0.0, 0.0, 0.0, 0.0 };
	point.x = float(double(x) / dquarter);
	point.y = float(double(y) / dquarter);
	point.w = 1.0;
	point.xy *= WinScale.xy;
	point.xy += PosPoint.xy;
	gl_Position = point;
	EmitVertex();
}

void main()
{
	for ( int i = 0; i < gl_in.length(); ++i )
	{
		vec4 PosPoint = gl_in[i].gl_Position;
		uint v, qtr = ~0u / 4, oct = ~0u / 8;
		double aim;
		double cap = double(~0u);
		double max = double(3);

		for ( v = 0, aim = 0.0; v < 3; ++v, ++aim )
		{
			uint rotate = uint((aim / max) * cap);
			uint linear = rotate % qtr;
			uint curved = linear + (linear / 3);

			/* Normal vertex */
			emit_vertex( PosPoint, linear, uquarter - linear );

			/* Curve vertex */
			if ( linear < oct )
				emit_vertex( PosPoint, curved, uquarter - linear );
			else
				emit_vertex( PosPoint, linear, uquarter - curved );
		}
	}
}

Getting this output:

make debug=1 run
...
cd bin && ./d-check_extra.elf
Attempting to open 'libd-extraglfw.so' & 'libd-extragl.so'
Creating program '[vfxapp.pyramid]'
text = 'point.glsl'
point=shaders/point.glsl
text = '2d-shape.glsl'
shape=shaders/2d-shape.glsl
text = 'pixel.glsl'
shaders/pixel.glsllsl
src/extra/viewfx/vfxapp.c:273: Error 0x00000002 (2) ENOENT
Unable to open 'shaders/pixel.glsllsl'
source = GL_DEBUG_SOURCE_API, defect = GL_DEBUG_TYPE_ERROR, weight = GL_DEBUG_SEVERITY_HIGH, seekid = 1 (GL_ID_UNKOWN)
report = GL_INVALID_OPERATION in glGetUniformLocation(program not linked)
test/extra/main.c:347: WinLimit not found
source = GL_DEBUG_SOURCE_API, defect = GL_DEBUG_TYPE_ERROR, weight = GL_DEBUG_SEVERITY_HIGH, seekid = 1 (GL_ID_UNKOWN)
report = GL_INVALID_OPERATION in glGetUniformLocation(program not linked)
test/extra/main.c:374: WinScale not found
source = GL_DEBUG_SOURCE_API, defect = GL_DEBUG_TYPE_ERROR, weight = GL_DEBUG_SEVERITY_HIGH, seekid = 1 (GL_ID_UNKOWN)
report = GL_INVALID_OPERATION in glGetAttribLocation(program not linked)
test/extra/main.c:399: Error 0xFFFFFFFF (-1) EUNKNOWN
test/extra/main.c:503: Error 0xFFFFFFFF (-1) EUNKNOWN
test/extra/main.c:254: Error 0xFFFFFFFF (-1) EUNKNOWN
Compilation finished successfully.

WinLimit I understand but WinScale? That IS in use so it should be locatable, any ideas?

The whole point of a geometry shader is to operate upon a complete primitive. Which it can’t do without knowing the type of the primitive.

What exactly are you trying to do that works identically for points, lines and triangles.

generate shapes using just the center point and vertex count, wether the shape is connected to a bigger primitive or not is irrelevant to the shader. I’m basically treating all standard 2d shapes as circles, just with varying numbers of vertices.

It has to know because that is its function. Your problem is that you want to do something that GS’s aren’t meant to do. What you seem to want is a vertex shader that can output multiple vertices. GS’s aren’t that.

A GS takes as input a primitive and outputs zero or more primitives. That’s its job. Taking a primitive requires knowing what primitive it is taking, because again, that’s its job.

The tool you want seems to be a compute shader. There, each invocation can read a separate vertex from an SSBO and write 6 vertices to a different SSBO. You can then use that buffer as source input data to a rendering operation. This works better because shared vertices don’t generate duplicate data (though if you’re using indexed rendering, you will have to change your indices accordingly).

Your problem is that the program didn’t link, almost certainly because the GS lacked an output declaration too. A GS needs a layout in declaration, but it needs other stuff too, as I linked to.

Uh, isn’t gl_Position an output though? Quite the important output too.

Edit: Side note, switched to compute shader as you suggested, compiles fine but haven’t been able to test it because of some bazar memory issue (unrelated to opengl, just mentioning for the curious), somehow my temporary buffer for paths is being both wiped & restored, the wiping is intentional, it’s to ensure the constructed path ends where I expect it to, however the weird part is that even though the debugger shows it being cleared it somehow gets restored before the next path is constructed, creating a corrupt path by the end of it, for example where I should get “shaders/color.glsl” I instead get “shaders/color.glsllsl”, I know where the end “lsl” came from but don’t understand how it’s still there after being wiped, I even tried looking for old pointers but even that doesn’t turn up anything, as far as I can find this situation should be impossible and yet it occurs.

I don’t know what you mean by that. As previously stated, a GS takes a primitive as input and outputs zero or more primitives. There are multiple kinds of primitives you can output, so your GS needs to specify what type of primitive gets output.

That is, a GS doesn’t have to output the same kind of primitive as it inputs. You can turn points into triangles, triangles into lines, etc.

A vertex, by itself, doesn’t mean anything. It only gains meaning when it (and others) are aggregated into one or more primitives. The GS’s output primitive type tells what kind of primitive the GS’s output vertices will be aggregated into.

I get specifying the output, that’s fine, but there still shouldn’t be a need to specify the input, that should be optional, how are GPUs supposed to know whether a shader is intended for many kinds of input or just a single? It should be set to all by default and let the developer switch to specific if they’re expecting only specific.

What you have said doesn’t make sense with the OpenGL rendering pipeline.

A GS takes a primitive as input. But a vertex shader outputs a series of vertices. Therefore, for a GS (or rendering in general) to make sense, those vertices must be assembled into a set of primitives.

Given a series of vertices, assembling a primitive involves reading some of these vertices based on a particular algorithm. This includes retaining the first vertex in a triangle fan (since each triangle in the fan has the same first vertex), front/back facing calculation for alternating triangles in a strip, etc. That algorithm is the primitive type.

A GS does not just get access to however many vertices were spat out by prior vertex processing stages. It receives a primitive. That means the vertex stream has to be assembled into primitives. So there needs to be an algorithm for that.

The GS’s input primitive type.

As previously stated, what you want is not what a GS is intended to provide.

If you want something more free-form, then you’re looking for NVIDIA’s mesh shader vertex pipeline. Of course, that’s an NVIDIA-only technology.

Then it’s been given a shitty name, instead of geometry (which implies any shape) it should been called the primitive shader, that would be more intuitive, either way it doesn’t serve the purpose I expected it to be doing so I’m trying out the compute shader as soon as I can fix this poxy corrupt path/buffer bug.

You’re preaching to the choir. Also, blame Microsoft; it was their name.

Glad I’m not the only one peeved at the naming of it… or confusing the purpose at the start because of the name

Compute shader wasn’t working out so I’ve resorted to using gl_VertexID and a uniform to decide how many vertices are expected for the referenced center point (for now the center is duplicated, I’ll switch to indexed later).

Was about to say “still having issues with uniforms though” but as I was typing I realised I forgot to send output to the fragment shader, fixing that resolved the issue quick smart, now I just gotta track down a segfault

Not sure if it’ll get you what you want. But you can output multiple points from a single vertex shader execution, and then render them with a draw call using whatever primitive type you want. Just use transform feedback in the middle.

That sounds like it might work, do you mind doing a quick and dirty example for a square? Just use a flat list of vertices inside the shader that you just add the input vertex to.

Well, it’s been a long time since I wrote a TF vertex shader. But you might try something like this.

#version 460 core

in layout (location = 0) vec3 IN_pos;

layout (xfb_buffer = 0, xfb_offset = 0, xfb_stride = 48) out vec3 pos[4];

void main ()
{
    pos[0] = IN_pos + vec3(1,1,0);
    pos[1] = IN_pos + vec3(1,-1,0);
    pos[2] = IN_pos + vec3(-1,-1,0);
    pos[3] = IN_pos + vec3(-1,1,0);
}

I think the output array should work. But if not, just expand it out:

#version 460 core

in layout (location = 0) vec3 IN_pos;

layout (xfb_buffer = 0, xfb_offset = 0, xfb_stride = 48) out vec3 pos0;
layout (xfb_buffer = 0, xfb_offset = 12, xfb_stride = 48) out vec3 pos1;
layout (xfb_buffer = 0, xfb_offset = 24, xfb_stride = 48) out vec3 pos2;
layout (xfb_buffer = 0, xfb_offset = 36, xfb_stride = 48) out vec3 pos3;

void main ()
{
    pos0 = IN_pos + vec3(1,1,0);
    pos1 = IN_pos + vec3(1,-1,0);
    pos2 = IN_pos + vec3(-1,-1,0);
    pos3 = IN_pos + vec3(-1,1,0);
}

For details, see: