Fast drawing lots of rectangles one at a time in WPF

My application is fed data from an external device. After each data point, there is a short electronic dead time (of about 10µs) in which no other data point can arrive, which my application should use to process and display the data on screen in a scatter plot. My most important goal is to not exceed this electronic dead time. How would one approach this problem in a WPF based application, and what would be a way to benchmark different methods?

Things I've tried are:

  • Creating a Rectangle in a Canvas for every arriving data point. This is too slow by a factor of 10.
  • The same approach, but drawing DrawingVisuals in a custom control. Better, but still a little too slow. Adding visual/logical children to the tree may have too much overhead.
  • A UserControl where all data points are stored in an array and displayed in the OnRender method. Here I have to draw every point again on each call to OnRender. This method therefore slows down over time, which is undesireable. Is there a way to tell OnRender not to clear the screen on each pass, so that I could paint incrementally?
  • Displaying each point as a pixel in a WriteableBitmap. This seems to work, but I 've not found a way to determine, if invalidating part of the Bitmap does not add a few very long wait times ocassionally (when the Image is actually refreshed on screen). Any Ideas for measuring this?

Edit:

In the comments, the point of buffering data and displaying it at a slower rate has been raised. The problem with that approach is, that at some point I have to process the buffer. Doing that during the measurement introduces a long time during which my system is busy and new events would be discarded. Therefore dealing with every point individually, but for good, would be more desireable. Using 10 µs to trigger the display for every event is much better than storing it into a buffer in no time and use 100µs every 50 ms or so to process the accumulated events.

I the olden (i.e. non-WPF) days, you could e.g. put the neccesary data into the graphics memory, and have the graphics card deal with it at its convenience. Of cource, it would not actually be displayed at a rate faster than 60Hz, but you did not have to touch this data again.

I hope I made clear what my requirements are. Dang my English =)

-------------Problems Reply------------

Using a WriteableBitmap will be the fastest approach. For testing you could pre-allocate an array and use a Stopwatch to sample timings as you go about rendering, you can then analyse the timings to get some idea of performance.

One overriding issue you have is with garbage collection. This will unfortunately introduce potential for the exact kind of performance issues you describe i.e. occasional stalling whilst GC is carried out. You could experiment with low latency GC to mitigate this.

Update

Here is an example of using low latency GC:

http://blogs.microsoft.co.il/blogs/sasha/archive/2008/08/10/low-latency-gc-in-net-3-5.aspx

You could leverage this to ensure that there are no garbage collections during your "dead time" i.e. rendering time.

Update 2

As I mentioned in my comment a while ago - are you batching updates to your WritableBitmap?

Your device update frequency is too high to able to sustain writing to the bitmap for each device update - I think there are 10k-100k updates per second. Try and update your bitmap on a more sensible frequency (e.g. 60 or 25 times per second), as the overhead of forcing a bitmap render will dominate performance at 10k-100k updates per second. Write to a buffer when you receive device updates, then periodically transfer this buffer to the WritableBitmap. You could use a timer for this, or do it every n device updates. In this way you will batch your updates and vastly reduce WritableBitmap render overhead.

Update 3

Ok, it sounds like you are updating the WritableBitmap 10k-100k times per second - this isn't feasible. Please try a frame\batch based mechanism as described previously. Also your display is only likely to be updated at 60 frames per second.

If you are concerned about blocking your device updates, then consider using two alternating back buffers and multi-threading. In this way you periodically switch which back buffer your device writes to, and use a second thread to render the swapped buffer to the WritableBitmap. As long as you can swap the buffer in < 10µs, you can do this in the dead time without blocking your device updates.

Update 4

Further to a response to my question, it would appear that there is currently a "lock\unlock" being called for each of the 100k updates per second. This is what is likely killing performance. On my (high-powered) system I measured 100k "lock\unlock" at ~275ms. That's pretty heavy and will be much worse on a lower powered system.

This is why I think 100k updates per second is not achievable i.e. lock -> update -> unlock. The locking is just too expensive.

You need to find a way of bringing the number of locking calls down by either not locking at all, locking every n operations, or perhaps batching requests and then applying the batched update in a lock. There's a few options here.

If you go for a batched update, it could be as small as 10 cycles, which would bring your update frequency down to 10k updates per second. This would reduce your locking overhead by a factor of 10.

Example benchmark code for locking overhead on 100k calls:

lock/unlock - Interval:1 - :289.47ms
lock/unlock - Interval:1 - :287.43ms
lock/unlock - Interval:1 - :288.74ms
lock/unlock - Interval:1 - :286.48ms
lock/unlock - Interval:1 - :286.36ms
lock/unlock - Interval:10 - :29.12ms
lock/unlock - Interval:10 - :29.01ms
lock/unlock - Interval:10 - :28.80ms
lock/unlock - Interval:10 - :29.35ms
lock/unlock - Interval:10 - :29.00ms

Code:

public void MeasureLockUnlockOverhead()
{
const int TestIterations = 5;

Action<string, Func<double>> test = (name, action) =>
{
for (int i = 0; i < TestIterations; i++)
{
Console.WriteLine("{0}:{1:F2}ms", name, action());
}
};

Action<int> lockUnlock = interval =>
{
WriteableBitmap bitmap =
new WriteableBitmap(100, 100, 96d, 96d, PixelFormats.Bgr32, null);

int counter = 0;

Action t1 = () =>
{
if (++counter % interval == 0)
{
bitmap.Lock();
bitmap.Unlock();
}
};

string title = string.Format("lock/unlock - Interval:{0} -", interval);

test(title, () => TimeTest(t1));
};

lockUnlock(1);
lockUnlock(10);
}

[SuppressMessage("Microsoft.Reliability",
"CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect")]
private static double TimeTest(Action action)
{
const int Iterations = 100 * 1000;

Action gc = () =>
{
GC.Collect();
GC.WaitForFullGCComplete();
};

Action empty = () => { };

Stopwatch stopwatch1 = Stopwatch.StartNew();

for (int j = 0; j < Iterations; j++)
{
empty();
}

double loopElapsed = stopwatch1.Elapsed.TotalMilliseconds;

gc();

action(); //JIT
action(); //Optimize

Stopwatch stopwatch2 = Stopwatch.StartNew();

for (int j = 0; j < Iterations; j++)
{
action();
}

gc();

double testElapsed = stopwatch2.Elapsed.TotalMilliseconds;

return (testElapsed - loopElapsed);
}

WPF relies on a retained composition engine which is cool, but it looks like you're more after a "simple" and raw bitmap display.

I think you have a good example of what you want to do here: http://khason.net/blog/how-to-high-performance-graphics-in-wpf/

Full Disclosure: I have contributed to the WriteableBitmapEx open source project, however it is not my library nor am I affiliated with its owner

To add to the excellent answer by chibacity, I would suggest looking at the WriteableBitmapEx library. This is an excellent WPF, Silverlight and Windows Phone library which adds GDI-like drawing extension methods (blitting, lines, shapes, transforms as well as batch operations) to the WriteableBitmap class.

The latest version of WBEx contains a refactor that I carried out to allow batch operations. The WriteableBitmapEx library now has an extension method called GetBitmapContext(), to return an IDisposable struct which wraps a single lock/unlock/invalidate block. With the following syntax you can easily batch your drawing calls and perform only one Lock/Unlock/Invalidate at the end

// Constructor of BitmapContext locks the bmp and gets a pointer to bitmap
using (var bitmapContext = writeableBitmap.GetBitmapContext())
{
// Perform multiple drawing calls (pseudocode)
writebleBitmap.DrawLine(...)
writebleBitmap.DrawRectangle(...)
// etc ...
} // On dispose of bitmapcontext, it unlocks and invalidates the bmp

If I get it right you have a scenario where you want to get data from your sensor for a few seconds - and show it. You have a realtime requirement - or do you store the data from your special "camera" as an image and the realtime plotting is just for shows?

If so you could wait the few seconds and then show the result?

It sounds like WritableBitmap could be a way to solve your problem. I would assume that there is an overhead each time you have a lock/unlock block since it has to do with theading - so I don't think it is a good idea for each point. To get timing on it you could use a profiler on a test project / test data - dotTrace from jetbrains is ok - I think they have a trial version. You could also use a performance counter - that might be usefull for other stuff as well.

I would make it multithreaded and have a high priority thread to process the incomming points - or do you recive interrups from your device? As i understand it is more important to get all point than to draw all points rightaway.

You write that WritableBitmap is barely fast enough - so with your current solution I would try saving calls to AddDirtyRect so it is only at every n points/millisec - transfer to the frontbuffer should be fast even if it is a large block. You should be able to get it just as fast with wpf as with forms - its just nicer.

With some code and more info on your system it would be easier to answer :)

Category:c# Views:0 Time:2010-12-15
Tags: c# wpf

Related post

  • How do Draw Rubber band rectangle in DirectX? 2008-10-28

    How can I draw a 2D rubber band rectangle in DirectX? Preferable using C#. --------------Solutions------------- The classic way to do rubberbanding is to: Draw the regular scene, i.e. the "background" Switch to "XOR mode", where your pen will XOR the

  • How can I draw a filled rectangle in an applet with half opacity? 2009-01-31

    How can I draw a filled rectangle in an applet with half opacity/transparency? --------------Solutions------------- What API are you using? If you use Graphics from Java2D, when you create Color objects, you can add transparency to them as an alpha b

  • How to Draw Two Detached Rectangles in DirectX using the D3DPT_TRIANGLESTRIP Primitive Type 2009-08-28

    I am new to DirectX and I am trying to draw two rectangles in one scene using D3DPT_TRIANGLESTRIP. One Rectangle is no problem but two Rectangles is a whole different ball game. Yes i could draw them using four triangles drawn with the D3DPT_TRIANGLE

  • How to paints a transparent circle like using CGContextClearRect to draw a transparent rectangle 2009-09-23

    Do anyone know how I can draw a transparent circle on a CALayer just like using CGContextClearRect to draw a transparent rectangle? My requirements is that I need to draw a mask on a picture, in some cases, I need to erase it, but CGContextClearRect

  • Android: Draw a scalable rectangle(Should change colours on my input)around a bitmap 2010-02-09

    Can anybody help me to draw a scalable rectangle around a bitmap And such that 1) The rectangle should scale based on the size of my bitmap 2) The colour of my rectangle should change on my input any help would be appreciated Thank you --------------

  • How to draw a translucent rectangle on a static text? 2010-06-19

    I draw a tranlucent rectangle on my panel but on the places that have static text's the rectangle is not filled. I've drawn rectangles inside each static text but when I do that, the correspondent text doesn't happear. How can I draw a translucent re

  • How can I draw a selection rectangle on the screen with Qt? 2010-09-22

    How can I draw a selection rectangle on my screen with Qt in X11? I want to be able to drag a rectangle on my screen (outside of the application) and then save the whole rectangle. Thanks in advance. --------------Solutions------------- Part of the s

  • How to draw a transparent rectangle? 2010-10-08

    How to draw a transparent rectangle in j2me? --------------Solutions------------- Transparency is supported only in immutable images, i.e. images loaded from files. So you can create appropriate image. Or create transparency via filling its transpare

  • Android draw text into rectangle on center and crop it if needed 2011-04-01

    I want to draw text into rectangle on center (horizontally and vertically). If there is too much of a text that crop it what do not fit into rect. I have try to do it as this example show, but without luck. Any ideas? --------------Solutions---------

  • How can I draw a rounded rectangle Label or View? 2011-08-19

    I need to draw a rounded rectangle bar in my iOS application, but without using a background image. Is there any way to make a rounded rectangle view or label? --------------Solutions------------- In addition to the other answer(s), don't forget to s

  • How to load/draw out visible rectangle of webview? 2011-09-05

    My question is described below: I am implementing an eReader's app, which sets pagination by css3-multi columns. Suppose pageWidth is 680. First, when uiwebView finishes loading, x of scrollview position is 0. If controller is running next page, x of

  • how to draw semi-transparent rectangle in php? 2011-12-09

    Here is an example what I would like to do: Here is the result: function red_rectangle($img_src,$x1,$y1,$x2,$y2,$tr = 50) { // Load image $img = imagecreatefromjpeg($img_src); // Transparent red $red = imagecolorallocatealpha($img, 255, 0, 0, $tr); /

  • How to draw a line ,rectangle and circle using canvas with transparent using ontouchevent in android? 2012-02-07

    I am trying to draw a line, rectangle, and circle in canvas with transparency using ontouchevent in android --------------Solutions------------- This blog should help you get started. http://www.kellbot.com/2009/06/android-hello-circle/

  • SWT Drawing a "tranparent" rectangle on a shell 2012-03-06

    I would like to create a "selection area" tool. This tool should allow to draw a rectangle area on the screen with the mouse. I am using a fullscreen, translucent, darken swt Shell as my background on which I draw a white rectangle to represent the s

  • Allow user to draw a drag rectangle in CStatic C++ MFC App 2013-06-17

    I have a MFC application where I have a Picture Control in the dialog. Eventually, I want to allow a user to draw a resizeable rectangle via mouse drag in the picture control over an image that I loaded. I defined my own picture control class as a su

  • Loading an image and draw a selection rectangle using flex 3 2013-11-24

    Hi, I wants to know how we can load an image to a flex container and draw a selection rectangle on it. I also wants to get the coordinates of rectangle related to image xy position. I wants to do it using flex 3, using mx controls. Shaheer VM

  • Faster : drawing a rectangle or resizing a sprite? 2011-05-13

    I have two options and i want to know whats faster I have a pool of 1000 sprites objects in as3 on screen when its needed each sprite has to resize itself I can 1 - make each sprite a simple container to use graphics to draw a rectangle, that is, cal

  • Faster way to perform rectangle merging based on their intersection 2010-01-09

    this is being used in a motion detection problem. Basically, I perform a motion detection algorithm on an image, and get a list of blobs, where each blob hopefully corresponds to an object that has moved. However, we have to merge these blobs as ther

  • Draw a transparent rectangle in pygame 2011-06-14

    How can I draw a rectangle that has a color with an alpha? I have: windowSurface = pygame.display.set_mode((1000, 750), pygame.DOUBLEBUF) pygame.draw.rect(windowSurface, pygame.Color(255, 255, 255, 128), pygame.Rect(0, 0, 1000, 750)) But I want the w

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.266 (s). 11 q(s)