Bug 1374

Summary: Support High-DPI for JRE>8 AWT on Windows, MacOSX and Linux
Product: [JogAmp] Jogl Reporter: Sven Gothel <sgothel>
Component: awtAssignee: Sven Gothel <sgothel>
Severity: major CC: GMoubarak, maheshkurmi2010, marcel.au, rami.santina, Rayan, wwalker3
Priority: P4    
Version: 2.5.0   
Hardware: pc_all   
OS: all   
Type: DEFECT SCM Refs:
c7858dc766cb9f76ac8f543796b1587a0f8f9279 24b75b2e91ec5f101b19fa24aa3804adb3819ebf 7ec068e0c95a230101450cc80031f76770a0cd49 ba83a59363023ba0cc314746d7864ccf2cdd4d7a
Workaround: ---
Bug Depends on:    
Bug Blocks: 1404, 1373    

Description Sven Gothel 2019-04-04 23:47:25 CEST
See Bug 1373 Comment 1


See AWT Java 9+ related: 'JEP 263: HiDPI Graphics on Windows and Linux' 


OSX uses a monitor related 'float[2] pixelScale', 
which we have adopted in bug 1120 and OSX High-DPI fix in bug 741.

Our groundwork for High-DPI support indeed has been done for bug 741.

AWT on OSX should work appropriately based on fixed for bug 741 and bug 1120.


AWT on Linux may use the environment variable GDK_SCALE for both dimensions.


AWT on Windows may use the DPI override.
Comment 2 Sven Gothel 2019-11-30 19:05:48 CET
    Bug 1363: Java 11: Don't use GraphicsDevice.getScaleFactor() on Java9+ [illegal reflective access]
    Use non-reflective method to get the pixel scale on Java9+
    It's now possible to use GraphicsConfiguration.getDefaultTransform()
    instead of using reflection to get the pixel scale, which eliminates an
    illegal reflective access warning.
    Orig patch by Wade Walker

    Bug 1363: Java 11: Use getPixelScale standard method even on Mac under Java9+
    Changed getPixelScale to use standard method, even on Mac
    Previously it used a Mac-specific method, but the new standard method of
    device.getDefaultConfiguration().getDefaultTransform() seems to work on
    Mac, so use it instead to avoid illegal reflective access warnings.
    Orig patch by Wade Walker.

    Bug 1363: Java 11: Resolve unsupported JAWTUtil.getMonitorDisplayID(..)
    Previous commits removed access to OSX's GraphicsDevice.getCGDisplayID()
    on Java9+, avoiding illegal reflective access.
    Here we JAWTUtil.getMonitorDisplayID(..) simply returns null
    if Java9 or !OSX, so the sole NewtFactory caller falls back
    to the alternative working solution.
    Orig patch Wade Walker:
        This was used on Mac OS only to create a MonitorDevice in
        NewtFactoryAWT. But there was a fallback method for creating
        MonitorDevice, and testing with TestGearsES2GLJPanelAWT shows that the
        fallback method seems to give identical results on Mac, so changed to
        just use the fallback method (which is now the only method) everywhere.
        This gets rid of an illegal reflective access.
Comment 3 Sven Gothel 2020-01-22 09:57:09 CET
While working on the whole tree of Bug 674, in particular Bug 1421, Bug 1422, Bug 1423 and Bug 1424 - I finally 'gave in' to this group of issues.


NEWT itself does not utilize a low level API for 'High-DPI' on certain platforms, namely Windows (GDI) and X11 (Xlib) on GNU/Linux and others.
Let's call these 'non native dpi scaling platforms', see Bug 1422.

Currently only on OSX, NEWT does handle its low level pixelScale from window-units to pixel-units.


In case a higher API tookit imposes some sort of 'dpi scale' 
on said 'non native dpi scaling platforms', both units gets scaled up:
- window units
- pixel units
(See Bug 1422)

In such cases using NEWT, we keep the imposed 'dpi scale'
agnostic to NEWT's native pixel-scale. Here the toolkit wrapper
like NewtCanvasAWT/SWT etc simply scale both units (window- and pixel)
while leaving NEWT's pixel-scale at 1f.


Therefor, we should not only handle such case for SWT (Bug 1422),
but also for the AWT and Swing toolkit in concert with using NEWT 
or plain using our direct AWT/Swing components.


