Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2009-09

Optimizing Lazarus drawing performance

5 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Adriaan van Os

For the Carbon widgetset, Lazarus uses HIViews for many objects, including, for example, objects of type TPanel. Given the disappointing drawing speed I measured, the question is how to optimize drawing performance.

In the HiView Programming Guide, chapter HIView Tasks, Apple writes under "Handling Draw Events" the following
<http://developer.apple.com/legacy/mac/library/documentation/Carbon/Conceptual/HIViewDoc/HIView_tasks/HIView_tasks.html>.

"In addition, whether you use QuickDraw or Quartz, the kEventControlDraw event also contains a kEventParamRgnHandle parameter. This region defines the visible portion of the view, and in most cases you should restrict your drawing to this area; any part of the view outside this area is presumably covered by another view and will be overwritten. The HIView compositor determines the size of this region."

So, for good drawing performance, we should only draw into the visible porting of the view. However, Lazarus doesn't use the kEventParamRgnHandle parameter and consequently the application can't do the optimization.

I suggest to add the region to the TCarbonContext class.

The next question is how this region, or at least its bounding box, should be known to the application. We have, for example, a GetClipRect method attached to various objects.

A further question is how to invalidate part of a user interface object, e.g. a TPanel. A good example is scrolling, were we only want to redraw that part of the object that really needs it. If the optimization is impossible using controls/HiViews, than maybe a TPanel shouldn't be a control/HiView ?

Regards,

Adriaan van Os

Reply by email

Hans-Peter Diettrich
to Adriaan van Os
Show quoted text 9 lines
"In addition, whether you use QuickDraw or Quartz, the kEventControlDraw event also contains a kEventParamRgnHandle parameter. This region defines the visible portion of the view, and in most cases you should restrict your drawing to this area; any part of the view outside this area is presumably covered by another view and will be overwritten. The HIView compositor determines the size of this region."

Windows creates separate WM_PAINT messages for all rectangles in the update region, and initializes the GDI clipping rectangle accordingly. This removes the need for region checks from the painting routines, at some performance penalties: the same component can be asked to paint itself multiple times, until all rectangles have been painted, so that the initialization of the Canvas and fetching data occurs multiple times. At least can a painting routine test the ClipRect, to prevent useless painting calls into clipped areas.

The Mac approach obviously leaves the clipping to the painting routines, and the drawing primitives seem not to handle any clipping themselves. If this analysis is correct, and if we want to use the same WM_PAINT handlers (consider custom controls!) also on a Mac, an emulation of the Windows procedure seems to be required.

Show quoted text 12 lines
So, for good drawing performance, we should only draw into the visible porting of the view. However, Lazarus doesn't use the kEventParamRgnHandle parameter and consequently the application can't do the optimization. I suggest to add the region to the TCarbonContext class. The next question is how this region, or at least its bounding box, should be known to the application. We have, for example, a GetClipRect method attached to various objects.

The painting emulator should handle the region, split it into rectangles, and call the paint handlers for every rectangle. The ClipRect has to be initialized for every rectangle, and it should be applied to all coordinates in the LCL/RTL painting methods, before calling the widgetset specific drawing primitives.

This behaviour may have been implemented in the widgetsets already (dunno)?

Show quoted text 7 lines
A further question is how to invalidate part of a user interface object, e.g. a TPanel. A good example is scrolling, were we only want to redraw that part of the object that really needs it. If the optimization is impossible using controls/HiViews, than maybe a TPanel shouldn't be a control/HiView ?

Windows has a function for scrolling screen contents without sending WM_PAINT requests. Only those parts of the client area have to be repainted, which have been scrolled into view.

DoDi

Reply by email

Adriaan van Os

Lazarus has the TCarbonBitmapContext class, implemented as a Quartz CGBitmapContext. User interface objects use a CGImage as pixel cache. During profiling a Lazarus application on Mac OS X, I noticed that the application spends a lot of time in TCarbonDeviceContext.DrawCGImage.

Apple writes
<http://developer.apple.com/mac/library/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html>

Graphics Contexts
Note: If you want to perform offscreen drawing, before you use a bitmap graphics context, you should first read ?CGLayer Drawing.? CGLayer objects, introduced in Mac OS X v10.4 and available in iPhone OS, support drawing to layers and provide a much more optimized solution for offscreen drawing than bitmap graphics contexts provide.

and

Creating a Bitmap Graphics Context
CGLayer objects (CGLayerRef), available in Mac OS X v10.4 and later, are optimized for offscreen drawing because, whenever possible, Quartz caches layers on the video card.

Therefore - unless someone else is working on it - I would like to add CGLayer support to the Carbon widget, using CGLayers as pixel cache for interface objects. Is this a change that the Lazarus team would welcome ? My work will is being sponsored by PGMusic <http://www.pgmusic.com>.

Regards,

Adriaan van Os

Reply by email

Mattias Gaertner
to Hans-Peter Diettrich: Windows creates separate WM_PAINT messages for all rectangles in the update region, and…
Show quoted text 21 lines
Adriaan van Os schrieb: > "In addition, whether you use QuickDraw or Quartz, the > kEventControlDraw event also contains a > kEventParamRgnHandle parameter. This region defines the visible > portion of the view, and in most > cases you should restrict your drawing to this area; any part of > the view outside this area is > presumably covered by another view and will be overwritten. The > HIView compositor determines the > size of this region." Windows creates separate WM_PAINT messages for all rectangles in the update region, and initializes the GDI clipping rectangle accordingly. This removes the need for region checks from the painting routines, at some performance penalties: the same component can be asked to paint itself multiple times, until all rectangles have been painted, so that the initialization of the Canvas and fetching data occurs multiple times. At least can a painting routine test the ClipRect, to prevent useless painting calls into clipped areas.

The clipping area is a region, not a rectangle. Of course often it is a rectangle.
The question is, if the carbon interface handles all clipping and region functions correctly.

Show quoted text 5 lines
The Mac approach obviously leaves the clipping to the painting routines, and the drawing primitives seem not to handle any clipping themselves. If this analysis is correct, and if we want to use the same WM_PAINT handlers (consider custom controls!) also on a Mac, an emulation of the Windows procedure seems to be required.

Since we are talking about speed: Avoid "emulation" and talk about mapping.

[...]

Mattias

Reply by email

Mattias Gaertner
to Adriaan van Os: Lazarus has the TCarbonBitmapContext class, implemented as a Quartz CGBitmapContext. User…
Show quoted text 28 lines
Lazarus has the TCarbonBitmapContext class, implemented as a Quartz CGBitmapContext. User interface objects use a CGImage as pixel cache. During profiling a Lazarus application on Mac OS X, I noticed that the application spends a lot of time in TCarbonDeviceContext.DrawCGImage. Apple writes <http://developer.apple.com/mac/library/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html> Graphics Contexts Note: If you want to perform offscreen drawing, before you use a bitmap graphics context, you should first read ?CGLayer Drawing.? CGLayer objects, introduced in Mac OS X v10.4 and available in iPhone OS, support drawing to layers and provide a much more optimized solution for offscreen drawing than bitmap graphics contexts provide. and Creating a Bitmap Graphics Context CGLayer objects (CGLayerRef), available in Mac OS X v10.4 and later, are optimized for offscreen drawing because, whenever possible, Quartz caches layers on the video card. Therefore - unless someone else is working on it - I would like to add CGLayer support to the Carbon widget, using CGLayers as pixel cache for interface objects. Is this a change that the Lazarus team would welcome ? My work will is being sponsored by PGMusic <http://www.pgmusic.com>.

ok for me

Mattias

Reply by email