summaryrefslogtreecommitdiff
path: root/src/render/frontend/qrenderaspect.cpp
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/render/frontend/qrenderaspect.cpp
parentaef625746025bbb5c5af1a3f8159c77413ceeaf5 (diff)
downloadqt3d-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.cpp73
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);