[DX11] - Compute Shader questions.

Started by
8 comments, last by Tordin 13 years, 4 months ago
Hey! im doing some Compute shaderstuff and got lost and since the lack of (in my opinion) good tutorials, i need some answers.

Q1 :
//C++csDesc.BindFlags			= D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;csDesc.CPUAccessFlags		= 0;csDesc.MiscFlags			= D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;csDesc.StructureByteStride	= sizeof(data);csDesc.ByteWidth			= sizeof(data) * t_Size_X * t_Size_Y;csDesc.Usage				= D3D11_USAGE_DEFAULT;


this code aboves creates a buffer, and that is starightforward.
But the only parameter value i find odd is the ByteWidth.

Data in this case is an float4.
why do i do the sizeof(data)*size_X*size_Y?
To specifi that i whant to make an 2d array of floats?

Q2 :
In the hlsl code, where should i put the eoutput?

Q3 :
(this question is related to question one)
If i specify to make a 2d array out of floats.
How do i know in wich element i am calculating right now?
my toughts where that the SV_GroupThreadID semantic would have the eye for that.

Q4 :
How do i read the output values in my cpp code?
(is this possible?)


If you have any good tutorials or any good booktips, let me know!
And thanks for all help.


"There will be major features. none to be thought of yet"
Advertisement
I'll try to give some insight on these topics:

Q1: The ByteWidth is the size of the buffer in bytes. So you say the size of the element, multiplied by the number of elements.

Q2: The output from the compute shader is done through an unordered access view (UAV). This is a big difference from the other stages - the compute shader handles its own output, allowing for fairly flexible setups.

Q3: That's right, but only if you have only a single thread group. If you are using a 2D grid represented by the 1D buffer, then you need to create a 1D index to use from your 2D ID information. If you have more than one group, then use the dispatch thread ID. If you only have one group, you can use either the dispatch or group thread ID's. The Water Simulation demo in my engine (link is in my signature) has just such a setup to hold the state of the water if you are looking for an example.

Q4: You need to create a staging buffer (a secondary buffer with staging usage) then copy the results to it, and then map that buffer and read the data out on the CPU side.
Q1 :
so there is no need to have a sizeof*x*y.
i could just go and create a array instead and size that?
Or i could make a real nig struct with diffrent kinds (if i would only whant to make one caluclation) of data types?

What i understood it from the tutorial (and hes purpose), was that he wanted to created a buffer big enough for a 16x16 float4 array, so he later could use it as an image.
and since images make most sence in 2d, he used the sizeX*sizeY.

Q2 :

That i know, to specify the question more, where do i output it in the hlsl code?
RWStructuredBuffer<BufferStruct> g_OutBuff;[numthreads( 4, 4, 1 )]void mainCS( uint3 threadIDInGroup : SV_GroupThreadID, uint3 groupID : SV_GroupID ){	float4 color = threadIDInGroup.x * threadIDInGroup.y * threadIDInGroup.z;	g_OutBuff[ 0 ].color = color;}


Here i am send the data to the g_OutBuff[0].color?
I just took this plain and simpel from the tutorial and i think i understand it so that the gOutbuff is the pixelshaders answer for "return color;".

Q3 :
Well, that was close to what i tought.
So the buffer is never ever a "2d buffer" it is allways a 1d buffer?
and there for i have to divide the size of (xNum*xElemntSize)/(yNum*yElementSize)?
and that index i allso use for the g_OutBuff[index]? instead of putting 0 there?
And i will have a look on your stuff!

Q4 :
Ah, so when i mapp the buffer, instead of writing to it, just read from it.
That make sense!

Thanks alot Jason!
"There will be major features. none to be thought of yet"
Quote:Original post by Tordin
Q2 :

That i know, to specify the question more, where do i output it in the hlsl code?
*** Source Snippet Removed ***

Here i am send the data to the g_OutBuff[0].color?
I just took this plain and simpel from the tutorial and i think i understand it so that the gOutbuff is the pixelshaders answer for "return color;".


Compute shaders don't really "return" anything; you declare one or more ouput buffers and you can write to them at any point during the execution of the shader, much like a normal C/C++ function writing to an array.
phantom : Precisly, i understand that, and that is why i wrote "Return color". it dose the similar thing in another way just.
"There will be major features. none to be thought of yet"
Quote:Original post by Tordin
Q1 :
so there is no need to have a sizeof*x*y.
i could just go and create a array instead and size that?
Or i could make a real nig struct with diffrent kinds (if i would only whant to make one caluclation) of data types?

What i understood it from the tutorial (and hes purpose), was that he wanted to created a buffer big enough for a 16x16 float4 array, so he later could use it as an image.
and since images make most sence in 2d, he used the sizeX*sizeY.

