Skip to content

Add setting to set the world renderer canvas scale factor automatically #16479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

Rinzwind
Copy link
Contributor

This pull request adds a setting to let the World’s OSWorldRenderer set the class’s #canvasScaleFactor automatically when performing #checkForNewScreenSize. On Macs with two displays, one of which is a ‘Retina display’ and one which is not, enabling the setting should make the canvas scale factor be changed automatically from 2 to 1 when moving the Pharo window from the ‘Retina display’ to the other one and vice-versa, as described in issue #16046. This, and the effect on Windows and Linux, may however need some further testing. The setting is by default disabled.

@Rinzwind Rinzwind force-pushed the setting-autosetcanvasscalefactor branch from 58cde82 to 77af184 Compare April 18, 2024 07:20
@MarcusDenker MarcusDenker reopened this Apr 19, 2024
@MarcusDenker MarcusDenker reopened this Apr 19, 2024
@jecisc jecisc merged commit c6e6546 into pharo-project:Pharo12 Apr 21, 2024
Rinzwind added a commit to Rinzwind/pharo that referenced this pull request Apr 23, 2024
…o set the world renderer canvas scale factor automatically”) to Pharo 11.
@Rinzwind
Copy link
Contributor Author

@guillep
Copy link
Member

guillep commented Apr 24, 2024

Hi @Rinzwind !

I tested it on Mac and fonts and icons become very slick :)

Now, @DurieuxPol and @estebanlm tested on windows and linux respectively, Esteban with a 4k monitor, and they did not see any change.

So, two things:

  • any idea of where to start debugging this?
  • would you recommend turning this ON by default? Or is there some drawback/potential risk we may look at?

G

@Rinzwind
Copy link
Contributor Author

Rinzwind commented Apr 24, 2024

It depends on whether setting the scale factor to 2 manually does work for them:

OSWorldRenderer autoSetCanvasScaleFactor: false; canvasScaleFactor: 2

If it does, then it’s the setting of the scale factor in #checkForNewScreenSize on OSWorldRenderer that needs to be improved; for that it would help to have the result of the following:

World worldState worldRenderer in: [ :renderer |
	{ renderer osWindowRenderer outputExtent. renderer windowExtent.
		World scaleFactor. renderer windowScaleFactor } ]

Leaving #autoSetCanvasScaleFactor disabled by default seemed better as it needs further testing. Those that want to enable it in every new image can use ‘Save to disk’ as shown on the screenshot above so that #resumeSystemSettings for SystemSettingsPersistence applies the saved value.

@Rinzwind
Copy link
Contributor Author

Now that there’s a new development version, I would suggest to have that one set #autoSetCanvasScaleFactor enabled by default to test it, I have opened a pull request for that: pull request #16529.

@Rinzwind
Copy link
Contributor Author

@guillep, @DurieuxPol and @estebanlm: I was wondering whether you tried setting the scale factor to 2 manually? What’s the result for the second snippet (so the value for #outputExtent and so on)?

@estebanlm
Copy link
Member

I juts tried:

OSWorldRenderer 
	autoSetCanvasScaleFactor: false; 
	canvasScaleFactor: 2.

This is the result:

{(1834@1237). (1834@1237). 1.0. 1}

@guillep
Copy link
Member

guillep commented May 22, 2024

In my machine, no matter what is the "canvas scale factor", with two different screens (a dell monitor and the mac retina screen) I have the following:

World worldState worldRenderer in: [ :renderer |
	{ renderer osWindowRenderer outputExtent. renderer windowExtent.
		World scaleFactor. renderer windowScaleFactor } ].
==> 
{(3840@1932). (1920@966). 1.0. 1}. 
{(3024@1832). (1512@916). 1.0. 1}.

Now, if I change the canvas scale factor from 1 to 2, images get "neater".
Doing that does not change the output of the script:

{(3840@1932). (1920@966). 1.0. 1}. 
{(3024@1832). (1512@916). 1.0. 1}.

Something I noticed too is that the display scale factor and the canvas scale factor have strange effects when mixed.
And from a user standpoint, it isn't easy to get the thing right :)

Scenario 1: Display scale factor = 1

  • with canvas scale factor = 1: fonts and icons are blurry
  • with canvas scale factor = 2: both icons and fonts are nice
  • with canvas scale factor = 3: icons are blurry, fonts are nice with imperfections
  • with canvas scale factor = 4: icons are blurry, fonts are nice with imperfections, worse than value=3

Scenario 2: change the Display scale factor to 2 (to zoom, for example for a demo)

  • with canvas scale factor = 1: fonts and icons are super blurry
  • with canvas scale factor = 2: icons are nice, fonts are a bit blurry
  • with canvas scale factor = 3: icons are blurry, fonts are nice but I have some pixelation/imperfections
  • with canvas scale factor = 4: icons are blurry, fonts are nice

Understanding the canvas vs display scale factor relation

@Rinzwind may I conclude that

  • fonts work well when the following holds?

(canvasScaleFactor / displayScaleFactor) = (outputExtent / windowExtent)

what is the error margin here if the division is not an exact number?

  • icons should also consider the following ratio (canvasScaleFactor / displayScaleFactor)? It looks like they are only considering the canvasScaleFactor...

More info required?

  • could it happen that the (canvasScaleFactor / displayScaleFactor) ratio is not a round number? I see that in the code there is a min that could give fishy results there :)
    (windowRenderer outputExtent / self windowExtent) min * self screenScaleFactor

  • What other info can we get? what else can we ask people to push this further?

  • We need people with strange displays?
    I've noticed that in both my screens (canvasScaleFactor / displayScaleFactor) = 2, which seems like the happiest case :)

