vtkInteractorStyles that draw selected area fail with QQuickVtkItem

I use vtkInteractorStyleRubberBandPick with QQuickVtkItem with VTK 9.3 in my C++ application that uses Qt and VTK. However when I drag the left mouse button, a selection area is not drawn but many warning/error messages are written to stderr. The same occurs when I use any vtkInteractorStyle that attempts to draw a selected area, such as vtkInteractorStyleDrawPolygon. These warning/error messages are generated when I begin left mouse button drag:

ESC[0mESC[33m2025-07-08 15:00:17.362 ( 28.565s) [ 7F8182151640] vtkOpenGLState.cxx:57 WARN| Error in cache state for GL_DEPTH_WRITEMASKESC[0m

ESC[0mESC[33m2025-07-08 15:00:17.362 ( 28.565s) [ 7F8182151640] vtkOpenGLState.cxx:133 WARN| Error in cache state for GL_VIEWPORTESC[0m

ESC[0mESC[33m2025-07-08 15:00:17.368 ( 28.570s) [ 7F8182151640] vtkOpenGLState.cxx:263 WARN| at stack loc

0x7f86cda15ba1 : ??? [(???) ???:-1]

0x7f86cda101db : vtksys::SystemInformation::GetProgramStack[abi:cxx11](int, int) [(libvtksys-9.3.so.1) ???:-1]

0x7f86c690333f : vtkOpenGLState::CheckState() [(libvtkRenderingOpenGL2-9.3.so.1) ???:-1]

0x7f86c6905061 : vtkOpenGLState::vtkglBindFramebuffer(unsigned int, unsigned int) [(libvtkRenderingOpenGL2-9.3.so.1) ???:-1]

0x7f86c690501d : vtkOpenGLState::vtkBindFramebuffer(unsigned int, vtkOpenGLFramebufferObject*) [(libvtkRenderingOpenGL2-9.3.so.1) ???:-1]

0x7f86c68026b0 : vtkOpenGLFramebufferObject::Bind(unsigned int) [(libvtkRenderingOpenGL2-9.3.so.1) ???:-1]

0x7f86c68d084a : vtkOpenGLRenderWindow::SetRGBACharPixelData(int, int, int, int, unsigned char*, int, int, int) [(libvtkRenderingOpenGL2-9.3.so.1) ???:-1]

0x7f86c67b5318 : vtkGenericOpenGLRenderWindow::SetRGBACharPixelData(int, int, int, int, unsigned char*, int, int, int) [(libvtkRenderingOpenGL2-9.3.so.1) ???:-1]

0x7f86ca42d075 : vtkInteractorStyleRubberBandPick::RedrawRubberBand() [(libvtkInteractionStyle-9.3.so.1) ???:-1]

0x7f86ca42c9c6 : vtkInteractorStyleRubberBandPick::OnMouseMove() [(libvtkInteractionStyle-9.3.so.1) ???:-1]

0x7f86c94b54b7 : vtkInteractorStyle::ProcessEvents(vtkObject*, unsigned long, void*, void*) [(libvtkRenderingCore-9.3.so.1) ???:-1]

0x7f86cf20f0cb : vtkCallbackCommand::Execute(vtkObject*, unsigned long, void*) [(libvtkCommonCore-9.3.so.1) ???:-1]

0x7f86cf3ef5f2 : ??? [(???) ???:-1]

0x7f86cf3efbe9 : vtkObject::InvokeEvent(unsigned long, void*) [(libvtkCommonCore-9.3.so.1) ???:-1]

0x7f86cb519b86 : QVTKInteractorAdapter::ProcessEvent(QEvent*, vtkRenderWindowInteractor*) [(libvtkGUISupportQt-9.3.so.1) ???:-1]

0x7f86d0211263 : ??? [(???) ???:-1]

0x7f86d02119c9 : ??? [(???) ???:-1]

0x7f86d021185a : ??? [(???) ???:-1]

0x7f86d0211707 : ??? [(???) ???:-1]

0x7f86d0213961 : ??? [(???) ???:-1]

0x7f86d0210d07 : QQuickVTKItem::updatePaintNode(QSGNode*, QQuickItem::UpdatePaintNodeData*) [(libvtkGUISupportQtQuick-9.3.so.1) ???:-1]

0x7f86cc3748b8 : QQuickWindowPrivate::updateDirtyNode(QQuickItem*) [(libQt6Quick.so.6) ???:-1]

0x7f86cc375234 : QQuickWindowPrivate::updateDirtyNodes() [(libQt6Quick.so.6) ???:-1]

0x7f86cc37925e : QQuickWindowPrivate::syncSceneGraph() [(libQt6Quick.so.6) ???:-1]

0x7f86cc589bdc : ??? [(???) ???:-1]

0x7f86cc58b114 : ??? [(???) ???:-1]

0x7f86cc58c3a7 : ??? [(???) ???:-1]

0x7f86ccb76ef8 : ??? [(???) ???:-1]

0x7f86cb680ac3 : ??? [(???) ???:-1]

0x7f86cb712850 : ??? [(???) ???:-1]

My code works properly when I use a vtkInteractorStyle that does not attempt to select an area, such as vtkInteractorStyleTrackballCamera, vtkInteractorStyleFlight, vtkInteractorStyleTerrain.

Seemingly most relevant part of my code:

  pipeline->interactorStyle_->SetDefaultRenderer(pipeline->renderer_);

  pipeline->qVtkInteractor_->SetPicker(pipeline->areaPicker_);
  pipeline->qVtkInteractor_->SetInteractorStyle(pipeline->interactorStyle_);
  pipeline->qVtkInteractor_->SetRenderWindow(renderWindow_);

where interactorStyle_ points to vtkInteractorStyle. E.g. it can point to vtkInteractorStyleTrackballCamera - which works - or vtkInteractorStyleDrawPolygon - which fails as described above.

What might be causing this behavior and how to fix it? Is this an issue with QVtkInteractor, QQuickVtkItem, or both?
Thanks!

Has no one encountered this issue before?
Also I note that QQuickVtkItem exits with an error message if handed a vtkRenderWindowInteractor that is not a QVtkInteractor.

Hi @Tomasso, my guess is you’re running into threading issues. QtQuick uses a threaded scenegraph with a main thread and a separate render thread. VTK draw calls should just be made on the render thread. This is why QQuickVTKItem exposes a dispatch_async method to ā€œscheduleā€ tasks on the render thread. The interactor styles you mentioned aren’t aware of this and likely try to make render calls on the main thread. You’d have to subclass the style and use dispatch_async wherever it makes direct Render calls.

1 Like

Thanks @sankhesh, I’ve done as you suggest - made a local copy of vtkInteractorStyleRubberBandPick, renamed it MyRubberBandStyle; I’ve added a class member qquickVTKItem_ that points to my QQuickVTKItem object. The errors I describe happen in MyRubberBandStyle::RedrawRubberBand(), called by MyRubberBandStyle::OnMouseMove(), i.e. both these are running in the same thread. I modified OnMouseMove() so that it queues RedrawRubberBand() to execute in the Qt-Render thread (instead of calling RedrawRubberBand() directly), by calling QQuickVTKItem::dispatch_async():

  // Dispatch lambda function to redraw rubber band in Qt render thread
  qquickVTKItem_->dispatch_async([this](vtkRenderWindow *renderWindow,
		  vtkSmartPointer<vtkObject> userData) {
    this->RedrawRubberBand();
  });

However this does not fix the errors, which are still emitted by RedrawRubberBand(). Debugging this, I see that RedrawRubberBand() is still running in the same thread as OnMouseMove(), despite being queued to run in the Qt-Render thread. Why is this? How can I make RedrawRubberBand() run in the Qt-render thread?

More detail - I copied vtkInteractorStyleRubberBandPick to MyRubberBandStyle, and see that the scene-graph related errors occur in MyRubberBandStyle::RedrawRubberBand(); this function attempts to draw a rectangle around the selected area as the mouse is dragged. Within RedrawRubberBand() I’ve established that the errors occur here:

  this->Interactor->
    GetRenderWindow()->SetRGBACharPixelData(
					    0, 0, size[0] - 1, size[1] - 1,
					    pixels, 0);

Document for SetRGBACharPixelData() is here.
I added debug statements to my code, printing out thread ID at various locations. I implemented a slot that I connect to QQuickWindow::beforeSynchronizing, which is emitted by the Qt-Render thread, so I get a definitive ID for the QT-Render thread. Here are the thread IDs:

main() thread:                                139815893882176
reassemblePipeline() thread:                  139815893882176   calls vtkRendering() with QQuickVTKItem::dispatch_async()
vtkRendering() thread:                        139815085459008   invokes VTK rendering
MyRubberBandStyle::OnMouseMove() thread:      139815085459008
MyRubberBandStyle::RedrawRubberBand() thread: 139815085459008   invokes VTK rendering
qt render thread:                             139815085459008   in my slot that's connected to  QQuickWindow::beforeSynchronizing

So calls to vtkRendering() and RedrawRubberBand(), which both invoke VTK Render calls, are running in the QT-render thread, and yet the SceneGraph-related errors still occur:

0x7f98511cfd07 : QQuickVTKItem::updatePaintNode(QSGNode*, QQuickItem::UpdatePaintNodeData*) [(libvtkGUISupportQtQuick-9.3.so.1) ???:-1]
0x7f984d3338b8 : QQuickWindowPrivate::updateDirtyNode(QQuickItem*) [(libQt6Quick.so.6) ???:-1]
0x7f984d334234 : QQuickWindowPrivate::updateDirtyNodes() [(libQt6Quick.so.6) ???:-1]
0x7f984d33825e : QQuickWindowPrivate::syncSceneGraph() [(libQt6Quick.so.6) ???:-1]

@sankhesh or anyone, can you recommend next things to try?
Thanks!

Hi @Tomasso, That looks correct. The error log that you posted seems more like a stack trace. What error do you get now?

@sankhesh these are the errors that appear on stderr as I’m dragging the mouse, i.e. not a stack trace:

0x7f98511cfd07 : QQuickVTKItem::updatePaintNode(QSGNode*, QQuickItem::UpdatePaintNodeData*) [(libvtkGUISupportQtQuick-9.3.so.1) ???:-1]
0x7f984d3338b8 : QQuickWindowPrivate::updateDirtyNode(QQuickItem*) [(libQt6Quick.so.6) ???:-1]
0x7f984d334234 : QQuickWindowPrivate::updateDirtyNodes() [(libQt6Quick.so.6) ???:-1]
0x7f984d33825e : QQuickWindowPrivate::syncSceneGraph() [(libQt6Quick.so.6) ???:-1]

But here is an interesting development. I provided claude.ai with the information provided in this post, and it responded with several possible solutions, one of which ā€˜fixed’ those errors, i.e. they no longer appear on stderr while dragging the mouse. The solution was this:

  /* **** Recommended by Claude.ai *** */
  vtkOpenGLRenderWindow* renWin = 
    vtkOpenGLRenderWindow::SafeDownCast(this->Interactor->GetRenderWindow());

  vtkOpenGLState* ostate;
  if (renWin) {
    std::cerr << "got renWin\n";
    ostate = renWin->GetState();
        
    // Push current state
    ostate->Push();
  }
  /* ******************************* */
  std::cerr << "RedrawRubberBand(): set rgb pixel data\n";

  this->Interactor->
    GetRenderWindow()->SetRGBACharPixelData(
					    0, 0, size[0] - 1, size[1] - 1,
					    pixels, 0);

  
  std::cerr << "RedrawRubberBand(): get render window frame\n";
  this->Interactor->GetRenderWindow()->Frame();

  std::cerr << "RedrawRubberBand(): delete tmpPixelArray\n";
  tmpPixelArray->Delete();
  std::cerr << "RedrawRubberBand(): tmpPixelArray DELETED\n";  

  /* **** Recommended by Claude.ai *** */
  if (renWin) {
    // Pop back to previous state
    ostate->Pop();
  }
  /* ******************************* */

So I don’t see error messages on mouse drag - but also do not see a red box tracking the area selected by the mouse. I.e. the call to SetRGBACharPixelData() doesn’t result in a red box. I do see a red box when using MyRubberBandStyle with a VTK-only application (i.e. no integration with Qt). Why might this be so? Here is the complete source for MyRubberBandStyle::RedrawRubberBand():

//------------------------------------------------------------------------------
void MyRubberBandStyle::RedrawRubberBand()
{
  std::cerr << "MyRubberBandStyle::RedrawRubberBand() thread: " <<
    std::this_thread::get_id() << "\n";
  
  // update the rubber band on the screen
  const int* size = this->Interactor->GetRenderWindow()->GetSize();

  vtkUnsignedCharArray* tmpPixelArray = vtkUnsignedCharArray::New();
  tmpPixelArray->DeepCopy(this->PixelArray);
  unsigned char* pixels = tmpPixelArray->GetPointer(0);

  int min[2], max[2];

  min[0] =
    this->StartPosition[0] <= this->EndPosition[0] ? this->StartPosition[0] : this->EndPosition[0];
  if (min[0] < 0)
  {
    min[0] = 0;
  }
  if (min[0] >= size[0])
  {
    min[0] = size[0] - 1;
  }

  min[1] =
    this->StartPosition[1] <= this->EndPosition[1] ? this->StartPosition[1] : this->EndPosition[1];
  if (min[1] < 0)
  {
    min[1] = 0;
  }
  if (min[1] >= size[1])
  {
    min[1] = size[1] - 1;
  }

  max[0] =
    this->EndPosition[0] > this->StartPosition[0] ? this->EndPosition[0] : this->StartPosition[0];
  if (max[0] < 0)
  {
    max[0] = 0;
  }
  if (max[0] >= size[0])
  {
    max[0] = size[0] - 1;
  }

  max[1] =
    this->EndPosition[1] > this->StartPosition[1] ? this->EndPosition[1] : this->StartPosition[1];
  if (max[1] < 0)
  {
    max[1] = 0;
  }
  if (max[1] >= size[1])
  {
    max[1] = size[1] - 1;
  }

  int i;
  for (i = min[0]; i <= max[0]; i++)
  {
    pixels[4 * (min[1] * size[0] + i)] = 255 ^ pixels[4 * (min[1] * size[0] + i)];
    pixels[4 * (min[1] * size[0] + i) + 1] = 255 ^ pixels[4 * (min[1] * size[0] + i) + 1];
    pixels[4 * (min[1] * size[0] + i) + 2] = 255 ^ pixels[4 * (min[1] * size[0] + i) + 2];
    pixels[4 * (max[1] * size[0] + i)] = 255 ^ pixels[4 * (max[1] * size[0] + i)];
    pixels[4 * (max[1] * size[0] + i) + 1] = 255 ^ pixels[4 * (max[1] * size[0] + i) + 1];
    pixels[4 * (max[1] * size[0] + i) + 2] = 255 ^ pixels[4 * (max[1] * size[0] + i) + 2];
  }
  for (i = min[1] + 1; i < max[1]; i++)
  {
    pixels[4 * (i * size[0] + min[0])] = 255 ^ pixels[4 * (i * size[0] + min[0])];
    pixels[4 * (i * size[0] + min[0]) + 1] = 255 ^ pixels[4 * (i * size[0] + min[0]) + 1];
    pixels[4 * (i * size[0] + min[0]) + 2] = 255 ^ pixels[4 * (i * size[0] + min[0]) + 2];
    pixels[4 * (i * size[0] + max[0])] = 255 ^ pixels[4 * (i * size[0] + max[0])];
    pixels[4 * (i * size[0] + max[0]) + 1] = 255 ^ pixels[4 * (i * size[0] + max[0]) + 1];
    pixels[4 * (i * size[0] + max[0]) + 2] = 255 ^ pixels[4 * (i * size[0] + max[0]) + 2];
  }

  /* **** Recommended by Claude.ai *** */
  vtkOpenGLRenderWindow* renWin = 
    vtkOpenGLRenderWindow::SafeDownCast(this->Interactor->GetRenderWindow());

  vtkOpenGLState* ostate;
  if (renWin) {
    std::cerr << "got renWin\n";
    ostate = renWin->GetState();
        
    // Push current state
    ostate->Push();
  }
  /* ******************************* */
  std::cerr << "RedrawRubberBand(): set rgb pixel data\n";

  this->Interactor->
    GetRenderWindow()->SetRGBACharPixelData(
					    0, 0, size[0] - 1, size[1] - 1,
					    pixels, 0);

  
  std::cerr << "RedrawRubberBand(): get render window frame\n";
  this->Interactor->GetRenderWindow()->Frame();

  std::cerr << "RedrawRubberBand(): delete tmpPixelArray\n";
  tmpPixelArray->Delete();
  std::cerr << "RedrawRubberBand(): tmpPixelArray DELETED\n";  

  /* **** Recommended by Claude.ai *** */
  if (renWin) {
    // Pop back to previous state
    ostate->Pop();
  }
  /* ******************************* */  


  std::cerr << "Leave MyRubberBandStyle::RedrawRubberBand()\n";  
}