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:

_graphicsDevice.SetRenderTarget(buf[1 - _currentBuf]);
_graphicsDevice.Clear(Color.Black); // probably not needed since RenderTargetUsage is DiscardContents
_effect.CurrentTechnique = _computeTechnique;
_currentBuf = 1 - _currentBuf;

Any clue?

  • \$\begingroup\$ 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. \$\endgroup\$
    – Roy T.
    Jul 3, 2012 at 21:01
  • \$\begingroup\$ 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. \$\endgroup\$ Jul 4, 2012 at 7:49
  • \$\begingroup\$ 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/… \$\endgroup\$
    – Roy T.
    Jul 4, 2012 at 8:08
  • \$\begingroup\$ 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? \$\endgroup\$ Jul 4, 2012 at 8:42
  • \$\begingroup\$ 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/… \$\endgroup\$
    – Roy T.
    Jul 4, 2012 at 11:10

1 Answer 1


Just found the answer myself, and it was a newbie issue.
Turns out the vertex shader was shifting the wole rendering that in a couple of updates, quickly exited the area visible when drawing results on the screen.

To fix this and have every pixel of the texture buffer aligned with its matching pixel on the RenderTarget buffer, the drawn quad has to be from [-1,-1] to [1,1] (and not from [0,0] to [1,1] as one could be tricked to think) and following vertex transform is needed:

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

so that Pos points exactly to the middle of a pixel/texel.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .