Skip to main content

Microsoft Silverlight

Answered Question How to increase performance of drawing a multitude of UI elements?RSS Feed

(0)

Grey Matter
Grey Matter

Member

Member

39 points

108 Posts

How to increase performance of drawing a multitude of UI elements?

Hi!

1. Now my application operates with 2513 polygons (25321 points for all of these polygons) and it takes about 0.4 second to change their coordinates (for moving or scaling). A similar application written in C++ that uses GDI API makes the same operation within 10-20 milliseconds. So, it's a great difference and it'll be even greater if the amount of objects is increased. But I'm not trying to complain about Silverlight performance, I just have a very slim hope that there may be any trick to get it just a little faster.

2. But it's only a half of my trouble that it may take too much time. The second half of the trouble is that it causes my user interface to stop responding for all of the operating period. I was trying to solve it with a background thread but it didn't help because any UI element cannot be created beyond UI thread, and it returned me to the same trouble with UI freezing.

If someone has any ideas about question 1 or 2, I would be very grateful for it.

Sergey.Lutay
Sergey.L...

Contributor

Contributor

7198 points

1,340 Posts

Re: How to increase performance of drawing a multitude of UI elements?

Hi,

To 1: try to find ways to optimize algorithm

To 2: You can use Dispatcher for access to UI thread from another thread. Look http://forums.silverlight.net/forums/p/82077/303493.aspx

(If this has answered your question, please click on "mark as answer" on this post. Thank you!)

Blog

Twitter

Sincerely,
Sergey Lutay

Grey Matter
Grey Matter

Member

Member

39 points

108 Posts

Re: How to increase performance of drawing a multitude of UI elements?

Hi Sergey,

> To 1: try to find ways to optimize algorithm

The algorithm is very simple. It takes next Polygon from a List<Polygon> and replaces its Points with new values. I think there is nothing to be optimized.

>To 2: You can use Dispatcher for access to UI thread from another thread.
As I said it returns me to the same problem -- operating within UI thread causes UI to be frozen for a time while coordinates of polygons are changed. So, what use is it to do it in a separate thread if in any case it will be executed in UI thread (through InvokeBegin or directly)? IOW this operation steal time from UI thread whether it is performed through InvokeBegin from another thread or directly from UI thread. InvokeBegin method looks like a self-deception in this issue. If I could create an UI element in another thread (before it’s rendered) and then connect it to the RootVisual tree in UI thread it might help, but it seems to be impossible.

Rangoric
Rangoric

Member

Member

62 points

21 Posts

Re: How to increase performance of drawing a multitude of UI elements?

Are you only changing the values when they are different?

Why are you changing the values as opposed to moving whole objects?

When he said optimize you algorithm it is more the whole approach to changing 25k points and having the UI update the drawing after each point is changed (which is why it takes so long in silverlight).

I'm gonna have to check if an object needs a dispatcher before it is in the UI, that seems odd. But other then that there has to be a better way.

Tuska
Tuska

Member

Member

21 points

7 Posts

Answered Question

Re: Re: How to increase performance of drawing a multitude of UI elements?

 If you have huge amount of points, you might consider using something else to render them. For example WriteableBitmap and implementing your own polygon algorithm and drawing them directly into bitmap so that silverlight doesn't have to render each polygon and point separately.

 

If you still want to use polygons, another option is to disable HitTesting on them and using BitmapCache on each polygon and be sure that rendering is as easy as possible. This means that no transparency or gradients.

 

Oh and if you change polygon points, silverlight leaks memory, better way to update points directly is this:

   public void Draw()
        {
            PointCollection collection = new PointCollection();

            for (int i = 0; i < newPoints.Count; i++)
            {
                collection.Add(newPointsIdea);
            }

            polygon.Points = collection;

        }

drnomad
drnomad

Member

Member

206 points

58 Posts

Re: Re: How to increase performance of drawing a multitude of UI elements?

"The algorithm is very simple. It takes next Polygon from a List<Polygon> and replaces its Points with new values. I think there is nothing to be optimized."

