Input Slots

Started by
10 comments, last by Ingenu 13 years, 1 month ago
Direct3D allows multiple streams (or input slots) of vertex inputs to shaders via D3D10_INPUT_ELEMENT_DESC, D3D11_INPUT_ELEMENT_DESC, and D3DVERTEXELEMENT9.

Does OpenGL, and if so how?


YogurtEmperor

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Advertisement
Yes you can do this as well in OpenGL. You do this through the glVertexAttribPointer* commands. The equivalent to a directX stream is an opengl VBO or "vertex buffer object".

To link a VBO to an input, you bind a VBO, call glVertexAttribPointer to link a shader input variable to a stream, repeat binding/pointering until you've setup all your variables, then render.

Theres a trillion VBO tutorials floating around the internet so I won't go into more detail than that for now, you can ask if you have more specific questions.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Thanks to your reply I have a whole system planned out for getting my next-gen engine working on OpenGL, DirectX 9, DirectX 10, DirectX 11, Nintendo Wii, and PlayStation 3.

Except for one thing.
According to the documentation, [font=monospace][size=2]glBindAttribLocation()[/font] prevents a generic number from 0 to GL_MAX_VERTEX_ATTRIBS - 1 from being assigned to attributes.
For my system to work, I will need more than GL_MAX_VERTEX_ATTRIBS locations, which is 29 on my machine (which is extremely high-end, so I can assume everyone else has fewer than this).
The documentation does not make this clear.
Does [font=monospace][size=2]glBindAttribLocation()[/font] allow values larger than GL_MAX_VERTEX_ATTRIBS?


Thank you,
Yogurt Emperor

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

No the spec is pretty clear for glBindAttribLocation:
"Errors:
GL_INVALID_VALUE is generated if index is greater than or equal to GL_MAX_VERTEX_ATTRIBS."

. Why do you think you need so many?

I have a similar setup where I have a cross-API shader control so I can switch my render from opengl/dx. What I do is in the shader I define a number next to all of my input variables, similar to an HLSL semantic.

So I have some inputs that look like:

input vec4 position :0
input vec2 texcoord :1

Then I use these 'semantics' to bind these to an attrib location, which is essentially the same as how hlsl works.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
I have written a new shader language in order to support all of my target platforms.
I have full control over my shader system, and I also use semantics.

However I do not want to my shader library to work so closely with my vertex buffer class.
Specifically, how would you handle the following case:

in vec2 vXzPos : POSITION0 // The X and Z positions on the terrain are shared, since many of them are duplicates.
in float vYPos : POSITION1 // The Y position is unique for each tile of the terrain, and comes in on stream 1.
in vec3 vNormal : NORMAL0 // Etc.



My vertex buffer defines 19 attributes, from POSITION to NORMAL to BINORMAL.
Each attribute has a location (assuming stream 0).
Thus POSITION0 is always attribute location 0. Normal follows, with NORMAL0 being attribute location 1.

In this way, the shader system does not need to communicate anything to the vertex buffer class about what is inside it.
This is really the best solution, as the two systems are not logically connected, and this is a high-performance situation, with this being the fastest possible solution.

Following this system, POSITION1 would be at location 19, NORMAL1 at 20, etc.
If the attribute locations can be computed with such a formula, the example snippet I gave is trivial.



But what about your method?
I can’t use attribute location 0 for both the stream-0 position and the stream-0 normal.
And I will have two vertex buffer classes here, one containing POSITION0 and NORMAL0, and the other containing POSITION1. But from the data given to the vertex buffer classes, all they see is, “I have a position and a normal,” and, “I have a position”. They have no idea to which stream they will be applied until it is actually time to apply them and render (CVertexBuffer::Apply( LSUINT32 _ui32Stream )). If I try to adjust data at that time, I am losing significant performance. Out of the question.

Precomputing the information by saying, “You will be assigned to stream 0 always and using this shader always, while you will always use the same shader and be in stream 1,” is also out of the question. This is a horribly inflexible system which I cannot impose upon the users of my engine.



So what do you suggest?


Yogurt Emperor

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

I actually came across the same dilemma you have, where I wanted to have as many attribs as possible semantics :)

The best I could come up with at the time would be to add separate data for GLSL versus HLSL.

in <variable> <name> : <hlsl semantic> : <glsl semantic>

in vec2 vXzPos : POSITION0 : 0
in float vYPos : POSITION1 : 1
in vec3 vNormal : NORMAL0 : 2

Then in your engine, you might have something like:

normalBuffer.BindVertexStream(blah, blah, NORMAL0, 2); //bind to NORMAL0 hlsl semantic, and glsl attrib #2.

Then your DX codepath can read the semantic and ignore the glsl #, and vice versa.

It's not the most elegant, but it was the best I could think of at the time.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
You can have 29 streams in D3D9?
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

You can have 29 streams in D3D9?

There are 16 streams in DirectX.
If I have 19 possible (predefined) vertex attributes, times 16 streams, I would need 304 unique attribute values.

karwosts, that still leaves me with the problem that I have to tell my vertex buffer which shader will be used with it, and to which stream it will be applied.
To me this is unacceptable, especially when I would only have this type of restrictive feature just because of OpenGL (in DirectX only there would never be a reason to have any association between the shader and the vertex buffers).

The next best solution I can imagine is this:
Using multiple streams is somewhat rare. I can reserve slots 0-18 for stream 0, so the shader will always apply stream-0 attribute locations in a specific order.
The vertex buffer class also knows that order so when it has been applied to stream 0, all is done.
When a vertex buffer is applied to a non-0 stream, at the moment of being rendered it will check the attributes of the shader currently active and use some fast look-up data to assign attributes for non-0 stream data.
Additionally, since the cases that involve multiple streams are usually special cases that use the same combination of vertex buffers and shaders, or at least shaders with the same input structure, I can cache these values on the vertex buffer class and next time it is activated on a non-0 stream it can quickly look up the input layout of the active shader and if the input layout for the given stream is the same then there is no need to make any changes.


This should be fairly optimal in performance while not forcing the user to ever specify the shader and stream combination beforehand.
Input on this idea is welcome.

Especially about reserving slots 0-18 for stream 0. My hardware has 29 slots, but I am running a $5,000 supercomputer. I would be in trouble if lower-end hardware only supports 20 slots or something.
[EDIT]
Ah I just read on another forum someone saying he only has 16. That there would already be a problem.

So, new plan.
As long as my buffers are applied to stream 0 and I know the order of the inputs, I can pack them equally well in both the shader and the vertex buffer as long as they both use the same number of attributes.
Normally TEX0 would be attribute 6 in my system, but if the shader only has POSITION, NORMAL, and TEX0, then TEX0 would be 2.
This only imposes the restriction that the inputs for the shader match the contents of the vertex buffer exactly, but I think the stricter binding rules in DirectX 10 and up force this anyway.
[/EDIT]


Thank you,
Yogurt Emperor

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Are you saying a stream is different from a slot? You can have more input slots such as up to 29?

I'm just not getting what the advantage of D3D over GL is here.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

Are you saying a stream is different from a slot? You can have more input slots such as up to 29?

I'm just not getting what the advantage of D3D over GL is here.

In terms of raw functionality there isn’t one. The challenge is how to make a neutral interface that exposes both functionalities in a common and generic way (for the purpose of making a multiplatform next-generation game engine similar to or better than CryEngine 3).
But I have found my solution.


Yogurt Emperor

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement