4

I have a Qt application with a MainWindow.

I embed a QOpenGLWidget in it. Everything works fine until I start using an Apple Retina Display and run my app in High DPI mode: my QOpenGLWidget is just 1/4 of the size it was supposed to have (i.e., it only fills the bottom-left part of the area it is supposed to fill). This widget is displaying raw OpenGL data (actually, an OpenSceneGraph context)

What can I do to solve this?

genpfault
  • 51,148
  • 11
  • 85
  • 139
manatttta
  • 3,054
  • 4
  • 34
  • 72
  • What do you mean with 1/4 of the size? Do you mean the widget is not filling its designated area or the content in the GL view is not filling the widget area? What are you displaying in the widget? Raw OpenGL? Maybe you can illustrate with a screenshot. – ypnos Sep 12 '16 at 17:32
  • @ypnos changed the question to answer you. Thanks! :) – manatttta Sep 13 '16 at 09:13
  • I understand. Then you are providing the right answer to your question, while vicrucann is also hinting at the right problem. I suggest you accept your own answer. – ypnos Sep 13 '16 at 10:07

2 Answers2

6

Found out that the best option for now, for OpenGL related widgets and events, is to use the QPaintDevice::devicePixelRatio() (http://doc.qt.io/qt-5/qpaintdevice.html#devicePixelRatio)

This implies multiplying everything that uses pixel coordinates, i.e., mouse events, resizing events, and so on. Example:

void MyGLWidget::resizeGL(int width, int height) {
  width *= Application::desktop()->devicePixelRatio(); 
  height *= Application::desktop()->devicePixelRatio(); 

  ...
  // Continue with previous code

}

When running in low resolution mode in a Retina/HighDPI display, or when running in a regular display, this ratio is 1, so this seems portable to me.

manatttta
  • 3,054
  • 4
  • 34
  • 72
3

From Qt docs (section OsX),

Note: The scaling is not applied to Open GL windows

I didn't try this approach on Mac, but it helped with the same issue on my Windows machine. I'm not sure if it's the best solution, though, there could be easier. Try and see if it works.

The main idea is to scale up your OpenGL content sizes manually.

First, Define the amount of scale to be performed. You can use the characteristic of physical dot per inch:

QApplication app(argc, argv);    
int x = QApplication::desktop()->physicalDpiX();
int y = QApplication::desktop()->physicalDpiY();
// values 284 and 285 are the examples of reference values that we determined when DPI scaling was disabled
double scaleX = 284.0/double(x);
double scaleY = 285.0/double(y);

physicalDpi* makes possible to judge how many pixels we have for an inch. In order to define the scale, detect how much is reference value of density and then scale proportionally against the density of the physical device (next step).

Second, you have to use the scaleX and scaleY inside your QOpenGLWidget and make sure we manually scale:

  • sizes such as QOpenGLWidget::width() and QOpenGLWidget::height() will turn into this->width()*m_scaleX and this->height()*m_scaleY
  • mouse events coordinates, e.g., event->x()*m_scaleX and event->y()*m_scaleY
vicrucann
  • 1,703
  • 1
  • 24
  • 34
  • 1
    Thank you! based on your answer, I was able to find `devicePixelRatio`, which I think does directly what I want – manatttta Sep 13 '16 at 16:16
  • 1
    Glad it helped. The `devicePixelRation` looks neater indeed. I think the manually calculated `scaleX` and `scaleY` would be slightly more precise. For my machine they were 2.0 and ~2.02; while the `devicePixelRation` would provide the value of 2.0 for the both dimensions. Not sure how perceivable the difference is, but it's nice to have both options. – vicrucann Sep 13 '16 at 17:28