ThinkGeo.com    |     Documentation    |     Premium Support

Increasing drawing performance

We are still a little disappointed at the rendering performance of MapSuite, compared to what we got with our own routines drawing using GDI+.    Currently, we're drawing with a statement like:



       canvas.DrawEllipse(shape, r, r, ((



PenAndBrush)m.Tag).Brush, DrawingLevel.LevelOne);

Where PenAndBrush is an object that holds a reference to a GeoBrush and GeoPen object, and "m" is the object that we have discovered containing the correct styles for the value of the object being drawn.  


Keep in mind we are executing this line about 20,000 times.   My total loop is taking 8 seconds, with 7 of it being spent in the canvas.DrawEllipse statement.   My old program, doing this same general logic, but drawing directly with GDI+ into a bitmap takes just over 2 seconds.


I recognize that recasting the Tag property to a PenAndBrush might be expensive, and I'm preparing to fix that.   But I'm also wondering about your use of the GeoBrush.   For each call, do you internally create a GDI Brush from your GeoBrush and destroy it?   Or do you instantiate a GDI brush one time, and use it for each call to the Canvas.Draw* function?


I'm wondering if I should revert to drawing these sites directly onto a bitmap, and then painting the bitmap into the GeoCanvas?


Are my questions clear as mud?  I guess I'm just trying to get a handle on what's going on inside your drawing routines that might be low-hanging fruit that could be picked off on a task like this.


 




Ted, 
  
   Your question is crystal clear, 'Why does it take so long to draw?".  Looking into the DrawEllipse code path my suspicion is that it is all the validation that is going on.  We validate every input parameter, WKB type, etc…  This is happening at a few levels, one in the concrete method and then some of it again in the Core method.  Most of the validation is very small and quick but some take additional time.  Let me run some tests here and performance profile it to see what I can find.  Relating to the GeoBrushes and GeoPens we cache them so that they can be reused for each subsequent call. 
  
 David

Ted, 
  
  I did some testing drawing 20,000 ellipses and it was quite fast.  It clocked it at around 2 seconds.  I ran a performance test on it and 75% of the time was in System.Drawing for the ellipse drawing.  I have a feeling it has to do with the brushes or something else.  Below is the super simple code I tried.  Of course it is very static but you can try it and see if you get the same results.  Then we can see how your case is different.   
  
 I will do whatever I can to speed things up for you.  I just first need to identify what is slow. 
  
             bitmap = new Bitmap(500, 500);             
  
             GdiPlusGeoCanvas canvas = new GdiPlusGeoCanvas(); 
             canvas.BeginDrawing(bitmap, new RectangleShape(-180.0, 83.0, 180.0, -90.0), GeographyUnit.DecimalDegree); 
  
             GeoSolidBrush brush = new GeoSolidBrush(GeoColor.StandardColors.Red); 
             PointShape p = new PointShape(0, 0); 
  
             for (int i = 0; i < 20000; i++) 
             { 
                 canvas.DrawEllipse(p, 100, 100, brush,DrawingLevel.LevelOne); 
  
             } 
  
             canvas.Flush(); 
             canvas.EndDrawing(); 
  
 David

Thank you, David.  I’m clearly going to need to do some very detailed profiling in this function.   One of the things I have to do is project the data if it has not already been projected.   But I think I had profiled on second passes, so the data should have already been projected.    I really need to determine how much that recasing of my pen and brush holder class from an object is taking.   
  
 In your example, you are doing a BeginDrawing, Flush, and EndDrawing.   I assme that when a DrawCore function is called with a canvas, those methods have already been called?   I’m not calling them. 
  
 This is the fifth layer in my application.  It is being drawn over the WMK, and other vector layers, does that have any impact?  Is there a GeoCanvas for each layer, and your components merge those layers? 
  
 I’ll do more experimenting this week and get back to you.   I want to stay focused on this while I’m at it.

Ted, 
  
   I am up for anything…  If you send a sample I would be happy to performance profile it with our full source and discuss the results and show you the timings per function etc.  I think we could arrange for you to get the source for the geocanvas and we could setup a test so you could render your own layers against that source. 
  
 The BeginDraw, Flush etc all happen in the Overlay.  The same canvas gets passed from layer to layer.  I think we might do a flush between layers but that is a fairly quick operation. 
  
 Being the fifth layer should not effect anything.  All the layers in an overlay draw on the same bitmap behind the scenes.  Of course the more overlays the more bitmap merging we have to do and on high resolution screens that takes more time. 
  
   Of course the time I was talking about was drawing in one shot.  If we are drawing tile by tile then maybe many of the ellipses that overlap tiles will be drawn multiple times.  How exactly are you generating the images?  I see you posted to the Services Edition so I assumed you were doing everything by hand against a bitmap. 
  
 David

I posted on services because I thought this was related to raw drawing, and that was the same for both services and desktop editions.   In my profiling, I’m running against the winforms map control, and using the overlays.   But the time I’m measuring is inside the DrawCore for my custom layer. 
  
 I’ll try to build a dedicated simple app that we can use to test this more effectively.

Ted, 
  
   Just posting to close this thread as we took the issues offline and got you squared away. 
  
 David