Conceptual Question On Separate Ps/vs Files

Started by
4 comments, last by Hodgman 7 years, 8 months ago
Hi all,
During my journey to go away from effects11 to own shader management, there's something I don't understand.

Effect files/FX:
- contains vertex and pixel shader (functions)
- contains constant buffers which can be used by the VS, PS (and GS etc)
- contains techniques which pick variants of combinations between the shaders

Now from what I understood, I will create separate files for my vertex and pixel shaders. So far so good.

But what do I do with constant buffers that are used by both the PS and VS (for example a CB per frame)?

- do I include the exact same CB definition in both the VS file and PS file?
- is 1 enough? And will the HLSL compiler accept that the CB is not defined in the shader file?
- do I need to create separate CB's for the PS and VS? I hope not, because the counter that goes to 14 will raise quickest that way.
- .... Other/ better option?

Any input is appreciated.
Note; I'm using VS 2013 community as IDE, which can compile all shaders for me using FXC under the hood.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement

You don't have to use separate files for PS/VS if you don't want to -- you can specify which function is the entry-point of the shader, and compile the same file twice using two different targets (ps/vs) and two different entry points (ps_main, vs_main, etc). Personally I like to keep them in the same file.
You can also use #include to pull code from other files into the one that's being compiled.

If the PS/VS are both going to read data from the same CBuffer, then yes, both shaders need to be compiled with the same CBuffer structure definition or you're gonna have a bad time. It might be a good idea to put your CBuffer definitions into header files that are #included into different shaders, so that you know they're all using the same structure.

If one of the shaders doesn't use the CBuffer --e.g. only used by VS, not by PS-- then of course you don't need to declare it to compile your PS.

No, you don't need to create separate CB instances for each shader stage. One CB resource can be simultaneously bound to multiple shader stages, or even to multiple 'slots' in the one shader stage!
Note that D3D11 does not have 14 cbuffer binding slots though -- it has 14 cbuffer binding slots per shader stage!

Technically it's completely fine to have "cbuffer resource A" bound to VS slot #7, and "cbuffer resource B" bound to PS slot #7 -- because each stage has it's own set of 14 slots :o
I would not recommend this though as it will get confusing real quick :) In my engine, I actually pretend that D3D11 only has 14 cbuffer binding slots total, and not 14 per stage.

If you want a CBuffer resource to be visible to the VS and the PS, then you will have to call ID3D11DeviceContext::VSSetConstantBuffers and ID3D11DeviceContext::PSSetConstantBuffers.

Lastly, you can just declare cbuffers in HLSL without regard for which binding slot they're assigned to, and then later use relfection to look up the cbuffer by name and discover the correct binding slot... The FX system will take this approach, I believe. I would recommend against this, as automatic slot assignment can do whatever it likes, including having your "Camera" cbuffer in slot #0 for the VS, but in slot #1 for the PS :(

To avoid that kind of complexity, I always assign cbuffers to slots explicitly in the HLSL code:


cbuffer Camera : register( b0 ) // SetConstantBuffers slot #0. Always :)
{
	float4x4 ViewProj;
};

Hodgman pretty much covered everything I just have one more thing to add:

You don't have to use separate files for PS/VS if you don't want to -- you can specify which function is the entry-point of the shader, and compile the same file twice using two different targets (ps/vs) and two different entry points (ps_main, vs_main, etc). Personally I like to keep them in the same file.
You can also use #include to pull code from other files into the one that's being compiled.

I'd like to keep them too in the same file, but keep in mind if you're aiming at cross platform some day (i.e. OpenGL + GLSL); in GLSL you must declare the vertex and pixel shaders in separate files. Although you can also use macros to workaround, i.e.


#if VERTEX_SHADER
void main()
{
}
#else
vec4 main()
{
    return vec4( 1.0, 1.0, 1.0, 1.0 );
}
#endif

Thanks guys, this clears things up and makes me feel prepared for the next step :cool:

Some thoughts

- for practice I'll first go for a basic VS and PS in one file

- with an include for the CBuffer(s)

- like hodgman said, I'll go for assuming 14 CB's in total, not per stage

(this also suits my 1st attempt of my CBuffer class, keeping track of a register/ slot number per CBuffer object, which wouldn't work if they differ per stage)

I'll also dig into HLSL debugging in Visual Studio (2013, community), which should be possible, although I didn't manage to get it working yet.

A last question;

When I create new items/files in VS, it gives me the following options (and some more on DS, HS, GS, CS etc.):

- HLSL Header file (.hlsli)

- Pixel shader file (.hlsl)

- Vertex shader file (.hlsl)

For the individual VS and PS files it's clear :)

I assume that for a combined VS/PS file I can/ should also use the .hlsl file exension.

What would be the best way to go for, for the CBuffer header and other files I will #include? (like light and material structs etc.)

(just .hlsl or .hlsli or different?)

Probably any extension will work technically, but I'd like to do things right at once, so what's best practice?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

You can use whatever extension you'd like, the compiler doesn't care. Personally I like to use .hlsl for all files containing shader code, but that's just preference. Putting shared structure and constant buffer definitions in a shared header file is definitely a good idea, since it will ensure that if you change a structure all of the shaders will see that change.

To illustrate that you can use any extension you like, I actually use .cgfx for HLSL files that will be compiled, and .h for included HLSL files :o

(for legacy reasons :P)

This topic is closed to new replies.

Advertisement