Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgcontextplugin.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <QtQuick/private/qsgcontext_p.h>
6#include <QtGui/qguiapplication.h>
7#include <QtCore/private/qfactoryloader_p.h>
8#include <QtCore/qlibraryinfo.h>
9
10// Built-in adaptations
11#include <QtQuick/private/qsgsoftwareadaptation_p.h>
12#include <QtQuick/private/qsgdefaultcontext_p.h>
13
14#include <QtGui/private/qguiapplication_p.h>
15#include <QtGui/qpa/qplatformintegration.h>
16
18
19QSGContextPlugin::QSGContextPlugin(QObject *parent)
20 : QObject(parent)
21{
22}
23
24QSGContextPlugin::~QSGContextPlugin()
25{
26}
27
28#if QT_CONFIG(library)
29Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
30 (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
31#endif
32
48
50{
51 // Fill in the table with the built-in adaptations.
52 builtIns.append(new QSGSoftwareAdaptation);
53}
54
56{
57 qDeleteAll(builtIns);
58}
59
60Q_GLOBAL_STATIC(QSGAdaptationBackendData, qsg_adaptation_data)
61
62// This only works when the backend is loaded (contextFactory() was called),
63// otherwise the return value is 0.
64//
65// Note that the default (OpenGL) implementation always results in 0, custom flags
66// can only be returned from the other (either compiled-in or plugin-based) backends.
67QSGContextFactoryInterface::Flags qsg_backend_flags()
68{
69 return qsg_adaptation_data()->flags;
70}
71
72QSGAdaptationBackendData *contextFactory()
73{
74 QSGAdaptationBackendData *backendData = qsg_adaptation_data();
75
76 if (!backendData->tried) {
77 backendData->tried = true;
78
79 const QStringList args = QGuiApplication::arguments();
80 QString requestedBackend = backendData->quickWindowBackendRequest; // empty or set via QQuickWindow::setSceneGraphBackend()
81
82 for (int index = 0; index < args.size(); ++index) {
83 if (args.at(index).startsWith(QLatin1String("--device="))) {
84 requestedBackend = args.at(index).mid(9);
85 break;
86 }
87 }
88
89 if (requestedBackend.isEmpty())
90 requestedBackend = qEnvironmentVariable("QMLSCENE_DEVICE");
91
92 // A modern alternative. Scenegraph adaptations can represent backends
93 // for different graphics APIs as well, instead of being specific to
94 // some device or platform.
95 if (requestedBackend.isEmpty())
96 requestedBackend = qEnvironmentVariable("QT_QUICK_BACKEND");
97
98 // If this platform does not support OpenGL, Vulkan, D3D11, or Metal, and no
99 // backend has been set, default to the software renderer. We rely on the
100 // static, build time flags only. This is to prevent the inevitable confusion
101 // caused by run time hocus pocus. If one wants to use the software backend
102 // in a GL or Vulkan capable Qt build (or on Windows or Apple platforms), it
103 // has to be requested explicitly.
104#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan) && !QT_CONFIG(metal) && !defined(Q_OS_WIN)
105 if (requestedBackend.isEmpty())
106 requestedBackend = QLatin1String("software");
107#endif
108
109 // As an exception to the above, play nice with platform plugins like
110 // vnc or linuxfb: Trying to initialize a QRhi is futile on these, and
111 // Qt 5 had an explicit fallback to the software backend, based on the
112 // OpenGL capability. Replicate that behavior using the new
113 // RhiBasedRendering capability flag, which, on certain platforms,
114 // indicates that we should not even bother trying to initialize a QRhi
115 // as no 3D API can be expected work.
116 if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering)) {
117 if (requestedBackend.isEmpty())
118 requestedBackend = QLatin1String("software");
119 }
120
121 // This is handy if some of the logic above goes wrong and we select
122 // e.g. the software backend when it is not desired.
123 if (requestedBackend == QLatin1String("rhi"))
124 requestedBackend.clear(); // empty = no custom backend to load
125
126 if (!requestedBackend.isEmpty()) {
127 qCDebug(QSG_LOG_INFO, "Loading backend %s", qUtf8Printable(requestedBackend));
128
129 // First look for a built-in adaptation.
130 for (QSGContextFactoryInterface *builtInBackend : std::as_const(backendData->builtIns)) {
131 if (builtInBackend->keys().contains(requestedBackend)) {
132 backendData->factory = builtInBackend;
133 backendData->name = requestedBackend;
134 backendData->flags = backendData->factory->flags(requestedBackend);
135 break;
136 }
137 }
138
139#if QT_CONFIG(library)
140 // Then try the plugins.
141 if (!backendData->factory) {
142 const int index = loader()->indexOf(requestedBackend);
143 if (index != -1)
144 backendData->factory = qobject_cast<QSGContextFactoryInterface*>(loader()->instance(index));
145 if (backendData->factory) {
146 backendData->name = requestedBackend;
147 backendData->flags = backendData->factory->flags(requestedBackend);
148 }
149 if (!backendData->factory) {
150 qWarning("Could not create scene graph context for backend '%s'"
151 " - check that plugins are installed correctly in %s",
152 qPrintable(requestedBackend),
153 qPrintable(QLibraryInfo::path(QLibraryInfo::PluginsPath)));
154 }
155 }
156#endif // library
157 }
158 }
159
160 return backendData;
161}
162
163
164
165/*!
166 \fn QSGContext *QSGContext::createDefaultContext()
167
168 Creates a default scene graph context for the current hardware.
169 This may load a device-specific plugin.
170*/
171QSGContext *QSGContext::createDefaultContext()
172{
173 QSGAdaptationBackendData *backendData = contextFactory();
174 if (backendData->factory)
175 return backendData->factory->create(backendData->name);
176 return new QSGDefaultContext();
177}
178
179
180
181/*!
182 Calls into the scene graph adaptation if available and creates a texture
183 factory. The primary purpose of this function is to reimplement hardware
184 specific asynchronous texture frameskip-less uploads that can happen on
185 the image providers thread.
186 */
187
188QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &image)
189{
190 QSGAdaptationBackendData *backendData = contextFactory();
191 if (backendData->factory)
192 return backendData->factory->createTextureFactoryFromImage(image);
193 return nullptr;
194}
195
196
197/*!
198 Calls into the scene graph adaptation if available and creates a hardware
199 specific window manager.
200 */
201
202QSGRenderLoop *QSGContext::createWindowManager()
203{
204 QSGAdaptationBackendData *backendData = contextFactory();
205 if (backendData->factory)
206 return backendData->factory->createWindowManager();
207 return nullptr;
208}
209
210void QSGContext::setBackend(const QString &backend)
211{
212 QSGAdaptationBackendData *backendData = qsg_adaptation_data();
213 if (backendData->tried)
214 qWarning("Scenegraph already initialized, setBackend() request ignored");
215
216 backendData->quickWindowBackendRequest = backend;
217}
218
219QString QSGContext::backend()
220{
221 QSGAdaptationBackendData *backendData = qsg_adaptation_data();
222 if (backendData->tried)
223 return backendData->name;
224
225 return backendData->quickWindowBackendRequest;
226}
227
228QT_END_NAMESPACE
229
230#include "moc_qsgcontextplugin_p.cpp"
QSGContextFactoryInterface * factory
QVector< QSGContextFactoryInterface * > builtIns