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
55QT_BEGIN_NAMESPACE
56
57Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO)
58
59QSGContextPlugin::QSGContextPlugin(QObject *parent)
60 : QObject(parent)
61{
62}
63
64QSGContextPlugin::~QSGContextPlugin()
65{
66}
67
68#if QT_CONFIG(library)
69Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
70 (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
71#endif
72
73struct 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
89QSGAdaptationBackendData::QSGAdaptationBackendData()
90{
91 // Fill in the table with the built-in adaptations.
92 builtIns.append(t: new QSGSoftwareAdaptation);
93}
94
95QSGAdaptationBackendData::~QSGAdaptationBackendData()
96{
97 qDeleteAll(c: builtIns);
98}
99
100Q_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.
107QSGContextFactoryInterface::Flags qsg_backend_flags()
108{
109 return qsg_adaptation_data()->flags;
110}
111
112QSGAdaptationBackendData *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*/
190QSGContext *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
211QQuickTextureFactory *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
225QSGRenderLoop *QSGContext::createWindowManager()
226{
227 QSGAdaptationBackendData *backendData = contextFactory();
228 if (backendData->factory)
229 return backendData->factory->createWindowManager();
230 return nullptr;
231}
232
233void 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
242QString QSGContext::backend()
243{
244 QSGAdaptationBackendData *backendData = qsg_adaptation_data();
245 if (backendData->tried)
246 return backendData->name;
247
248 return backendData->quickWindowBackendRequest;
249}
250
251QT_END_NAMESPACE
252
253#include "moc_qsgcontextplugin_p.cpp"
254

source code of qtdeclarative/src/quick/scenegraph/qsgcontextplugin.cpp