Sign in Join

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

Mailing lists / gtk2 / 2008-07

About bug 11523: analysis and proper fix(es)

9 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

Luiz Americo Pereira Camara

The problem occurs because each device context instance has a text cache while the layout is shared between all device contexts that have the same font.

In TextOutCacheGtk2.zip there's a project that helps to show the problem.

Considering that "Single Line" option is set:
Str1 is draw to Bitmap1.Canvas:
- The text cache of Bitmap1.Canvas is empty and is set to Str1 data
- Str1 is set as the layout text
Str2 is draw to Bitmap2.Canvas:
- The text cache of Bitmap2.Canvas is empty and is set to Str2 data
- Str2 is set as the layout text
Str1 is draw (again) to Bitmap1.Canvas:
- The text cache of Bitmap1.Canvas has Str1 data so it does not set the layout text
- The layout still have Str2 as the text...

I can't explain what's going on when "Single Line" option is not set...

The fix is simple, instead of caching the text data at each time the layout text is set, retrieve the text directly from the layout using pango_layout_get_text (unlike the *set_text function this is pretty cheap since it just returns a pointer of the stored text). With this approach i have two wons: no data copy/duplication and avoid the out of sync between cache and layout texts.

I implemented in three ways (see the patches):

1) Stores the OldFont (Pangolayout) and compare the Old/New strings using strcomp*

Than i noticed that is not necessary to store the old font and comes with the 2nd implementation. There's also no more need to be a method of TGtk2DeviceContext.

2) Just compare the two strings using StrComp*

* Is better to use StrLComp instead of StrComp

But i lost the shortcut evaluation of length that prevents a string comparation. So...

3) Stores the old length in the layout object using a gquark* and compare both strings with comparebytes (i know that both strings are the same size)

** The old length can be also stored in a field of font GdiObject

Luiz

-------------- next part --------------
A non-text attachment was scrubbed...
Name: TextOutCacheGtk2.zip
Type: application/zip
Size: 2836 bytes
Desc: not available
URL: <http://lists.lazarus.freepascal.org/pipermail/gtk2/attachments/20080712/e239c59e/attachment.zip> -------------- next part --------------
An embedded and charset-unspecified text was scrubbed... Name: gtk2settext_ver1.diff
URL: <http://lists.lazarus.freepascal.org/pipermail/gtk2/attachments/20080712/e239c59e/attachment.ksh> -------------- next part --------------
An embedded and charset-unspecified text was scrubbed... Name: gtk2settext_ver2.diff
URL: <http://lists.lazarus.freepascal.org/pipermail/gtk2/attachments/20080712/e239c59e/attachment-0001.ksh> -------------- next part --------------
An embedded and charset-unspecified text was scrubbed... Name: gtk2settext_ver3.diff
URL: <http://lists.lazarus.freepascal.org/pipermail/gtk2/attachments/20080712/e239c59e/attachment-0002.ksh>

Reply by email

Mattias Gaertner
to Luiz Americo Pereira Camara
Show quoted text 39 lines
The problem occurs because each device context instance has a text cache while the layout is shared between all device contexts that have the same font. In TextOutCacheGtk2.zip there's a project that helps to show the problem. Considering that "Single Line" option is set: Str1 is draw to Bitmap1.Canvas: - The text cache of Bitmap1.Canvas is empty and is set to Str1 data - Str1 is set as the layout text Str2 is draw to Bitmap2.Canvas: - The text cache of Bitmap2.Canvas is empty and is set to Str2 data - Str2 is set as the layout text Str1 is draw (again) to Bitmap1.Canvas: - The text cache of Bitmap1.Canvas has Str1 data so it does not set the layout text - The layout still have Str2 as the text... I can't explain what's going on when "Single Line" option is not set... The fix is simple, instead of caching the text data at each time the layout text is set, retrieve the text directly from the layout using pango_layout_get_text (unlike the *set_text function this is pretty cheap since it just returns a pointer of the stored text). With this approach i have two wons: no data copy/duplication and avoid the out of sync between cache and layout texts. I implemented in three ways (see the patches): 1) Stores the OldFont (Pangolayout) and compare the Old/New strings using strcomp* Than i noticed that is not necessary to store the old font and comes with the 2nd implementation. There's also no more need to be a method of TGtk2DeviceContext. 2) Just compare the two strings using StrComp*

That's better.

Show quoted text 10 lines
* Is better to use StrLComp instead of StrComp But i lost the shortcut evaluation of length that prevents a string comparation. So... 3) Stores the old length in the layout object using a gquark* and compare both strings with comparebytes (i know that both strings are the same size) ** The old length can be also stored in a field of font GdiObject

Have you compared times?
I guess option 3 will be even slower for normal texts.

Mattias

Reply by email

Mattias Gaertner
to Luiz Americo Pereira Camara: The problem occurs because each device context instance has a text cache while the layout…
Show quoted text 25 lines
The problem occurs because each device context instance has a text cache while the layout is shared between all device contexts that have the same font. [...] I implemented in three ways (see the patches): 1) Stores the OldFont (Pangolayout) and compare the Old/New strings using strcomp* Than i noticed that is not necessary to store the old font and comes with the 2nd implementation. There's also no more need to be a method of TGtk2DeviceContext. 2) Just compare the two strings using StrComp* * Is better to use StrLComp instead of StrComp But i lost the shortcut evaluation of length that prevents a string comparation. So... 3) Stores the old length in the layout object using a gquark* and compare both strings with comparebytes (i know that both strings are the same size) ** The old length can be also stored in a field of font GdiObject

