Bug 570534 - [BigSur] Control#redraw(int, int, int, int, boolean) causes full area rendering .
Summary: [BigSur] Control#redraw(int, int, int, int, boolean) causes full area renderi...
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.19   Edit
Hardware: PC Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 575659 569361
  Show dependency tree
 
Reported: 2021-01-20 21:03 EST by Jeeeyul Lee CLA
Modified: 2022-11-09 12:57 EST (History)
8 users (show)

See Also:


Attachments
Snippet to reproduce the problem (1.81 KB, application/octet-stream)
2022-11-09 12:54 EST, Mario Marinato CLA
no flags Details
The shell created by the snippet (27.90 KB, image/png)
2022-11-09 12:54 EST, Mario Marinato CLA
no flags Details
The coalesced redrawn region (10.49 KB, image/png)
2022-11-09 12:55 EST, Mario Marinato CLA
no flags Details
The redrawn regions, not coalesced (28.80 KB, image/png)
2022-11-09 12:55 EST, Mario Marinato CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jeeeyul Lee CLA 2021-01-20 21:03:33 EST
[BigSur] Control#redraw(int, int, int, int, boolean) causes full area rendering .


Steps to reproduce problem:

1. Create a canvas.
2. Add a SWT.Paint listener on it.
3. invoke canvas.redraw(0, 0, 10, 10, false);

Expected Result:

1. Dispatched Paint Event should have a clipped rendering context with 0, 0, 10, 10

Actual Result:

1. Paint Event did not have clipped rendering context.

- - -

It causes serious performance problem since we don't have correct dirty region information, so we have to paint entire region. (StyledText, GEF Figure Canvas)

- - -

This symptom occur on NSView in the same way.

1. NSView.setNeedsDisplayInRect(NSMakeRect(0, 0, 50, 50)); to invoke render.
2. NSView.drawRect() did invoked with entire client region.

[NSView.getRectsBeingDrawn:count:to] seems to return wrong information.

- - -

I found a clue from https://developer.apple.com/forums/thread/663256

- - -

And I will try to explain my inference:

1. On BigSur, A NSView may not have it's own independent buffer automatically.
2. macOS automatically gives layers(buffer) to NSViews those are meet with some specific condition. (eg, has scrolling pane)

Unified layer may can affects rendering order (eg, painting order and compositing order), so, we may can explains many SWT rendering issues about BigSur also.


- - -

When I give a explicit layer and it's content type, wrong dirty region problem is gone.

aView.wantsLayer = YES;
aView.layer.contentsFormat = kCAContentsFormatRGBA8Uint;


So we may have to give explicit layer(as a independent drawing buffer) to e controls those have  paint listeners.

- - -

I tried to create a patch for it, and it works.

However I can't sure whether did I do it properly.

Basically I added NSView.setContentsFormat(NSString) and kCAContentsFormatRGBA8Uint constant to OS.java

1. I had to edit QuartzCoreFull.bridgesupport. I knew that I had to generate it, there was no luck. documentation about it was not enough to me.
2. I had to edit `OS.h` to include QuartzCore
3. I had to make_macosx.mak to add "-framework QuartzCore" to LFLAGS.
4. I did generate using Mac Generator.
5. I did build native libraries.
6. I added layer configuration code for Canvas initialization.

- - -

Please give me some hints about the walk flow about SWT/Cocoa JNI, so I can make a Gerrit.


Thanks.
Comment 1 Lakshmi P Shanmugam CLA 2021-01-22 09:09:46 EST
(In reply to Jeeeyul Lee from comment #0)

> Basically I added NSView.setContentsFormat(NSString) and
> kCAContentsFormatRGBA8Uint constant to OS.java
> 
> 1. I had to edit QuartzCoreFull.bridgesupport. I knew that I had to generate
> it, there was no luck. documentation about it was not enough to me.

@Jeeeyul, Thanks for looking into this.
The bridgesupport files were generated for macOS 10.11 and so they don't have the newer APIs.
I suggest to not edit QuartzCoreFull.bridgesupport and add the selector to OS.java and Selector.java under /** 10.12 selector */
Also, please add version check (10.12) where the code is used.

> 2. I had to edit `OS.h` to include QuartzCore
> 3. I had to make_macosx.mak to add "-framework QuartzCore" to LFLAGS.

> 4. I did generate using Mac Generator.
> 5. I did build native libraries.
> 6. I added layer configuration code for Canvas initialization.
> 
> - - -
> 
> Please give me some hints about the walk flow about SWT/Cocoa JNI, so I can
> make a Gerrit.
> 

You should install the SWT tools. Links to jni docs:
https://www.eclipse.org/swt/jnigen.php
https://www.eclipse.org/swt/macgen.php

Looks like you have made the required changes, please push the changes in SWT source repository to gerrit for review.
Comment 2 Lakshmi P Shanmugam CLA 2021-02-15 17:32:55 EST
(In reply to Lakshmi P Shanmugam from comment #1)
> (In reply to Jeeeyul Lee from comment #0)
> > 
> > Please give me some hints about the walk flow about SWT/Cocoa JNI, so I can
> > make a Gerrit.
> > 
> 
> You should install the SWT tools. Links to jni docs:
> https://www.eclipse.org/swt/jnigen.php
> https://www.eclipse.org/swt/macgen.php
> 
> Looks like you have made the required changes, please push the changes in
> SWT source repository to gerrit for review.

@Jeeyul, let us know if you need any help with the gerrit patch.
Comment 3 Alexandr Miloslavskiy CLA 2022-04-07 00:03:17 EDT
Judging from the description, it may be resolved already via Bug 574618.
Comment 4 Mario Marinato CLA 2022-11-09 12:53:17 EST
I've been facing a redrawing problem on macOS, and I think it may be related to this bug.  I'm attaching a snippet and some screenshots to illustrate my case.

This snippet creates a shell with two composites and a button, vertically (see attachment "Bug570534_Shell.png")

The two composites have PaintListeners attached to them, which fill them with green and blue, respectively.

When the button is clicked, it calls redraw() on the first composite.

The problem is that both PaintListeners are called.  And there's a twist:  if the PaintListeners use random colors, only the first composite effectively changes.

Using Apple's Quartz Debug app, which highlights regions that will be redrawn, I could confirm that a big, coalesced region is redrawn when the button is clicked (see attachment "Bug570534_Coalesced.png").  Everything inside this region is redrawn.

I discovered that if the composites are created with the SWT.BORDER style, the regions are not coalesced (see attachement "Bug570534_NotCoalesced.png").

Tinkering with SWT's source code, I modified Composite.createHandle() method, removing the if that checks "(scrolled || hasBorder ())" and then everything works as expected.

I believe it confirms Jeeeyul's inference that "macOS automatically gives layers(buffer) to NSViews those are meet with some specific condition. (eg, has scrolling pane)", because by removing the if every Composite gets its own NSScrollView.

My tests were made using Eclipse 2022-09 on macOS 13 - Ventura, so Bug 574618 did not solve it, as Alexandr Miloslavskiy suspected.
Comment 5 Mario Marinato CLA 2022-11-09 12:54:15 EST
Created attachment 288823 [details]
Snippet to reproduce the problem
Comment 6 Mario Marinato CLA 2022-11-09 12:54:48 EST
Created attachment 288824 [details]
The shell created by the snippet
Comment 7 Mario Marinato CLA 2022-11-09 12:55:22 EST
Created attachment 288825 [details]
The coalesced redrawn region
Comment 8 Mario Marinato CLA 2022-11-09 12:55:52 EST
Created attachment 288826 [details]
The redrawn regions, not coalesced