Constant buffer per object

Started by
5 comments, last by ongamex92 8 years, 1 month ago

Hi,

I have shader with uniform inputs for whole object, like Position and Scale.

In OpenGL I used glUniform* functions to pass those values into my struct inside shaders.

Now I moving this stuff under D3D11 and I'm not sure if its good idea to have one constant buffer per object?

My simple frame logic is:

- Update global constant buffer (map, write, unmap)

- Time

- MVP

- Foreach game objects

- Call update method which will modify position and scale on CPU side

- Map constant buffer (which is already created when object is spawned to the scene)

- Copy CPU position and scale to constant buffer

- Unmap

- Draw

Is good idea to have one constant buffer per object? Or do I have to use one global constant buffer and just update values for every new object?

Thank you

Advertisement

I've never viewed the cbuffer as something that is or has to be tied to an object. Instead a better way to view a cbuffer is as a container (That really could care less what TYPE of data is stored within it) who's only goal is to have the compacity to transfer your data from the CPU to the GPU. Ultimately the job of data interpretation is up to the Shader.

A constant buffer that holds let's say, a matrix (like XMMATRIX) is able to carry 64 bytes. Lets say all the Matrices you use throughout your game only ever use 64 bytes. Why would you need another constant buffer to represent a 64 byte container?


D3D11_BUFFER_DESC cDesc;ZeroMemory(&cDesc, sizeof(D3D11_BUFFER_DESC));
cDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cDesc.Usage = D3D11_USAGE_DEFAULT;
cDesc.ByteWidth = sizeof(XMMATRIX); // XMMATRIX being 64 bytes I believe
And not only could you use this cbuffer for other matrices. You could also use to transfer other structures that are 64 bytes in length. i.e.


struct Light
{
    float4 pos;
    float4 diffuse;
    float4 ambient;
    float4 specular;
};
And assign that light to the cbuffer that used the XMMATRIX as a reference for the size.

D3D11_SUBRESOURCE_DATA resource;
resource.pSysMem = &light; // notice how the type is void*, The subresource could care less WHAT the data is. Ultimately that's up to the shader to handle.

But nothing is wrote in stone. If you don't mind burning the extra memory, and object count doesn't get ridculous, you may find it's easier to continue on the path that your on. It then becomes a simple design decision.

Marcus

In my application i have 2 cbuffers (per stage, in theory you can use only two for all stages).
1 that is updated once per frame and the other is updated for every object.

Those 2 buffers are always bound!
I update them via Map/Unmap and I found out that for my case binding once buffer and updating it multiple times via Map/Unmap is much faster than just binding new cbuffer.

Your design is idling the GPU on every draw as you map, copy to, unmap, and bind the CB. You're also fitted to make separate draw calls for every object. That's bad.

Make one big CB. Stream all your objects' data into it. Use instance indices to access the correct transform at render time.

With the right setup and simpler data, you might even be able to reach an ideal case where you stream all updates in one fast memcpy to a persosyently-mapped buffer and then issue a single draw call that saturates your GPU and maximizes it's processing power.

Sean Middleditch – Game Systems Engineer – Join my team!


Your design is idling the GPU on every draw as you map, copy to, unmap, and bind the CB

This isn't necessarily true -- you don't need to idle the gpu when uploading data to it. Even if this were the case, you'd be doing this when uploading to a single combined constant buffer anyway.


one fast memcpy to a presistently-mapped buffer

Afaik D3D11 doesn't allow presistently mapped buffers? I'm pretty sure a buffer needs to be unmapped if it's going to be used in DX11. Win8/DX11.1 allow D3D11_MAP_WRITE_NO_OVERWRITE to be used with constant buffers which I think would be the next best thing.

Thank you all for responses.

So I will rewrite my design to use just one "Transform Buffer".

If I understand it correctly - for every "game object" I have to map (just one CB), write data and unmap to push data to GPU right?

Yep

This topic is closed to new replies.

Advertisement