HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

SharpDX ScreenCapture

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
screencapturesharpdxstackoverflow

Problem

I'm currently working on a monitor screen capture with C# and the SharpDX library. The code works and allow recording bitmap screenshots (dynamically for DirectX 11 games and desktop) in a loop.

But I have a little performance problem in my loop and I'm trying to get 60 records per second at least (I reach 40 records/sec max on my computer).

As you can see, I was tried to use Tasks to perform this but it's not enough and I'm not an expert in parallel programming.

I hope that my project will be useful to you and it would be great if someone would have some optimizations to suggest to me.

```
class DXCapture
{
PictureBox pictureBox;
bool ready = false;
bool Recording = false;
Task RecordingTask;
int saveSizeX;
int saveSizeY;
int width;
int height;
int numAdapter;
int numOutput;
Factory1 factory;
Adapter1 adapter;
SharpDX.Direct3D11.Device device;
Output output;
Output1 output1;
Texture2DDescription texture2DDescription;
Texture2D screenTexture;
OutputDuplication duplicatedOutput;
SharpDX.DXGI.Resource screenResource;

public DXCapture(PictureBox pictureBox, BenchMark bench, int sizeX = 1920, int sizeY = 1080, int numAdapter = 0, int numOutput = 0)
{
this.pictureBox = pictureBox;
this.saveSizeX = sizeX;
this.saveSizeY = sizeY;
this.numAdapter = numAdapter;
this.numOutput = numOutput;
this.bench = bench;
InitDX();
}

public void InitDX()
{
try
{
factory = new SharpDX.DXGI.Factory1();
adapter = factory.GetAdapter1(numAdapter);
device = new SharpDX.Direct3D11.Device(adapter);
output = adapter.GetOutput(numOutput);
output1 = output.QueryInterface();

// Width/Height of desktop to capture
width = output.Description.DesktopBounds.Left + output.Description.DesktopBounds.Right;
height = output.Description.Deskto

Solution

Console.WriteLine("Error GetShot ACCESS LOST - relaunch in 2s !");
Thread.Sleep(2000);


This second line might be killing the performance but even if it's hit only occasionally it's usually a bad practice. Thread.Sleep is blocking a thread completely. Nothing else can be handled by it during the wait period. You are using Tasks in other places so try to use a Task.Delay here or even better a timer that will trigger a relaunch.

Thread.Sleep(2000);
DisposeDX();
GC.Collect();
InitDX();


I also think you should dispose everything right away and then wait if necessary.

You could also try to make the GetShot method a real async one by changing its signature to

private async Task GetShot()


this will allow you to wait like this

Console.WriteLine("Error GetShot ACCESS LOST - relaunch in 2s !");
await Task.Delay(TimeSpan.FromSeconds(2000));


or to replace

Task.Factory.StartNew(() =>


with

await Task.Run(() =>


which is actaully a shortcut for the StartNew where you add the await keyword.

You'll also need to adjust the StartRecord method to something like this:

public void StartRecord(int limitFPS = 0)
{
    if (!Recording)
    {
        Recording = true;
        RecordingTask = Task.Run(async () =>
        {
            while (Recording)
            {
                await GetShot();
            }
        });
        RecordingTask.Start();
    }
}

Code Snippets

Console.WriteLine("Error GetShot ACCESS LOST - relaunch in 2s !");
Thread.Sleep(2000);
Thread.Sleep(2000);
DisposeDX();
GC.Collect();
InitDX();
private async Task GetShot()
Console.WriteLine("Error GetShot ACCESS LOST - relaunch in 2s !");
await Task.Delay(TimeSpan.FromSeconds(2000));
Task.Factory.StartNew(() =>

Context

StackExchange Code Review Q#162536, answer score: 4

Revisions (0)

No revisions yet.