Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Using multiple constant buffer


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 caballero   Members   -  Reputation: 100

Like
0Likes
Like

Posted 29 January 2012 - 02:04 PM

Hi,
I've started to learn dx11 with the slimdx framework.
Currently i tried to use two constant buffer to update informations more frequent then other.

But with my current shader code I get some strange behaviour using the two constant buffers:
// cbuffer definition
struct ShaderLightBuffer
{
public Vector3 Ambient;
public float Alpha;
public Vector3 Diffuse;
public float Shininess;
public Vector3 Specular;
public float padding;
public Vector2 SpecularTextured;
public Vector2 padding2;
}

struct ShaderMatrixBuffer
{
public Matrix World;
public Matrix WorldViewProjection;
public Vector3 CameraPosition;
public float padding1;
}

// buffer initialization
_light_constant_buffer = new Buffer(Device, Marshal.SizeOf(typeof(ShaderLightBuffer)), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
_matrix_constant_buffer = new Buffer(Device, Marshal.SizeOf(typeof(ShaderMatrixBuffer)), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);

// render logic
ImmediateContext.InputAssembler.InputLayout = _input_layout;
ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;

ImmediateContext.InputAssembler.SetVertexBuffers(0, _buffer_bindings.ToArray());
ImmediateContext.VertexShader.Set(_vertex_shader);

ImmediateContext.VertexShader.SetConstantBuffer(_matrix_constant_buffer, 0);
ImmediateContext.VertexShader.SetConstantBuffer(_light_constant_buffer, 1);

ImmediateContext.Rasterizer.SetViewports(Engine.DeviceManager.Viewport);

ImmediateContext.PixelShader.Set(_pixel_shader);
ImmediateContext.PixelShader.SetConstantBuffer(_light_constant_buffer, 2);

ImmediateContext.OutputMerger.SetTargets(DepthBuffer, RenderTarget);

// .. set wvp, world, camera position to matrix buffer..
ShaderMatrixBuffer matrix_buffer = new ShaderMatrixBuffer();
matrix_buffer.WorldViewProjection = view_proj;
matrix_buffer.World = world_matrix;
matrix_buffer.CameraPosition = Engine.Camera.Eye;

// update matrix constant buffer
var matrix_stream = new DataStream(Marshal.SizeOf(typeof(ShaderMatrixBuffer)), true, true);
matrix_stream.Write(matrix_buffer);
matrix_stream.Position = 0;

ImmediateContext.UpdateSubresource(new DataBox(0, 0, matrix_stream), _matrix_constant_buffer, 0);
ImmediateContext.VertexShader.SetConstantBuffer(_matrix_constant_buffer, 0);

foreach (var material in Materials)
{
ShaderLightBuffer light_buffer = new ShaderLightBuffer();
light_buffer.Alpha = 1f;
light_buffer.Ambient = material.Ambient;
light_buffer.Diffuse = material.Diffuse;
light_buffer.Specular = material.Specular;
light_buffer.Shininess = (int)material.Shininess;
light_buffer.SpecularTextured = new Vector2 (0);

if (!string.IsNullOrEmpty(material.TextureFilename))
{
light_buffer.SpecularTextured = new Vector2(1);
if (_shader_resource == null)
{
var texture = Texture2D.FromFile(Device, Path.Combine(material.Path, material.TextureFilename));
_shader_resource = new ShaderResourceView(Device, texture);
}

ImmediateContext.PixelShader.SetShaderResource(_shader_resource, 0);
}

ImmediateContext.PixelShader.SetSampler(_sampler_state, 0);

var light_stream = new DataStream(Marshal.SizeOf(typeof(ShaderLightBuffer)), true, true);
light_stream.Write(light_buffer);
light_stream.Position = 0;

ImmediateContext.UpdateSubresource(new DataBox(0, 0, light_stream), _light_constant_buffer, 0);

ImmediateContext.VertexShader.SetConstantBuffer(_light_constant_buffer, 1);
ImmediateContext.VertexShader.SetConstantBuffer(_light_constant_buffer, 2);

ImmediateContext.Draw(_vertices_count[i], 0);
}
// end render logic
Alright, I hope this code is straight forward, just setting all infos for the pipeline stages, updating the general constant buffer and the cbuffer
for each material used for the geometry.

Now the odd part - shader code
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output;

// Transform the position into world space for lighting, and projected space
float4 vPosWorld = mul( float4(input.position,1), World );
output.position = mul( float4(input.position,1), WorldViewProjection );

// pass texture coordinate
output.texcoord = input.texcoord;

// transform normal into world space for lighting
float3 normal_world = mul( input.normal, (float3x3) World);
float3 light_vector = normalize( LightPosition - vPosWorld.xyz );

// compute the ambient and diffuse components of illumination
output.color.rgb = LightColor * MaterialAmbient;
output.color.rgb += LightColor * MaterialDiffuse * saturate( dot( light_vector, normal_world ) );

if( SpecularTextured.x > 0)
{
float3 camera = normalize( vPosWorld.xyz - CameraPosition );
float3 reflection = reflect ( light_vector, normal_world );
float phone_value = saturate( dot( reflection, camera ) );
output.color.rgb += MaterialSpecular * pow( phone_value, MaterialShininess );
}

// odd things happens if i comment the next line -> [7480] D3D11: WARNING: ID3D11DeviceContext::Draw: The size of the Constant Buffer at slot 1 of the Vertex Shader unit is too small (64 bytes provided, 144 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects. [ EXECUTION WARNING #351: DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL ]
output.color.rgb = MaterialDiffuse;
output.color.a = MaterialShininess;

return output;
}

float4 PS( PS_INPUT input ) : SV_Target
{
float4 output = input.color;
//// Sample and modulate the texture
if ( SpecularTextured.y > 0 )
output.rgb *= MeshTexture.Sample( samLinear, input.texcoord );
return output;
}
If I set the color values to diffuse the in the vertex shader it draws my geometry correctly with the defined color.
But commenting out the color assignment (since this line was used for debugging), will give me the following warning:
[7480] D3D11: WARNING: ID3D11DeviceContext::Draw: The size of the Constant Buffer at slot 1 of the Vertex Shader unit is too small (64 bytes provided, 144 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects. [ EXECUTION WARNING #351: DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL ]

This happens also if I use UpdateSubResource method to update both constant buffers.
It seems that the second constant buffer update overwrites also the first constant buffer.

I wanted to ask how to handle multiple constant buffer updates? Am I missing something?

Sponsor:

#2 iedoc   Members   -  Reputation: 1043

Like
1Likes
Like

Posted 29 January 2012 - 03:18 PM

When you have multiple constant buffers, you have to put them in separate slots. i don't know how to use slimdx, but in regular dx11, you can set the vertex's constant buffer by calling VSSetConstantBuffers of the device context, and setting the second parameter as 0 for the first constant buffer, and 1 for the second. If the vertex and pixel shader share a constant buffer, you will have to bind the same constant buffer separately to each shader, using VSSetConstantBuffers and VSSetConstantBuffers.
Braynzar Soft - DirectX Lessons & Game Programming Resources!

#3 caballero   Members   -  Reputation: 100

Like
0Likes
Like

Posted 29 January 2012 - 03:53 PM

Thanks for the quick response!
I think you meant VSSetConstantBuffer and PSSetConstantBuffer in the last sentence.

I've replaced setting both cbuffer at the same time

ImmediateContext.VertexShader.SetConstantBuffers(new[] { _matrix_constant_buffer, _light_constant_buffer }, 0,2);

with

ImmediateContext.VertexShader.SetConstantBuffer(_matrix_constant_buffer, 0);
ImmediateContext.VertexShader.SetConstantBuffer(_light_constant_buffer, 1);

and also set the cbuffer to the pixel shader
ImmediateContext.PixelShader.SetConstantBuffer(_light_constant_buffer, 1);

I also tried to attach - : register(cbx) to the cbuffer declaration in the shader code.
but the result is the same error message Posted Image

Alright, I tried the same code with the sharpdx framework with the same ouput..

Edited by caballero, 29 January 2012 - 05:07 PM.


#4 iedoc   Members   -  Reputation: 1043

Like
0Likes
Like

Posted 30 January 2012 - 01:01 AM

sorry it didn't work for you, but one other thing, iis (as far as i know) you have to put each buffer in it's own slot, even if two shaders use the same buffer, they should go into separate slots, so when you bind your pixel shaders buffer, you should try changing the '1' to a '2'

also, can you show the structure of your constant buffers?
Braynzar Soft - DirectX Lessons & Game Programming Resources!

#5 caballero   Members   -  Reputation: 100

Like
0Likes
Like

Posted 30 January 2012 - 04:14 AM

The structure of the constant buffer is


cbuffer Matrixbuffer : register(cb0)
{
matrix World;           
matrix WorldViewProjection;
float3 CameraPosition;
float padding;
};
and

cbuffer LightBuffer : register(cb1)
{
float3 MaterialAmbient;   // Material's ambient color
float  MaterialAlpha;
float3 MaterialDiffuse;   // Material's diffuse color
float  MaterialShininess;
float3 MaterialSpecular;   // Material's specular color
float padding2;
float2 SpecularTextured;
float2 padding3;
};

It seems to me that updating the constant buffer in the foreach loop overwrites the first "global" constant buffer.
Could there be something that I am missing?

Would a pix run file help you to get more information out of it?

#6 iedoc   Members   -  Reputation: 1043

Like
0Likes
Like

Posted 30 January 2012 - 05:59 AM

actually, could you post the constant buffers in your main app?

This might not be the problem, but just check it out. Are you making sure you are packaging your constant buffers correctly in your app? the shader takes 16 byte chunks for the constant buffer, so if you have a variable that's split between two chunks, it will cause problems. float variables are 4 bytes, float3's are 12 bytes, matrices are 16 bytes. I see you have it aligned correctly in the shader, so i'm guessing it's probably the same for your app, but double check.
Braynzar Soft - DirectX Lessons & Game Programming Resources!

#7 iedoc   Members   -  Reputation: 1043

Like
0Likes
Like

Posted 30 January 2012 - 06:14 AM

I just noticed you are not setting your constant buffers after you change them. I think you have to reset them every time they change. also, try using update subresource instead:
ImmediateContext->UpdateSubresource( light_buffer, 0, NULL, &_light_constant_buffer, 0, 0 );
Somethng like that anyway
Braynzar Soft - DirectX Lessons & Game Programming Resources!

#8 kauna   Crossbones+   -  Reputation: 2744

Like
1Likes
Like

Posted 30 January 2012 - 06:44 AM

[7480] D3D11: WARNING: ID3D11DeviceContext::Draw: The size of the Constant Buffer at slot 1 of the Vertex Shader unit is too small (64 bytes provided, 144 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects. [ EXECUTION WARNING #351: DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL ]


The error message has all the information about the problem. Your constant buffer bound at slot 1 has size of 64 bytes, but the shader is reading data from area outside of the 64 bytes area.

This means that you have the light buffer bound to slot 1, but on the shader expects the matrix buffer to be at slot 1. You have to have same registers at the program side and at the shader side. Remember that the register indices are 0-based.


Cheers!



#9 caballero   Members   -  Reputation: 100

Like
0Likes
Like

Posted 30 January 2012 - 07:52 AM

Hi, I've updated all code parts in my previous posts.

Thx kauna for the hint since after changing the slots in the code no warnings or errors occur.

// I've set the following for slots for the buffers to be comprehensible
vs.setconstantbuffer(matrix_buffer, 1);
vs.setconstantbuffer(light_buffer, 0);
ps.setconstantbuffer(light_buffer, 2);

I thought that the cbuffers in the shader will be declared in sequential order since I'm defining first the Matrix cbuffer then the Light cbuffer. I tried to fixate that by setting : register(cb#).

Obviously i was wrong with this assumption.

Now it's all black (of course it is black, I think I am really learning dx the hard way) without any warnings thanks for your help!

Theoretically, if I define more cbuffers, how can I find out which slots they were assigned to?

#10 kauna   Crossbones+   -  Reputation: 2744

Like
0Likes
Like

Posted 30 January 2012 - 12:24 PM

// I've set the following for slots for the buffers to be comprehensible
vs.setconstantbuffer(matrix_buffer, 1);
vs.setconstantbuffer(light_buffer, 0);
ps.setconstantbuffer(light_buffer, 2);


Hi, you may set the light_buffer to slot 0 for vertex shader and pixel shader. I assume that in the shader code you have probably slot 0 (both vs and ps) for the light_buffer?

You may use shader reflection API to extract information from the shaders (including which constant buffer is expected at which register ...)

Best regards!

#11 caballero   Members   -  Reputation: 100

Like
0Likes
Like

Posted 30 January 2012 - 01:10 PM

Thanks for info!

Additionally some further gamedev redirections:
how to find the constant buffer slots via shader reflection
http://www.gamedev.net/topic/607104-d3d11shaderreflection-and-constant-buffer-slot/

some thoughts about UpdateSubResource vs Map/Unmap
http://www.gamedev.net/topic/616350-dx11-fastest-way-to-update-a-constant-buffer-per-draw-call/




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS