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

        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