Bug 574618 - [Cocoa] Scrolling a Table with SWT.MeasureItem+SWT.PaintItem is very slow
Summary: [Cocoa] Scrolling a Table with SWT.MeasureItem+SWT.PaintItem is very slow
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.21   Edit
Hardware: Macintosh Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact: Alexandr Miloslavskiy CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-07-02 06:43 EDT by Alexandr Miloslavskiy CLA
Modified: 2021-12-17 18:18 EST (History)
3 users (show)

See Also:


Attachments
Test snippet (8.42 KB, application/octet-stream)
2021-07-02 07:51 EDT, Alexandr Miloslavskiy CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alexandr Miloslavskiy CLA 2021-07-02 06:43:45 EDT
The steps to reproduce are basically:
1) Have a Table with many columns and rows (so that 200 or more subitems are
   visible)
2) Have 'SWT.MeasureItem' and 'SWT.PaintItem' listeners that merely
   'GC.drawText()' and 'GC.textExtent()'
3) Scroll the Table by holding the down arrow key.
4) While the next item is on screen, moving between items is fast.
5) When next item is not on screen, so that the Table needs to be scrolled,
   moving between items becomes quite slow.

I have studied and found that cocoa implementations of 'GC.drawText()' and 'GC.textExtent()' are quite slow.
Comment 1 Alexandr Miloslavskiy CLA 2021-07-02 07:51:09 EDT
Created attachment 286717 [details]
Test snippet

This is the test snippet I'm currently using.

I'm already investigating, hopefully I will be able to make a patch.
Comment 2 Thomas Wolf CLA 2021-07-02 08:05:40 EDT
Is this also a problem for Trees? Is it also a problem for scrolling with the mouse? EGit is considering using owner-drawing in the staging view (unstaged items). See [1]. 

[1] https://git.eclipse.org/r/c/egit/egit/+/182394/5/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java#2252
Comment 3 Thomas Wolf CLA 2021-07-02 08:09:06 EDT
As for gc.textExtent() and gc.drawText() being slow on Mac, also see bug 458872.
Comment 4 Alexandr Miloslavskiy CLA 2021-07-02 08:13:18 EDT
> Is this also a problem for Trees?

Yes, when changing snippet to use Tree instead of Table, the same slow scrolling is observed.

> Is it also a problem for scrolling with the mouse?

Yes.

Both answers are expected because the underlying problem is that text-based GC operations are slow in SWT.
Comment 5 Alexandr Miloslavskiy CLA 2021-07-02 08:15:04 EDT
(In reply to Thomas Wolf from comment #3)
> also see bug 458872.

Thanks for the tip! Added it to "See Also"
Comment 6 Eclipse Genie CLA 2021-07-21 15:10:01 EDT
New Gerrit change created: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/183253
Comment 7 Alexandr Miloslavskiy CLA 2021-07-21 15:27:21 EDT
The patch addresses two issues:

1) macOS 10.14 and 10.15: view caching was not enabled. When scrolling
   partially, everything was repainted instead of painting newly scrolled
   area and moving the area that is still in view.

2) macOS 11: due to new macOS defaults, entire 512x512px tiles are painted
   even when the change is small. For example, selecting a different row in
   Table only needs to paint to rows (deselect old and select new), but
   instead 512x512 blocks are painted, which includes a lot of rows.

For the developer's reference, here's what happens in (2) on macOS 11:
----------------------------------------------------------
1) 'NSViewUsesAutomaticLayerBackingStores' is set be default on macOS 11.
2) This setting causes '-[NSCGSWindow setUsesAutomaticContentsFormat:true]'
3) This sets flag in 0x20 'NSCGSWindow::0x98' and calls '-[NSCGSWindow _updateLayerContext]'.
4) This causes 'kCAContentsFormatAutomatic' to be passed to '-[CAContext setContentsFormat:]'.
   QuartzCore`-[CAContext setContentsFormat:] + 60
   AppKit`-[NSCGSWindow _updateLayerContext] + 79
   AppKit`-[NSCGSWindow setUsesAutomaticContentsFormat:] + 62
   AppKit`-[NSWindow setDepthLimit:] + 163
   AppKit`-[NSWindow _commonAwake] + 1980
   AppKit`-[NSWindow _commonInitFrame:styleMask:backing:defer:] + 787
   AppKit`-[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1177
   AppKit`-[NSWindow initWithContentRect:styleMask:backing:defer:] + 42

5) This sets 6 in 'CAContext::0x118' (6 is 'kCAContentsFormatAutomatic')
6) This causes 'default_contents_image_format()' to set 6 in 'CALayer::0x2c'.
   QuartzCore`default_contents_image_format(CA::Layer*) + 199
   QuartzCore`-[CALayer _display] + 1175

7) This causes '-[CALayer _display]' to select image format 0x24.
8) 0x24 is passed as argument to 'CABackingStoreUpdate_()', which takes
   a special path.
9) 'CABackingStoreUpdate_()' creates a special context with 'CGDisplayListContextCreate()'
   CoreGraphics`CGDisplayListContextCreate
   QuartzCore`CACGContextEvaluator::CACGContextEvaluator(unsigned long, unsigned long, CGColorSpace*) + 154
   QuartzCore`CABackingStoreUpdate_ + 151
   QuartzCore`invocation function for block in CA::Layer::display_() + 53
   QuartzCore`-[CALayer _display] + 2183

10) Clip region is not applied on that special path.
   On the regular path, clip region is applied in
   'CABackingStoreBeginUpdate_()' with code:
       CGContextReplacePathWithShapePath(context, CABackingStore::0x1c0);
       CGContextClip(context);

Judging from 'CG::DisplayList::executeEntries()', this special context doesn't really render things, but instead remembers performed operations to render them later. This probably explains why it ignores clip region: to "virtually" render everything and maybe decide what needs to be actually painted later.
Comment 8 Alexandr Miloslavskiy CLA 2021-07-21 15:29:07 EDT
The patch is likely to solve similar problems in other Controls.
The patch does NOT address problems with slow 'GC.drawText()'.
Comment 9 Alexandr Miloslavskiy CLA 2021-07-22 20:27:06 EDT
Updated the patch to fix another bug with focus rings.

This other bug is not resulting from the patch and is also seen when running with JDK15 (because it is compiled for macOS sdk 10.14)
Comment 11 Alexandr Miloslavskiy CLA 2021-12-17 18:18:42 EST
Verified with current 'master' using attached test snippet.