Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm looking for an elegant way to handle input layouts in my directx11 code.

The problem I have that I have an Effect class and a Element class. The effect class encapsulates shaders and similar settings, and the Element class contains something that can be drawn (3d model, lanscape etc)

My drawing code sets the device shaders etc using the effect specified and then calls the draw function of the Element to draw the actual geometry contained in it.

The problem is this - I need to create an D3D11InputLayout somewhere. This really belongs in the Element class as it's no business of the rest of the system how that element chooses to represent it's vertex layout. But in order to create the object the API requires the vertex shader bytecode for the vertex shader that will be used to draw the object. In directx9 it was easy, there was no dependency so my element could contain it's own input layout structures and set them without the effect being involved.

But the Element shouldn't really have to know anything about the effect that it's being drawn with, that's just render settings, and the Element is there to provide geometry.

So I don't really know where to store and how to select the InputLayout for each draw call. I mean, I've made something work but it seems very ugly.

This makes me thing I've either missed something obvious, or else my design of having all the render settings in an Effect, the Geometry in an Element, and a 3rd party that draws it all is just flawed.

Just wondering how anyone else handles their input layouts in directx11 in a elegant way?

share|improve this question
add comment

4 Answers 4

up vote 3 down vote accepted

The way I handle this is that I have a VertexFormat.h file in which I have a bunch of input layouts of different types (VertexPositionNormal, VertexNormalUV...) wrapped in structs for easy creation/destruction. It works pretty well even though it's ugly IMO. It's very easy to add a new vertex format to the file if you have a shader that uses a layout that is not currently supported. Then I have a VertexFormatManager that creates/destroys those layouts when I need them. So when I need to create one, I feed the shader byte code and a vertexformat ID to the manager and it creates it for me and stores it in a pool so that you only ever have one of each layout. Then you need to create your geometry. To do this, I have a Create method on my geometry class that takes an ID for a vertex format. In the create function it queries the vertex format manager with the given ID. The manager returns an integer that serves as a bitfield with a flag set for every type of element the input layout contains. So I could have something like this:

int bitfield = VertexFormatManager::QueryFormat( formatID );
if (bitfield & VertexFormat::NORMAL)
{
    // do somethings
}
if (bitfield & VertexFormat::UV)
{
    // do somethings
}
...

Each input layout element is created into a separate ID3D11Buffer. That allows me to build a mesh given any type of vertex format. Say you want to render a cube with a texture, it needs vertex positions and uv coords. You feed it the VertexPositionUV (as an example) format ID, and the query return a bitfield contain set bits for the POSITION and UV flags. That create two ID3D11Buffers: one for the positions, one for the uv coords. Then you attach both of these to the pipeline before drawing. The advantage of doing this is that if you want to do something like shadow maps, you can render a mesh with only its vertex position buffer set.

I'm not sure much of this is very clear, I'm at work and I'll try and do a proper write up later tonight. In the mean time, I asked this question a while ago and got this answer . It's good, but I find that the way I'm doing it now makes more sense, especially in the case of DX11.

share|improve this answer
    
This makes a lot of sense, thank you for the comprehensive answer... So you use multiple vertex buffers per draw command? –  JohnB Mar 12 '12 at 15:09
    
Yes, I use on buffer for each element (position, normals, uv...), it's usefull depending on the type of rendering, and can be pretty flexible. It's surely not the only way to do it, but it works well for most rendering routines IMHO. I've added a little more details and pseudo code here: pastebin.com/XfqS6N7g Hope it helps. –  dotminic Mar 12 '12 at 20:03
add comment

Thanks for the answers on this, they are very helpful. I'll add an answer to my own question because I've moved on a bit from there.

In the end I realized that perhaps wanting to entirely separate the shaders from the drawable items was a mistake. They are fundamentally coupled in "real life" so it's perhaps not an issue that they are in the design.

For example a water shader will only work with an element that wants to draw water. Only that will be able to provide the data it needs. A shader that draws animated models will only work with an animated model element. I can't suddenly decide to use a water shader with an animated model. It simply can't work.

Trying to make an abstract shader class that can load any shader and work with any drawable element is a mistake. It doesn't reflect how they can be used in reality.

So instead I've made shader classes AnimatedModelShader, WaterShader, LandscapeShader. Each of these might well have options that cause it to load different physical shader files but they will always have the same basic interface by necessity because a landscape shader will always need the same kind of data input.

So the shader is now responsible for creating it's own input layout and it tells the element using it how to layout it's vertices by having a public typedef called vertexType that the element uses if it wishes to use that shader.

Not at all my original design but as it turns out, the desire to separate the two concepts wasn't very useful anyway.

share|improve this answer
add comment

I do something similar to dotminic - I have a routine that I pass an array of D3D11_INPUT_ELEMENT_DESC to, which then constructs a fake vertex shader with a matching input signature, compiles it, creates a layout from it, finally Releasing the fake shader.

Yes, it's ugly, and yes, it means needing to be a mite more careful than I otherwise would be if I did it the proper way, but they're tradeoffs I'm currently prepared to accept in exchange for a cleaner separation.

share|improve this answer
add comment

Looks to me like you really shouldn't need to worry. After glancing across the MSDN documentation for CreateInputLayout, I came across this:

Once an input-layout object is created from a shader signature, the input-layout object can be reused with any other shader that has an identical input signature (semantics included). This can simplify the creation of input-layout objects when you are working with many shaders with identical inputs. (Bingo) If a data type in the input-layout declaration does not match the data type in a shader-input signature, CreateInputLayout will generate a warning during compilation. The warning is simply to call attention to the fact that the data may be reinterpreted when read from a register. You may either disregard this warning (if reinterpretation is intentional) or make the data types match in both declarations to eliminate the warning.

http://msdn.microsoft.com/en-gb/library/windows/desktop/ff476512(v=vs.85).aspx

The makes it quite clear that you should be able to treat your input layouts in almost exactly the same way as your old DX9 vertex declarations. Providing shader bytecode the first time you create each of them just allows DX11 to validate them. And apparently the worst that will happen if you avoid or fail this step is a runtime warning which seems safe to ignore.

So DX11 isn't "creating a dependency" between your input layouts and your shaders... it's offering free validation! :D

share|improve this answer
    
CreateInputLayout can also be used to validate a shader against an existing input layout, so you can check all the shaders that would use it - which I'd recommend doing, at least in debug builds, for safety. –  Nathan Reed Jan 24 '13 at 6:24
    
Hmm, when I attempted this, I found that providing an existing input layout as a parameter would just cause the old pointer to be overwritten, resulting in a memory leak. Shame there isn't a separate 'Validate' function. –  Richard Copperwaite Jan 26 '13 at 7:13
    
Sorry, by "an existing input layout" I really meant the array of D3D11_INPUT_ELEMENT_DESCs used to create it. That can be validated against another shader's bytecode without creating a new input layout object. –  Nathan Reed Jan 26 '13 at 22:20
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.