The sizeof*x*y is just to select enough memory to hold his 2D grid of points (I assume). Buffers are always 1D, while texture resources can be 1D, 2D, or 3D. Technically you can use a Texture2D to achieve the same result, so you just need to choose the resource type that allows for the most coherent memory access with a minimal amount of address calculations.
Quote:Original post by Tordin
Q2 :

That i know, to specify the question more, where do i output it in the hlsl code?
*** Source Snippet Removed ***

Here i am send the data to the g_OutBuff[0].color?
I just took this plain and simpel from the tutorial and i think i understand it so that the gOutbuff is the pixelshaders answer for "return color;".

This depends on the type of 'resource object' you declare in your shader, which is the interface that you work with your resource through. When you bind a resource to the compute shader through either an SRV or a UAV, on the HLSL side you must declare an object that represents it. In your case, it is a RWStructuredBuffer<BufferStruct> (which is a clever name by the way :P ). This object allows for array like access to its contents (which are again only 1D). Other objects like an append/consume buffer have different access mechanisms.
Quote:Original post by Tordin
Q3 :
Well, that was close to what i tought.
So the buffer is never ever a "2d buffer" it is allways a 1d buffer?
and there for i have to divide the size of (xNum*xElemntSize)/(yNum*yElementSize)?
and that index i allso use for the g_OutBuff[index]? instead of putting 0 there?
And i will have a look on your stuff!

I don't clearly understand the equation you show above, but in general if you have the 2D location in the grid that you want, you can find the index by using the following: index = location.x + size_x * location.y You are just making a linear index out of a 2D one like you would in the same situation in C++.
Quote:Original post by Tordin
Q4 :
Ah, so when i mapp the buffer, instead of writing to it, just read from it.
That make sense!

Thanks alot Jason!

Keep in mind that you have to provide the correct arguments to the map function in order to be able to read the data, and that it must be created with the proper access flags as well!
Q1 :
Yes well now i understand it perfect :)

Q2 :
Hmm alright... This was a bit confusing thoe so i think i have to read up on that subject!
(and i couldent find a way to see your water shader demo)

Q3 :
haha, no that equation was wrong, but what i was trying to say is what you just said :P

Q4 :
What bindflags should i use for the mapp buffer?
I just started to test this with the following code, but since i dident know wich bindflag to use i just used the "Shader_Resource" one.
like this
cbDesc.Usage					= D3D11_USAGE_STAGING;cbDesc.BindFlags				= D3D11_BIND_SHADER_RESOURCE;cbDesc.CPUAccessFlags			        = D3D11_CPU_ACCESS_READ;

"There will be major features. none to be thought of yet"
Since you won't be binding the staging resource to the pipeline at all, it doesn't matter what bind flag you use (and you should probably set it to 0). The key is in the ID3D11DeviceContext::Map() function - you need to pass the D3D11_MAP_READ flag for reading the contents of the buffer.
I managed to create the buffer and all that, but that brings me to another question, how do i know what in the buffer i am looking for?

this is my shader so far
struct BufferStruct{	float4 color;};RWStructuredBuffer<BufferStruct> g_OutBuff;[numthreads( 4, 1, 1 )]void mainCS( uint3 threadID : SV_GroupThreadID, uint3 groupID : SV_GroupID ){	g_OutBuff[threadID.x].color = float4(10+10,0.0f,0.0f,0.0f);}

im just trying to experiment with one calculation of a float4, so i specifed the numthreads to x4,y1,z1 since i only what 4 threads in xdim and none more since there is only one float. ( i think i got that correct )

Now i am outputting the value to the G_OutBuffer[at the threads x value];

And in my map function i am just pointing in the buffer i converted from the mapped resource.
like this
m_pD3DContex->CopyResource(MapBuffer,m_pComputeShaderBuffer);hr = m_pD3DContex->Map(MapBuffer,0,D3D11_MAP_READ,0,&cbMapped);if(ChekReturnError(hr))    return false;Buffer = (MORN_VARIABLE_BUFFER_COMPUTE*)cbMapped.pData;m_pD3DContex->Unmap(MapBuffer,0);


in my head this is correct, but my values are not.
please point me in the right direction for this.

cheers!
"There will be major features. none to be thought of yet"
I just did slove it, i did managed to create the destination buffer a bit to small :)

! Thanks alot guys for all the help, this has been very intressting and learning in all ways :)



(this post might even gets sticked becuase it contain lost of questions about ComputeShaders)
"There will be major features. none to be thought of yet"

This topic is closed to new replies.

Advertisement