* * *

Author Topic: Performance question  (Read 689 times)

CCRDude

  • Sr. Member
  • ****
  • Posts: 407
Performance question
« on: November 08, 2018, 11:51:54 am »
Still looking for ways to improve, even though thanks to the help here, my apps work fine now :)

One issue are tables. Right now, I've got a custom table control that creates a full height bitmap, and then writes it on a full height control within a scrollbox. Works well for small tables, but tables with like 800 lines start to get slow.

I wonder what the best route to optimize would be, maybe someone has experience regarding the performance impact of the following alternatives I thought of:

1. Replace TScrollBox with a single scrollbar at the side of the control, in the background still create the full size picture, but only paint the currently visible part on the canvas.
2. Replace TScrollBox with a single scrollbar at the side of the control, and create only a part of the visible both in internal picture and canvas.

Logically, I would think the later would be faster, but since I cache the full size bitmap and only overlay (focus, hover, ...) changes to the foreground, I might have to give up the full size background cache (or use a full size background cache and a partial overlay ...).

Would this have positive impact on scrolling at all?

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 6584
Re: Performance question
« Reply #1 on: November 08, 2018, 11:53:11 am »
Allocate the whole bitmap, but only calculate it in stages as the scrollbar moves more of it in view.

Or an array of bitmaps, and sometimes you just have to do two blits.

wp

  • Hero Member
  • *****
  • Posts: 5056
Re: Performance question
« Reply #2 on: November 08, 2018, 11:59:24 am »
Right now, I've got a custom table control that creates a full height bitmap, and then writes it on a full height control within a scrollbox. Works well for small tables, but tables with like 800 lines start to get slow.
I don't understand: You are drawing the table to a bitmap and put this into a scrollbox? What is "full height"? The entire height of the table?

If the answer to both questions is yes, then this will certainly be slow once the size of the table exceeds some limit because all cells of the table will be painted although maybe only a small number is visible. Why don't you use a TStringGrid or TDrawGrid? They paint only those cells which are visible.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

CCRDude

  • Sr. Member
  • ****
  • Posts: 407
Re: Performance question
« Reply #3 on: November 08, 2018, 12:09:58 pm »
Sorry for being unclear :)

I have a TScrollbox, and inside a custom control. I resize that control to the full height (indeed meaning entire height) of the table, and use the Paint method of the control the draw from two internal bitmaps (static and overlay) to the custom control's canvas.

I don't use a TStringGrid or TDrawGrid because the table is quite a custom style, has collapsible sections (which may even contain custom controls, which I would have to solve differently with any optimizations). I'm attaching an example of such a table.

Initially, those tables were quite small, and with like 30 or 40 entries I don't notice a slowdown. But as projects grow... ;)

Calculation needs to be on the complete table, since it's nearly impossible to guess due to custom height columns, collapsible groups, etc..

Does BGRA support negative offsets or offsets outside the picture? So that I could easily draw control parts that are just partly shown?

Paul_

  • Full Member
  • ***
  • Posts: 116
Re: Performance question
« Reply #4 on: November 08, 2018, 12:41:04 pm »
So you have one big bitmap for whole grid? If yes, make small bitmaps for each line and draw only those on the screen + bitmaps for header etc.

Blaazen

  • Hero Member
  • *****
  • Posts: 2662
  • POKE 54296,15
    • Eye-Candy Controls
Re: Performance question
« Reply #5 on: November 08, 2018, 02:20:07 pm »
My experience is that the slowest operation is rendering text. I designed TECGrid so that when you scroll down (or up), then piece of bitmap is shifted (via Canvas.CopyRect) and only new lines are rendered.

Current position:
Code: Pascal  [Select]
  1. ____________________
  2. Row 1
  3. ____________________
  4. Row 2
  5. ____________________
  6. Row 3
  7. ____________________

New position:
Code: Pascal  [Select]
  1. ____________________
  2. Row 2
  3. ____________________
  4. Row 3
  5. ____________________
  6. Row 4
  7. ____________________

This peice of bitmap is copied to a new position:
Code: Pascal  [Select]
  1. ____________________
  2. Row 2
  3. ____________________
  4. Row 3
  5. ____________________
and new line is rendered:
Code: Pascal  [Select]
  1. ____________________
  2. Row 4
  3. ____________________
Lazarus 2.1.0 r59474M FPC 3.3.1 r40247 x86_64-linux-qt Chakra, Qt 4.8.7/5.11.2, Plasma 5.14.2
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.14

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

circular

  • Hero Member
  • *****
  • Posts: 2780
    • Personal webpage
Re: Performance question
« Reply #6 on: November 08, 2018, 06:37:20 pm »
It is indeed slow to redraw a very big bitmap, especially text as Blaazen points out. Also it is memory consuming.

I would recommend to use:
- just one virtual screen (ex: TBGRAVirtualScreen or a BGRA bitmap being just the size of the visible part)
- a separate scrollbar that you configure yourself depending on the full size (TScrollBar)
- handle scrollbar events to determine new offset and discard virtual screen (TBGRAVirtualScreen.DiscardBitmap)
- draw in the virtual screen with the offset (add values to x/y depending on current offset) (in OnRedrawBitmap event for TBGRABirtualScreen)

Redrawing the whole visible part may not be too slow. However if you want to optimize this as well, then:
- determine which part of the Bitmap is to be kept. Then do a PutImage of the virtualscreen on itself with the relative offset.
- do a ClipRect on the remaining part to be redrawn
- do the drawing (always with the global offset)
- refresh the visual component (Invalidate or Refresh)

Negative coordinates are fine with BGRABitmap. You may also avoid calling drawing routines when the object is clearly not visible.
« Last Edit: November 08, 2018, 06:39:20 pm by circular »
Conscience is the debugger of the mind

CCRDude

  • Sr. Member
  • ****
  • Posts: 407
Re: Performance question
« Reply #7 on: November 09, 2018, 10:03:04 am »
Thank you so much!

I now have my own ScrollBar and draw on my current canvas just the visible area according to the scrollbar offset.
Haven't used TBGRAVirtualScreen yet, will take a look at it.

Will write some tests with some really huge tables to continue testing, but it looks much better now already!

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus