Jump to content

  • Log In with Google      Sign In   
  • Create Account


Geometry Shader with StreamOutput


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

#1 adrianj   Members   -  Reputation: 100

Like
0Likes
Like

Posted 09 April 2012 - 09:40 PM

I've just recently joined the GameDev forum, though I've been using this fabulous resource for some time now. Up until now I've managed to find the answers to most of my SlimDX questions. But this one is giving my trouble.

I have a terrain engine where the height is taken from a texture in the vertex shader. I use a simple geometry shader to calculate face normals, and the pixel shader is just colouring terrain based on height. All this works well. What I want now is to get the vertex data back from the geometry shader, and I understand that this is what the StreamOutput is all about.

My GS Shader code looks like:
struct PS_TEX
{
  float4 pos : SV_POSITION;
  float3 uv : TEXCOORD;
};
struct PS_NORM_TEX
{
  float4 pos : SV_POSITION;
  float3 norm : NORMAL;
  float3 uv : TEXCOORD;
};
[maxvertexcount(3)]
void GS (triangle PS_TEX input[3], inout TriangleStream<PS_NORM_TEX> TriStream)
{
  PS_NORM_TEX output = (PS_NORM_TEX)0;
  float3 faceEdgeA = input[1].pos.xyz - input[0].pos.xyz;
  float3 faceEdgeB = input[2].pos.xyz - input[0].pos.xyz;
  float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
  for( int v=0; v<3; v++ )
  {
	  output.pos = input[v].pos;
	  output.pos = mul( output.pos, View );
	  output.pos = mul( output.pos, Proj );
	
	  output.norm = faceNormal;
	  
	  output.uv = input[v].uv;
	  
	  TriStream.Append( output );
  }
  TriStream.RestartStrip();
}
GeometryShader pGSwSO = ConstructGSWithSO(CompileShader( gs_4_0, GS()),
		 "SV_POSITION.xyz; NORMAL.xyz; TEXCOORD.xyz");
technique10 Render
{
  pass ExTerrain
  {
	SetGeometryShader(pGSwSO);
	SetVertexShader( CompileShader( vs_4_0, VS() ) );
	SetPixelShader( CompileShader( ps_4_0, PS() ) );
  }
}
In my C# code I'm setting up some buffers (one bound to streamoutput, the other staging) and then trying to read back the vertex data. This code looks like:
using D3D = SlimDX.Direct3D10;
//...
void BindToDevice(D3D.Device device)
{
	 D3D.BufferDescription bdesc = new D3D.BufferDescription()
	 {
	 BindFlags = D3D.BindFlags.StreamOutput,
	 CpuAccessFlags = D3D.CpuAccessFlags.None,
	 OptionFlags = D3D.ResourceOptionFlags.None,
	 SizeInBytes = 1024*1024*4,
	 	 Usage = D3D.ResourceUsage.Default
	 };
	 gsOutput = new D3D.Buffer(device, bdesc);
	 D3D.BufferDescription sbdesc = new D3D.BufferDescription()
	 {
	 	 BindFlags = D3D.BindFlags.None,
	 	 CpuAccessFlags = D3D.CpuAccessFlags.Read,
	 	 OptionFlags = D3D.ResourceOptionFlags.None,
	 	 SizeInBytes = bdesc.SizeInBytes,
		  Usage = D3D.ResourceUsage.Staging
	 };
	 staging = new D3D.Buffer(device, sbdesc);
}

void Draw()
{
	 D3D.StreamOutputBufferBinding[] bindings = new D3D.StreamOutputBufferBinding[] { new D3D.StreamOutputBufferBinding(gsOutput, 0) };
	 device.StreamOutput.SetTargets(bindings);
	 //... Do normal drawing stuff, eg, SetInputLayout, SetVertexBuffer, SetIndexBuffer,
	 device.DrawIndexed(Indices.Length);
	
	 device.CopyResource(gsOutput, staging);
	 using (DataStream stream = staging.Map(D3D.MapMode.Read, D3D.MapFlags.None))
	 {
	 	 float[] data = new float[stream.Length / 4];
	 	 stream.ReadRange<float>(data.Length);
	 	 //... Do something with data here.  Except it is just an array filled with 0s.
	 }
	 staging.Unmap();
}
It all compiles, and runs without error whilst still showing my terrain as always. Problem is the mapped data all comes up as 0s.
Is there something I'm missing?
Am I doing this correctly?

Sponsor:

#2 Tsus   Members   -  Reputation: 1022

Like
0Likes
Like

Posted 10 April 2012 - 04:02 PM

Hi!

If I see this correctly, you don’t assign the data you read from the stream.
float[] data = stream.ReadRange<float>(stream.Length / 4);
Aside from that it's looking good!

When this happens to me, it’s always the last thing I’m looking for. Posted Image

Cheers!

Acagamics e.V. – IGDA Student Game Development Club (University of Magdeburg, Germany)


#3 adrianj   Members   -  Reputation: 100

Like
0Likes
Like

Posted 10 April 2012 - 07:00 PM

Thanks for the reply.

You're quite right, that bit of code isn't correct. I figured for the time being I would just attempt to read floats to see if anything came out. My actual code looks like:

struct GS_OUT
{
	 public Vector4 Position;
	 public Vector3 Normal;
	 public Vector3 Texcoord;
}
//...
data = new GS_OUT[stream.Length / Marshal.SizeOf(typeof(GS_OUT))];
stream.ReadRange<GS_OUT>(data, 0, data.Length);

Even if I try to read out Bytes using the ReadByte() method, I still get nothing but 0s.

Is there something about the ReadRange<T> method that I am doing incorrectly? I've also tried looping through and using the Read<T> method with no success.

I have used the ReadRange<T> method successfully when reading back Staging Textures.

It all leads me to believe that the staging buffer is in fact empty, so my problem lies earlier on in the piece.

#4 adrianj   Members   -  Reputation: 100

Like
0Likes
Like

Posted 10 April 2012 - 07:23 PM

Well... somehow I've fixed it. Posted Image Posted Image

I'm pleased that it works, but I'm not sure what I've done differently. Checking through the code I posted above it all looks basically exactly the same. All I changed was how I specify the size of the buffer, in that now it's set as "Marshal.SizeOf(typeof(GS_OUT)) * someMaximumNumber"

Thanks for the vote of confidence Tsus - maybe that's all it needed Posted Image




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