Qt5.6: high DPI and OpenGL support (OpenSceneGraph)

I have a minimal application that uses QOpenGLWidget , which integrates the OpenGL wrapper library (OpenSceneGraph). I'm trying to figure out how to properly use Qt5.6 support for high DPI screens when working with OpenGL content as I use.

The function My main() has the following code:

 int main(int argc, char** argv) { // DPI support is on QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); QMainWindow window; // QOpenGLWidget with OpenSceneGraph content QtOSGWidget* widget = new QtOSGWidget(); window.setCentralWidget(widget); window.show(); return app.exec(); } 

QtOSGWidget derived from a QOpenGLWidget with the contents of OpenSceneGraph: I use osgViewer::GraphicsWindowEmbedded to render my simple scene.

To combine OSG with Qt, I override the *GL() methods: paintGL() , resizeGL() and initializeGL() . I follow the Qt docs about what each of the *GL() methods should contain, i.e.:

  • paintGL() checks to see if the viewer is being updated.
  • resizeGL() ensures the correct resizing of the graphics window (along with the camera and viewport);
  • initializeGL() provides initialization of OpenGL state.
  • I also redefined Qt mouse events to pass events to OSG

When I run my example on the screen with normal resolution or using QApplication::setAttribute(Qt::AA_DisableHighDpiScaling); , the scene looks like this:

cylinder example - high DPI support disabled

In addition, when I manipulate the camera view, the coordinates of the mouse are fixed correctly.

However, when I set the high DPI option, this is what I get:

high DPI enabled

Mouse coordinates for events are also scaled and not passed to the OpenSceneGraph event handler.

As you can see, the size of the graphics window is not scaled by Qt. This is probably due to the way I set the size:

 virtual void resizeGL( int width, int height ) { // resize event is passed to OSG this->getEventQueue()->windowResize(this->x(), this->y(), width, height); // graphics window resize m_graphicsWindow->resized(this->x(), this->y(), width, height); // camera viewport osg::Camera* camera = m_viewer->getCamera(); camera->setViewport(0, 0, this->width(), this->height()); } 

This size does not scale Qt. The same thing happens with the coordinates of the mouse events.

My question is: is there a way to find out what size the scaling will be done to properly execute resizeGL() ? Or how to solve the problem?

Update / solution using manual scaling : thanks to @AlexanderVX's answer, I figured out a scaling solution. First I need to know some DPI reference values ​​in sizes X and Y. Then I calculate the sliding coordinates based on this and pass them to my QtOSGWidget widget. So, the main() code should contain:

 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); int x = QApplication::desktop()->physicalDpiX(); int y = QApplication::desktop()->physicalDpiY(); // values 284 and 285 are the reference values double scaleX = 284.0/double(x); double scaleY = 285.0/double(y); QMainWindow window; QtOSGWidget* widget = new QtOSGWidget(scaleX, scaleY, &window); // etc. 

Then, whenever I access the calibration functions that need to be passed to OpenSceneGraph (OpenGL), I need to do the scaling, for example:

 // resizeGL example this->getEventQueue()->windowResize(this->x()*m_scaleX, this->y() * m_scaleY, width*m_scaleX, height*m_scaleY); // mouse event example this->getEventQueue()->mouseButtonPress(event->x()*m_scaleX, event->y()*m_scaleY, button); 

Final update : since the target platform of my application is Windows 7-10, it makes sense to stick to the proposed answer @AlexanderV (second part), i.e. use SetProcessDPIAware() .

+3
source share
1 answer

Is there any way to know what size will be performed by scaling what to do resizeGL() correctly?

First find the monitor:

  // relative to widget int screenNum = QApplication::desktop()->screenNumber(pWidget); 

or maybe

  // relative to global screen position int screenNum = QApplication::desktop()->screenNumber(pWidget->topLeft()); 

and this gives us a pointer to QScreen :

  QScreen* pScreen = QApplication::desktop()->screen(screenNum); 

from which you can read many characteristics of the screen, including the "physical dot per inch", which allows us to judge how many pixels per inch:

  qreal pxPerInch = pScreen->physicalDotsPerInch(); 

With pixels per inch, you can programmatically scale your drawing code. Determine how β€œnormal” the density is and then scale in proportion to the density found on the physical device. Of course, this approach is more suitable for accurate graphics. Keep in mind both physicalDotPerInch () and devicePixelRatio () , though.

  qreal scaleFactor = pScreen->physicalDotsPerInch() / normalPxPerInch; 

Or how to solve the problem?

However, with widgets and a common graphical interface, it is often easier to let Qt / system scale the entire user interface. Qt Documentation: High DPI indicators .

If Windows is at least Vista or higher and setting Qt for high DPI sounds more complicated, then there is a shortcut that I take and it helps me, although Qt complains about the log: "SetProcessDpiAwareness failed: "COM error 0xffffffff80070005 (Unknown error 0x0ffffffff80070005)" " I call this function from main() to the event loop: SetProcessDPIAware () , and then the entire user interface looks the same no matter what monitor density I use with Qt 5.5, but there is also a SetProcessDpiAwareness () function . I use SetProcessDPIAware because it is available with Windows Vista, but SetProcessDpiAwareness is only available with Windows 8.1. Thus, the decision may depend on potential customer systems.

A "shortcut":

 int main(int argc, char** argv) { // DPI support is on // QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // on Windows? ::SetProcessDPIAware(); // MSDN suggests not to use SetProcessDPIAware() as it is obsolete and may not be available. // But it works with widgets. QApplication app(argc, argv); QMainWindow window; // QOpenGLWidget with OpenSceneGraph content QtOSGWidget* widget = new QtOSGWidget(); window.setCentralWidget(widget); window.show(); return app.exec(); } 
+2
source

All Articles