Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-53022

HighDPi: Update scale factor setting for devicePixelRatio scaling (AA_EnableHighDpiScaling)

    XMLWordPrintable

Details

    Description

      Introduction

      The windowing system provides Qt with a per-display logical DPI value.

      For Windows, the possible values are:

      DPI percentage Registry Data Value
      Smaller 100% 96
      Medium 125% 120
      Larger 150% 144
      Extra Large 200% 192
      Custom 250% 240
      Custom 300% 288
      Custom 400% 384

      [ Physical DPI should not be used, since display data is unreliable and does not respect user settings ]

      The 100% DPI is the base DPI. The ratio between the actual DPI and the base DPI is the scale factor, aka devicePixelRatio.

      By default Qt reports the logical DPI via accessors such as QScreen::logicalDpi(), which applications can use to scale the UI. Fonts are automatically scaled. Historically the problem with this has been that not all UI elements respect the DPI.

      In addition Qt supports a mode (AA_EnableHighDpiScaling) where the entire UI is automatically scaled. The logicalDpi accessors then returns the base DPI in order to avoid duplicate scaling. The devicePixelRatio() accessors returns the UI scale factor, but unlike the “classic” mode these are much less used since the scaling is automatic.

      Example: For 200% (192 DPI) scaling on Windows we can configure Qt in one of two modes:
      1) 192@1x (default)
      2) 96@2x (AA_EnableHighDpiScaling)

      So far so good.

      Handling Fractional Scale Factors (like 250%)

      Fractional scale factors pose a challenge since Qt may not render correctly. One option is then to round the scale factor. When rounding we also have the option of adjusting the logical DPI (as reported to the app) to compensate for the rounding error.

      Rounding: We may round down or round up. The former gives visually small UI elements while the latter gives visually large UI elements. Qt currently rounds using qRound(), which for critical values like 250% means ‘up’. We should consider rounding down instead for .5.

      DPI: We can fix the DPI to be the base DPI or compensate for the inaccurate scale factor. The former makes the text size match the rest of the application UI, while the latter gives correct text size for the display. We should consider at least not rounding down here (don't present DPI values below the base DPI).

      Combined table of options for handling 250%: (AA_EnableHighDpiScaling mode only)
      1) 96@2.5x (correct UI and text size, maybe painting artifacts)
      2) 120@2x (small UI with larger text)
      3) 96@2x (small UI with matching text)
      4) 80@3x (large UI with smaller text) (5.6 behavor)
      5) 96@3x (large UI with matching text)

      QPA and QHighDpiScaling API

      Current Behavior

      • the platform screen provides the logical dpi
      • the platform screen provides the scale factor: qRound(logical-dpi / base-dpi)
      • qhighdpiscaling recovers the base-dpi by computing logical-dpi / scale factor.
      • qhighdpiscaling provides QScreen::logicalDpi(), which the base dpi for the main screen

      Suggested Changes:

      • (the platform screen continues to provide the logical dpi)
      • the platform screen provides the base-dpi instead of the scale factor
      • qhighdpiscaling computes the scale factor
      • qhighdpiscaling provides per-screen DPI for QScreen::logicalDpi().
      • round .5 scale factors down
      • perhaps compensate for rounding by increasing the reported logical DPI.

      Code (gerrit)
      https://codereview.qt-project.org/#/c/157173/
      https://codereview.qt-project.org/#/c/157174/
      https://codereview.qt-project.org/#/c/157175/

      Data Flow overview

      https://docs.google.com/drawings/d/1mnfCEwAL5Oo-xq4PbGwgofHq_t3Xm3xDguWNc_-YxzM

      New user interface (environment variables)

      Control how the scale factor is computed:
      QT_SCALE_FACTOR_ROUNDING_POLICY: Round, Ceil, Floor, RoundPreferFloor, PassThrough
      Control DPI adjustment:
      QT_DPI_ADJUSTMENT_POLICY: AdjustDpi, DontAdjustDpi, AdjustUpOnly

      tests/manual/highdpi has been updated with "--metrics" tests that displays the DPI and devicePixelRatio values.

      Platform Changes

      Windows: Windows already uses the logical DPI and can be trivially ported over from pixelDensity() to logicalBaseDpi().
      X11: Use logical DPI instead of physical DPI. QT_FONT_DPI is now respected:

      QT_FONT_DPI=160 QT_AUTO_SCREEN_SCALE_FACTOR=1./highdpi --metrics
      

      Can we possibly use config values from the desktop?

      GDK_SCALE=0.5 GDK_DPI_SCALE=0.5
      org.gnome.desktop.interface scaling-factor 
      org.gnome.desktop.interface text-scaling-factor
      

      Android The Android base DPI is 160, but QAndroidPlatformScreen::logicalDpi() computes the logical DPI values as density * 72. This might be throwing our scale factor calculations off. Implementing QAndroidPlatformScreen::logicalBaseDpi() and making it return 72 should correct this.

      Attachments

        1. qtbug53022.zip
          4 kB
        2. QTBUG-53022.diff
          64 kB
        3. Capture.PNG
          Capture.PNG
          85 kB

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              sorvig Morten Sørvig
              sorvig Morten Sørvig
              Votes:
              70 Vote for this issue
              Watchers:
              82 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: