Jump to content

WPF - UI performane problems


photo

Recommended Posts

Hi all,

I am curious if someone can help me with Unigine Engine running in an WPF-environment or if someone has overall experience with integration into an WPF-application. We started our project based on the WPF sample with multiple windows (based on 2.15.1 version), but currently running only in the main one. This works fine and we didn't experience any issues. However, once we extend the window with some UI content (mainly content that seems to be animated) the UI becomes very unresponsive or updating the result very late, with lags/flickering e.g.. While running the WPF performance profiler, most time it spends rendering/updating the WindowsFormsHost. I don't see any issue here, because the engine should run as fast as possible. However, this made it very hard to work with the other UI items properly.

How to reproduce:

Simply modify the MainWindow.xaml file int the "main_wpf/D3D11SharpDXWPF" example with the following content:

Spoiler
<Window x:Class="WPFApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFApplication"
        xmlns:unigine="clr-namespace:Unigine"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <ComboBox Grid.Row="0">
            <ComboBoxItem Content="One"/>
            <ComboBoxItem Content="Two"/>
            <ComboBoxItem Content="Three"/>
            <ComboBoxItem Content="Four"/>
            <ComboBoxItem Content="Five"/>
            <ComboBoxItem Content="Six"/>
            <ComboBoxItem Content="Seven"/>
            <ComboBoxItem Content="Eight"/>
            <ComboBoxItem Content="Nine"/>
            <ComboBoxItem Content="Ten"/>
            <ComboBoxItem Content="Eleven"/>
            <ComboBoxItem Content="Twelve"/>
            <ComboBoxItem Content="Thirteen"/>
            <ComboBoxItem Content="Fourteen"/>
            <ComboBoxItem Content="Fifteen"/>
            <ComboBoxItem Content="Sixteen"/>
            <ComboBoxItem Content="Seventeen"/>
            <ComboBoxItem Content="Eighteen"/>
            <ComboBoxItem Content="Nineteen"/>
            <ComboBoxItem Content="Twenty"/>
        </ComboBox>
        <WindowsFormsHost Grid.Row="1" Margin="25,25,25,25">
            <unigine:UnigineControl x:Name="unigine"/>
        </WindowsFormsHost>
    </Grid>
</Window>

 

When running the application and try selecting any content, the ComboBox seems to lag/ expand only when moving the mouse down. This doesn't happen always, but very noticeable and frequent. When you comment the WindowsFormsHost item, the issue completely disappears. It also seems to be more noticeable, when we tried to implement any syncfusion content (https://hidrive.ionos.com/lnk/5wMAinbi#file) but this also happens with the standard UI items as shown above. As said, this mainly happen with animated UI-content (so expanding/collapsing items).

My guess is that the main UI thread is too busy calling the OnPaint()-function in the WindowsFormsHost, so that other content will not be updated fast enough. We also tried to limit the rendering to 60 FPS, but that doesn't seem to work (because the limitation will done inside UNIGINE and do not affect the OnPaint-function). Are there any ideas how to improve the situation? One idea was to use the engine control in an separate thread and only syncing the input, but we aren't sure if that affects the performance in an better way.

Hope someone can help and direct me in the right direction.

Best

Christian

Link to comment

Hi Christian,

You are right in your assumptions.

Current WPF integration is targeting the highest possible framerate. Basically all the WPF event loop is being occupied by our OnPaint events (after calling Invalidate()), which somehow starting to affect other events that WPF is trying to insert in queue. 

In theory you can rewrite WPF integration a bit and use the CompositionTarget.Rendering, but in that case you have basically no control on frame time:

In that case UI should become a bit smoother, but you may see tearing, doubled frames and overall very unstable frametimes in the 3D viewport.

Or you can also try to limit OnPaint events calling using external timer (for example, call it every 1ms). That will result in overall WM_PAINT events reduction and should help with UI animations.

Separate thread can also help, but there is a high risk to find some unexpected multi-htreading bugs, so I would recommend to start with external timer or CompositionTarget.Rendering first :)

Thanks!

How to submit a good bug report
---
FTP server for test scenes and user uploads:

Link to comment

Hi silent,

many thanks for your response. The CompositionTarget.Rendering seems to be my "last way" since the unpredicted framerate and still existing tearing.

I tried to implement the external timer today but currently doesn't seem to have so much luck with it as well. Limiting the OnPaint execution time by an early timer doesn't seem to solve anything rather than limiting the engines internal FPS update. But WPF still seems to throtle itself, always when Invalidate() is involved. Limiting the Invalidate() itself to the external timer doesn't call any OnPaint() event afterwards, so I guess that functions make sure, that another OnPaint()-method will be called asap in the Dispatcher.

Another thing I tried is to manually call the OnPaint()-function from other parts of my code, which at least seem to work, until it is an separate thread. Calling them in the UI thread provides me the same result as above.

Spoiler
public MainWindow()
{
    InitializeComponent();

    Task.Factory.StartNew(() => { RenderEngineThread(); });

}


private async Task RenderEngineThread()
{
    await Task.Delay(2000); //startup delay

    while (true)
    {
        //Sync with the UI-thread
        Application.Current.Dispatcher.Invoke(new Action(() =>
        {
            unigine.OnPaint(null, null);
        }));
        await Task.Delay(1);	//so we can render 1000 FPS maximum
    }

}

 

Anyway, this seem to be "a" solution, but I don't know if it is the best way because "scaling" with the engines FPS is pretty non-existent.

For the multi-threading part (which is still an rough idea in my head): What would be the problem with starting/painting/updating the engine in an complete separate thread? Sure, we need to make sure that any synchronisation between those two threads is safe but are there any other things I am missing? I thought maybe something about letting SharpDX be rendered "headless" or to an texture. On the UI-thread an WriteableBitmap could be used in an UIElement (instead of an User Control) and let the SharpDX-implementation fill the bitmaps back-buffer as many times as possible. This is, what SkiaSharp is actually doing, when syncing their frontend with the render backend.

And maybe last question: Does an engine upgrade seem to solve our issue (regarding CustomSystemProxy-implementation) or does this issue still persists?

Best

Christian

Link to comment

Engine upgrade will not solve this behavior, since there is no good solution for that kind of issue. At least, we could not find one yet.

We never tried to implement multi-threading WPF update, so it's hard to predict which issues you may found here. Maybe there will be none of them. It would be interesting to see the results, though of this implementation :)

How to submit a good bug report
---
FTP server for test scenes and user uploads:

Link to comment
14 hours ago, silent said:

We never tried to implement multi-threading WPF update, so it's hard to predict which issues you may found here. Maybe there will be none of them. It would be interesting to see the results, though of this implementation :)

Okay, thanks. We will try this approach, when the above "solution" will not satisfy our needs. Of course we will keep you updated. :)

  • Thanks 1
Link to comment
×
×
  • Create New...