# Using SurfaceFormat.Single and HLSL for GPGPU with XNA

I'm trying to implement a so-called ping-pong technique in XNA; you basically have two RenderTarget2D A and B and at each iteration you use one as texture and the other as target - and vice versa - for a quad rendered through an HLSL pixel shader.

• step1: A--PS-->B
• step2: B--PS-->A
• step3: A--PS-->B

...

In my setup, both RenderTargets are SurfaceFormat.Single.

In my .fx file, I have a tachnique to do the update, and another to render the "current buffer" to the screen.

Before starting the "ping-pong", buffer A is filled with test data with SetData<float>(float[]) function: this seems to work properly, because if I render a quad on the screen through the "Draw" pixel shader, i do see the test data being correctly rendered.

However, if i do update buffer B, something does not function proerly and the next rendering to screen will be all black.

For debug purposes, i replaced the "Update" HLSL pixel shader with one that should simply copy buffer A into B (or B into A depending on which among "ping" and "pong" phases we are...). From some examples i found on the net, i see that in order to correctly fetch a float value from a texture sampler from HLSL code, i should only need to care for the red channel.

So, basically the debug "Update" HLSL function is:

float4 ComputePS(float2 inPos  : TEXCOORD0) : COLOR0
{
float v1 = tex2D(bufSampler, inPos.xy).r;
return float4(v1,0,0,1);
}


which still doesn't work and results in a all-zeroes ouput. Here's the "Draw" function that seems to properly display initial data:

float4 DrawPS(float2 inPos  : TEXCOORD0) : COLOR0
{
float v1 = tex2D(bufSampler, inPos.xy).r;
return float4(v1,v1,v1,1);
}


Now: playing around with HLSL doesn't change anything, so maybe I'm missing something on the c# side of this, so here's the infamous Update() function:

_effect.Parameters["bufTexture"].SetValue(buf[_currentBuf]);
_graphicsDevice.SetRenderTarget(buf[1 - _currentBuf]);
_graphicsDevice.Clear(Color.Black); // probably not needed since RenderTargetUsage is DiscardContents
_effect.CurrentTechnique = _computeTechnique;
_computeTechnique.Passes[0].Apply();
_graphicsDevice.SetRenderTarget(null);
_currentBuf = 1 - _currentBuf;


Any clue?

• Have you tried using SurfaceFormat.Color for all render targets? That should at least get you something. Also when in doubt if your shaders are working just let them return a color based on the pixel postion (like .r = inPos.x, .g = inPos.y), at least that will tell you something is working. Jul 3 '12 at 21:01
• First thing i tried was to return float4(inPos.xy,0,1) from "Draw" pixel shader and that works, so everything seems to be ok as long as I use plain colors. I'm obviously missing something about how to use Single format. Later i will try to do what you suggest even for the "Update" part and see what happens, but that cannot be a permanent solution. Jul 4 '12 at 7:49
• Are you sure your GPU supports the single format? Also here is some info on MSDN where they check and use the single format, the value should indeed be in the .r component msdn.microsoft.com/en-us/library/… Jul 4 '12 at 8:08
• It's an nVidia 9400, so it should support that. I downloaded and executed the sample you linked and althrough it shows some glitches, it seems to work, overall. Also: isn't the framework supposed to check for this kind of issues and maybe throw an exception? Jul 4 '12 at 8:42
• Eh in XNA there are two profiles, reach and Hi-Def, if your computer can run the Hi-Def profile it should be able to use the SurfaceFormat.Single, so yes I think it should give an exception if it isn't supported: blogs.msdn.com/b/shawnhar/archive/2010/03/12/… Jul 4 '12 at 11:10

output.Pos = input.Pos + float4(-0.5f/renderTargetSize.x, 0.5f/renderTargetSize.y, 0, 0);