1// Copyright (C) 2017 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
4#include "qscene2d.h"
5#include "qscene2d_p.h"
6#include "scene2d_p.h"
7#include "scene2dmanager_p.h"
8#include "scene2devent_p.h"
9
10QT_BEGIN_NAMESPACE
11
12using namespace Qt3DCore;
13
14namespace Qt3DRender {
15
16namespace Quick {
17
18class RenderControl : public QQuickRenderControl
19{
20public:
21 RenderControl(QWindow *w) : m_window(w) { }
22 QWindow *renderWindow(QPoint *offset) override;
23
24private:
25 QWindow *m_window;
26};
27
28QWindow *RenderControl::renderWindow(QPoint *offset)
29{
30 if (offset)
31 *offset = QPoint(0, 0);
32 return m_window;
33}
34
35/*!
36 \internal
37 Constructs qml render manager.
38 */
39Scene2DManager::Scene2DManager(QScene2DPrivate *priv)
40 : m_rootItem(nullptr)
41 , m_item(nullptr)
42 , m_priv(priv)
43 , m_sharedObject(new Scene2DSharedObject(this))
44 , m_renderPolicy(QScene2D::Continuous)
45 , m_requested(false)
46 , m_initialized(false)
47 , m_renderSyncRequested(false)
48 , m_backendInitialized(false)
49 , m_mouseEnabled(true)
50{
51 m_sharedObject->m_surface = new QOffscreenSurface;
52 m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat());
53 m_sharedObject->m_surface->create();
54
55 // Create render control
56 m_sharedObject->m_renderControl = new RenderControl(nullptr);
57
58 // Create window to render the QML with
59 m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl);
60 // TODOQT6 see qtdeclarative 0d43e21429ee23442ec3a99f641a5665d66e75e2
61 //m_sharedObject->m_quickWindow->setClearBeforeRendering(true);
62 m_sharedObject->m_quickWindow->setColor(Qt::transparent);
63
64 connect(sender: m_sharedObject->m_renderControl, signal: &QQuickRenderControl::renderRequested,
65 context: this, slot: &Scene2DManager::requestRender);
66 connect(sender: m_sharedObject->m_renderControl, signal: &QQuickRenderControl::sceneChanged,
67 context: this, slot: &Scene2DManager::requestRenderSync);
68}
69
70Scene2DManager::~Scene2DManager()
71{
72 m_sharedObject = nullptr;
73}
74
75void Scene2DManager::requestRender()
76{
77 // Don't request render until the backend is initialized.
78 if (m_sharedObject->canRender()) {
79 if (!m_requested) {
80 m_requested = true;
81 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::Render));
82 }
83 }
84}
85
86void Scene2DManager::requestRenderSync()
87{
88 // Don't request render until the backed is initialized.
89 if (m_sharedObject->canRender()) {
90 if (!m_requested) {
91 m_requested = true;
92 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
93 }
94 } else {
95 m_renderSyncRequested = true;
96 }
97}
98
99void Scene2DManager::startIfInitialized()
100{
101 if (!m_initialized && m_backendInitialized && m_item != nullptr) {
102 m_rootItem = m_item;
103
104 // Associate root item with the window.
105 m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
106
107 // Update window size.
108 updateSizes();
109
110 m_initialized = true;
111 m_sharedObject->setInitialized();
112
113 // Request render if we have already been requested and preparation has already been done
114 if (m_sharedObject->isPrepared() && m_renderSyncRequested) {
115 if (!m_requested) {
116 m_requested = true;
117 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
118 }
119 m_renderSyncRequested = false;
120 }
121 }
122}
123
124void Scene2DManager::stopAndClean()
125{
126 if (m_sharedObject->isInitialized()) {
127 QMutexLocker lock(&m_sharedObject->m_mutex);
128 m_sharedObject->requestQuit();
129 m_sharedObject->wait();
130 m_sharedObject->cleanup();
131 }
132}
133
134void Scene2DManager::updateSizes()
135{
136 const int width = m_rootItem->width();
137 const int height = m_rootItem->height();
138 if (width == 0 || height == 0) {
139 qWarning() << "QScene2D: Root item size not set.";
140 return;
141 }
142 m_sharedObject->m_quickWindow->setGeometry(posx: 0, posy: 0, w: width, h: height);
143}
144
145void Scene2DManager::setItem(QQuickItem *item)
146{
147 m_item = item;
148 startIfInitialized();
149}
150
151bool Scene2DManager::event(QEvent *e)
152{
153 switch (static_cast<Scene2DEvent::Type>(e->type())) {
154
155 case Scene2DEvent::Render: {
156 // just render request, don't need to call sync in render thread
157 QMutexLocker lock(&m_sharedObject->m_mutex);
158 m_sharedObject->requestRender(sync: false);
159 m_requested = false;
160 return true;
161 }
162
163 case Scene2DEvent::RenderSync: {
164 // sync and render request, main and render threads must be synchronized
165 if (!m_sharedObject->isQuit())
166 doRenderSync();
167 m_requested = false;
168 return true;
169 }
170
171 case Scene2DEvent::Prepare: {
172 m_sharedObject->m_renderControl->prepareThread(targetThread: m_sharedObject->m_renderThread);
173 m_sharedObject->setPrepared();
174
175 if (m_renderSyncRequested) {
176 if (!m_requested) {
177 m_requested = true;
178 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
179 }
180 m_renderSyncRequested = false;
181 }
182 return true;
183 }
184
185 case Scene2DEvent::Initialized: {
186 // backend is initialized, start the qml
187 m_backendInitialized = true;
188 startIfInitialized();
189 return true;
190 }
191
192 case Scene2DEvent::Rendered: {
193 // render is done, excellent, now clean anything not needed anymore.
194 stopAndClean();
195 return true;
196 }
197
198 default:
199 break;
200 }
201 return QObject::event(event: e);
202}
203
204void Scene2DManager::doRenderSync()
205{
206 QMutexLocker lock(&m_sharedObject->m_mutex);
207
208 m_sharedObject->requestRender(sync: true);
209 m_sharedObject->m_renderControl->polishItems();
210
211 // begin waiting render thread
212 m_sharedObject->wait();
213 m_requested = false;
214}
215
216void Scene2DManager::cleanup()
217{
218 stopAndClean();
219}
220
221} // namespace Quick
222} // namespace Qt3DRender
223
224QT_END_NAMESPACE
225
226#include "moc_scene2dmanager_p.cpp"
227

source code of qt3d/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp