Share via

WriteableBitmap performance is better in Debug than in Release.

MarcioAB 96 Reputation points
2020-10-17T20:47:36.333+00:00

I found a noticeable WriteableBitmap performance improvement when executing in Debug in contrast with Release.
Follow results from a simple benchmark program to move 10K Rectangles in the screen:

Debug w/ render by hardware: 185 fps with 40% CPU and 12% GPU.
Release w/ render by hardware: 150 fps with 53% CPU and 25% GPU.
Debug w/ render by software: 150 fps with 50% CPU and 0% GPU.
Release w/ render by software: 30 fps with 35% CPU and 0% GPU.

WriteableBitmap is faster, and CPU and GPU consumption are smaller in Debug than in Release.

I wonder if it is possible to request an enhancement to make WriteableBitmap Release's performance similar or even better than Debug's performance.

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace WpfApp12
{
    // Render : Software  x   Hardware (GPU-3D)
    //
    // BITMAP BASED
    // WriteableBitmap in Image : ( 150* fps, 50% CPU, 0% GPU ) x ( 185  fps, 40% CPU, 12% GPU ) Debug mode, * = skip frames
    // WriteableBitmap in Image : (  30  fps, 35% CPU, 0% GPU ) x ( 150  fps, 53% CPU, 25% GPU ) Release mode
    //
    // RETAINED / VECTOR MODE
    // Shapes in Canvas         : (  22  fps, 52% CPU, 0% GPU ) x (  22* fps, 52% CPU,  3% GPU ) * = skip frames
    // Drawings in Image        : (  14  fps, 48% CPU, 0% GPU ) x (  14* fps, 52% CPU,  3% GPU ) * = skip frames

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        const int width1 = 1000;
        const int height1 = 800;

        Stopwatch clock1;
        long t1;
        int frames_counter = 0;

        int num_elements_X;
        int num_elements_Y;
        int shift = 0;
        int max_shift;

        byte[] video_array;
        WriteableBitmap writeableBitmap;

        public MainWindow()
        {
            InitializeComponent();
            Execute(new Size(120, 80)); // Despite number of "elements" does not affect WriteableBitmap performance
        }

        void Execute(Size size)
        {
            if (size.Width * 2 > width1) throw new Exception();
            if (size.Height * 2 > height1) throw new Exception();
            num_elements_X = (int)size.Width;
            num_elements_Y = (int)size.Height;
            var maxX = width1 - 2 * num_elements_X;
            var maxY = height1 - 2 * num_elements_Y;
            max_shift = (maxX < maxY) ? maxX : maxY;

            SizeToContent = SizeToContent.WidthAndHeight;
            ResizeMode = ResizeMode.NoResize;
            RenderOptions.SetEdgeMode(this, EdgeMode.Aliased); // don't know how this affect performance.

            _ = new DispatcherTimer(new TimeSpan(0, 0, 0, 1), DispatcherPriority.Background, Callback_Title, Dispatcher.CurrentDispatcher);
            clock1 = Stopwatch.StartNew();
            t1 = clock1.ElapsedTicks;

            Content = Setup_ImageBitmap();

            var d = Application.Current.Dispatcher;
            while (true)
            {
                Update_ImageBitmap();
                d.Invoke(() => 0, DispatcherPriority.Background); // Wait to empty queues to process next frame.
            }
        }

        Image Setup_ImageBitmap()
        {
            video_array = new byte[width1 * height1 * 4];
            writeableBitmap = new WriteableBitmap(width1, height1, 96, 96, PixelFormats.Bgr32, null);
            var i = new Image()
            {
                Stretch = Stretch.None,
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                IsHitTestVisible = false,
                Source = writeableBitmap
            };
            return i;
        }

        void Update_ImageBitmap()
        {
            Array.Fill<byte>(video_array, 255);

            for (var nx = 0; nx < num_elements_X; nx++)
            {
                for (var ny = 0; ny < num_elements_Y; ny++)
                {
                    var index0 = 4 * (shift + 2 * nx + (shift + 2 * ny) * width1); // B G R A {0,1,2,3}
                    video_array[index0] = 0; // B=0
                    video_array[index0 + 1] = 0; // G=1
                    video_array[index0 + 2] = 0; // R=2
                    //a1[index0 + 3] = 0; // A=3
                }
            }
            writeableBitmap.WritePixels(new Int32Rect(0, 0, width1, height1), video_array, width1 * 4, 0, 0);
            shift++;
            frames_counter++;
            if (shift > max_shift) shift = 0;
            Show();
        }

        void Callback_Title(object sender, EventArgs e)
        {
            var t2 = clock1.ElapsedTicks;
            var fps = 10000000D / (t2 - t1) * frames_counter;
            Title = $"{fps:F1} fps";
            frames_counter = 0;
            t1 = t2;
        }
    }
}

I can include the simple benchmark code if necessary.

Developer technologies | Windows Presentation Foundation

Answer accepted by question author

MarcioAB 96 Reputation points
2020-10-23T00:39:51.977+00:00

This performance difference is not reproduced anymore with Preview 5 of Visual Studio Community 2019 Version 16.8.0

Was this answer helpful?

0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.