summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2019-11-14 16:02:30 +0000
committerMike Krus <mike.krus@kdab.com>2019-11-14 21:32:49 +0000
commiteaa0d0d632f258500d4b0ab9fd2ee3d3f47c1c8a (patch)
tree264431a19c8936358050eee0d0743a04e3a0a55c /src
parentaef625746025bbb5c5af1a3f8159c77413ceeaf5 (diff)
Disable threaded rendering macOS 10.14 and later
Making context current from background thread crashes on Catalina. In this case, we disable threaded rendering. This implies changes in the order in which initialization and rendering happens. We can't just rely on rendering type since Scene3D is not threaded but has it's own initialization logic. Ideally 5.15 should introduce proper API since currently manually setting a QWindow based app to use Synchronous rendering will hang at initialization time. Task-number: QTBUG-80049 Change-Id: Ic346a44d8e0add8232a16129e878423f4cf2f4f1 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src')
-rw-r--r--src/core/aspects/qabstractaspect.cpp5
-rw-r--r--src/core/aspects/qabstractaspect_p.h1
-rw-r--r--src/core/jobs/qaspectjobproviderinterface_p.h1
-rw-r--r--src/core/qscheduler.cpp3
-rw-r--r--src/render/frontend/qrenderaspect.cpp73
-rw-r--r--src/render/frontend/qrenderaspect_p.h2
6 files changed, 82 insertions, 3 deletions
diff --git a/src/core/aspects/qabstractaspect.cpp b/src/core/aspects/qabstractaspect.cpp
index 19b6f70c1..6e0d3bd02 100644
--- a/src/core/aspects/qabstractaspect.cpp
+++ b/src/core/aspects/qabstractaspect.cpp
@@ -508,6 +508,11 @@ QVector<QAspectJobPtr> QAbstractAspectPrivate::jobsToExecute(qint64 time)
return res;
}
+void QAbstractAspectPrivate::jobsDone()
+{
+
+}
+
/*!
* Called in the context of the aspect thread once the aspect has been registered.
* This provides an opportunity for the aspect to do any initialization tasks that
diff --git a/src/core/aspects/qabstractaspect_p.h b/src/core/aspects/qabstractaspect_p.h
index 325fca678..b4120cb20 100644
--- a/src/core/aspects/qabstractaspect_p.h
+++ b/src/core/aspects/qabstractaspect_p.h
@@ -127,6 +127,7 @@ public:
QAbstractAspectJobManager *jobManager() const;
QVector<QAspectJobPtr> jobsToExecute(qint64 time) override;
+ void jobsDone() override;
QBackendNode *createBackendNode(const NodeTreeChange &change) const;
void clearBackendNode(const NodeTreeChange &change) const;
diff --git a/src/core/jobs/qaspectjobproviderinterface_p.h b/src/core/jobs/qaspectjobproviderinterface_p.h
index 29b44b3c1..f7d0f9d39 100644
--- a/src/core/jobs/qaspectjobproviderinterface_p.h
+++ b/src/core/jobs/qaspectjobproviderinterface_p.h
@@ -69,6 +69,7 @@ public:
private:
virtual QVector<QAspectJobPtr> jobsToExecute(qint64 time) = 0;
+ virtual void jobsDone() = 0;
friend class QScheduler;
};
diff --git a/src/core/qscheduler.cpp b/src/core/qscheduler.cpp
index e714e477d..03d5670cb 100644
--- a/src/core/qscheduler.cpp
+++ b/src/core/qscheduler.cpp
@@ -94,6 +94,9 @@ void QScheduler::scheduleAndWaitForFrameAspectJobs(qint64 time)
for (auto &job : qAsConst(jobQueue))
QAspectJobPrivate::get(job.data())->postFrame(m_aspectManager);
+
+ for (QAbstractAspect *aspect : aspects)
+ QAbstractAspectPrivate::get(aspect)->jobsDone();
}
} // namespace Qt3DCore
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index 72f114481..bc79982ba 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -170,13 +170,53 @@
#include <Qt3DCore/QAspectEngine>
#include <Qt3DCore/private/qservicelocator_p.h>
-#include <QDebug>
-#include <QOffscreenSurface>
#include <QThread>
-#include <QWindow>
+
+#ifdef Q_OS_MACOS
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#endif
QT_BEGIN_NAMESPACE
+#ifdef Q_OS_MACOS
+namespace {
+
+// adapted from qcocoahelpers.mm in QtBase
+typedef QPair<QOperatingSystemVersion, QOperatingSystemVersion> VersionTuple;
+
+VersionTuple versionsForImage(const mach_header *machHeader)
+{
+ static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk) {
+ return qMakePair(
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS,
+ dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff),
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS,
+ sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff)
+ );
+ };
+
+ auto commandCursor = uintptr_t(machHeader) + sizeof(mach_header_64);
+ for (uint32_t i = 0; i < machHeader->ncmds; ++i) {
+ load_command *loadCommand = reinterpret_cast<load_command *>(commandCursor);
+ if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) {
+ auto versionCommand = reinterpret_cast<version_min_command *>(loadCommand);
+ return makeVersionTuple(versionCommand->version, versionCommand->sdk);
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13)
+ } else if (loadCommand->cmd == LC_BUILD_VERSION) {
+ auto versionCommand = reinterpret_cast<build_version_command *>(loadCommand);
+ return makeVersionTuple(versionCommand->minos, versionCommand->sdk);
+#endif
+ }
+ commandCursor += loadCommand->cmdsize;
+ }
+ Q_ASSERT_X(false, "QCocoaIntegration", "Could not find any version load command");
+ Q_UNREACHABLE();
+}
+
+}
+#endif
+
using namespace Qt3DCore;
namespace Qt3DRender {
@@ -202,11 +242,30 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type)
, m_nodeManagers(nullptr)
, m_renderer(nullptr)
, m_initialized(false)
+ , m_renderAfterJobs(false)
, m_renderType(type)
, m_offscreenHelper(nullptr)
{
m_instances.append(this);
loadSceneParsers();
+#ifdef Q_OS_MACOS
+ static VersionTuple version = []() {
+ const mach_header *executableHeader = nullptr;
+ for (uint32_t i = 0; i < _dyld_image_count(); ++i) {
+ auto header = _dyld_get_image_header(i);
+ if (header->filetype == MH_EXECUTE) {
+ executableHeader = header;
+ break;
+ }
+ }
+ Q_ASSERT_X(executableHeader, "QCocoaIntegration", "Failed to resolve Mach-O header of executable");
+ return versionsForImage(executableHeader);
+ }();
+ if (m_renderType == QRenderAspect::Threaded && version.second >= QOperatingSystemVersion(QOperatingSystemVersion::MacOSMojave)) {
+ m_renderType = QRenderAspect::Synchronous;
+ m_renderAfterJobs = true;
+ }
+#endif
}
/*! \internal */
@@ -239,6 +298,12 @@ void QRenderAspectPrivate::syncDirtyFrontEndNode(QNode *node, QBackendNode *back
renderBackend->syncFromFrontEnd(node, firstTime);
}
+void QRenderAspectPrivate::jobsDone()
+{
+ if (m_renderAfterJobs)
+ m_renderer->doRender(true);
+}
+
/*! \internal */
void QRenderAspectPrivate::registerBackendTypes()
{
@@ -539,6 +604,8 @@ QVariant QRenderAspect::executeCommand(const QStringList &args)
void QRenderAspect::onEngineStartup()
{
Q_D(QRenderAspect);
+ if (d->m_renderAfterJobs) // synchronous rendering but using QWindow
+ d->m_renderer->initialize();
Render::NodeManagers *managers = d->m_renderer->nodeManagers();
Render::Entity *rootEntity = managers->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
Q_ASSERT(rootEntity);
diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h
index b4cb0812c..305e58403 100644
--- a/src/render/frontend/qrenderaspect_p.h
+++ b/src/render/frontend/qrenderaspect_p.h
@@ -87,6 +87,7 @@ public:
static QRenderAspectPrivate* findPrivate(Qt3DCore::QAspectEngine *engine);
void syncDirtyFrontEndNode(Qt3DCore::QNode *node, Qt3DCore::QBackendNode *backend, bool firstTime) const override;
+ void jobsDone() override;
void registerBackendTypes();
void unregisterBackendTypes();
@@ -101,6 +102,7 @@ public:
Render::AbstractRenderer *m_renderer;
bool m_initialized;
+ bool m_renderAfterJobs;
QList<QSceneImporter *> m_sceneImporter;
QVector<QString> m_loadedPlugins;
QVector<Render::QRenderPlugin *> m_renderPlugins;