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

Alright, thanks for that info @mwestphal. I may try upgrading our Qt to 5.12.3 (using Qt 5.12.0 on macOS at the moment), though I doubt that changes anything. If it doesn’t, I guess we’ll revert to using QVTKOpenGLNativeWidget instead.

We, too, use QVTKOpenGLNativeWidget in most cases. You must use this native variant if the widget is embedded in certain Qt widgets, such as those that can do scrolling, but probably the same is true for tab widget. We only use the non-native for small popup windows.

Right, I’m aware of the restrictions on the QVTKOpenGLWidget, but did not think QTabWidget was one of those circumstances. AFAIK it has no nested QScrollArea or similar inside it.

We have a couple of VTK widgets where we have to use the native widget (e.g. color/opacity settings, similar to Paraview’s situation).

…but, I’m actually pleasantly shocked, because upgrading to Qt 5.12.3 seems to have solved that particular problem I described above.

Still having some problem with another one of our VTK widgets on macOS though, the problem there being that the very first render seems to be a hit and miss (sometimes it works, sometimes it doesn’t, and a resize is necessary to get it back into shape).

QTabWidget does not have these restrictions afaik. They are macOS specific issues though.

Glad an update fixed parts of your issues.

The remaining issue we have on macOS (occurring in just one of our VTK widgets, this time not in a QTabWidget, but just in a QSplitter in our central application area) seems very similar to the issue we had on Windows actually (start of this thread). The initial render is ineffective (sometimes, seems timing dependent/racy), and a resize is required to get it back into shape (after that, it seems to work alright).

I made a separate post with some questions about choosing the native or non-native widget: How to decide between QVTKOpenGL{Native}Widget?

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).

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 believe it does matter. IIRC, compatibility profile is legacy OpenGL (version <= 2) where you only have fixed functions (no shaders; software rendering only), while core profile is modern OpenGL (includes shaders; render on gpu).

Windows ships with legacy OpenGL (in case you don’t have hardware to support modern OpenGL). Even though switching to compatibility profile will make it work, you’re likely not getting minimal (if any) hardware acceleration.

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).

Has anyone seen this problem before?

Yes, I see this as well. You can refer to my issue QPainter::begin: Paint device returned engine == 0, type: 1. I added gif’s showing this exact problem.

This is independent of QVTKOpenGLWidget. In my example, I inherit from QWidget. I’m able to recreate the problem without using QVTKOpenGLWidget at all.

Since Qt4, all QWidget’s are double-buffered, and WA_PaintOnScreen was added for backwards-compatibility to allow setting a widget to use single buffering.

I believe the issue stems from how VTK interprets how Qt version >=4 renders. I think it is still interpreting that Qt is single-buffered by default.

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

Compatibility Profile is legacy OpenGL (version <= 2) where you only have fixed functions (no shaders; software rendering only), while core profile is modern OpenGL (includes shaders; render on gpu). Most OS’s ship with legacy OpenGL to handle the case where you don’t have dedicated rendering hardware.

I don’t recommend enabling it on all configurations because then you’re turning off hardware rendering.

Hm I don’t think this is the case. Even if the compatibility profile includes fixed-function APIs that were deprecated in OpenGL 3.0, while the core profile does not, surely those fixed-function APIs are hardware accelerated by the common OpenGL implementations (Intel, NVIDIA, AMD, …)?

And in any case, the question is more how VTK will react to running under compatibility profile vs core profile, which I think is up to VTK. Everything in core profile is also available in compatibility profile, so in theory it could run the exact same code. But I did find back when struggling with this issue that it seemingly “fixed” itself when using a compatibility profile.

I haven’t looked back at this issue in a long time, but as far as I know we are still using QVTKOpenGLNativeWidget everywhere (note QVTKOpenGLWidget), partly because of this.

I don’t believe so because you’re telling Qt: “I don’t have hardware to accelerate my graphics, so please use software rendering.” The “compatible” in “compatibility profile” means “use old opengl so we work.”

I don’t think that’s correct: Otherwise, there would be no need for 2 profiles. Core should have more functions that compatibility.

1 Like

@estan From the Qt Wiki:

When using the Core profile, all access to the legacy fixed-functionality pipeline is removed. This means that to get anything drawn on screen we have to make use of glsl shaders and vertex arrays or buffers.

and interestingly, they also note:

This is known to work under Linux but Windows and macOS have some issues inside of Qt for creating Core Profile contexts.

Some more interesting information from Qt’s blog:

The Problem

What about modern OpenGL, though?

That is where the problems started appearing: around Qt 5.0 those who were in need of a core profile context due to doing custom OpenGL rendering that needed this ended up running into roadblocks quite often. Components like Qt Quick were initially unable to function with such contexts due to relying on deprecated/removed functionality (for example, client-side pointers), lacking a vertex array object, and supplying GLSL shaders of a version the support for which is not mandated in such contexts.

In some cases opting for a compatibility profile was a viable workaround. However, Mac OS X / macOS famously lacks support for this: there the choice has been either OpenGL 2.1 or a 3.2+ core profile context. Attempts to work this around by for instance rendering into textures in one context and then using the texture in another context via resource sharing were often futile too, since some platforms tend to reject resource sharing between contexts of different version/profile.

Can you share a reference that says core/compatibility has anything to do with hardware acceleration? I don’t think that is the case. I think the core profile is simply the compatibility profile with the fixed-function APIs deprecated in 3.0 removed.

For example, from the OpenGL 4.6 (Compatibility Profile) specification:

It does not say anything about whether it runs on the hardware or not, that would be up to the OpenGL implementation, but I’m pretty sure the fixed-function APIs runs on the hardware in the Intel/NVIDIA/AMD OpenGL implementations.

Regarding the issue in this thread, I think the investigation done by @lassoan and the Slicer team is the most exhaustive so far.

Apologies, I’m mixing up things. Fixed functions are on hardware. It’s just configuration/state-machine based as opposed to programmable with shaders. And compatibility profile is indeed core + fixed functions, sorry.

Without drivers, Windows defaults to software rendering on the CPU and Mesa can fall back to software rendering as a last resort, but these are different from OpenGL fixed functions.

Regarding the issue in this thread, I think the investigation done by @lassoan and the Slicer team is the most exhaustive so far.

Agreed, thanks for redirecting me to this. Apologies for cluttering this discussion with erroneous comments.

1 Like

Yes, I see this as well. You can refer to my issue QPainter::begin: Paint device returned engine == 0, type: 1. I added gif’s showing this exact problem.

This is independent of QVTKOpenGLWidget. In my example, I inherit from QWidget. I’m able to recreate the problem without using QVTKOpenGLWidget at all.

Since Qt4, all QWidget’s are double-buffered, and WA_PaintOnScreen was added for backwards-compatibility to allow setting a widget to use single buffering.

I believe the issue stems from how VTK interprets how Qt version >=4 renders. I think it is still interpreting that Qt is single-buffered by default.

My example was using the python vtkmodules/qt/QVTKRenderWindowInteractor and that interactor uses a native vtkWin32OpenGLRenderWindow on Windows by default. I also have an NVIDIA GPU, so my previous comment was wrong. My example is a different issue.

I’ve been trying to update my software (QT4.8, VTK 5.2 compiled with VS2008 on Windows 7 - a stable configuration but antiquated!) into the modern era with Windows 10 and VS2019 and 64 bit. My first attempt with VTK 8.2.0 and QT 5.15.2 has run into exactly the same problem with QVTKOpenGLWidget not redrawing on a QT ui->vtkwidget->update(), but only redrawing after tweaking the size, where vtkwidget is the name of the QVTKOpenGLWidget.

Unfortunately the compatibility profile settings made no difference for me. I was running this on an i5 laptop with a Intel Iris Xe graphics controller. The only way I could get reliable rendering updates was with a slightly ridiculous workaround of replacing

ui->vtkwidget->update() ;

with

int x = ui->vtkwidget->width();
int y = ui->vtkwidget->height();
ui->vtkwidget->resize(x,y+1);
ui->vtkwidget->resize(x,y);

I also tried another PC, Windows 10, i7, NVidia RTX A2000 graphics with VS2019 64-bit mode, QT 6.5.2 and both VTK 8.2.0 and VTK 9.3.0-rc1 (in the latter I had to replace QVTKOpenGLWidget with QVTKOpenGLStereoWidget) in the hope that either (or both) of the QT and VTK end of things would have been fixed, but I am still getting the same problem, and the same crazy workaround still works.

Struggling to know how to go forwards - my workaround is ok when I don’t need too much updating, but on the slower laptop it does make the rendering a little bit jiggly and it does seem a bit of a crazy thing to do!

Hello @SimonH

We will need more context about your use of QVTKOpenGLWidget. Where/When do you call update()? Ideally, the widget’s paintGL function is automatically invoked when it decides the widget is out-of-date. so invoking update wouldn’t always repaint the widget. By resizing, you’re forcefully modifying the widget state, which is why it works.

@SimonH Please create a new thread in the future for different issues. It makes it easily accessible to other people facing the same issue.

  1. Prefer using VTK 9 (latest version) over an older version. It would make future upgrades easier.
  2. Prefer using the QVTKOpenGLNativeWidget unless your app is doing stereo rendering.
  3. Instead of calling update on the QVTKOpenGLNativeWidget, call Render on the vtkRenderWindow associated with the widget. That is the recommended way to update a VTK scene. In this case, it will also schedule an update on the Qt widget.

