Jump to content

  • Log In with Google      Sign In   
  • Create Account


C++ Directx 11 CBuffers and HLSL.


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
16 replies to this topic

#1 Migi0027   Crossbones+   -  Reputation: 1520

Like
0Likes
Like

Posted 02 July 2012 - 08:54 AM

Hello, im new to Game Dev, and i have a problem with c++ sending a value to the hlsl code:
These are snippets of my code:

My Shader file:

cbuffer ConstantBuffer
{
    float4x4 final;
    float4x4 rotation;    // the rotation matrix
    float4 lightvec;	  // the light's vector
    float4 lightcol;	  // the light's color
    float4 ambientcol;    // the ambient light's color
    float mp;
}

Here I just defined my constant buffer in my hlsl file.

Declaration in c++:
struct CBUFFER
{
    public:D3DXMATRIX Final;
    public:D3DXMATRIX Rotation;
    public:D3DXVECTOR4 LightVector;
    public:D3DXCOLOR LightColor;
    public:D3DXCOLOR AmbientColor;
    public:float MP;
};

Then later on:
cBuffer.Final = UmatRotate * UmatPosition * UmatScaling * matView * matProjection;
cBuffer.Rotation = UmatRotate;
cBuffer.MP = 2.0f;

And:
devcon->UpdateSubresource(pCBuffer, 0, 0, &cBuffer, 0, 0);

And also some other code, but which is irrelevant.

So all the values other than the mp works, the mp in my shader is not given a value, and I would like to ask why? What did I do wrong?

Best Regards
Miguel Petersen

Sponsor:

#2 L. Spiro   Crossbones+   -  Reputation: 12965

Like
0Likes
Like

Posted 02 July 2012 - 09:16 AM

Firstly, switch to debug mode for your DirectX application. This prints any suspicious activity in your code.
Secondly use PIX to determine what value “mp” actually has inside the shader. When my CPU-side cbuffer’s are created I initialize every 4 bytes with float value 62.0f to make it clear what has not been properly updated when I view the buffers in PIX.

The buffer needs to be created with a size that is a multiple of 16.

Also, I use Map() and Unmap() to update buffers.

                    LSVOID * pvConstData;
                    D3D11_MAPPED_SUBRESOURCE msMapped;
                    CDirectX11::GetDirectX11Context()->Map( m_vConstantBuffers[I], 0UL, D3D11_MAP_WRITE_DISCARD, 0UL, &msMapped );
                    pvConstData = msMapped.pData;
                    CStd::MemCpy( pvConstData, &m_vConstBufferRawData[I].vRaw[0], m_vConstBufferRawData[I].vRaw.Length() );
                    CDirectX11::GetDirectX11Context()->Unmap( m_vConstantBuffers[I], 0 );


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#3 mhagain   Crossbones+   -  Reputation: 7609

Like
0Likes
Like

Posted 02 July 2012 - 09:53 AM

The buffer needs to be created with a size that is a multiple of 16.


This will be the cause - just add 3 extra floats at the end to pad it out (in both your .cpp and your HLSL).

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#4 CryZe   Members   -  Reputation: 768

Like
0Likes
Like

Posted 03 July 2012 - 03:28 AM

The best advice when working with constant buffers is to always take a look at the listing which can be generated while compiling the shader (/Fc <output> when using fxc). Inside the listing you can see all the compiled constant buffers (and everything else that got compiled), and even more important, the offsets of your constants which helps you understand the alignment of your constants.

Edited by CryZe, 03 July 2012 - 03:28 AM.


#5 iedoc   Members   -  Reputation: 726

Like
0Likes
Like

Posted 03 July 2012 - 05:42 AM

I'm pretty sure directx adds padding to the end of constant buffers when they do not add up to a multiple of 4 bytes.
Braynzar Soft - DirectX Lessons & Game Programming Resources!

#6 L. Spiro   Crossbones+   -  Reputation: 12965

Like
0Likes
Like

Posted 03 July 2012 - 06:42 AM

This will be the cause - just add 3 extra floats at the end to pad it out (in both your .cpp and your HLSL).

I'm pretty sure directx adds padding to the end of constant buffers when they do not add up to a multiple of 4 bytes.

In my experience, creation of the cbuffer simply fails when you do not pass an initial size that is a multiple of 16 bytes.
That would indicate that he has passed a multiple of 16 bytes if he is able to get any result at all.

But the reason I mentioned it is because I am also open to the possibility that I do not know about some quirks or such regarding DirectX 11, and maybe there are some circumstances that allow creating buffers of other sizes.

For now I am sitting on the fence. Since he is able to get any result at all, I am generally going to assume he passed a multiple of 16 when creating the buffer, but am waiting for evidence that this is not the case and that there is some other way to create a buffer that is not a multiple of 16 in size.


L. Spiro

Edited by L. Spiro, 03 July 2012 - 07:14 AM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#7 iedoc   Members   -  Reputation: 726

Like
0Likes
Like

Posted 03 July 2012 - 07:05 AM

I forgot to mention that it is of course a bad habit to assume directx will pad the buffer for you. but although i made that comment above, I do think the buffer packaging is probably his problem considering his post

Edited by iedoc, 03 July 2012 - 07:08 AM.

Braynzar Soft - DirectX Lessons & Game Programming Resources!

#8 mhagain   Crossbones+   -  Reputation: 7609

Like
0Likes
Like

Posted 03 July 2012 - 08:39 AM

What I've seen happen is: declare a struct in C++ that's larger than the intended corresponding cbuffer declaration in HLSL (e.g. by padding to 16), create a ID3D11Buffer from it - works, assign it to a cbuffer slot - works, Map for writing - works, write stuff to it - works, Unmap - BOOM.

In theory because you can have any ID3D11Buffer assigned to any buffer slot, problems won't happen until such a time as you actually try to do something where the declaration difference(s) become(s) significant, and when that happens you'll likely get either a CRT crash, a crash somewhere deep in driver or kernel code, or weird behaviour.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#9 Migi0027   Crossbones+   -  Reputation: 1520

Like
0Likes
Like

Posted 03 July 2012 - 10:30 AM

Alright, thanks guys for your help, i finally understood what to do. As my float needed more bytes, i increased the amount of allocated memory. Thanks guys.

#10 Jason Z   Crossbones+   -  Reputation: 4859

Like
0Likes
Like

Posted 03 July 2012 - 05:38 PM

Alright, thanks guys for your help, i finally understood what to do. As my float needed more bytes, i increased the amount of allocated memory. Thanks guys.

The issue is not that your float needed more bytes - it is that you have to declare data on 16-byte boundaries. This makes it easier for the driver and hardware to make certain assumptions about copying data around (i.e. 4xfloat = 16 bytes) and allows the use of registers more easily. I typically just declare float4, and if I use a sub-portion of a float4 then so be it. There is just room for expansion later on :)

#11 iYossi   Members   -  Reputation: 128

Like
0Likes
Like

Posted 05 July 2012 - 02:21 AM

In the C++ code, do
__declspec( align( 16 ) ) struct ConstantBuffer
{
/*...*/
};

#12 Migi0027   Crossbones+   -  Reputation: 1520

Like
0Likes
Like

Posted 05 July 2012 - 06:14 AM

In the C++ code, do
__declspec( align( 16 ) ) struct ConstantBuffer
{
/*...*/
};


Ok, i never saw that function, but ill research it... thanks!

#13 sss_abaker   Members   -  Reputation: 132

Like
0Likes
Like

Posted 05 July 2012 - 04:27 PM

__declspec(align(16)) seems like a simpler option, but will that translate over to video memory? You're aligning it in system memory just fine, but I'm not sure if it is treated the same way when you map it.

Please confirm.

Edited by sss_abaker, 05 July 2012 - 04:33 PM.


#14 mhagain   Crossbones+   -  Reputation: 7609

Like
0Likes
Like

Posted 05 July 2012 - 04:48 PM

It's not going to matter because when you map it you're getting a pointer to a different chunk of memory that has already been properly aligned/sized/etc when the cbuffer was created.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#15 sss_abaker   Members   -  Reputation: 132

Like
0Likes
Like

Posted 05 July 2012 - 04:57 PM

I figured. Thanks for the confirmation. I was nodding my head throughout this thread until I came across that claim and was pretty sure that's not how it worked.

#16 QPig   Members   -  Reputation: 104

Like
0Likes
Like

Posted 05 July 2012 - 08:31 PM

in my opinion
first. make your data full with 4 float every unit both in hlsl and c++, forget your c++ ruler and habit, what you contact with is gpu not cpu, and also hlsl is just like c but not c, naturally there are big differents at asm level. if ok, forget order of readableness just align it.
second. Updatesubresource sounds great, i agree, but map and unmap is handy, obviously. next time, try map, you will like it
third. i do not know why i still find d3dx*** at directx11, is it pure one, if it is, en, d3dx*** is history.
ok, i wish it can help you, if someone has different opinion please let me know

#17 MJP   Moderators   -  Reputation: 10632

Like
1Likes
Like

Posted 05 July 2012 - 11:40 PM

Aligning a struct to 16-bytes will affect the alignment and size of that structure, but not the members within it. The reason it's useful this case is because it will round up your structure size to the next multiple of 16-bytes (which is a requirement for constant buffers), but you could also do that just by rounding it up yourself. What you really need to be careful about with constant buffers is the alignment of the individual variables within the constant buffer. HLSL has its own particular rules for this that differ from the defaults for 32-bit and 64-bit C++, which means if you want to use a C++ struct to fill a constant buffer then you need to pay attention to member alignment. One way to do this will be to use __declspec(align(16)) to align individual members to the next 16-byte boundary. Here's a simple example:

struct ConstantBuffer
{
    float3 position;
    __declspec(align(16)) float3 color;
};

Without the alignment on the "color" member, it will be placed 12-bytes from the start of the constant buffer while HLSL requires it to be placed at the next 16-byte boundary.




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