title: Qt3D Crashing when removing frame graph
body: <p>I'm trying to create an application using Qt3D that where I can create multiple view windows on the same scene.  I started with the code from the Qt3DWindow and the <a href="https://doc.qt.io/qt-5.10/qt3d-simple-cpp-example.html" rel="nofollow noreferrer">Simple C++ Example</a> and started moving things around.  What I figured is that each view window would define its own frame graph (just using a simple QForwardRenderer for now) and camera and then I would add each window's frame graph to the main frame graph in my scene.</p>
  
  <p>Everything appears to be working fine as I create multiple windows, but when I close the windows and start removing frame graphs, the application crashes.  It's crashing on a background thread somewhere down in the Qt3DCore or Qt3DRender module and I can't get to the source code.  As I understand it I should be able to modify the frame graph dynamically at run time, but is that not thread safe?  Are you expected to wholesale replace one frame graph with another as opposed to modifying the active frame graph like I'm doing?</p>
  
  <p><strong>--- Edit ---</strong></p>
  
  <p>I did a little more testing and if I delay destroying the QWindow (i.e., the surface that it's trying to render to) a bit after removing its frame graph from the parent frame graph, I don't get the crash.  I <em>do</em> however get some warnings on the console that say:</p>
  
  <blockquote>
    <p>Qt3D.Renderer.Backend: bool __cdecl Qt3DRender::Render::GraphicsContext::makeCurrent(class QSurface *) makeCurrent failed</p>
  </blockquote>
  
  <p>My guess is it's a threading issue, that the backend is still trying to use the QSurface to render to after it has been destroyed on the main thread.  I don't really like my solution (I just used a single shot timer to delay destroying the window by 1 second), but it's better than crashing.</p>
  
  <p><strong>RenderWindow.h</strong></p>
  
  <pre><code>#ifndef RENDERWINDOW_H
  #define RENDERWINDOW_H
  #include &lt;QWindow&gt;
  #include &lt;Qt3DCore&gt;
  #include &lt;Qt3DRender&gt;
  #include &lt;Qt3DInput&gt;
  #include &lt;Qt3DExtras/QForwardRenderer&gt;
  
  class RenderWindow : public QWindow
  {
  public:
    RenderWindow(QScreen* screen = nullptr);
    ~RenderWindow();
  
    Qt3DRender::QCamera* camera() const;
    Qt3DRender::QFrameGraphNode* frameGraph() const;
  
  protected:
    void resizeEvent(QResizeEvent *) override;
  
  private:
    // Rendering
    Qt3DRender::QFrameGraphNode* mpFrameGraph;
    Qt3DRender::QCamera* mpCamera;
  
    static bool msFormatDefined;
  };
  
  #endif // RENDERWINDOW_H
  </code></pre>
  
  <p><strong>RenderWindow.cpp</strong></p>
  
  <pre><code>#include "renderwindow.h"
  #include &lt;QDebug&gt;
  
  bool RenderWindow::msFormatDefined = false;
  
  namespace
  {
      // Different clear colors so that it's obvious each window is using a
      // different camera and frame graph.
      static QColor sClearColors[] = {
          Qt::darkBlue,
          Qt::blue,
          Qt::darkCyan,
          Qt::cyan
      };
      static int sViewCount = 0;
  }
  
  RenderWindow::RenderWindow(QScreen* screen)
      : QWindow(screen)
      , mpFrameGraph(nullptr)
      , mpCamera(new Qt3DRender::QCamera)
  {
      setSurfaceType(QWindow::OpenGLSurface);
  
      // Set the default surface format once
      if (!msFormatDefined)
      {
          QSurfaceFormat format;
          format.setVersion(4, 3);
          format.setProfile(QSurfaceFormat::CoreProfile);
          format.setDepthBufferSize(24);
          format.setSamples(4);
          format.setStencilBufferSize(8);
          setFormat(format);
  
          QSurfaceFormat::setDefaultFormat(format);
          msFormatDefined = true;
      }
  
      // Camera
      mpCamera-&gt;lens()-&gt;setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
      mpCamera-&gt;setPosition(QVector3D(0, 0, 40.0f));
      mpCamera-&gt;setViewCenter(QVector3D(0, 0, 0));
  
      // Frame Graph (using forward renderer for now)
      Qt3DExtras::QForwardRenderer* renderer = new Qt3DExtras::QForwardRenderer;
      renderer-&gt;setCamera(mpCamera);
      renderer-&gt;setSurface(this);
      renderer-&gt;setClearColor(sClearColors[sViewCount++ % 4]);
      mpFrameGraph = renderer;
  }
  
  RenderWindow::~RenderWindow()
  {
      qDebug() &lt;&lt; "start ~RenderWindow";
  
      // Unparent objects.  Probably not necessary but it makes me feel
      // good inside.
      mpFrameGraph-&gt;setParent(static_cast&lt;Qt3DCore::QNode*&gt;(nullptr));
      mpCamera-&gt;setParent(static_cast&lt;Qt3DCore::QNode*&gt;(nullptr));
  
      delete mpFrameGraph;
      delete mpCamera;
  
      qDebug() &lt;&lt; "end ~RenderWindow";
  }
  
  Qt3DRender::QCamera* RenderWindow::camera() const
  {
      return mpCamera;
  }
  
  Qt3DRender::QFrameGraphNode* RenderWindow::frameGraph() const
  {
      return mpFrameGraph;
  }
  
  void RenderWindow::resizeEvent(QResizeEvent *)
  {
      mpCamera-&gt;setAspectRatio((float)width()/(float)height());
  }
  </code></pre>
  
  <p><strong>Scene.h</strong></p>
  
  <pre><code>#ifndef SCENE_H
  #define SCENE_H
  #include &lt;Qt3DCore/QEntity&gt;
  
  #include &lt;Qt3DInput/QInputAspect&gt;
  
  #include &lt;Qt3DRender/QFrameGraphNode&gt;
  #include &lt;Qt3DRender/QRenderAspect&gt;
  #include &lt;Qt3DRender/QRenderSettings&gt;
  
  class RenderWindow;
  
  class Scene
  {
  public:
      Scene();
      ~Scene();
  
      Qt3DCore::QEntityPtr rootNode() const;
  
      void addView(RenderWindow* window);
  
  private:
      void setupScene();
  
  private:
      Qt3DCore::QEntityPtr mpRoot;
  
      // Frame Graph
      Qt3DRender::QFrameGraphNode* mpFrameGraph;
      Qt3DRender::QRenderSettings* mpRenderSettings;
  
      // Aspects
      Qt3DCore::QAspectEngine* mpEngine;
      Qt3DRender::QRenderAspect* mpRenderAspect;
      Qt3DInput::QInputAspect* mpInputAspect;
  };
  
  #endif // SCENE_H
  </code></pre>
  
  <p><strong>Scene.cpp</strong></p>
  
  <pre><code>#include "scene.h"
  
  #include &lt;QDebug&gt;
  #include &lt;QPropertyAnimation&gt;
  
  #include &lt;Qt3DCore/QTransform&gt;
  
  #include &lt;Qt3DRender/QClearBuffers&gt;
  
  #include &lt;Qt3DExtras/QPhongMaterial&gt;
  #include &lt;Qt3DExtras/QCylinderMesh&gt;
  #include &lt;Qt3DExtras/QSphereMesh&gt;
  #include &lt;Qt3DExtras/QTorusMesh&gt;
  
  #include "orbittransformcontroller.h"
  #include "RenderWindow.h"
  
  Scene::Scene()
      : mpRoot(nullptr)
      , mpFrameGraph(new Qt3DRender::QFrameGraphNode)
      , mpRenderSettings(new Qt3DRender::QRenderSettings)
      , mpEngine(new Qt3DCore::QAspectEngine)
      , mpRenderAspect(new Qt3DRender::QRenderAspect)
      , mpInputAspect(new Qt3DInput::QInputAspect)
  {
      mpEngine-&gt;registerAspect(mpRenderAspect);
  
      mpRenderSettings-&gt;setActiveFrameGraph(mpFrameGraph);
  
      setupScene();
  
      mpRoot-&gt;addComponent(mpRenderSettings);
      mpEngine-&gt;setRootEntity(mpRoot);
  }
  
  Scene::~Scene()
  {
      qDebug() &lt;&lt; "start ~Scene";
  
      mpEngine-&gt;setRootEntity(Qt3DCore::QEntityPtr());
      mpRoot.clear();
  
      delete mpEngine;
      // mpRenderSettings and mpFrameGraph are children of the
      // root node and are automatically destroyed when it is.
  
      qDebug() &lt;&lt; "end ~Scene";
  }
  
  Qt3DCore::QEntityPtr Scene::rootNode() const
  {
      return mpRoot;
  }
  
  void Scene::addView(RenderWindow* window)
  {
      // Add the window's frame graph to the main frame graph
      if (window-&gt;frameGraph())
      {
          window-&gt;frameGraph()-&gt;setParent(mpFrameGraph);
      }
  }
  
  void Scene::setupScene()
  {
      mpRoot.reset(new Qt3DCore::QEntity);
  
      Qt3DCore::QEntity* entity = new Qt3DCore::QEntity;
      entity-&gt;setParent(mpRoot.data());
  
      // Create the material
      Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial(entity);
      material-&gt;setAmbient(Qt::black);
      material-&gt;setDiffuse(QColor(196, 196, 32));
      material-&gt;setSpecular(Qt::white);
  
      // Torrus
      Qt3DCore::QEntity *torusEntity = new Qt3DCore::QEntity(entity);
      Qt3DExtras::QTorusMesh *torusMesh = new Qt3DExtras::QTorusMesh;
      torusMesh-&gt;setRadius(5);
      torusMesh-&gt;setMinorRadius(1);
      torusMesh-&gt;setRings(100);
      torusMesh-&gt;setSlices(20);
  
      Qt3DCore::QTransform *torusTransform = new Qt3DCore::QTransform;
      torusTransform-&gt;setScale3D(QVector3D(1.5, 1, 0.5));
      torusTransform-&gt;setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), -45.0f));
  
      torusEntity-&gt;addComponent(torusMesh);
      torusEntity-&gt;addComponent(torusTransform);
      torusEntity-&gt;addComponent(material);
  
      // Sphere
      Qt3DCore::QEntity *sphereEntity = new Qt3DCore::QEntity(entity);
      Qt3DExtras::QSphereMesh *sphereMesh = new Qt3DExtras::QSphereMesh;
      sphereMesh-&gt;setRadius(3);
  
      Qt3DCore::QTransform *sphereTransform = new Qt3DCore::QTransform;
      /*OrbitTransformController *controller = new OrbitTransformController(sphereTransform);
      controller-&gt;setTarget(sphereTransform);
      controller-&gt;setRadius(20.0f);
  
      QPropertyAnimation *sphereRotateTransformAnimation = new QPropertyAnimation(sphereTransform);
      sphereRotateTransformAnimation-&gt;setTargetObject(controller);
      sphereRotateTransformAnimation-&gt;setPropertyName("angle");
      sphereRotateTransformAnimation-&gt;setStartValue(QVariant::fromValue(0));
      sphereRotateTransformAnimation-&gt;setEndValue(QVariant::fromValue(360));
      sphereRotateTransformAnimation-&gt;setDuration(10000);
      sphereRotateTransformAnimation-&gt;setLoopCount(-1);
      sphereRotateTransformAnimation-&gt;start();*/
  
      sphereEntity-&gt;addComponent(sphereMesh);
      sphereEntity-&gt;addComponent(sphereTransform);
      sphereEntity-&gt;addComponent(material);
  }
  </code></pre>
  
  <p><strong>MainWindow.h</strong></p>
  
  <pre><code>#ifndef MAINWINDOW_H
  #define MAINWINDOW_H
  
  #include &lt;QMainWindow&gt;
  
  #include "scene.h"
  
  namespace Ui {
  class MainWindow;
  }
  
  class MainWindow : public QMainWindow
  {
      Q_OBJECT
  
  public:
      explicit MainWindow(QWidget *parent = 0);
      ~MainWindow();
  
      void createWindow();
  
  private:
      Ui::MainWindow *ui;
      Scene* scene;
  };
  
  #endif // MAINWINDOW_H
  </code></pre>
  
  <p><strong>MainWindow.cpp</strong></p>
  
  <pre><code>#include "mainwindow.h"
  #include &lt;QDebug&gt;
  #include "ui_mainwindow.h"
  #include "renderwindow.h"
  
  MainWindow::MainWindow(QWidget *parent) :
      QMainWindow(parent),
      ui(new Ui::MainWindow),
      scene(new Scene())
  {
      ui-&gt;setupUi(this);
      connect(ui-&gt;createButton, &amp;QPushButton::clicked, this, &amp;MainWindow::createWindow);
  }
  
  MainWindow::~MainWindow()
  {
      qDebug() &lt;&lt; "~MainWindow";
  
      delete scene;
      delete ui;
  }
  
  void MainWindow::createWindow()
  {
      RenderWindow* window = new RenderWindow();
      scene-&gt;addView(window);
      window-&gt;resize(640, 480);
      window-&gt;show();
  
      QVector3D pos[] = {
          QVector3D(0, 0, 40),
          QVector3D(0, 25, -30),
          QVector3D(-20, -20, -20),
          QVector3D(40, 0, 0)
      };
      static int count = 0;
      window-&gt;camera()-&gt;setPosition(pos[count++%4]);
      window-&gt;camera()-&gt;setViewCenter(QVector3D(0, 0, 0));
  
      // Delete the window when it is closed.
      connect(window, &amp;QWindow::visibilityChanged, this, [=](bool on)
      {
          if (!on)
              window-&gt;deleteLater();
      });
  }
  </code></pre>