[d3d9/10] Moving away from Effects

Started by
10 comments, last by MJP 13 years, 6 months ago
So I've looked into shader reflection and it seems to me that it serves 3 purposes (and please correct me if I'm wrong) :

1) used to grab data from the shaders (possibly for debugging purposes)
2) used to validate if 2 more shaders are compatible with each other. so in the case of a vertex shader and a pixel shader, it can be used to see if the vs' output struct matches ps' input struct?

and lastly I'm not too sure about this one :

3) used to dynamically create constant buffers in the renderer? With shader reflection, you can see what constant buffers and its variables are in that particular shader (as well as texture buffers). But even though you know the variable's type, name, etc, how exactly do you use that data to dynamically create a constant buffer?

My other questions are :
It seems like shader reflection is completely optional and isn't required to create a constant buffer?

When defining a "hard-coded" constant buffer, do the variables in the application
//.cppstruct CB_VS_PER_OBJECT{    D3DXMATRIX m_WorldViewProj;    D3DXMATRIX m_World;};


have to exactly match the constant buffer in the shader (order and type)?
//.fxcbuffer cbPerObject : register( b0 ){	matrix		g_mWorldViewProjection	: packoffset( c0 );	matrix		g_mWorld		: packoffset( c4 );};
Advertisement
Quote:Original post by 16bit_port
So I've looked into shader reflection and it seems to me that it serves 3 purposes (and please correct me if I'm wrong) :

1) used to grab data from the shaders (possibly for debugging purposes)
2) used to validate if 2 more shaders are compatible with each other. so in the case of a vertex shader and a pixel shader, it can be used to see if the vs' output struct matches ps' input struct?


Yup you can do both of those things. You can also look at the input signature of a vertex shader, and determine whether a vertex buffer contains the necessary elements. So for instance if a normal mapping shader requires a tangent frame, you can use reflection to determine that the shader requires tangents and binormals.

Quote:Original post by 16bit_port
and lastly I'm not too sure about this one :

3) used to dynamically create constant buffers in the renderer? With shader reflection, you can see what constant buffers and its variables are in that particular shader (as well as texture buffers). But even though you know the variable's type, name, etc, how exactly do you use that data to dynamically create a constant buffer?

My other questions are :
It seems like shader reflection is completely optional and isn't required to create a constant buffer?

When defining a "hard-coded" constant buffer, do the variables in the application
*** Source Snippet Removed ***

have to exactly match the constant buffer in the shader (order and type)?
*** Source Snippet Removed ***


Ultimately the data that you copy into the mapped ID3D10Buffer has to exactly match the data layout specified in your shader code. So if your shader specifies a buffer with a float4x4 and a float3, then you need to copy 19 floats into that constant buffer (and your constant buffer has to be the size of 19 floats.

So if you use reflection, you can figure out the size and offset (from the start of the constant buffer) of each variable. So sticking with our simple case of a float4x4 and a float3...if you reflected that data, you would know that you would need a constant buffer that's (16 * 4) + (3 * 4) bytes in size. You would also know the name of the constants...so for instance if you had some code that took the string name and a value, you could say "okay so the 'Color' parameter is 12 bytes in size, and is located 64 bytes into the constant buffer". Then you could use that offset and size to memcpy the data into the constant buffer.

If you want to hard-code the constant buffer, then the easiest way to do so is to create a struct whose memory layout exactly matches the layout in your shader. That way you can just use sizeof() to determine the size for your ID3D10Buffer, and also you can just memcpy in the whole struct when mapping the buffer (or you can just cast the pointer you get from Map to your struct type). You have to be careful though, because unless you specify otherwise in your shader code your constants will be aligned to float4 boundaries. So for instance if you had a few float2's in your constant buffer, you would have to align the corresponding D3DXVECTOR2's in your struct to 16 bytes. You can use __declspec(align(16)) with VC++ to do this.

EDIT: look for the page titled "Packing Rules for Constant Variables" in your SDK docs for the rules on how constants are aligned.

[Edited by - MJP on October 15, 2010 7:49:42 PM]

This topic is closed to new replies.

Advertisement