D3D10: Confused over cbuffer creation and manipulation

Started by
3 comments, last by PropheticEdge 13 years ago
I've been doing some preliminary delving into D3D10 recently, and I've come across cbuffers in .FX files.

I've read through the Frank Luna Introduction to 3D Game Programming with DirectX 10 book, and it gives a small description of cbuffers that amounts to this.

They're constant values that can be used as points of communication between a shader and the C++ program. These are collections of global values that are organized based on how frequently they need to be updated (life of the shader, per frame, per object). Grouping them as such allows for greater performance.

In the example code from the book, access to variables within a cbuffer takes this form.

mfxWVPVar = mFX->GetVariableByName("gWVP")->AsMatrix();

where :
mfxWVPvar is a ID3D10EffectMatrixVariable pointer.
mFX is a ID3D10Effect pointer.
"gWVP" is the name of a variable in the per-object cbuffer defined in the FX file.

And then the code goes on its merry way to set the mWVPVar using the mfxWorldVar->SetMatrix(arg) function.

That's all well and good, I'm cool with that, but I've been poring over the MSDN documentation and gotten myself thoroughly confused.

The MSDN documentation seems to imply that cbuffers are, in fact, constant buffers. That they are full on buffers that are created, defined with a description, and bound to the rendering pipeline just like a vertex buffer or index buffer is. This is described in here.

http://msdn.microsoft.com/en-us/library/bb205130%28v=vs.85%29.aspx

And the code MSDN provides looks like:

ID3D10Buffer* g_pConstantBuffer10 = NULL;

struct VS_CONSTANT_BUFFER
{
D3DXMATRIX mWorldViewProj; //mWorldViewProj will probably be global to all shaders in a project.
//It's a good idea not to move it around between shaders.
D3DXVECTOR4 vSomeVectorThatMayBeNeededByASpecificShader;
float fSomeFloatThatMayBeNeededByASpecificShader;
float fTime; //fTime may also be global to all shaders in a project.
float fSomeFloatThatMayBeNeededByASpecificShader2;
float fSomeFloatThatMayBeNeededByASpecificShader3;
};

D3D10_BUFFER_DESC cbDesc;
cbDesc.ByteWidth = sizeof( VS_CONSTANT_BUFFER );
cbDesc.Usage = D3D10_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
hr = g_pd3dDevice->CreateBuffer( &cbDesc, NULL, &g_pConstantBuffer10 );
if( FAILED( hr ) )
return hr;

g_pd3dDevice->VSSetConstantBuffers( 0, 1, g_pConstantBuffer10 );


However, in the example code I'm looking at, no such thing happens! Unless I'm being really blind, I cannot see any calls that bind a buffer with the D3D10_BIND_CONSTANT_BUFFER bind flag, nothing to create the buffer, no constant buffer structs, nothing! They're just accessing the variables in the FX cbuffer one at a time and leaving it at that.

So here are my questions:

1) Are the cbuffers found in the FX file the same as constant buffers described in the MSDN? If not, what's the difference?
2) If so, how are their values being referenced piecemeal without ever declaring the buffer and binding it to the pipeline in c++?
3) Is there wizardry afoot that automatically figures out that I'm referencing a variable to a constant buffer without me binding it? If so, is this incurring a performance tradeoff versus defining the actual constant buffer like a regular buffer and binding it to the pipeline myself?
4) Do tbuffers operate the same way as cbuffers in this regard?
Advertisement
I'm guessing the wizardry is in the Effects (FX) system.

At the core of D3D, you can load individual shader programs and manage shader constants yourself. Optionally, there's an easier-to-user layer built on top of this, called the Effects Framework, which gives you the '.fx' file format, all those [font="Lucida Console"]ID3D*Effect*[/font] classes, and does a lot of the tedious low-level tasks for you.


If you choose not to use the effects framework and write all this stuff yourself, then you might get better performance, assuming you're just as familliar with the D3D API as the authors of the effects framework are, and know why the existing framework isn't a good fit for your usage patterns ;)

If you choose not to use the effects framework and write all this stuff yourself, then you might get better performance, assuming you're just as familliar with the D3D API as the authors of the effects framework are, and know why the existing framework isn't a good fit for your usage patterns ;)


Pffffffffttttbtbttt no. No way am I abandoning this sweet, sweet framework.

Thanks a lot for the response, Hodgman. I'm totally cool with darke magicks going on in the background, so long as I know they're occurring. I am a little disappointed that none of the documentation I read made a clear point that there was this framework in place that I've been unwittingly working with.

Edit: Oh, another question.

I've heard that variables placed in the global space of a FX file will be automatically packaged into a default cbuffer. However, in Frank Luna's book he mentions that Texture2D variables cannot be placed inside of a cbuffer because "nonnumeric values cannot be added to a cbuffer."

Is this true? If so, why are they not being added to the default cbuffer? Are they just floating around in the global namespace?
A constant buffer contains raw numeric data. So your int's float's, bool's, etc. A Texture2D is not a piece of data, but rather a variable representing a resource (block of device memory) that you can query in specific ways through various methods. This is why a Texture2D (as well as other resource types) just gets declared as a global, rather than as part of a constant buffer.

Also if you want to learn a bit more about what's going on behind the scenes with the effects framework, I would suggest using PIX to capture a frame. Doing this will show all of the native D3D calls (wrapped in markers showing the corresponding Effect call that you made), which let's you piece together what's going on. There's also full source code available for the Effects11 framework, if you want to look at that (although some things have been removed or replaced with that version). You can also look at the D3D10 and D3D11 samples that don't use effects, and try your hand at setting up some simple shaders manually. Doing this should help you learn what's required to set up a shader, which in turn will give you some insight into what the Effects framework does.
Ok, that makes sense.

Thanks MJP, I'll check out PIX and likely attempt manually setting up shaders at some point in the future, but it's only recently that I've finally wrapped my head around how Direct3D is setup, how the rendering pipeline works, the precise divisions between C++ and shader code, the work involved in setting up relatively normal draw calls, etc. I still have some questions and a ways to go, so when I have a bit more experience under my belt I'll brave a peek under the hood.

This topic is closed to new replies.

Advertisement