Monogame slow inside WPF

Hey,

I’m trying to render via Monogame inside multiple WPF controls (as preview what it’s going to look like) and I have serve performance issues. I am rendering to renderTargets and then transforming them into bitmaps. The issue is this process takes way too long for a frame (50 ms) and freezes the window. Even when outsourcing it to a different thread, the rendering would be too slow and my PC is quite powerful, so I might be way worse on others. Here his how I transform the Monogame RenderTarget2D to a WriteableBitmap:

`

        Stopwatch sw0 = new Stopwatch();
               
        sw0.Start();

        renderTarget.GetData(buffer);
      
        // get the data from the render target


        sw0.Stop();
        Console.WriteLine("Get data duration: " + sw0.ElapsedMilliseconds + " ms");
       
        // because the only 32 bit pixel format for WPF is 
        // BGRA but XNA is all RGBA, we have to swap the R 
        // and B bytes for each pixel

        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < buffer.Length - 2; i += 4)
        {
            byte r = buffer[i];
            buffer[i] = buffer[i + 2];
            buffer[i + 2] = r;
        }
        sw.Stop();
        Console.WriteLine("Pixel shift duration: " + sw.ElapsedMilliseconds + " ms");

        Stopwatch sw2 = new Stopwatch();
        sw2.Start();

        // write our pixels into the bitmap source
        writeableBitmap.Lock();
        Marshal.Copy(buffer, 0, writeableBitmap.BackBuffer, buffer.Length);
        writeableBitmap.AddDirtyRect(
            new Int32Rect(0, 0, renderTarget.Width, renderTarget.Height));
        writeableBitmap.Unlock();

        sw2.Stop();
        Console.WriteLine("To bitmap duration: " + sw2.ElapsedMilliseconds + " ms");`

I implemented some stopwatches to measure time. rendertarget.GetData costs the most time. The pixel shifting costs medium time too. Any way to fix this? As far as I read WPF controls have no HWND, so cannot render directly into them.

On some occasions GetData() will switch to copying one by one byte. On my desktop that’s 8x times slower compared to XNA. After a quick patch I was able to get it run at decent speed.

IMO, You should open a ticket at https://github.com/MonoGame/MonoGame/issues
as that’s something that can be greatly improved.

Have you tried MonoGame.Framework.WpfInterop?

However if you don’t want to use this, then please take a look at how we are getting the back buffer data in the MonoGame.Forms.GL library.

It is faster than getting the data from a RenderTarget, but it is still slow.

1 Like

Huh, I don’t get why we copy byte by byte, rather than copying full rows at once. That’s terrible. Easy to fix though.

I use WpfInterop, it works plenty well enough. Only had to tweak a few things for making it spin down the render rate when the application is unfocused, force render (to conceal resize issues).

WPF and DX11 don’t really mix too well though so there’s issues. Not as bad as if you try to shoe OpenGL into WPF … but still annoying.

You have to run at 60fps at all times though or you’ll make WPF angry and then WPF Dispatcher can and will drop dispatches, which is really annoying and causes all sorts of insidious issues if you depend on WPFs stuff working correctly.