Problem in VTK 8.2 with defaultFormat() and QVTKOpenGLWidget on Windows 10/Intel

Hi all,

I’m in the process of porting our application to VTK 8.2.0, so switching to the new QVTKOpenGLWidget where possible (and staying with QVTKOpenGLNativeWidget where necessary).

I’m struggling with a problem I’m seeing on Windows 10 / Intel graphics in the new QVTKOpenGLWidget.

When we add some actors to the renderer during runtime and then call Render(), the rendering seems ineffective (nothing shows up) until the user resizes the widget a little (causing a second render). The problem can be “worked around” of course by simply issuing two successive Render() calls, but this is obviously an ugly workaround.

The problem is not appearing on our Linux or macOS test machines, only on the Windows 10 machine (Intel graphics, though not sure that matters).

I started digging around, and it seems the problem can also be “fixed” by using a OpenGL compatibility profile instead of core profile (which is what QVTKOpenGLWidget::defaultFormat() returns).

So instead of

  QSurfaceFormat::setDefaultFormat(QVTKOpenGLWidget::defaultFormat());

if I do

  auto format = QVTKOpenGLWidget::defaultFormat();
  format.setProfile(QSurfaceFormat::CompatibilityProfile);
  QSurfaceFormat::setDefaultFormat(format);

that seems to “solve” the problem.

Below is a minimal test case where I simply show a QVTKOpenGLWidget, and 2 seconds later I set the renderer background to red and call Render(). For me, the window will not turn red until I resize it a little (or if I uncomment either of the two commented lines).

Has anyone seen this problem before?

I have not tested with VTK master yet, and I know there has been some changes, but we would really like to stick to a released version (8.2.0).

Versions used:

  • Windows 10
  • Intel UHD Graphics 620 (driver 24.20.100.6344)
  • VTK 8.2.0
  • Qt 5.12.3 (5.11.1 also tested)

Many thanks in advance for any tips/advice.

renderbug.cpp

#include <QApplication>
#include <QSurfaceFormat>
#include <QTimer>
#include <QtDebug>

#include <QVTKOpenGLWidget.h>

#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkNew.h>
#include <vtkRenderer.h>

int main(int argc, char *argv[])
{
    auto format = QVTKOpenGLWidget::defaultFormat();
    //format.setProfile(QSurfaceFormat::CompatibilityProfile);
    QSurfaceFormat::setDefaultFormat(format);

    QApplication app(argc, argv);

    vtkNew<vtkRenderer> renderer;

    vtkNew<vtkGenericOpenGLRenderWindow> window;
    window->AddRenderer(renderer);

    QVTKOpenGLWidget widget;
    widget.SetRenderWindow(window);

    QTimer::singleShot(2000, [&window, &renderer]() {
        qDebug() << "Setting background to red and rendering";
        renderer->SetBackground(1.0, 0.0, 0.0);
        window->Render();
        //window->Render();
    });

    widget.show();

    return app.exec();
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(renderbug)

find_package(Qt5Widgets REQUIRED)

find_package(VTK 8.2.0 REQUIRED COMPONENTS
    vtkGUISupportQt
    vtkInteractionStyle
    vtkRenderingCore
    vtkRenderingOpenGL2
)

add_executable(renderbug WIN32
    renderbug.cpp
)

target_link_libraries(renderbug PRIVATE
    Qt5::Widgets
    vtkGUISupportQt
    vtkInteractionStyle
    vtkRenderingCore
    vtkRenderingOpenGL2
)

target_include_directories(renderbug SYSTEM PRIVATE
    ${VTK_INCLUDE_DIRS}
)

target_compile_definitions(renderbug PRIVATE
    ${VTK_DEFINITIONS}
)
2 Likes

I’ve been struggling with this (or very similar) issue in 3D Slicer running on Surface Laptop and Surface Pro (both with Intel HD 620 graphics cards). Adding format.setProfile(QSurfaceFormat::CompatibilityProfile); fixes the issue in Slicer, too!

I’m not sure what is the impact of enabling QSurfaceFormat::CompatibilityProfile. Could we just enable it on all configurations?

VTK bug report associated with this problem is available here: https://gitlab.kitware.com/vtk/vtk/issues/17572

Glad to hear we’re not alone. I saw that issue and even commented a few days ago, but wasn’t sure it was the same bug. It probably is though (?).

I’m not sure what the implications of enabling compat profile (I don’t know OpenGL). I guess it might demand more of the driver than what VTK wants to demand, and that’s the reason defaultFormat() is a core profile? Maybe it’s just a plain driver bug, some behavioral difference in some GL instruction in core vs compat that the new QVTKOpenGLWidget happen to trigger?

I’ve uploaded your test application to GitHub, updated it so that it can be tested with latest VTK master, and added another minimal test application that allows testing updates of standard Qt widgets: https://github.com/lassoan/vtk-delayed-rendering-bug

My test results with these on a Surface Laptop (Intel HD 620) with Qt-5.10.0, same with VTK-8.2 and latest VTK master:

  • Without compatibility profile:
    • Double rendering is needed to update background color -> FAIL
    • Hovering over standard tool buttons, highlight is not displayed correctly (button is highlighted when mouse leaves it) -> FAIL
  • With compatibility profile:
    • Double rendering is not needed to update background color -> SUCCESS
    • Hovering over standard tool buttons, highlight is displayed correctly (button is highlighted when mouse hover overs it) -> SUCCESS

These are all extremely simple examples, so VTK experts should be able to use them to reproduce and fix the problem.

@jcfr with the help of these examples, could somebody from Kitware look at the problem? If it is not possible in the near term, then as a workaround we should add an application settings to 3D Slicer that can enable requesting compatibility profile.

Thanks @lassoan!

For what it’s worth I did some quick print debugging yesterday, and got as far as confirming that paintGL of the underlying QVTKOpenGLWindow is not called when Render() is called in my test case.

@lassoan : you may want to put all relevant infos in the issue, including a link to your repository.

With compatibility profile […] SUCCESS

After chatting with @ken-martin, this is most like due to an issue in Qt, compatibility mode should be used on Windows.

@ben.boeckel would QTBUG-60742 be related to this ?

We did not have this issue with VTK 8.1.2 (so with QVTKOpenGLNativeWidget, or QVTKOpenGLWidget as it was called there), using the same Qt version. Did something change in VTK which triggers this Qt bug?

I’m not sure QTBUG-60742 is this particular issue (if I understand that bug report right). When I was debug printing stuff a few days ago, I seem to remember debug printing the QSurfaceFormat that the underlying QOpenGLContext actually had gotten, and it looked alright. But I can double check.

Not doubting it’s a Qt issue, just not sure it’s that particular one…

If it is a Qt issue, it would be good if it’s identified and reported, so we can stick a link to that report in a comment where we work around it by setting a compat profile.

I don’t think that specific Qt issue is related here either. That one is mostly about Mesa which gives the minimum profile without any attributes to say otherwise. IIRC, Windows drivers tend to give the max profile by default (which I believe is against the spec) and Qt’s logic fails with Mesa.

I think that’s what I saw too in my debug printing. If not doing anything, the profile that was in effect looked very featureful.

It sounds like you have a good handle on what happens in Qt WRT to this.

As for this issue, we’ll be doing

    auto format = QVTKOpenGLWidget::defaultFormat();
#if defined(Q_OS_WIN)
    // On Windows we use a compatibility profile to work around
    // https://gitlab.kitware.com/vtk/vtk/issues/17572
    //
    // See also our Discourse post at
    // https://discourse.vtk.org/t/problem-in-vtk-8-2-with-defaultformat-and-qvtkopenglwidget-on-windows-10-intel
    format.setProfile(QSurfaceFormat::CompatibilityProfile);
#endif
    QSurfaceFormat::setDefaultFormat(format);

in the meantime, until it is figured out why things don’t work out-of-the-box with core profile.

I can help out with debugging, but I think it’s rather easy to reproduce (Win 10 / Intel HD graphics, not sure if the exact GPU model or driver version is important). I’m afraid I don’t really have much skill in OpenGL. I can try to figure out why paintGL of the underlying QVTKOpenGLWindow seems to not be called when Render is called.

Thanks for the update. That said, do you know if the particular problem discussed here has been reported to Qt.

It sounds like you have a good handle on what happens in Qt WRT to this.

Only insofar as trying to get Mesa working on Windows guided me.

That said, do you know if the particular problem discussed here has been reported to Qt.

I haven’t reported it. If someone can give me a description, I already have a Qt account to file it with. I also haven’t searched for it either.

Has it been ruled out that this is a bug in VTK yet though? It works on Linux and Mac, and it works with the old VTK widget (QVTKOpenGLNativeWidget aka QVTKOpenGLWidget in older VTKs). Could it not be some missing event handling or something in the new widget?

The smallest reproducer I have is the VTK program in my post above. I’m not sure how I would go about reproducing it without VTK (just plain QOpenGLWidget).

Probably VTK probably does something “special”. It may be a valid operation but it is something uncommon, that most other applications don’t do.

I’ve found that in Slicer if I start up the application without having any QVTK widget and then later add a QVTK widget to the layout then the problem does not occur.

I think you’re right @lassoan , just remains to find what that “special” thing is, and if it’s a valid assumption by VTK or not.

That it works by later adding a QVTK widget I guess could be simply that circumstances causes two renders (so the bug won’t manifest itself). I think I noticed something similar in our app while I was playing around: We have a QVTKOpenGLNativeWidget in another place, and if that widget is initially visible (it’s normally not, but I hacked it to be so), then the QVTKOpenGLWidget did not seem to exhibit the bug.

We have done some more research and testing in 3D Slicer and the conclusion is the following:

Why the problem occurs? If an application does not work correctly with a core profile then it indicates that still some old API or methods are used somewhere. Of course it may also mean that there are some other OpenGL handling mistakes that happen to not cause any problems when a compatibility profile is used. Qt is supposed to fully support core profiles since Qt-5.10, but it is a large project, so maybe there are still some issues. Overall, it is somewhat more likely that VTK has some OpenGL usage related bug, most probably related to initialization (as the application works well even with core profile, depending on what the main application window contains on application startup). We will not spend more time trying to pinpoint the issue, hopefully it will come up and fixed in another scenario (either in VTK or Qt).

What is the solution? We have decided to use compatibility profile for Windows, and core profile on Mac & Linux. Compatibility profiles are not fully supported on Mac, so core profile must be used there. We added an application setting option (not exposed on the application user interface) that allows forcing compatibility/core profile so that we can experiment with it and users can override it as needed.

Any regressions or risks of regressions? Using a compatibility profile on Windows does not seem to have any disadvantages. Performance may be even better than with a core profile.

Thanks @lassoan , we have done the same thing (sans the runtime toggle). Would of course really like to track this down, if it’s in VTK or Qt (like you, I suspect the former).

@lassoan Just thought I should ask: Have you guys ran into any trouble on macOS after porting to the new widget?

After some more testing here, I realised that we have a serious issue on macOS as well - one of our VTK windows will not update/re-render until you resize the window a little, or if you Command+Tab to another application and back again. That particular widget is in a tab in a QTabWidget (though I’m not sure that has any relevance, just that we have another VTK widget that also uses the same new QVTKOpenGLWidget, and it seems to work alright, and it’s not in a QTabWidget).

Just thought I should ask, since the problem seems slightly similar to this one.

(We are currently running with the same workaround as you guys, compete profile on Windows, core profile (the default) on Linux and macOS)

@utkarshayachit may confirm, but we are always using QVTKOpenGLNativeWidget on MacOS in ParaView as they are way too many bugs in Qt in this case.