Do you want to start a war? you crazy guy!
paroj wrote: Fri Dec 22, 2017 6:02 pm
To me the RTSS is a strict superset of HLMS in the sense that it can do everything HLMS can and more.
I could say the opposite and we'd scream at each other the same ad infinitum.
paroj wrote: Fri Dec 22, 2017 6:02 pm
At its core the HLMS shader templates are just another variation of an uber-shader with all of its drawbacks like the
#ifdef explosion accompanied by the hard to maintain paths through the shader. Bad encapsulation basically.
That is really left to the maintainer (the one writing the templates). So you could say I am the one to blame for the poor encapsulation, but not the technology itself.
In that sense Hlms is very much like C++. Very flexible, can be very fast, and a billion ways of doing the same. And when you shoot yourself in the foot you blow yourself the entire leg.
TBH at the time I wrote the Hlms, the reasons I didn't properly encapsulated and implemented as functions like RTSS does (which is indeed cleaner) were 3:
- For functions, I did not trust GL drivers in particular at optimizing them. So I ended up going straight for code chunk insertion. The parser wasn't complex, so it couldn't handle functions itself (i.e. implement function calling parsing inside the Hlms, rather than leaving it to the shader compiler). In particular, Android Mobile was (and still is) the main concern (ironically, it ended up as the platform with poorest support) The @foreach statement was literally born out of necessity from an Adreno driver bug by hardcoding and manually unrolling a regular for loop.
- I did not trust GL shader compilers at correctly handling macros either. At that time I did not know we actually ran our own GLSL macro preprocessor (literally because the GL shader compilers had proven to not be trustworthy in that area!) rather than leaving it to the driver. Had I known that, I'd made more use of macro-like functions. In fact I'm slowly porting the current code to this style which results in cleaner, more modular and understandable code.
- Absolutely no C++ integration (more on this later)
Certainly the current RTSS implementation is rather arcane and badly documented, but this can be solved
Another of the reasons I didn't bother with the RTSS and preferred to rather start anew.
About C++ integration:
The Hlms does more than just gluing shader code together.
Because there's a C++ part, each implementation can upload const and texture buffers as efficiently and flexible as possible. The RTSS inherited the "shader parameter" paradigm of old Ogre, which doesn't map well to modern APIs; and gets in the way of high performance.
Another important part of the Hlms is handling PSO. PSO is one big blob of everything:
- Shaders to use (vertex, pixel, geometry, hull, domain shaders)
- Vertex format (position, normals, uvs, etc)
- Raster state such as (aka 2.1's macroblocks):
- Depth writes
- Depth comparison function
- Alpha to coverage setting
- Culling mode
- Polygon fill mode
- Scissor setup
- etc
- Blending state (alpha blending setup per color attachment, aka 2.1's blendblocks)
- Information about the render target:
- Pixel format of each color target
- Pixel format of depth and stencil buffers
- MSAA setting
As a result there are 3 different moments we can distinguish:
- Material bind time. At that point we know information about the model (such as normals, UVs), and the intrinsic material information (such as whether there's a normal map, the blending modes).
- Pass time. We do not know about an individual object (unless the one writing the Hlms implementation can perform certain assumptions, eg. Terrain rendering), but we do know about global stuff: MSAA settings, depth setting overrides, whether shadow mapping is supported, etc. We can also upload toe const buffers pass-invariant data such as view and projection matrices.
- Draw time. That's where the material and pass are merged together and we know all the information to properly generate a shader and the PSO.
In terms of the Hlms, that's literally two hashes that are merged to form a final hash; and that is used to retrieve the PSO from a cache, and generate it if it's not there.
This algorithm solves the PSO problem, allows for efficient caching and decouples information evaluation. It's not without its problems as now we don't have a way to predict the parameter combinations / permutations which makes shader precaching a lot harder.
The RTSS did none of that. It simply handled the GPU side of things, and surrendered itself to the old material system, evaluating everything either at draw time or at bind time. The Hlms was instead in charge (in fact, old materials are now implemented as an Hlms implementation).
And the RTSS had really poor documentation.
Comparing the Hlms to RTSS at this point is more like comparing apples to cows really. Unless you stick to the generated shader side.
Now let's see what the users say...
