MITK segmentation plugins based on the AutoSegmentationWithPreviewTool tool manager API can't be used with QThreads for non-blocking operations.
Specifically, the call
tool->UpdatePreview()
inside a QThread will cause OpenGL error: Cannot make QOpenGLContext current in a different thread.
This occurs arguably due to the encapsulation of segmentation process ComputeMLPreview and consequently, the segmentation data node creation + rendering of the computed LabelSet image inside the single function call.
Description
Event Timeline
I did some debugging and found some more insights into the situation and workarounds.
So, the AutoSegmentationWithPreviewTool tool manager not supporting QThreads has threading has 2 implications-
- Rendering issues: OpenGL error: Cannot make QOpenGLContext current in a different thread.
Insight: This rendering issue occurs at 2 places:- In mitk::AutoMLSegmentationWithPreviewTool::UpdateCleanUp method; to be exact: at the mitk::AutoSegmentationWithPreviewTool::ResetPreviewNode() call. This cannot be done in a sub-thread.
Workaround: UpdateCleanUp can be overriden in the plugin child class (ie. eg mitknnUnet.cpp) to make sure the ResetPreviewNode() is not invoked while UpdatePreview() is running. ResetPreviewNode() call can done later in the main thread. - In mitk::AutoMLSegmentationWithPreviewTool::DoUpdatePreview method; from where the m_MLPreviewNode is set with the output from ComputeMLPreviewmethod. In that snippet, RenderingModeProperty is created & set. This cannot be done in a sub-thread.
Workaround - Requires modification to the AutoMLSegmentationWithPreviewTool API. The snippet for data node creation + rendering of the computed LabelSet image can be migrated to another new function eg. SetNodeProperties(mitk::LabelSetImage::Pointer newMLPreview). This new function SetNodeProperties can be overridden in the plugin child class (ie. eg mitknnUnet.cpp) to make sure the node properties are not set immediately after the ComputeMLPreview call, but later from the main thread.
- In mitk::AutoMLSegmentationWithPreviewTool::UpdateCleanUp method; to be exact: at the mitk::AutoSegmentationWithPreviewTool::ResetPreviewNode() call. This cannot be done in a sub-thread.
Hence, when the 2 abovementioned situations are handled as per the workarounds, the issue is fixed. Tested in feature/T28553-nnUNet-in-MITK branch.
- Exception Handling: leading to Segmentation fault and Workbench crash
Any exceptions occurring in ComputeMLPreview, when thrown back to the calling function (eg. using mitkThrow()<<"I am an exception") will lead to:
QObject::setParent: Cannot set parent, new parent is in a different thread.
Insight (might not be accurate):
This occurs in the first catch block of mitk::AutoSegmentationWithPreviewTool::UpdatePreview, specifically at ErrorMessage.Send(msg).
I suppose, this is not supported by Qt in a sub-thread.
Workaround:
Don't throw back any exception, merely return nullptr and throw a generic exception in the main thread after a null check.
We can discuss more on this.