@guillep
Copy link
Member

guillep commented May 22, 2024

Some more info here. While checking how automatic canvas scale factor is computed, I see it uses screenScaleFactor, which boils down to:

screenScaleFactor
	self fetchDPIAndRaiseEvent.
	^ screenScaleFactor

fetchDPIAndRaiseEvent
    self fetchDPI ...

The thing is, this last method fetchDPI has a special case for Mac os!!

fetchDPI
	Smalltalk os isMacOSX ifTrue: [
		diagonalDPI := verticalDPI := horizontalDPI := self screenScaleFactorBaseDPI.
		screenScaleFactor := 1.0.
		^ false
	].
	"Then code for the rest of the platforms!"

EDIT: When commenting that conditional, pharo zooms up like using a 2x display scale factor :)

@Ducasse
Copy link
Member

Ducasse commented May 22, 2024

I got {(2890@1832). (1445@916). 1.0. 1}
for OSWorldRenderer autoSetCanvasScaleFactor: false; canvasScaleFactor: 2

@Rinzwind
Copy link
Contributor Author

Rinzwind commented May 22, 2024

There seems to be some confusion over the two snippets that I gave: the values in the array given by the second snippet do not change when the canvas scale factor is changed. It’s the other way around: those are the values used in the automatic setting of the canvas scale factor in #checkForNewScreenSize on OSWorldRenderer.

The following simplification might help clarify some of the questions:

arguments bind: [ :formExtent :canvasScale |
	form := Form extent: formExtent depth: 32.
	(ScalingCanvas formCanvas: form getCanvas scale: canvasScale)
		fullDraw: World.
	(window := OSWindow new)
		extent: 300@150.
	(window newFormRenderer: form) updateAll ]

Using { 300@150. 1 } for arguments gives what Pharo looks like by default:

Using { 200@200. 1 } shows the Form being stretched horizontally and squished vertically to fill the window:

That stretching is used when the World’s #scaleFactor (called ‘Display scale factor’ in the Settings Browser, not to be confused with WorldMorph’s #displayScaleFactor) is set to 2 to make the window appear zoomed in by conversely halving the extent of the Form, so using { 150@75. 1 } as arguments:

What may not immediately be obvious is that the Form is actually also stretched in the first window, as on a ‘Retina display’, the extent in pixels of the window is 600@300; so when using { 600@300. 1 } as arguments, there’s no stretching, but the window appears zoomed out:

When OSWorldRenderer’s #canvasScaleFactor is set to 2, the Form’s extent is similarly multiplied by 2, but the World is drawn on the Form using a ScalingCanvas that also multiplies all coordinates by 2 so that it won’t appear zoomed out, the Form’s extra pixels are used to draw images and text with more detail, as when using { 600@300. 2 } as arguments:

Setting both the World’s #scaleFactor and OSWorldRenderer’s #canvasScaleFactor to 2 is like using { 300@150. 2 } so the Form is again stretched to fill the window:

The stretching can be avoided again by setting the World’s #scaleFactor to 2 and OSWorldRenderer’s #canvasScaleFactor to 4, like when using { 600@300. 4 } (the menu icon being drawn with less detail in this case is due to the icon pack not having icons at scale 4, likewise for the background logo as provided in pull request #16305):

Note that when not using a ‘Retina display’ to view the above screenshots, you’ll presumably need to click them to zoom in to see some of the differences.

PS: do not try using { 450@225. 1.5 } or similar arguments in which the second one is not an integer, it’s not supported and will cause morphs to have a draw error. If you just missed the first ‘not’ in that sentence, do: World allMorphs do: #resumeAfterDrawError.

Erratum: for the second screenshot, the Form is described as being squished vertically, but it’s actually stretched vertically as well, just not by as much as horizontally, from 200 pixels vertically in the Form to 300 in the window. An example of the Form being squished vertically is when using { 600@400. 2 } as arguments.

@Rinzwind
Copy link
Contributor Author

As previously noted here, the icon pack currently lacks PNG files for the icons at scale 3 and 4. In pharo-icon-packs pull request #14, I replaced the scripts for generating the files by a new one that allows adding additional scales a bit more easily. I could open a pull request for adding PNG files at scale 3 and 4 if desired.

@Rinzwind
Copy link
Contributor Author

I tested this on Windows, albeit through a virtual machine on macOS. I used VirtualBox v7.0.20 with the corresponding Windows 11 development environment virtual machine that Microsoft provides, with 3D acceleration disabled in the settings for the virtual machine as per a forum post suggesting that as a solution for it failing to load. When the Windows display setting ‘Scale’ is set to 200%, enabling the automatic setting of the canvas scale factor causes the scale factor to be set to 2 as I would expect:

Demo.Windows.Set.Canvas.Scale.Factor.Automatically.mp4

An improvement that can be made is to take into account that on Windows the output height always seems to be odd, so the height of the world’s display form is currently always off by one: World worldState worldRenderer osWindowRenderer outputExtent is for example 2000@1399, while World display extent is 2000@1400. To adjust for that, #actualDisplaySize on OSWorldRenderer can be modified to:

actualDisplaySize

	^ self actualScreenSize * self canvasScaleFactor + (0 @ -1)

The following screenshots show the ‘full content’ of an inspector on a string before and after making the adjustment, the text on the first is slightly less sharp than on the second (click to zoom in):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants