reneschulte / WriteableBitmapEx

Collection of extension methods for the XAML WriteableBitmap
MIT License
536 stars 122 forks source link

need advice in multythread #91

Open epsi1on opened 4 weeks ago

epsi1on commented 4 weeks ago

Hi, If i want to use WriteableBitmapEx in a multi thread app, which a single thread is responsible for rendering an image in real-time, very much like rendering a game, but not exactly like that. just like one. The problem is the main UI thread is different than rendering thread and i'll get the exception by wpf which says owner thread only can access the bitmap. if I create the WriteableBitmap in the render thread, then UI cannot access it and vice versa.

I was wondering if you guys have any suggestion for my case?

Thanks

DDDDDragon commented 3 weeks ago

I have the same problem, i want to draw a writeableBitmap by multiple threads to increase the draw speed, but seem like it cannot work

epsi1on commented 3 weeks ago

Seems wpf have a strict diplomacy in cross thread access, which every call is checked with DispatcherObject.VerifyAccess() and DispatcherObject.CheckAccess(), even when it is not needed. The way this library for example draws a line, is first create an instance of BitmapContext struct ,which is not public structure. This structure is not thread sensitive, but when a new instance of BitmapContext is creating in the constructor it tries to access the WriteableBitmap's dependency properties which i think that causes the error. There are two solutions i think. source code should be edited:

first solution need least effort, but not so much general second solution need more effort but general, also i think improves the performance as for every line draw it do not creates am instance of BitmapContext. I think it could be pull request. @reneschulte, could you please let us know your opinion about this? this is more like a architectural plan. If it is OK with you, I can do the code and make the pull request... Thanks

epsi1on commented 3 weeks ago

after exploring the code, i've found a way:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WriteableBitmapExMultythreadExample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        WriteableBitmap Bitmap;

        public MainWindow()
        {
            InitializeComponent();

            var w = 500;
            var h = 500;

            Bitmap = BitmapFactory.New(w, h);

            bmp.Source = Bitmap;

            var ctx = Bitmap.GetBitmapContext();

            var thr = new Thread(DrawLine);            thr.Start();            thr.Join();

            //DrawLine();

            ctx.Dispose();
            //Bitmap.AddDirtyRect(new Int32Rect(0, 0, w, h));
        }

        public void DrawLine()
        {
            Bitmap.DrawLineAa(20, 20, 400, 400, Colors.Black, 2);
        }

    }
}

if you call var ctx = Bitmap.GetBitmapContext(); in the main thread, you can do edits in another threads and finally when you call ctx.Dispose(); changes would be applied. seems the WritebleBitmapEx is managing the multy threaded access with some extra cost. I think better to let user handle the complexity, as discussed in #92.