I made some annotations earlier:

commit ba83a59363023ba0cc314746d7864ccf2cdd4d7a

    Bug 1374: NEWT/AWT: Annotation regarding general High-DPI for even non native DPI toolkit aware platforms (Linux, Windows)
    NEWT + NewtCanvasAWT:
    Maybe create "interface ScalableSurface.Upstream {
      void pixelScaleChangeNotify(final float[] curPixelScale, final float[] minPixelScale, final float[] maxPixelScale); }"
    to allow downstream to notify upstream ScalableSurface implementations like NEWT's Window to act accordingly.
    AWT GLCanvas: Add remark where to add the potential pixel scale.
Comment 4 Sven Gothel 2020-01-22 10:03:24 CET
(In reply to Sven Gothel from comment #3)

In particular, the following finding by Wade allows us to 
react on AWT's detected 'dpi scale' on the non native dpi scaling platforms:

    Bug 1363: Java 11: Use getPixelScale standard method even on Mac under Java9+
    Changed getPixelScale to use standard method, even on Mac
    Previously it used a Mac-specific method, but the new standard method of
    device.getDefaultConfiguration().getDefaultTransform() seems to work on
    Mac, so use it instead to avoid illegal reflective access warnings.
    Orig patch by Wade Walker.
Comment 5 maheshkurmi2010 2021-08-17 16:59:26 CEST
NewtAwtCanvas does't honour the pixelScale factor with swing layout on hidpi screens.
I added NewtAwtCanvas to JFrame with layout set to fill jframe on my surface pro 6(2k Resolution).But the canvas is taking quarter of space (that is because of pixelScaleFactor being 2).

I have two workarounds which work fine with JDK9 and windows 10.
1. Set layout as null, and manually scale dimesions of canvas by pixelScaleFactor.
2. Override getPreferredSize() ,getWidth() and getHeight() of NewtAwtCanvas and returned scaled dimensions.

Associated test snippet can be found here.

I came to conclusion that there is some layout related bug (not taking pixelScale factor in account) in NewTAwtCanvas implementation.
Comment 6 Sven Gothel 2023-01-24 20:53:14 CET
(In reply to maheshkurmi2010 from comment #5)

Copying from my forum post:

Great job Mahesh & Martin, Julien ..

I will consider this for 2.4.0 and thx for putting it in bugzilla as well.

One question, would you expect this pixel scale also being used 'naturally' by a NEWT window (w/o AWT)?
In such case we would have seamless pixel scale in NEWT, AWT or not (Note: reparenting is possible).
That probably means to read out the windowing system's pixel scale, 
potentially an environment variable or something.

When I added the pixel scale API .. well, it was mostly for NEWT and a client request :)

For NEWT, I was hoping ppl would use the monitor DPI info we provide to render the 
objects in the desired _size_. But who am I to judge and choose :)

So status is pixel scale works 
- using GLCanvas + GLJPanel
- using MacOS anyways (in NEWT too)
- missing for NEWT alone and with NewtCanvasAWT


- Our Bugzilla issue 1374 https://jogamp.org/bugzilla/show_bug.cgi?id=1374
- Martin's issue tracker https://github.com/jzy3d/jogl/issues/8
- This forum post https://forum.jogamp.org/GLcanvas-vs-NEWT-on-Hi-DPI-Screens-tp4041191p4042115.html
- Harvey's kicking https://forum.jogamp.org/Release-2-4-0-Progress-tp4042061p4042114.html
Comment 7 Sven Gothel 2023-01-24 22:58:55 CET
(In reply to Sven Gothel from comment #6)

'pixel scale', an arbitrary scaling factor, 
customized by the user, to please the eyes etc.
This in contrast to actual DPI naturally scaled rendering. 'true to scale'.


Generic way to determine the OS's windowing system's so called 'pixel scale':

  1a) GetDpiForMonitor(ddmon, MDT_EFFECTIVE_DPI, int *dpi_x, int *dpi_y)
    - NOTE: MDT_EFFECTIVE_DPI returns the custom user DPI setting
            according to user pixel scale setting (See above).
      This is not the true dpi, which NEWT already calculates
      per monitor by its size and resolution!
      (or attribute MDT_RAW_DPI here)

  or, if 1a is n/a

  1b) { dpi_x, dpi_y } = GetDeviceCaps(hdc, {LOGPIXELSX, LOGPIXELSX})
    - NOTE: Same for all monitors

  2) pixel_scale_x = (float)dpi_x / (float)96
     pixel_scale_y = (float)dpi_x / (float)96

  0) See https://wiki.archlinux.org/title/HiDPI

  1) KDE Plasme: How to read the setup value?
    - System Settings > Display and Monitor > Display Configuration > Global Scale
    - range 100 - x00% in 25% steps, i.e. float

  3) ... 
  9) GDK3+ GTK3/4: int GDK_SCALE, an environment variable 
    - NOTE: just an int type, not pleasing - from GDK3 world

  Note: JDK-17 seems to use GDK_SCALE only .. 
  Note: We might end up using an AWT Compatibility mode
        - and - a proper pixel scale mode (when and if available)
  Note: Needs more investigation.