I did something like this in a game (which is not published). It was very, very slow. But the main operation I performed on the polygons was rotate. I trashed the algorithmn, created the polygons I wanted and I used RotateTransform instead. Then it became very fast.

Online Silverlight games on http://www.seujogo.com

Grofit
Grofit

Member

Member

229 points

310 Posts

Re: Re: How to increase performance of drawing a multitude of UI elements?

 Not sure if this will help in your scenario or if you have already implemented something similar, but are you always updating EVERY point or are you just doing it for things on the screen?

If you need things to move even if they are off the screen then it wouldnt work, but if you implemented some sort of primitive quad tree or some spatial partitioning you would be able to restrict updates to things on screen, which would only update the required polygons...

Also if you are constantly messing around with small objects, are you creating them as structs or classes? if you are constantly creating/removing small objects its *generally* better to make them as structs so they live within the stack.

Grey Matter
Grey Matter

Member

Member

39 points

108 Posts

Re: How to increase performance of drawing a multitude of UI elements?

Hi guys,

Rangoric:
Are you only changing the values when they are different?

Yes, only when they are visible and different.

Rangoric:
Why are you changing the values as opposed to moving whole objects?

drnomad:
I did something like this in a game (which is not published). It was very, very slow. But the main operation I performed on the polygons was rotate. I trashed the algorithmn, created the polygons I wanted and I used RotateTransform instead. Then it became very fast.
 

If you mean using transforms it's because the most common operation in my application is scaling. May be ScaleTransfrom works faster but it scales not only position, it changes StrokeThickness too that is not appropriate to my needs as well as there are some other aspects that don't make transforms very convenient in my case.

Rangoric:
When he said optimize you algorithm it is more the whole approach to changing 25k points and having the UI update the drawing after each point is changed (which is why it takes so long in silverlight).
 

I do these changings within one method, so I guess Silverlight renders them all at once.

Tuska:
 If you have huge amount of points, you might consider using something else to render them. For example WriteableBitmap and implementing your own polygon algorithm and drawing them directly into bitmap so that silverlight doesn't have to render each polygon and point separately.
 

If I'd be sure that I could do it faster than Silverlight .. :)

Tuska:
If you still want to use polygons, another option is to disable HitTesting on them and using BitmapCache on each polygon and be sure that rendering is as easy as possible. This means that no transparency or gradients.

Thanks, I'll try it.

Tuska:

Oh and if you change polygon points, silverlight leaks memory, better way to update points directly is this:

   public void Draw()
        {
            PointCollection collection = new PointCollection();

            for (int i = 0; i < newPoints.Count; i++)
            {
                collection.Add(newPointsIdea);
            }

            polygon.Points = collection;

        }



Is liking memory a bug?

 

It is unexpected for me but your loop makes it in half the time! I thought that it is faster not to create a new PointCollection than changing the the points for an existing PointCollection, but as I see it is not so. I don't think that Silverlight recalculates a whole polygon on when each point is changing, so I have no idea why there is difference. Thank you for this correction!

 

 

Grofit:

 Not sure if this will help in your scenario or if you have already implemented something similar, but are you always updating EVERY point or are you just doing it for things on the screen?

If you need things to move even if they are off the screen then it wouldnt work, but if you implemented some sort of primitive quad tree or some spatial partitioning you would be able to restrict updates to things on screen, which would only update the required polygons...

Also if you are constantly messing around with small objects, are you creating them as structs or classes? if you are constantly creating/removing small objects its *generally* better to make them as structs so they live within the stack. 

Thank you for your advice, I really have made a simple spatial tree and it's taken a very good effect. But when I change scale to show a whole map it doesn't. Now I'm thinking about changing detail depending on scaling.

Grey Matter
Grey Matter

Member

Member

39 points

108 Posts

Re: Re: How to increase performance of drawing a multitude of UI elements?

Tuska:
If you still want to use polygons, another option is to disable HitTesting on them and using BitmapCache on each polygon and be sure that rendering is as easy as possible. This means that no transparency or gradients.
 

I was trying to add new BitmapCache() to each polygon but it made a converse effect: redrawing became slower.

cyric74
cyric74

Member

Member

62 points

20 Posts

Re: Re: Re: How to increase performance of drawing a multitude of UI elements?

You're kind of forcing Silverlight to do something it doesn't like to do when you're passing a new Points[] every frame.  Basically it's going to invalidate and re-draw everything.

To take full advantage of the hardware acceleration (and if you're drawing this many objects, you must do so) you're going to have to figure out Scale/Rotate/Translate for your objects.  Translation is the key to your problem.

Grey Matter
Grey Matter

Member

Member

39 points

108 Posts

Re: Re: Re: How to increase performance of drawing a multitude of UI elements?

No, I'm not passing a new Points[] every frame. I only do it when user moves map's plane or scales it. I tried using standard Scale engine, but it scale strokes too which is not what I need. However, I use standard transforms for quick preview and only then transform it manually.

cyric74
cyric74

Member

Member

62 points

20 Posts

Re: Re: Re: How to increase performance of drawing a multitude of UI elements?

I see.  The setting of various stroke sizes and such is going to cause a lot of overhead if you're doing it often with many objects.  It isn't accelerated, and Silverlight is going to do its re-drawing calculations every time you invalidate by making the change.  Silverlight has a short list of what is actually hardware accelerated behavior (scale/rotate/translate, opacity off the top of my head).  Doing anything but these in the render thread can bring your app to its knees.

I'm not sure what kind of application you're doing (and a brief description may be helpful) -- you say that you only do these changes when a user moves the map or scales it. Does this mean you're doing something like making all objects get bigger when they scroll the mouse wheel (ie zooming the map)?  If so, what you should be doing is a single scale/transform on a canvas object which holds all of the children, and not each individual child.

Also make sure you're using the hardware acceleration visualization to confirm that you are actually taking advantage of the GPU.  You can easily break it by doing something as simple as a rotating a clipped image to a non-right angle, and suddenly your app drags for no apparent reason.

Grey Matter
Grey Matter

Member

Member

39 points

108 Posts

Re: Re: Re: How to increase performance of drawing a multitude of UI elements?

 > I'm not sure what kind of application you're doing (and a brief description may be helpful)
It's a kind of interactive maps that loads a particular territory like a town. It must be something like this and better than.

> Does this mean you're doing something like making all objects get bigger when they scroll the mouse wheel (ie zooming the map)?
Yes, and I was trying to explain why I don't use transforms -- may be I was unclear.. I'll try again :)

I completely agree with all of your statements about transforms' advantages -- I tested and found them much more faster than making it "manually" (like I do now). I understand that I lose much speed but Silverlight transforms give me some drawbacks against my requirements spec. and I don't know whether there is any way to get rid of them: objects like texts/lines mustn't change their sizes/thickness while scaling, but if I use scaletransform they do. So I don't know how to gain good performance with Silverlight transforms and at the same time to avoid scale's side effects. May be you have any idea? It would be really valuable to me.

cyric74
cyric74

Member

Member

62 points

20 Posts

Re: Re: Re: How to increase performance of drawing a multitude of UI elements?

 

Grey Matter:
It's a kind of interactive maps that loads a particular territory like a town. It must be something like this and better than.

 

You can duplicate the background map behavior by creating a single canvas, drop your background elements onto it, then do a single calculation for moving the map.  I took a few minutes and made this to show you what I'm talking about.  I avoided using complicated transformations, and just manipulate a Scale transform.

Map Zoom Demo

(Use the mouse wheel, click-and-drag.  Zoom in on LA or New York City to see detail)

Source Code

 

 

Grey Matter:
objects like texts/lines mustn't change their sizes/thickness while scaling, but if I use scaletransform they do

 

The next step for these "unchanging text or objects" elements would be to wrap everything in a parent Canvas.

This parent canvas would hold your background map, as well as each unchanging object.  You would need to calculate the screen location for each object based on how your background map is zoomed and focused, then Translate each unchanging object to that screen point.

The objects would not require any Scale transformation, would remain the same size no matter how your map was zoomed, and would use Silverlight's hardware acceleration because they're using a translate.

  • Unanswered Question
  • Answered Question
  • Announcement
Microsoft Communities