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

OpenGL window does not relayout correctly after dpi change.

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 6.3.1, 6.6.1, 6.7.0
    • GUI: High-DPI
    • None
    • Windows 11, two monitors both 1080p, one at 125% and the other at 100%.
    • Windows

    Description

      Sometimes when moving a window across two monitors with different DPIs a window which contains an OpenGL widget, the window gets incorrect bounds. This shows by either having block borders or the content getting clipped.

      Example code:

      #include <QApplication>
      #include <QOpenGLWidget>
      #include <QMainWindow>
      #include <QGridLayout>
      #include <QOpenGLPaintDevice>
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      public:
          MainWindow() {
              auto* widget = new QWidget;
              auto* layout = new QGridLayout;
              auto* openGLWidget = new QOpenGLWidget;        
      
              setCentralWidget(widget);
              setStyleSheet("background: red");
              widget->setLayout(layout);
              layout->addWidget(openGLWidget);
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          auto* window = new MainWindow;
          window->show();
          return a.exec();
      }
      
      #include "main.moc"
      

      Normal screenshot:

      Bugged state screenshots:

      Reproduction steps:

      In this video I reproduce the bug by dragging the border across two monitors with different DPI's (125% & 100%).

      https://drive.google.com/file/d/1e7YDHMjwfVC6diTvfocn-lbU8ePtJR60/view?usp=sharing

      It is also possible to reproduce this using windows snap, however I find it much harder to consistently achieve.

       

      When reproducing the bug I also noticed that once in this state the bug persists until a resize occurs, moving the window kept the bad bounds.

      I also noticed that whether or not there was an OpenGL widget, the last resizeEvent (when windows changes the DPI as it's a different screen) has a different event->size() to this->size(). Calling this->size() seems to provide the new updated size, but the events size seemingly doesn't reflect the updated DPI and the docs say they should be the same.

      A somewhat fix we found was to add this into the MainWindow class:

          void resizeEvent(QResizeEvent* event) override {
              QMainWindow::resizeEvent(event);
              if (event->size() != this->size()) {
                  QSize diff = event->size() - event->oldSize();
                  QSize offset = QSize(std::clamp(diff.width(), -1, 1), std::clamp(diff.height(), -1, 1));
                  resize(this->size() + offset);
              }
          } 

      For the majority of cases this resolved the issue as it forced a resize to occur (resizing with the same size gets ignored), though with a bit of flickering. It also didn't fix the cases where the sizes happened to stay the same after the DPI change.

       

      Attachments

        1. image-2024-04-03-16-40-38-050.png
          26 kB
          Daniel Herald
        2. image-2024-04-03-16-41-03-430.png
          24 kB
          Daniel Herald
        3. image-2024-04-03-16-41-14-347.png
          28 kB
          Daniel Herald
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            sorvig Morten Sørvig
            danielh Daniel Herald
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes