NV_register_combiners vs. shaders

I’m currently using NV_register_combiners to perform per-pixel lightning in a application of mine and I’m experienceing quite a bit of slowdowns with them.

I’ve tried optimising for a while now but still I get poor and results. The rendering can go from 60FPS to 12FPS in some cases which is just not good enough.

Im curios if it’s worth spending time digging through shaders. I have experienced a lot of trouble working with Nvidias CG shaders (Im pretty green on the topic yet do…) so I’d prefer working with the OpenGL Shading language instead.

Does anyone think it might speed things up for me ?

Best Regards,
/Jimmie.

If you’re combiner limited, then you’re likely fragment processing limited. Try making your window 1/4 the size, and see if performance improves a lot. If it does, then it’s certain that you’re fragment limited.

Shaders probably won’t help. It’s all the same hardware. Shaders get compiled to the same hardware that register combiners get compiled to. What you can try to do is drawing front-to-back, to take advantage of early Z, and perhaps simplifying your shaders or reducing overdraw in general.

I would recommend to switch to vertex programs and fragment programs instead of register combiners, if your hardware supports this… it does not give you a speedup but at least it is much more powerful and more comfortable to use, and also, register combiners are definitely outdated.

Originally posted by JanHH:
I would recommend to switch to vertex programs and fragment programs instead of register combiners, if your hardware supports this… it does not give you a speedup but at least it is much more powerful and more comfortable to use, and also, register combiners are definitely outdated.
Well, that obviously depends on target hardware. There’s plenty of Gf4Ti (and Gf4MX) cards out there, and if you want to support them, fragment programs simply aren’t an option.

Jimmie,
what graphics card are you working on, or rather, what would you like to target?
Can you tell us a little more about your reg combiner setup (full disclosure, if possible)?
How often do you change it?

Thanks for taking time to read and reply to my question. I really was’nt expecting it.

Well, I want to target as many as possible.
But I’m certain that the graphic card MUST support at least register combiners (which almost every NV cards support, I hope).

I think I’ve cornered myself a bit do, because I also require support for Vertex Object Buffer.
I dont know which cards that support this feature, but I suppose only newer do.
But I will support Display Lists as an alternative too, if time given.

But If I cant get a speed improvement from writing shaders for per-pixel lightning I think it’s a waste of time, or ?

I will, however, have some other shaders too (optional, if card supports them).
Since the program Im writing is for a game contest I want to throw in as much features as possible to impress the jury.

Here is the code for setting up the register combiners :

// Set up texture unit 1 for the 1D radial ramp map texture
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_1D, PointLight1D);	

// Set up texture unit 0 for the 2D radial map texture
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, PointLight2D);
	
//setup the register combiners to use 1 general combiner
glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);

/*
 SMALL CODE PART HERE THAT I REMOVED, ALL IT DOES
     IS CHANGE THE Mod_Color DEPENDING ON A TIMER FUNCITON
*/	

//store the light mod_color
//into the Constant Color 0 register	
glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, (float*)&Mod_Color);


//setup combiner 1 to calculate the attenuation factor 
//(1*Texture0 + 1*Texture1), and store it in the Spare 0 register
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
	GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
	GL_ZERO,GL_UNSIGNED_INVERT_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, 
	GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, 
	GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, 
	GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE);

//setup the final combiner to calculate (1-Attenuation)*Color
glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_SPARE0_NV, 
	GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO, 
	GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_CONSTANT_COLOR0_NV, 
	GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, 
	GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_ZERO, 
	GL_UNSIGNED_INVERT_NV, GL_ALPHA);

//enable the combiner  
glEnable(GL_REGISTER_COMBINERS_NV);

// END OF CODE.

I assume that with changing it you mean how often I call this function (the code above is the function “activate_light()”).
I do this for every world-polygon drawn (a polygon that is part of the world, not enemies or items, just the polygons contained in a bsp leaf), I also check if the light can reach the polygon (if not, then that light is’nt considered for the polygon).
After that, the dynamic lightmaps that is created by doing this are blended with the original texture.

If you want to include as many effects as possible, I would stick with shaders instead of register comibers. fancy effects are a lot easier to do with them.

Also, I think compatibility is not such a problem. Everyone who is really interested in “up to date” graphics will have a card that supports ARB/NV_fragment_program in the next time. Of course it is a different thing when you are doing something to sell to as many people as possible, but if it’s for a contest and only a certain audience, I would stick to what is state of the art at the moment.

Jan

NVIDIA may be something like 30% of the current grahpics card market (I don’t have well grounded numbers to give you). But those other 70% do not support NVIDIA register combiners.

The path you NEED is the basic dual-texture path with COMBINE_EXT texture blending. This is supported by anything on the market today. As soon as you raise beyond two textures, you start dropping supported cards (GF2/4MX has 2 textures; Radeon 7x has 3; Intel Extreme and GF3/4 have 4).

The next step up would be to use ARB_vertex_program and ARB_fragment_program. Most NVIDIAs being sold today support it, and many ATIs do as well. Intels don’t – and Intel Extreme 3D Graphics is a BIG part of the market.

The third step, if you need more trade-offs between quality (_programs) and wide support, is register combiners. Starting with register combiners may be convenient if you have hardware that only supports that, but it’s not the best way to ensure widest possible compatibility.

Anyway, did you reduce the size of the window? What happened to frame rate?

Originally posted by Jimmie:
I do this for every world-polygon drawn
Bingo! Don’t :wink:
Set the state once to what you need it to be, and then submit as much geometry as humanly possible that requires that state. Don’t touch it, if you don’t intend to change it.

What about these two textures (attenuation maps, I suppose? Are they the same for all world geometry?

What about the constant color you set. How often does that need to change?