DirectX 11 Constant Buffers vs Effect Framework

I'm having some trouble understanding the differences between using constant buffers or using the effect framework of DirectX11 for updating shader constants.

From what I understand they both do exactly the same thing, although from reading the documentation it appears as if using effects is meant to be 'easier'. However they seem the same to me, one uses VSSetConstantBuffers and the other GetConstantBufferByName.

Is there something I'm missing here?

4 Answers

Effect interface has always been the highest level shader-related interface. Most probably the Effect interface simply abstracts away some of the problems in dealing with constant buffers but it also uses them under the hood.

Whether the API is actually easier could probably be a question of requirements. If you want to build a very simple application, the effect interface might prove itself useful. However, if a more sophisticated engine is what you actually need then the Effect interface could probably even slow down the development and impose restrictions on some of the required optimizations.

• Thanks for the clarification, would you be able to provide more information on the limitations of the Effect interface (or a link to where I can find out more), as I can't seem to find anything. – Alex Oct 26 '12 at 13:43
• Yeah, the MSDN docs aren't good enough to do that easily. Basically the effects have to store all kinds of previous state before they set their own and reset it after rendering, that creates some overhead that could otherwise be avoided. – snake5 Oct 26 '12 at 14:54

The Effects framework is nothing more than a wrapper around the main API, so yes, under the hood it ends up calling VSSetConstantBuffers/etc.

While it's true to say that using Effects can take away some of the hassle of having to get down and dirty with actual cbuffers, for any non-trivial case it's actually an incredibly leaky abstraction in that the reality of cbuffers tends to rear it's ugly head more often than you might like; you have to be conscious and aware that yes, there are actual real-life cbuffers behind the scenes, and you have to be conscious and aware of what the good and bad usage and update patterns are, even despite the abstraction.

While Effects tries to make some best guesses, it's not a mind reader - you know your program better and you know what you intend by your code better, so you're in a better position to organize things properly.

None of this was a big problem in D3D9 where you had standalone constants (although it was also the case even back then that batching constant updates would lead to higher performance); in D3D10 and 11 it's a huge problem, and in many cases it's actually easier to bypass Effects and just use the raw API.

This perhaps is one reason why the use of Effects is heading to deprecation land.

The Effects API gives you an interface where you don't need to worry about constant buffers yourself. (At least, that's the intention.) You can instead work in terms of individual parameters and set their values one at a time. Internally, it's keeping track of the constant buffers and updating them as needed. The shaders still do have constant buffers, but the CPU side of your application doesn't need to know about them. Although you can get access to the constant buffers yourself with GetConstantBufferByName etc., you wouldn't normally do so.

However, that does mean that you're incurring a function call and other overhead every single time you set a parameter. Depending on the internals, there might be additional overhead in memory use, extra bus traffic, and so on. As the other answers mentioned, for a high-performance engine it might be preferable to just deal with constant buffers yourself. If you know the layout, you can create a struct in C++ that matches, so setting the parameters is just setting the members of a struct and doing a couple of API calls for the whole thing.

• +1, but personally I think the fact that Effects hides the cbuffers is a fairly huge point against it; it's easy for a beginner (or naive programmer) to - say - update one constant per draw call (for an alpha value or something) and cause Effects to do a huge cbuffer upload each time as a result. That's why you really can't pretend that cbuffers don't exist, and that's why Effects fails (in D3D10/11) for trying to do so. – Maximus Minimus Oct 26 '12 at 19:53

As said above the Effects framework is an additional layer on top which gives you some higher level of abstraction.

It's not deprecated in any way, it's only provided outside the DirectX core, and also in source code form (which means you can see what it does under the hood and tune it to fit your needs).

The biggest disadvantage of it, as mentioned above, is that it's really easy not to use declarative buffers at all and create unoptimized code if you're not careful (you can use separate buffers using effects framework and it's pretty recommended to do so).

This is perfectly valid using effects framework:

cbuffer cbPerScene : register( b1 )
{
float4x4 tViewProjection;
};

cbuffer cbPerObject : register( b0 )
{
float4 ambientcolor;
float4 diffusecolor;
float4x4 tWorld;
};


When you modify a variable it will mark it's parent buffer as "dirty" , and update accordingly (please note it only updates resource when you Apply Pass, not when you set a variable).

Now some advantages of it.

• Layout validation : It will verify that data you pass between shader stages are compatible (data passed from vertex shader to pixel shader for example). In a production environment it's not too useful, but a design stage it's quite handy.
• Reflection/Semantics : Having the ability to enumerate individual variables and attach semantics to them allows to have some dynamic pipeline, which can be really useful for prototyping (as soon as you recompile your shader you can automatically create gui elements for variables to test it, semantics are commonly used for global settings, for example:

float4x4 tViewProjection : VIEWPROJECTION;

you can detect the semantic and automatically send your camera transform.

So now when you do a lot of draw calls with plenty of different material shaders, it's true that it can introduce some performance hit (even tho in modern dx11 programming Instancing and using Buffers/StructuredBuffers is pretty much the way to go), for other parts like post processing the hit is generally very minimal.