For more context, here is the program I am using to test my VTK/QT installation.

Boilerplate QT startup code:

#include "mainwindow.h"
#include <vtkAutoInit.h>
#include <QApplication>

VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)

int main( int argc, char ** argv )
{
    QApplication qtapplication( argc, argv );
    MainWindow mw;
    mw.show(); 
    return qtapplication.exec(); 
}

Very simple QT form handler. The form simply consists of a button ‘drawSphere_button’ and a render window widget ‘openGLWidget’ in whichever flavour of QVTKOpenGL…Widget I’ve been testing.

The constructor simply initialises the user interface and sets up the render window.

The function onDrawSphereClick() adds a new sphere to a 3D stack of spheres on each button press and changes the background colour, stepping from red through to green.

#include <mainwindow.h>
#include "ui_MainWindow.h"
#include <vtkspheresource.h>
#include <vtkactor.h>
#include <vtkpolydataMapper.h>
#include <vtkRenderer.h>
#include <vtkGenericOpenGLRenderWindow.h>

MainWindow::MainWindow(QWidget *parent) :
   QMainWindow( parent )
{
   ui = new Ui::MainWindow;
   ui->setupUi( this ); 
   mRenderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
   mRenderer = vtkSmartPointer<vtkRenderer>::New();
   mInteractor = vtkSmartPointer<QVTKInteractor>::New();
   mInteractorStyle = vtkSmartPointer<vtkInteractorStyle>::New();
   mRenderWindow->AddRenderer( mRenderer ); 
   mRenderWindow->SetInteractor( mInteractor ); 
   ui->openGLWidget->setRenderWindow(mRenderWindow);
   mInteractor->SetInteractorStyle( mInteractorStyle ); 
   mInteractor->Initialize(); 
   mRenderer->SetBackground(0,0,1); // Set the initial render window to blue.

   connect( ui->drawSphere_button, SIGNAL(clicked()), this, SLOT(onDrawSphereClick() ));
}

MainWindow::~MainWindow()
{
   delete ui;
}

void MainWindow::onDrawSphereClick() 
{
   vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New(); 
   sphereSource->SetRadius( 5 ); 
   sphereSource->SetPhiResolution(20);
   sphereSource->SetThetaResolution(20);
   sphereSource->SetCenter(mx, my, mz);
   sphereSource->Update(); 
   vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); 
   sphereMapper->SetInputData( sphereSource->GetOutput() );   
   vtkSmartPointer<vtkActor> sphere = vtkSmartPointer<vtkActor>::New(); 
   sphere->SetMapper( sphereMapper ); 
   mRenderer->AddActor( sphere ); 
   mRenderer->ResetCamera(); 
   mRenderer->SetBackground(1.0 - mc, mc, 0);

   mRenderer->Render();
   ui->openGLWidget->update();

   //With the following 4 lines uncommented, it works. 
   //int x = ui->openGLWidget->width();
   //int y = ui->openGLWidget->height(); 
   //ui->openGLWidget->resize(x, y + 1);
   //ui->openGLWidget->resize(x, y);

   // Update position ready for next sphere.
   mx += 10; 
   if (mx > 20)
   {
	   mx = -20; 
	   my += 10; 
	   if (my > 20)
	   {
		   my = -20; 
		   mz += 10;
	   }
   }
   // Update colour ready for next background
   mc += 0.1;
   if (mc >= 1.0) mc = 0;
}

And the associated header file for MainWindow

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderer.h>
#include <QVTKInteractor.h>
#include <vtkInteractorStyle.h>

namespace Ui {
   class MainWindow; 
}

class MainWindow : public QMainWindow
{
   Q_OBJECT

public:
   MainWindow( QWidget *parent = nullptr );
   ~MainWindow(); 

public slots: 
   void onDrawSphereClick(); 

private:
	Ui::MainWindow* ui;
	vtkSmartPointer<vtkGenericOpenGLRenderWindow> mRenderWindow;
	vtkSmartPointer<vtkRenderer> mRenderer;
	vtkSmartPointer<QVTKInteractor> mInteractor;
	vtkSmartPointer<vtkInteractorStyle> mInteractorStyle;

	int mx = -20;  // Position of next sphere in stack. 
	int my = -20;
	int mz = -20;
	double mc = 0; // Next background colour ( 0 = Red through to 1 = Green)
};

#endif // MAINWINDOW_H

I am getting the same problem (not redrawing until I resize) whether I use QVTKOpenGLNativeWindow, QVTKOpenGLWidget or QVTKOpenGLStereoWidget. Is there something I’m missing that is causing the image not to be redrawn simply with these after the new actor and colour change have been added to the scene?

   mRenderer->Render();
   ui->openGLWidget->update();

Try mRenderWindow->Render()