Ok, I’ve ended up slip-sliding into doing more work this week than I was really supposed to. Hmm – I guess I love my work far too much than is healthy.
My excuse (which makes my wife roll her eyes) is that I’ve been picking off stuff that’s not that demanding, and it’s stuff I’ve wanted to add anyway. Well, here’s what you get from today’s commit: unified program definitions.
What’s that? Well, first a bit of background. We’ve found that whilst Cg is great for targetting both DirectX and GL with one program, the compiler isn’t always that great at sequencing the assembler it produces, particularly pixel shaders that need to do a lot of texture fetches. This has resulted in people (including us on the OGRE team) using specific HLSL and GLSL programs for the more complex effects. Cg 1.5 tries to do something about this, but has some other issues too so at the moment I’m sticking to HLSL and GLSL for the hard stuff. Recently that’s included HDR and the shader-based texture shadow effects.
The only problem with this has been that until now, it has required you to create multiple material techniques. OGRE’s technique system used for many things, including material LOD, hardware fallback, and for scheme-switching (say, flipping to unbounded HDR shaders, or other things). This is all fine when the techniques are actually different in their outcome, but using them to just automatically flip between totally equivalent GLSL and HLSL pipelines was really too cumbersome – you had to duplicate a lot of definition and it got worse the more complex your material got.
So, now you can skip all that and define a ‘unified’ program which wraps many equivalent programs:
vertex_program myVertexProgram unified
{
delegate myVertexProgramGLSL
delegate myVertexProgramHLSL
}
At runtime when your materials reference this unified material, OGRE will automatically pick the delegate that’s supported by the current rendersystem / hardware. It’s almost like a mini-technique system, but it’s only for one program and can only be used when the programs are totally interchangeable (ie they have all the same inputs & outputs). I’ve used this to simplify my HDR shaders and I intend to use it on my depth shadowmapping system when I write the GLSL path (which is why this feature occurred to me now). It nicely addresses a very real problem, leaving the full technique system for the more complicated things where the results are actually different. Hope it’s useful to you too.
Doing this also caused me to iron out a historical quirk in the way that GLSL and HLSL addressed arrays of uniform parameters. You can now access the arrays in GLSL the exact same way as you did in Cg / HLSL, so that should resolve some issues – this affected my gaussian bloom shaders when I switched to a unified definition which is why I had to fix it
On another topic – Nine Black Alps have to be one of the most underappreciated bands out there. I hadn’t heard of them at all until Pandora brought them to my attention, despite the fact that they’re a fairly recent band. I had their album ‘Everything Is’ for Christmas and it’s superb.
December 31st, 2006 at 3:03 am
Very nice idea on the unified shader definitions. I probably would have went a slightly different route, using explicit shader environment tags so you can easily tell the HLSL from the GLSL just based on the delegation tag alone (rather than embedding it in the name), but nonetheless this is certainly a worthy and obviously necessary feature.
I tend to still be a bit of a glutton for pain, so I have to ask: Does it also work when using assembly language shaders as well, or does it only work for delegating between HLSL and GLSL?
December 31st, 2006 at 12:28 pm
I didn’t want to include a language tag in the delegate option because that’s duplication of information – the underlying language is already defined in the shader it refers to, so there’s no need to say it again there. Personally I tend to include the language in the shader name just so I can use the same names for both languages but with that one difference, but you can of course do whatever you like – there is no requirement to have the language name in the shader name of course.
This only delegates between high-level languages because it supports the high-level language interface (ie named parameters). So it works with Cg, HLSL and GLSL, and any other high-level language plugins that might be registered later. It won’t delegate to low-level shaders because named parameters could not be supported. Does anyone even write shaders in assembler anymore? That’s so 2002
December 31st, 2006 at 8:42 pm
Higher level shader languages are quite useful given that they provide a reasonable path to the “try and see” approach to shader programming.
How does the delegate resolution work? Run first match, ignore the rest? I’m only curious because you’re apparently concurrently supporting GLSL and Cg within the same delegate set, which is a conflicting resolution. (ie, they can both match at the same time) Or is it basically up to the material programmer to know that they shouldn’t do things like that?
January 1st, 2007 at 1:13 pm
Just like techniques, the first one supported is used. It’s perfectly valid for multiple delegates to be valid at once, and the first one takes precedence.
January 2nd, 2007 at 2:17 am
That clears things up quite tidily then. Keep up the good work!