• Advertisement
Sign in to follow this  

Managing inputlayouts (and reducing changes)

This topic is 566 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all,

In the journey of creating my new d3d11 engine, I've come to the point where I'm going to add and create the shader classes and system.

 

My struggle:

- I want to create a base/ parent class CD3dShader

-- there will be child classes inherited from the CD3dShader class, for pixelshader, vertexshader etc. etc.

 

In my current D3D11 experience I've always linked an inputlayout (ID3D11InputLayout) to a shader.

This is very convenient for several reasons:

- when creating/ compiling the shader I have the blob around and can easily create the inputlayout

- I have a 'GetInputLayout' member function in the shader class, which returns a pointer to the inputlayout for that shader

 

But... I think there's cost in this approach, because now I would always set the needed InputLayout when switching to another shader. Which potentially is the same inputlayout that was already set.

 

My questions:

- how would you handle this?

- is there significant cost (performance wise) in setting inputlayouts which are already set?

(or is ignored for the biggest part, because D3D11 recognizes it?)

- would it be a good idea to create a shadermanager class, which keeps track of the current shader and stores the input layouts, where each shader class object simply has an ID to the corresponding inputlayout?

-- I could also store a std::vector within the shader class, with all the shader class objects

Edited by cozzie

Share this post


Link to post
Share on other sites
Advertisement

Switching shaders is relatively expensive, and switching input layout on top of that probably isn't going to make it significantly worse.

 

Start by doing the simple thing, and if you find out later it's a problem you can always change it.

Share this post


Link to post
Share on other sites


class CRenderState
{
 ID3D11InputLayout* CurrentLayout;

};

  class CD3D11Context
{
   CRenderState  m_RenderState;
  
public:

  void SetVertexShader(CVertexShader* VertexShader)
  {
     ID3D11InputLayout* NewLayout = ((CD3D11VertexShader*)VertexShader)->GetInputLayout();
    
     //only set the input layout if it is new 
     if(m_RenderState.CurrentLayout != NewLayout)
     {
        D3D11Context->SetInputLayout(NewLayout); 
        m_RenderState.CurrentLayout= NewLayout;
     }

  }


};

Problem Solved. Create a cache for input layouts so that you don't recreate already created layouts

i.e

  gRendDevice->CreateInputLayout(...an array of all of the vertex elements).

Share this post


Link to post
Share on other sites
Thanks. I already planned to create the inputlayouts just once (at initial loading/ startup), but that still means I have to find a way to decide when to switch or simply always switch when I switch from shader.

Share this post


Link to post
Share on other sites

Can someone confirm, but I thought that at a driver level, any assignments were checked to ensure that only changes were set.  Anything where you set the same state again, or VB, etc would not impact performance. 

Share this post


Link to post
Share on other sites

I think there's cost in this approach, because now I would always set the needed InputLayout when switching to another shader. Which potentially is the same inputlayout that was already set.   My questions: - how would you handle this?

As above, just cache the last one that you set so you can avoid setting it twice.
 

Can someone confirm, but I thought that at a driver level, any assignments were checked to ensure that only changes were set.  Anything where you set the same state again, or VB, etc would not impact performance.

I'm pretty sure that the D3D runtime itself doesn't (flow is: Your App -> D3D runtime -> NVidia/AMD/Intel Driver -> GPU)  -- so even if the driver does discard redundant commands, it's still kinda wasteful to call D3D functions for no reasons. In my experience it's (very slightly) beneficial to do redundancy checking yourself, as above.
 

In my current D3D11 experience I've always linked an inputlayout (ID3D11InputLayout) to a shader. This is very convenient for several reasons: - when creating/ compiling the shader I have the blob around and can easily create the inputlayout - I have a 'GetInputLayout' member function in the shader class, which returns a pointer to the inputlayout for that shader

The inconvenience here is that this creates a hard link between your vertex shader and a particular in-memory data layout of the vertex attributes.
 
In general it's possible to have one model with:
[position][texcoord][position][texcoord][position][texcoord]
And another model with:
[position][normal][position][normal][position][normal]
But then render them both with the same VS that only requires a position attribute (e.g. a shadow-mapping shader), by using two different input layouts.
 
Also note that two different VS's can also share an input layout object if they both declare the same attributes (and are used with the same vertex buffer layout)!

The completely general solution needs a dictionary of input-layouts, which is looked up using the model's buffer layout and the VS's input attributes as the key. This is what the IL does -- it maps the VS attributes to a particular layout in memory. So if you support multiple different mesh formats in memory, you'll need one IL per mesh-layout/VS-attribute-set pair.

Edited by Hodgman

Share this post


Link to post
Share on other sites

I'm pretty sure that the D3D runtime itself doesn't (flow is: Your App -> D3D runtime -> NVidia/AMD/Intel Driver -> GPU)  -- so even if the driver does discard redundant commands, it's still kinda wasteful to call D3D functions for no reasons. In my experience it's (very slightly) beneficial to do redundancy checking yourself, as above.

 

D3D does do redundancy checking. You're still paying more than the cost of a compare/branch in your own code, but probably not by much.

Share this post


Link to post
Share on other sites

I'm pretty sure that the D3D runtime itself doesn't (flow is: Your App -> D3D runtime -> NVidia/AMD/Intel Driver -> GPU)  -- so even if the driver does discard redundant commands, it's still kinda wasteful to call D3D functions for no reasons. In my experience it's (very slightly) beneficial to do redundancy checking yourself, as above.

 
D3D does do redundancy checking. You're still paying more than the cost of a compare/branch in your own code, but probably not by much.

I thought so as when debugging through the graphics interface in visual studio it seems aware was has been set or unset from the previous call.

Share this post


Link to post
Share on other sites

 

I'm pretty sure that the D3D runtime itself doesn't (flow is: Your App -> D3D runtime -> NVidia/AMD/Intel Driver -> GPU)  -- so even if the driver does discard redundant commands, it's still kinda wasteful to call D3D functions for no reasons. In my experience it's (very slightly) beneficial to do redundancy checking yourself, as above.

 

D3D does do redundancy checking. You're still paying more than the cost of a compare/branch in your own code, but probably not by much.

 

 

I should also clarify - D3D11 does redundancy checking. D3D12 does not. Before someone quotes that out of context :)

Share this post


Link to post
Share on other sites

 

 

I'm pretty sure that the D3D runtime itself doesn't (flow is: Your App -> D3D runtime -> NVidia/AMD/Intel Driver -> GPU)  -- so even if the driver does discard redundant commands, it's still kinda wasteful to call D3D functions for no reasons. In my experience it's (very slightly) beneficial to do redundancy checking yourself, as above.

 

D3D does do redundancy checking. You're still paying more than the cost of a compare/branch in your own code, but probably not by much.

 

 

I should also clarify - D3D11 does redundancy checking. D3D12 does not. Before someone quotes that out of context :)

 

Immediate or deferred? :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement