There are 2 issues in your synthetic sample:
- The first issue is that you are calling
target.GetDataAsImage
which is unoptimized in scenarios where you need to do it each frame. Internally the GetDataAsImage is creating a CPU/GPU staging resource (same size as the render target) and allocating an Image on the CPU (again same size on the render target). A correct way to do it (see samples below) is to pre-allocate yourself the staging resource and the image just once, and then get the data from the render target to the image through this allocated staging resource.
- The second issue is that you don't make any draw calls. The flush of the graphics device is usually automatically done if you are making many consecutive draw calls (to split the GPU command buffer) or at least one draw call in a frame before a swap chain present (then the flush will be done at present time). Usually, during a flush, Direct3D takes the time to cleanup things that it can cleanup (like allocated staging resources). That's why by adding an explicit flush (and because of no draw calls), you are able to let D3D freeing some resources. I don't have Windows 7, but I would believe that It would fix your issue.
Minor issue: don't perform any GPU interaction in the update method but only in Draw (in fixed time step, this method can be called several times per frame).
The correct way to implement the micro-synthetic test is to do it like this:
// TestLeak.cs
using System.Diagnostics;
using SharpDX;
using SharpDX.Toolkit;
using SharpDX.Toolkit.Graphics;
public class TestLeak : Game
{
private GraphicsDeviceManager graphicsDeviceManager;
RenderTarget2D target;
private Texture targetStaging;
private Image image;
public TestLeak()
{
graphicsDeviceManager = new GraphicsDeviceManager(this);
}
protected override void LoadContent()
{
target = RenderTarget2D.New(GraphicsDevice, 1000, 1000, PixelFormat.R8G8B8A8.UNorm);
// Pre-Allocate an image same size as the render target
image = Image.New(target.Description);
// Pre-Allocate a staging resource for the render target
targetStaging = target.ToStaging();
base.LoadContent();
}
private Color GetColor(int x, int y)
{
// Get the data from the RenderTarget using the allocated staging resource and the
// allocated image
target.GetData(targetStaging, new DataPointer(image.DataPointer, image.TotalSizeInBytes));
var buffer = image.PixelBuffer[0];
var color = buffer.GetPixel<Color>(x, y);
return color;
}
protected override void Draw(GameTime gameTime)
{
// Just clear the target with red
GraphicsDevice.Clear(target, Color.Red);
// Check the color
var color = GetColor(5, 5);
Debug.Assert(color == Color.Red);
base.Draw(gameTime);
}
}