Sign in to follow this  
coorn

A lot of GPU programs

Recommended Posts

coorn    122
In my game engine I use a general vertex and a general fragment program for all shading. This is really slow in some cases where a specialized GPU program would do the job much faster. The problem is that if I write like 10 specialized programs and then want to change something in the general program. I will have to apply the change to all of the 10 specialized programs. This is a real pain! This must be a pretty common problem so I expect there is a solution... like have some precompiler generate all the specialized programs from the general program. Is there a solution? I’m using in Cg but I’m willing to change if some other language is better... // Coorn

Share this post


Link to post
Share on other sites
nts    968
One way would be to put all the common functionality in one file and then simply do an #include, just like in c/c++. This will also work with HLSL but I dont think GLSL supports this (might work on NVIDIA cards though because it uses the CG compiler).

HTH

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
You can write shader fragments, and then use ID3DXFragmentLinker to "merge" them together to build your full shaders. For example, merge lighting and texturing fragments to get a light & tex shader.

Share this post


Link to post
Share on other sites
matches81    474
Hi there! I´m sorry to ask my question in another one´s thread, but it just fits so nicely and essentially it covers the same material:
a) Are there any simple tutorials for the use of this FragmentLinker, perhaps one just merging a simple light fragment and tex fragment?
b) One thing that has been bothering me for some time now, is the following problem:
Let´s say I have about 10 different shaders I want to use in one frame, I would really love to set the world, view and projection matrix only once for all these shaders. Is there a way that different shaders share the same variables?

Share this post


Link to post
Share on other sites
coorn    122
Quote:
Original post by Anonymous Poster
You can write shader fragments, and then use ID3DXFragmentLinker to "merge" them together to build your full shaders. For example, merge lighting and texturing fragments to get a light & tex shader.


Sorry I'm using OpenGL...

Quote:
Original post by nts
One way would be to put all the common functionality in one file and then simply do an #include, just like in c/c++. This will also work with HLSL but I dont think GLSL supports this (might work on NVIDIA cards though because it uses the CG compiler).

HTH


I don't really understand how to use #include to help me with my problem... Could you please explain a bit more?

Share this post


Link to post
Share on other sites
Monder    993
In your include file you'd have functions to perform all your common functions, e.g. you'd have functions like DoLighting, SkinVertex (for animation in the vertex shader) etc.

Half-Life 2 uses a rather brute force approach of having a tool pregenerate all permutations of a shader from a general shader. Here's an example of how it works:


//STATIC: "OPTION1" 0...1
//STATIC: "OPTION2" 0...1

static const bool option1 = OPTION1;
static const bool option2 = OPTION2;

void ShaderMain(InStruct in)
{
if(option1)
{
//do option1 stuff
}
if(option2)
{
//do option2 stuff
}
}



The offline tool looks at the stuff in comments at the top and generates all possible permutations from the ranges you've listed, in this case you'll get a shader with both OPTION1 and OPTION2 #defined to 0, one with OPTION1 #defined to 1 one with OPTION2 #defined to 1 and one with OPTION1 and OPTION2 #defined to 1. Then you have some C++ code that tells the engine what permutation to choose. In this way you can create a general shader that generates many specialised shaders (some of the HL2 shaders have several thousand permutations).

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Quote:
Original post by matches81
Hi there! I´m sorry to ask my question in another one´s thread, but it just fits so nicely and essentially it covers the same material:
a) Are there any simple tutorials for the use of this FragmentLinker, perhaps one just merging a simple light fragment and tex fragment?
b) One thing that has been bothering me for some time now, is the following problem:
Let´s say I have about 10 different shaders I want to use in one frame, I would really love to set the world, view and projection matrix only once for all these shaders. Is there a way that different shaders share the same variables?


In DirectX, you can tell the compiler to bind a constant to a specific register, and set the constants once

For example:

uniform float4x4 mWorldViewProj : register(c0)

will force the matrix to be bound to register c0. You can then set it with
something like:

device->SetVertexShaderConstantF(0, (float*)&matrix, 4);

One gotcha here is that if you're transforming matrices the usual way:

mul(P,mWorldViewProjection)

the matrices have to be passed in column-major order, so if you're setting shader constants directly, you need to transpose them first.

Share this post


Link to post
Share on other sites
bleyblue2    180
Quote:
Original post by Anonymous Poster
Quote:
Original post by matches81
Hi there! I´m sorry to ask my question in another one´s thread, but it just fits so nicely and essentially it covers the same material:
a) Are there any simple tutorials for the use of this FragmentLinker, perhaps one just merging a simple light fragment and tex fragment?
b) One thing that has been bothering me for some time now, is the following problem:
Let´s say I have about 10 different shaders I want to use in one frame, I would really love to set the world, view and projection matrix only once for all these shaders. Is there a way that different shaders share the same variables?


In DirectX, you can tell the compiler to bind a constant to a specific register, and set the constants once

For example:

uniform float4x4 mWorldViewProj : register(c0)

will force the matrix to be bound to register c0. You can then set it with
something like:

device->SetVertexShaderConstantF(0, (float*)&matrix, 4);

One gotcha here is that if you're transforming matrices the usual way:

mul(P,mWorldViewProjection)

the matrices have to be passed in column-major order, so if you're setting shader constants directly, you need to transpose them first.


Or, you can forget about the registers and just declare your variables "shared" i.e. shared uniform float4x4 mWorldViewProj; (just keep the same name for all your hlsl files)
Then, you have to create one ID3DXEffectPool, passing it to D3DXCreateEffect*** everytime you want to load an effet which will then share its parameters with all the other effects using this same pool. Hope this is clear enough.

Share this post


Link to post
Share on other sites
matches81    474
great! That helped a lot, thx! I will look into this effect pool thingie, as it sounds exactly like the thing I´m looking for. Thx for the hint :)

Share this post


Link to post
Share on other sites
AndyTX    806
Regarding combining shaders and updating uniforms, etc. easily, Sh (http://libsh.org) has by far the best system I have seen for this... you treat shader programs as C++ instances which can be combined together using simple operators (composition, currying, input/output binding and so on) and uniform management is handled automatically (you simply use your C++ variables in your shader program). Check out the site for more info.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this