I committed 2 in r15758.

Mattias

Reply by email

Luiz Americo Pereira Camara
to Mattias Gaertner
Mattias Gaertner wrote 16 lines
> 2) Just compare the two strings using StrComp* > > * Is better to use StrLComp instead of StrComp > > But i lost the shortcut evaluation of length that prevents a string > comparation. So... > > 3) Stores the old length in the layout object using a gquark* and > compare both strings with comparebytes (i know that both strings are > the same size) > > ** The old length can be also stored in a field of font GdiObject > I committed 2 in r15758.

It seems you commited 3 (I see the g_quark stuff)

Luiz

Reply by email

Mattias Gaertner
to Luiz Americo Pereira Camara
Show quoted text 19 lines
Mattias Gaertner wrote: >> 2) Just compare the two strings using StrComp* >> >> * Is better to use StrLComp instead of StrComp >> >> But i lost the shortcut evaluation of length that prevents a >> string comparation. So... >> >> 3) Stores the old length in the layout object using a gquark* and >> compare both strings with comparebytes (i know that both strings >> are the same size) >> >> ** The old length can be also stored in a field of font GdiObject >> > > I committed 2 in r15758. > It seems you commited 3 (I see the g_quark stuff)

Changed in 15761.

Mattias

Reply by email

Luiz Americo Pereira Camara
to Mattias Gaertner: On Sat, 12 Jul 2008 12:37:17 -0300 That's better. Have you compared times? I guess option…
Mattias Gaertner wrote 30 lines
On Sat, 12 Jul 2008 12:37:17 -0300 Luiz Americo Pereira Camara wrote: > > > Than i noticed that is not necessary to store the old font and comes > with the 2nd implementation. There's also no more need to be a method > of TGtk2DeviceContext. > > 2) Just compare the two strings using StrComp* > That's better. > * Is better to use StrLComp instead of StrComp > > But i lost the shortcut evaluation of length that prevents a string > comparation. So... > > 3) Stores the old length in the layout object using a gquark* and > compare both strings with comparebytes (i know that both strings are > the same size) > > ** The old length can be also stored in a field of font GdiObject > Have you compared times?

No.
There are two theoretical benefits in 3:
- If the length of the NewText is different from the OldText skip the string comparation
- CompareBytes is supposed to be faster than StrComp since is hand optimized (asm) and don't need to check for PChar length/ending

The overhead of storing the oldlength using g_object function can be removed by storing as a field in the TGDIObject record. I did not tried that because i don't know the effects of adding an extra field. Also the function should be modified to receive a font object instead of a pango layout.

Luiz

Reply by email

Paul Ishenin
to Luiz Americo Pereira Camara
Luiz Americo Pereira Camara wrote 13 lines
No. There are two theoretical benefits in 3: - If the length of the NewText is different from the OldText skip the string comparation - CompareBytes is supposed to be faster than StrComp since is hand optimized (asm) and don't need to check for PChar length/ending The overhead of storing the oldlength using g_object function can be removed by storing as a field in the TGDIObject record. I did not tried that because i don't know the effects of adding an extra field. Also the function should be modified to receive a font object instead of a pango layout.

Simplier ways are better - less chances to make a bug. Anyway with any optimization we have about 2 time faster Canvas.TextOut in gtk2.

And thanks for research.

Best regards,
Paul Ishenin.

Reply by email

Luiz Americo Pereira Camara
to Mattias Gaertner: On Sun, 13 Jul 2008 08:26:31 -0300 Changed in 15761. Mattias
Mattias Gaertner wrote 14 lines
On Sun, 13 Jul 2008 08:26:31 -0300 Luiz Americo Pereira Camara wrote: > Mattias Gaertner wrote: > >> I committed 2 in r15758. >> >> > It seems you commited 3 (I see the g_quark stuff) > Changed in 15761.

Can you also take the suggestion of using StrLComp instead of StrComp? (I just noticed this problem after exiting my linux machine)

If only a substring is used there must be unnecessary cache misses, e.g.:

TextOut(DC, 0, 0, 'very long text', 4);

Only 'very' is draw and set in layout text

Luiz

Reply by email

Mattias Gaertner
to Luiz Americo Pereira Camara
Show quoted text 25 lines
Mattias Gaertner wrote: > On Sun, 13 Jul 2008 08:26:31 -0300 > Luiz Americo Pereira Camara wrote: > > >> Mattias Gaertner wrote: >> >>> I committed 2 in r15758. >>> >>> >> It seems you commited 3 (I see the g_quark stuff) >> > > Changed in 15761. > Can you also take the suggestion of using StrLComp instead of StrComp? (I just noticed this problem after exiting my linux machine) If only a substring is used there must be unnecessary cache misses, e.g.: TextOut(DC, 0, 0, 'very long text', 4); Only 'very' is draw and set in layout text

Done in 15763.

Mattias

Reply by email