commit 48416440c455db02918d5a184ecd228a99f41f26
Author: Ievgen Liubymkin <il@ticra.com>
Date:   Mon Jun 28 10:12:06 2021 +0200

    qt3d: render: offscreensurfacehelper: avoid data race accessing renderer
    
    This fixes a crash. When under heavy load and, the renderer (living in
    other thread) may be destructed before OffscreenSurfaceHelper gets to
    read surface and screen out of it.

diff --git a/render/backend/abstractrenderer_p.h b/render/backend/abstractrenderer_p.h
index c8dd537..7b09f77 100644
--- a/render/backend/abstractrenderer_p.h
+++ b/render/backend/abstractrenderer_p.h
@@ -56,7 +56,6 @@
 #include <Qt3DRender/private/handle_types_p.h>
 #include <Qt3DCore/qaspectjob.h>
 #include <Qt3DCore/qnodeid.h>
-#include <QtGui/qsurfaceformat.h>
 
 #include <QtGui/qopenglcontext.h>
 
@@ -180,7 +179,6 @@ public:
     virtual QScreen *screen() const { return nullptr; }
 
     virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0;
-    virtual QSurfaceFormat format() = 0;
     virtual QOpenGLContext *shareContext() const = 0;
 
 
diff --git a/render/backend/offscreensurfacehelper.cpp b/render/backend/offscreensurfacehelper.cpp
index 38558d4..1c679f2 100644
--- a/render/backend/offscreensurfacehelper.cpp
+++ b/render/backend/offscreensurfacehelper.cpp
@@ -51,14 +51,10 @@ namespace Qt3DRender {
 namespace Render {
 
 /*! \internal */
-OffscreenSurfaceHelper::OffscreenSurfaceHelper(AbstractRenderer *renderer,
-                                               QObject *parent)
+OffscreenSurfaceHelper::OffscreenSurfaceHelper(QObject *parent)
     : QObject(parent)
-    , m_renderer(renderer)
     , m_offscreenSurface(nullptr)
-{
-    Q_ASSERT(renderer);
-}
+{}
 
 /*!
  * \internal
@@ -66,13 +62,13 @@ OffscreenSurfaceHelper::OffscreenSurfaceHelper(AbstractRenderer *renderer,
  * which can later be made current with the Qt 3D OpenGL context to
  * then allow graphics resources to be released cleanly.
  */
-void OffscreenSurfaceHelper::createOffscreenSurface()
+void OffscreenSurfaceHelper::createOffscreenSurface(QSurfaceFormat format, QScreen* screen)
 {
     Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
     m_offscreenSurface = new QOffscreenSurface;
     m_offscreenSurface->setParent(this);
-    m_offscreenSurface->setFormat(m_renderer->format());
-    m_offscreenSurface->setScreen(m_renderer->screen());
+    m_offscreenSurface->setFormat(format);
+    m_offscreenSurface->setScreen(screen);
     m_offscreenSurface->create();
 }
 
diff --git a/render/backend/offscreensurfacehelper_p.h b/render/backend/offscreensurfacehelper_p.h
index 8dc86d9..4f29e6e 100644
--- a/render/backend/offscreensurfacehelper_p.h
+++ b/render/backend/offscreensurfacehelper_p.h
@@ -60,21 +60,17 @@ class QOffscreenSurface;
 namespace Qt3DRender {
 namespace Render {
 
-class AbstractRenderer;
-
 class Q_AUTOTEST_EXPORT OffscreenSurfaceHelper : public QObject
 {
     Q_OBJECT
 public:
-    OffscreenSurfaceHelper(AbstractRenderer *renderer,
-                           QObject *parent = nullptr);
+    OffscreenSurfaceHelper(QObject *parent = nullptr);
     inline QOffscreenSurface *offscreenSurface() const { return m_offscreenSurface; }
 
 public slots:
-    void createOffscreenSurface();
+    void createOffscreenSurface(QSurfaceFormat, QScreen*);
 
 private:
-    Render::AbstractRenderer *m_renderer;
     QOffscreenSurface *m_offscreenSurface;
 };
 
diff --git a/render/frontend/qrenderaspect.cpp b/render/frontend/qrenderaspect.cpp
index a42da49..46296f4 100644
--- a/render/frontend/qrenderaspect.cpp
+++ b/render/frontend/qrenderaspect.cpp
@@ -571,7 +571,7 @@ void QRenderAspect::onRegistered()
 
     // Create a helper for deferring creation of an offscreen surface used during cleanup
     // to the main thread, after we know what the surface format in use is.
-    d->m_offscreenHelper = new Render::OffscreenSurfaceHelper(d->m_renderer);
+    d->m_offscreenHelper = new Render::OffscreenSurfaceHelper();
     d->m_offscreenHelper->moveToThread(QCoreApplication::instance()->thread());
     d->m_renderer->setOffscreenSurfaceHelper(d->m_offscreenHelper);
 
diff --git a/render/renderers/opengl/renderer/renderer.cpp b/render/renderers/opengl/renderer/renderer.cpp
index aced13f..c46f0f8 100644
--- a/render/renderers/opengl/renderer/renderer.cpp
+++ b/render/renderers/opengl/renderer/renderer.cpp
@@ -520,8 +520,10 @@ void Renderer::initialize()
         // for use when we want to shutdown the renderer. We need to create
         // the offscreen surface on the main thread because on some platforms
         // (MS Windows), an offscreen surface is just a hidden QWindow.
-        m_format = ctx->format();
-        QMetaObject::invokeMethod(m_offscreenHelper, "createOffscreenSurface");
+        QMetaObject::invokeMethod(m_offscreenHelper,
+		[h=m_offscreenHelper, f=ctx->format(), s=screen()]{
+			h->createOffscreenSurface(f, s);
+		});
     }
 
     // Awake setScenegraphRoot in case it was waiting
@@ -947,11 +949,6 @@ void Renderer::setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper)
     m_offscreenHelper = helper;
 }
 
-QSurfaceFormat Renderer::format()
-{
-    return m_format;
-}
-
 // When this function is called, we must not be processing the commands for frame n+1
 void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderViews)
 {
diff --git a/render/renderers/opengl/renderer/renderer_p.h b/render/renderers/opengl/renderer/renderer_p.h
index ee01754..ed4a643 100644
--- a/render/renderers/opengl/renderer/renderer_p.h
+++ b/render/renderers/opengl/renderer/renderer_p.h
@@ -292,7 +292,6 @@ public:
 
     QVariant executeCommand(const QStringList &args) override;
     void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) override;
-    QSurfaceFormat format() override;
 
     struct ViewSubmissionResultData
     {
@@ -333,7 +332,6 @@ private:
     ShaderParameterPack m_defaultUniformPack;
 
     QScopedPointer<SubmissionContext> m_submissionContext;
-    QSurfaceFormat m_format;
 
     RenderQueue *m_renderQueue;
     QScopedPointer<RenderThread> m_renderThread;
