Jump to content
  • Advertisement
Sign in to follow this  
cozzie

Shader class design question

This topic is 634 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 my new engine/framework (using d3d11), I've arrived at the decision how to "relate" vertex and pixel shaders (and maybe more).
My current design has:

- a base shader class, with members that all shaders have (defines, identifier, blob etc)
- derived/ inherited class for pixelshader and vertexshader (more in the future)
-- containing the d3d11vertex or pixelshader object, VS class has input layout elementDescs etc.

Now there are some pro's and cons here.
Can you give me some pointers to be able to make my decision?

- I could also go for 2 completely seperate classes (resulting in redundant code)
- continue as I'm doing now
- create one class, having both vertexhader, pixelshader etc. Objects and more, and some ID that specifies which kind of shader it is

Another thing I'm curious about; how often will you don't have a 1 to 1 relationship between a VS and PS?
If in practice 99% of the same they'll be used together and not interchanged without another VS/ PS, then this could influence the choice I'm going to make.

Any input is appreciated.

Share this post


Link to post
Share on other sites
Advertisement
When authoring shaders, IMHO you really want to be authoring something like a Microsoft FX / CGFX / shader, which is a whole collection of different programs that will be used by one object in different circumstances.

In my engine, I author "shaders", which are a collection of passes (where 'pass' is shadow-map, gbuffer attributes, forward-translucent, etc...), which contain one or more permutations, which are a tuple of entry points for PS/VS/etc.
The tool actually bundles many of these "shaders" into a shader pack file (which lets me do things like de-duplicate a bytecode program if two "shaders" happen to have produced the same bytecode at some point), therefore the main class used by a graphics programmer when loading shaders is called ShaderPack. This class then lets you iterate the individual "shaders" and use their IDs to render objects. The back end of the renderer can then use those IDs to peek inside a "shader" and select the appropriate pass, select the appropriate permutation of that pass, and then get the right PS/VS pointers to use.

So as a user of the library (graphics programmer) you never get given any classes to act as an interface for PS's/VS's or even pairs of the two.
Moreover, because the engine loads entire shader packs, all the logic for deciding which PS/VS to use where is move to the shader compiler tool. Basically, this file format has a big list of VS's/PS's/etc, a big list of shaders with indices of passes, a big list of passes with indices of permutations, and big list of permutations with indices of VS's/PS's/etc.

Share this post


Link to post
Share on other sites

Thanks Hodgman.

I understand that this design works like a charm and gives flexibility, but on the other hand, it's not something I could create in my sparse spare time. So let's try to draw some conclusions/ answers out of your design, which might help me in taking the next small step (with maybe a system like you described as a long term goal):

 

- it's not useful/ worth it to handle a VS and PS as a completely different object

- in practice you should 'author' an 'Effect'(shader) which consists of a passes, a vertex shader, pixel shader, maybe a geometry shader and more

-- the effect can have many/ multiple permutations (like the ubershader principle)

- a VS should always be linked to some PS and the other way around;

-- chances that you'll be mixing VS/PS combinations in runtime, independent from the assets/ content you load.

- this also means that there should be a balance in codebase/ design flexibility and assumptions on the pipeline/ content generation.

They cannot live separately..

 

From this I conclude it might be actually better to create 1 class for an 'effect', for now having just a VS and PS.

Which could expand in the future.

 

Any thoughts?

Edited by cozzie

Share this post


Link to post
Share on other sites

- it's not useful/ worth it to handle a VS and PS as a completely different object
- in practice you should 'author' an 'Effect'(shader) which consists of a passes, a vertex shader, pixel shader, maybe a geometry shader and more
-- the effect can have many/ multiple permutations (like the ubershader principle)
- a VS should always be linked to some PS and the other way around;
-- chances that you'll be mixing VS/PS combinations in runtime, independent from the assets/ content you load.
- this also means that there should be a balance in codebase/ design flexibility and assumptions on the pipeline/ content generation.
From this I conclude it might be actually better to create 1 class for an 'effect', for now having just a VS and PS.

Yeah I'd definately go for having something like a "Program" class, which contains a full set of VS/PS/etc... If you ever want to port to GL, it actually prefers that you work this way anyway!
Sure, if you go with "effects", you can start with effect having one program, and expand it to being able to select one from a collection of permutations/passes.

Note that it's valid to have a program that contains a VS but no PS -- this is common for depth-only rendering.

Share this post


Link to post
Share on other sites

Thanks this really helps. 

@Hodgman: really appreciated, your input is like clockwork/ my morning alarm clock :)

 

I can start implementing now, will also take the 'VS only' situation in consideration.

Also Fastcall gave me the advice to think about 'unions', but I've never used them so far. From what I've read, this could be a solution where can have 1 shader class, either having a VS, PS or other one. So I'll skip that thought for now.

Edited by cozzie

Share this post


Link to post
Share on other sites

I've created a v0.1 dataset for a 'ShaderEffect' in my engine.

What do you think/ what do you miss?

 

This is the set of data I store in a file and use to create the shaders in the new 'ShaderEffect' class.

<SHADER_EFFECT_0>
#VS		VS_PS_basic.hlsl	VS_main
#PS		VS_PS_basic.hlsl	PS_main
#GS		no
#DEFINES	MAX_PLIGHT_8;NORMALMAP;;
#IDENTIFIER	8PTLIGHT-NORMALMAP

<SHADER_EFFECT_1>
#VS		VS_PS_basic.hlsl	VS_main
#PS		VS_PS_basic.hlsl	PS_main
#GS		no
#DEFINES	MAX_PLIGHT_4;NORMALMAP;;
#IDENTIFIER	4PTLIGHT-NORMALMAP

<SHADER_EFFECT_2>
#VS		VS_thingie.hlsl		VS_main
#PS		no
#GS		no
#DEFINES	no
#IDENTIFIER	SPECIAL-VS-ONLY

<SHADER_EFFECT_3>
#VS		VSGS_special.hlsl	VS_main
#PS		no
#GS		VSGS_special.hlsl	GS_dostuff
#DEFINES	no
#IDENTIFIER	SPECIAL-VSGS

Note; the exact way of writing the 'labels' are just a first draft.

It should be easily readable through an IFSTREAM, I'll move towards binary reading/writing later on (this is easier during development).

Edited by cozzie

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!