diff options
author | Mike Krus <mike.krus@kdab.com> | 2019-11-14 16:02:30 +0000 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2019-11-14 21:32:49 +0000 |
commit | eaa0d0d632f258500d4b0ab9fd2ee3d3f47c1c8a (patch) | |
tree | 264431a19c8936358050eee0d0743a04e3a0a55c /src/render/frontend/qrenderaspect.cpp | |
parent | aef625746025bbb5c5af1a3f8159c77413ceeaf5 (diff) | |
download | qt3d-eaa0d0d632f258500d4b0ab9fd2ee3d3f47c1c8a.tar.gz |
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/render/frontend/qrenderaspect.cpp')
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 73 |
1 files changed, 70 insertions, 3 deletions
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); |