Debugging w/ AWT:
  X) float J2D_UISCALE, an environment variable
    - Windows: value is kept as float
    - Unix: valye is cut-off to int (duh!)

.. to be continued ..
Comment 8 Sven Gothel 2023-01-24 23:25:50 CET
(In reply to Sven Gothel from comment #7)
Further re `AWT Compatibility mode`:
  - OpenJDK17 uses float on Windows and int on Unix/X11
  - IF we are able to retrieve the fractional pixel scale on Unix/X11, 
    such a compatibility mode might be required ..
Comment 9 Sven Gothel 2023-01-24 23:30:45 CET
(In reply to Sven Gothel from comment #8)

Q: Are non-integer scale factors supported?
A: Qt uses qreal in the API, and will allow setting non-integer scale factors via QT_SCALE_FACTOR. However, Qt does not guarantee that graphics and styles will be glitch-free in that case. Styles may break first: the fusion style is generally most scalable. The Qt platform plugins round the reported scale factors to the nearest integer.

Q: Could a scale factor of 0.5 allow me to work in device pixels on a 2x device?
A: That’s uncharted waters, but a possibility.



Note: Non-integer scale factors may cause significant scaling/painting artifacts.

Hence fractional scaling is supported, but also limited to same scale factor for both axis.
Comment 10 Sven Gothel 2023-01-27 11:48:51 CET
(In reply to Sven Gothel from comment #9)


On the MacOS and iOS, 
window units are used for the native UI component's position and size.
Here the surface size in pixel units = window-units-size * pixelScale.
This has been implemented already.

On Windows-GDI and X11,
pixel units are used for the native UI component's position and size.
Here we need to convert NEWT's window position and size 
to and from the pixel-size, i.e. window units = pixel-units / pixelScale.

Hence all NEWT window-unit position and size values must 
be appropriately converted from/to window-units on Windows and X11.

WIP ..
Comment 11 Sven Gothel 2023-01-31 07:57:33 CET
(In reply to Sven Gothel from comment #10)

NEWT's Soft-PixelScale done, used for X11 and Windows.

TODO: Test and fix utilization with AWT, i.e. NewtCanvasAWT
Comment 12 Sven Gothel 2023-02-01 12:08:13 CET
(In reply to Sven Gothel from comment #11)


Soft PixelScale on X11/Windows
.. we sort up end up with the requirement of mapping window-units  <-> pixel-units
taking the monitor viewport layout into account.

X11/Windows: A simple scaling of the window-units position is not suitable due to multiple monitors,
i.e. a window-units gap will be created and fullscreen/spanning coordinates will be wrong.

TODO: Implement seamless conversion of units incl. monitor viewport mapping
- X11, Windows: Recalculate monitor window-units viewport (native is pixels)
- MacOS Recalculate monitor pixel-units viewport (native is 'points', aka window-units)

Impact will be to have the ability to use either pixel- or window-units
for positioning and size and hence be fully platform independent.

Not sure how and when to complete this task and where to cut the line ..
This work asks to be resolved to have a nice solution though.

(Or it is 'Looking for a problem'? Discussion welcome)
Comment 13 Sven Gothel 2023-03-01 03:10:12 CET
(In reply to Sven Gothel from comment #12)

Mind notes in this forum thread
Comment 14 Sven Gothel 2023-07-12 01:13:05 CEST
Bug 1373 comment 3 details NEWT Soft-PixelScale.