Skip to content

Support fractional device pixel ratio in native Qt widget

Elvis Stansvik requested to merge estan/vtk:fractional-dpi-scaling into master

When fractional DPI scaling is used, the VTK render window / interactor has the wrong size because it's calculated from devicePixelRatio() which is an integer API returning a rounded value.

Starting with Qt 5.6, there's a devicePixelRatioF() API that can return a non-integer device pixel ratio. This makes sure the new API is used in QVTKOpenGLNativeWidget, when available.

The problem was first reported by me on the VTK developers mailing list:

https://www.vtk.org/pipermail/vtk-developers/2018-February/035826.html

Test Program (Sphere.cxx)

#include <vtkSphereSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkGenericOpenGLRenderWindow.h>

#include <QApplication>
#include <QPointer>
#include <QSurfaceFormat>

#include <QVTKOpenGLNativeWidget.h>

int main(int argc, char *argv[])
{
  QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());

  QApplication app(argc, argv);

  vtkNew<vtkGenericOpenGLRenderWindow> window;
  QPointer<QVTKOpenGLNativeWidget> widget = new QVTKOpenGLNativeWidget();
  widget->SetRenderWindow(window.Get());

  // Create a sphere
  vtkSmartPointer<vtkSphereSource> sphereSource = 
    vtkSmartPointer<vtkSphereSource>::New();
  sphereSource->SetCenter(0.0, 0.0, 0.0);
  sphereSource->SetRadius(5.0);

  vtkSmartPointer<vtkPolyDataMapper> mapper = 
    vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputConnection(sphereSource->GetOutputPort());

  vtkSmartPointer<vtkActor> actor = 
    vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);

  vtkSmartPointer<vtkRenderer> renderer = 
    vtkSmartPointer<vtkRenderer>::New();
  window->AddRenderer(renderer);

  renderer->AddActor(actor);

  widget->resize(300, 300);
  widget->show();

  return app.exec();
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
 
PROJECT(dpibug)
 
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
 
add_executable(Sphere MACOSX_BUNDLE Sphere.cxx)
 
if(VTK_LIBRARIES)
  target_link_libraries(Sphere ${VTK_LIBRARIES})
else()
  target_link_libraries(Sphere vtkHybrid vtkWidgets)
endif()

Output Before (Qt 5.9.5, run with QT_SCREEN_SCALE_FACTORS=1.4 ./Sphere)

before

Notice how the render window has the wrong size.

Output After (Qt 5.9.5, run with QT_SCREEN_SCALE_FACTORS=1.4 ./Sphere)

after

The render window is now the correct size.

Edited by Elvis Stansvik

Merge request reports