9
votes

I’m writing a WPF image viewer, displaying a grid of images. I’m baffled because of the sluggish performance: Displaying even an 11 x 11 grid makes a VM unresponsive, slow and sluggish for long durations of times. Even on the powerful host the performance in non-snappy.

The program is based on the design in SO WPF: arranging collection items in a grid: An ItemsControl is bound to Items, an ObservableCollection. Each Item contains has a file-system absolute URI. The ItemsControl‘s DataTemplate contains an Image element whose Source is bound to the URI.

It seems the problem can’t be the disk (SSD), the memory (8GB VM, 24GB host), or CPU (i750). Moreover, most of the work is done by WPF, so it’s not even as if I could locate a problem in my code: My code simply loads URIs (i.e. the paths to the images, not the images) to the collection and quickly returns. Then there is a wait, and WPF displays the images.

The only problem I could think about is image processing – down scaling by WPF. But even on the host, which has a "good-enough" 5850 ATI Radeon HD card, the performance is not snappy.

So, my question is: How can I make displaying images on WPF more “snappy”?

Edit: The images are 1920x1080 22 bit HD JPEGs captured from HD m2ts video. I tried pre-scaling them (using FFmpeg) to 'ega' 640x350. There was a performance improvement but FFmpeg's scaled-down images looks much worse than WPF's.

Edit: Thanks to David Osborne the code now runs as x64. Still sluggish.

Edit What really improved the situation is what Matěj Zábský called scalling the images: reducing the resolution. For the benefit of future readers:

            fullPath = new Uri(path, UriKind.Absolute);


            BitmapImage smallerBitmapImage = new BitmapImage();
            smallerBitmapImage.BeginInit();
            smallerBitmapImage.DecodePixelWidth = (int) (theWidthOfTheGrid / theNumberOfColumns);
            smallerBitmapImage.UriSource = fullPath;
            smallerBitmapImage.EndInit();

            FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap();
            formatConvertedBitmap.BeginInit();
            formatConvertedBitmap.Source = smallerBitmapImage;
            formatConvertedBitmap.DestinationFormat = PixelFormats.Gray16;
            formatConvertedBitmap.EndInit();
            formatConvertedBitmap.Freeze();

            this.ImageSource = formatConvertedBitmap;
4
So you have a static grid of "known" images? How big are the images?Matěj Zábský
Future readers facing this problem - see my answer here: stackoverflow.com/questions/9265725/wpf-bitmap-performanceAvi
Are you using shadows?Louis Kottmann

4 Answers

9
votes

I have been in similar position (I had to display thumbnail versions of large images in real-time).

If you are using data binding to display the images, you can try two things:

  • Make the binding OneWay (this helped me the most).
  • Try making the binding async.

The only other thing is to prescale the images - preferably separate thread. Possibly you could even prescale images which could be potentially used in the future while the processor is idle - for example if you are developing a map-like application, you could prescale images in areas to which the user is most likely to move.

2
votes

You can try Virtualization for control, It help considerably when loading more images in listview. VirtualizingStackPanel

<ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="True"  VirtualizingStackPanel.VirtualizationMode="Recycling"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>

If want to use Viruatalization with wrap-panel, there is some from Codeplex, Virtualalizing Wrappanel

I know it is an old thread, but if someone is still interested.

1
votes

Have you tried experimenting with different Target Platform settings? I.e. x86 or AnyCPU.

1
votes

If you're running on a VM, you are probably hitting issues with hardware (or at least emulated-hardware) rendering of graphics. WPF makes heavy use of hardware graphics and, on machines with low graphics capability, performance will suffer.

You can work around this by enabling a registry setting that forces-off the hardware acceleration. This is particularly useful on machines that may have over-reported their capability (from experience, this particularly affects VMs and embedded graphics chipsets).

The registry key you need is HKEY_CURRENT_USER\SOFTWARE\Microsoft\Avalon.Graphics\DisableHWAcceleration, a DWORD that you should set to 1. Note that this is system-wide and will affect all WPF apps - don't set it as part of your application, but use it in your VM environment and make sure you test again on proper hardware before releasing.

Further reading here.