1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQuick module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qsgcontextplugin_p.h" |
41 | #include <QtQuick/private/qsgcontext_p.h> |
42 | #include <QtGui/qguiapplication.h> |
43 | #include <QtCore/private/qfactoryloader_p.h> |
44 | #include <QtCore/qlibraryinfo.h> |
45 | |
46 | // Built-in adaptations |
47 | #include <QtQuick/private/qsgsoftwareadaptation_p.h> |
48 | #if QT_CONFIG(opengl) |
49 | #include <QtQuick/private/qsgdefaultcontext_p.h> |
50 | #endif |
51 | |
52 | #include <QtGui/private/qguiapplication_p.h> |
53 | #include <QtGui/qpa/qplatformintegration.h> |
54 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO) |
58 | |
59 | QSGContextPlugin::QSGContextPlugin(QObject *parent) |
60 | : QObject(parent) |
61 | { |
62 | } |
63 | |
64 | QSGContextPlugin::~QSGContextPlugin() |
65 | { |
66 | } |
67 | |
68 | #if QT_CONFIG(library) |
69 | Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, |
70 | (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph" ))) |
71 | #endif |
72 | |
73 | struct QSGAdaptationBackendData |
74 | { |
75 | QSGAdaptationBackendData(); |
76 | ~QSGAdaptationBackendData(); |
77 | Q_DISABLE_COPY(QSGAdaptationBackendData) |
78 | |
79 | bool tried = false; |
80 | QSGContextFactoryInterface *factory = nullptr; |
81 | QString name; |
82 | QSGContextFactoryInterface::Flags flags; |
83 | |
84 | QVector<QSGContextFactoryInterface *> builtIns; |
85 | |
86 | QString quickWindowBackendRequest; |
87 | }; |
88 | |
89 | QSGAdaptationBackendData::QSGAdaptationBackendData() |
90 | { |
91 | // Fill in the table with the built-in adaptations. |
92 | builtIns.append(t: new QSGSoftwareAdaptation); |
93 | } |
94 | |
95 | QSGAdaptationBackendData::~QSGAdaptationBackendData() |
96 | { |
97 | qDeleteAll(c: builtIns); |
98 | } |
99 | |
100 | Q_GLOBAL_STATIC(QSGAdaptationBackendData, qsg_adaptation_data) |
101 | |
102 | // This only works when the backend is loaded (contextFactory() was called), |
103 | // otherwise the return value is 0. |
104 | // |
105 | // Note that the default (OpenGL) implementation always results in 0, custom flags |
106 | // can only be returned from the other (either compiled-in or plugin-based) backends. |
107 | QSGContextFactoryInterface::Flags qsg_backend_flags() |
108 | { |
109 | return qsg_adaptation_data()->flags; |
110 | } |
111 | |
112 | QSGAdaptationBackendData *contextFactory() |
113 | { |
114 | QSGAdaptationBackendData *backendData = qsg_adaptation_data(); |
115 | |
116 | if (!backendData->tried) { |
117 | backendData->tried = true; |
118 | |
119 | const QStringList args = QGuiApplication::arguments(); |
120 | QString requestedBackend = backendData->quickWindowBackendRequest; // empty or set via QQuickWindow::setBackend() |
121 | |
122 | for (int index = 0; index < args.count(); ++index) { |
123 | if (args.at(i: index).startsWith(s: QLatin1String("--device=" ))) { |
124 | requestedBackend = args.at(i: index).mid(position: 9); |
125 | break; |
126 | } |
127 | } |
128 | |
129 | if (requestedBackend.isEmpty()) |
130 | requestedBackend = qEnvironmentVariable(varName: "QMLSCENE_DEVICE" ); |
131 | |
132 | // A modern alternative. Scenegraph adaptations can represent backends |
133 | // for different graphics APIs as well, instead of being specific to |
134 | // some device or platform. |
135 | if (requestedBackend.isEmpty()) |
136 | requestedBackend = qEnvironmentVariable(varName: "QT_QUICK_BACKEND" ); |
137 | |
138 | // If this platform does not support OpenGL, and no backend has been set |
139 | // default to the software renderer |
140 | if (requestedBackend.isEmpty() |
141 | && !QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::OpenGL)) { |
142 | requestedBackend = QString::fromLocal8Bit(str: "software" ); |
143 | } |
144 | |
145 | if (!requestedBackend.isEmpty()) { |
146 | qCDebug(QSG_LOG_INFO, "Loading backend %s" , qUtf8Printable(requestedBackend)); |
147 | |
148 | // First look for a built-in adaptation. |
149 | for (QSGContextFactoryInterface *builtInBackend : qAsConst(t&: backendData->builtIns)) { |
150 | if (builtInBackend->keys().contains(str: requestedBackend)) { |
151 | backendData->factory = builtInBackend; |
152 | backendData->name = requestedBackend; |
153 | backendData->flags = backendData->factory->flags(key: requestedBackend); |
154 | break; |
155 | } |
156 | } |
157 | |
158 | #if QT_CONFIG(library) |
159 | // Then try the plugins. |
160 | if (!backendData->factory) { |
161 | const int index = loader()->indexOf(needle: requestedBackend); |
162 | if (index != -1) |
163 | backendData->factory = qobject_cast<QSGContextFactoryInterface*>(object: loader()->instance(index)); |
164 | if (backendData->factory) { |
165 | backendData->name = requestedBackend; |
166 | backendData->flags = backendData->factory->flags(key: requestedBackend); |
167 | } |
168 | if (!backendData->factory) { |
169 | qWarning(msg: "Could not create scene graph context for backend '%s'" |
170 | " - check that plugins are installed correctly in %s" , |
171 | qPrintable(requestedBackend), |
172 | qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath))); |
173 | } |
174 | } |
175 | #endif // library |
176 | } |
177 | } |
178 | |
179 | return backendData; |
180 | } |
181 | |
182 | |
183 | |
184 | /*! |
185 | \fn QSGContext *QSGContext::createDefaultContext() |
186 | |
187 | Creates a default scene graph context for the current hardware. |
188 | This may load a device-specific plugin. |
189 | */ |
190 | QSGContext *QSGContext::createDefaultContext() |
191 | { |
192 | QSGAdaptationBackendData *backendData = contextFactory(); |
193 | if (backendData->factory) |
194 | return backendData->factory->create(key: backendData->name); |
195 | #if QT_CONFIG(opengl) |
196 | return new QSGDefaultContext(); |
197 | #else |
198 | return nullptr; |
199 | #endif |
200 | } |
201 | |
202 | |
203 | |
204 | /*! |
205 | Calls into the scene graph adaptation if available and creates a texture |
206 | factory. The primary purpose of this function is to reimplement hardware |
207 | specific asynchronous texture frameskip-less uploads that can happen on |
208 | the image providers thread. |
209 | */ |
210 | |
211 | QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &image) |
212 | { |
213 | QSGAdaptationBackendData *backendData = contextFactory(); |
214 | if (backendData->factory) |
215 | return backendData->factory->createTextureFactoryFromImage(image); |
216 | return nullptr; |
217 | } |
218 | |
219 | |
220 | /*! |
221 | Calls into the scene graph adaptation if available and creates a hardware |
222 | specific window manager. |
223 | */ |
224 | |
225 | QSGRenderLoop *QSGContext::createWindowManager() |
226 | { |
227 | QSGAdaptationBackendData *backendData = contextFactory(); |
228 | if (backendData->factory) |
229 | return backendData->factory->createWindowManager(); |
230 | return nullptr; |
231 | } |
232 | |
233 | void QSGContext::setBackend(const QString &backend) |
234 | { |
235 | QSGAdaptationBackendData *backendData = qsg_adaptation_data(); |
236 | if (backendData->tried) |
237 | qWarning(msg: "Scenegraph already initialized, setBackend() request ignored" ); |
238 | |
239 | backendData->quickWindowBackendRequest = backend; |
240 | } |
241 | |
242 | QString QSGContext::backend() |
243 | { |
244 | QSGAdaptationBackendData *backendData = qsg_adaptation_data(); |
245 | if (backendData->tried) |
246 | return backendData->name; |
247 | |
248 | return backendData->quickWindowBackendRequest; |
249 | } |
250 | |
251 | QT_END_NAMESPACE |
252 | |
253 | #include "moc_qsgcontextplugin_p.cpp" |
254 | |