rpi-rgb-led-matrix icon indicating copy to clipboard operation
rpi-rgb-led-matrix copied to clipboard

How to update different screens independently with animations, scrolltext etc.

Open Jan1503 opened this issue 3 years ago • 1 comments

Hi!

I'm using the C#-bindings for my matrix and would like to instantiate multiple threads that update different parts of the screen, for example playing an animation or scrolling some text.

I've tried different approaches but I still don't understand when to swap the canvas to the display. For now, I'm writing directly to the foreground-buffer but this produces bad flicker as expected.

Following some short example-code to explain my problem. It's not optimized and clean in any way but should help to show the point.

This is a simple Task to scroll some Text on the screen.

`Task.Run(() => { var font = new RGBLedFont(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Fonts", "WaltDisneyScriptv4.1-32.bdf")); var c0 = new RGBLedMatrixWrapper.Color(0, 0, 0); var c1 = new RGBLedMatrixWrapper.Color(255, 128, 255);

var stringLength = foreGroundCanvas.DrawText(font, 512, 512, c0, "Test-Scroller");

while (true)
{
    for (int i = 384; i > 0 - stringLength + 1; i--)
    {
        foreGroundCanvas.DrawText(font, i + 1, 192, c0, "Test-Scroller");
        foreGroundCanvas.DrawText(font, i, 192, c1, "Test-Scroller");

        Thread.Sleep(10);
    }

    Thread.Sleep(2000);
}

});`

Note, I'm not using 'swapOnVSync()' here as this writes directly to the foreground-buffer resulting in ugly flicker. This way I could use multiple Tasks updating different parts of the matrix with no problem but the image quality is bad.

So I tried to place the 'SwapOnVSync()' in another thread and tried to only update the buffer if the swap does not occur using a volatile, thread-safe boolean like this:

`Task.Run((() => {

while (true)
{

ConsoleApp1.Program.Interlock = true; matrix.SwapOnVsync(backgroundCanvas); ConsoleApp1.Program.Interlock = false; }

}));`

After updating the other tasks to only update the canvas if 'Interlock' is false this produces some weird 'effects' on the matrix.

I then thought of implementing a bitmap for each task so every task writes it's stuff to this bitmap, then merge all bitmaps to one 'final' bitmap and push this one to the matrix follwied by a 'SwapOnVSync'. But as expected I cannot update a tasks bitmap while it is merged to the final bitmap cause I need to lock/unlock the bitmap for fast reading/writing the data.

So, I hope my problem becomes clear. I've found some issues here updating multiple parts of the screen and some tips parting the canvas into some sub-canvi but all examples are using static pixel modifications so all tasks return immediately after the modification. I need a solution that allow me to independently update part of the screen with time-consuming animations and stuff. There must be a way to update multiple canvi, some kind of 'merging' them into the final one and the displaying it, all synced across all tasks.

In the past I've used the SmartMatrix-library which implements some kind of layers, where each layers acts completely indepedent and does not interfere with others. Sadly, I don't have the knowledge and skills to dig into that stuff to re-use it with C#.

Thanks! Jan

Jan1503 avatar Jan 24 '22 16:01 Jan1503

Forgot the aforementioned approach, it's nonsense. Now I'm writing to different bitmaps in each animation and before swapping the canvas I merge them all together. This works fine using SkiaSharp by directly modifying the pointers in memory...it crashes with System.Drawing.Bitmap so I'll stick with Skia.

Jan1503 avatar Jan 25 '22 15:01 Jan1503