From eaa0d0d632f258500d4b0ab9fd2ee3d3f47c1c8a Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 14 Nov 2019 16:02:30 +0000 Subject: 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 --- src/render/frontend/qrenderaspect.cpp | 73 +++++++++++++++++++++++++++++++++-- src/render/frontend/qrenderaspect_p.h | 2 + 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'src/render') 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 #include -#include -#include #include -#include + +#ifdef Q_OS_MACOS +#include +#include +#endif QT_BEGIN_NAMESPACE +#ifdef Q_OS_MACOS +namespace { + +// adapted from qcocoahelpers.mm in QtBase +typedef QPair 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(commandCursor); + if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) { + auto versionCommand = reinterpret_cast(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(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(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 m_sceneImporter; QVector m_loadedPlugins; QVector m_renderPlugins; -- cgit v1.2.3