1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "declarativerendernode_p.h" |
5 | #include "abstractdeclarative_p.h" |
6 | #include <QtOpenGL/QOpenGLFramebufferObject> |
7 | #include <QtCore/QMutexLocker> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | DeclarativeRenderNode::DeclarativeRenderNode(AbstractDeclarative *declarative, |
12 | const QSharedPointer<QMutex> &nodeMutex) |
13 | : QSGGeometryNode(), |
14 | m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4), |
15 | m_texture(0), |
16 | m_declarative(declarative), |
17 | m_controller(0), |
18 | m_fbo(0), |
19 | m_multisampledFBO(0), |
20 | m_window(0), |
21 | m_samples(0), |
22 | m_dirtyFBO(false) |
23 | { |
24 | m_nodeMutex = nodeMutex; |
25 | setMaterial(&m_material); |
26 | setOpaqueMaterial(&m_materialO); |
27 | setGeometry(&m_geometry); |
28 | setFlag(UsePreprocess); |
29 | } |
30 | |
31 | DeclarativeRenderNode::~DeclarativeRenderNode() |
32 | { |
33 | delete m_fbo; |
34 | delete m_multisampledFBO; |
35 | delete m_texture; |
36 | |
37 | m_nodeMutex.clear(); |
38 | } |
39 | |
40 | void DeclarativeRenderNode::setSize(const QSize &size) |
41 | { |
42 | if (size == m_size) |
43 | return; |
44 | |
45 | m_size = size; |
46 | m_dirtyFBO = true; |
47 | markDirty(bits: DirtyGeometry); |
48 | } |
49 | |
50 | void DeclarativeRenderNode::update() |
51 | { |
52 | if (m_dirtyFBO) { |
53 | updateFBO(); |
54 | m_dirtyFBO = false; |
55 | } |
56 | } |
57 | |
58 | void DeclarativeRenderNode::updateFBO() |
59 | { |
60 | m_declarative->activateOpenGLContext(window: m_window); |
61 | |
62 | if (m_fbo) |
63 | delete m_fbo; |
64 | |
65 | m_fbo = new QOpenGLFramebufferObject(m_size); |
66 | m_fbo->setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); |
67 | |
68 | // Multisampled |
69 | if (m_multisampledFBO) { |
70 | delete m_multisampledFBO; |
71 | m_multisampledFBO = 0; |
72 | } |
73 | if (m_samples > 0) { |
74 | QOpenGLFramebufferObjectFormat multisampledFrambufferFormat; |
75 | multisampledFrambufferFormat.setSamples(m_samples); |
76 | multisampledFrambufferFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); |
77 | |
78 | m_multisampledFBO = new QOpenGLFramebufferObject(m_size, multisampledFrambufferFormat); |
79 | } |
80 | |
81 | QSGGeometry::updateTexturedRectGeometry(g: &m_geometry, |
82 | rect: QRectF(0, 0, |
83 | m_size.width() |
84 | / m_controller->scene()->devicePixelRatio(), |
85 | m_size.height() |
86 | / m_controller->scene()->devicePixelRatio()), |
87 | sourceRect: QRectF(0, 1, 1, -1)); |
88 | |
89 | delete m_texture; |
90 | const uint id = m_fbo->texture(); |
91 | m_texture = QNativeInterface::QSGOpenGLTexture::fromNative(textureId: id, window: m_window, size: m_size); |
92 | m_material.setTexture(m_texture); |
93 | m_materialO.setTexture(m_texture); |
94 | |
95 | m_declarative->doneOpenGLContext(window: m_window); |
96 | } |
97 | |
98 | void DeclarativeRenderNode::setQuickWindow(QQuickWindow *window) |
99 | { |
100 | Q_ASSERT(window); |
101 | |
102 | m_window = window; |
103 | } |
104 | |
105 | void DeclarativeRenderNode::setController(Abstract3DController *controller) |
106 | { |
107 | QMutexLocker locker(m_nodeMutex.data()); |
108 | m_controller = controller; |
109 | if (m_controller) { |
110 | connect(sender: m_controller, signal: &QObject::destroyed, |
111 | context: this, slot: &DeclarativeRenderNode::handleControllerDestroyed, type: Qt::DirectConnection); |
112 | } |
113 | } |
114 | |
115 | void DeclarativeRenderNode::setSamples(int samples) |
116 | { |
117 | if (m_samples == samples) |
118 | return; |
119 | |
120 | m_samples = samples; |
121 | m_dirtyFBO = true; |
122 | } |
123 | |
124 | void DeclarativeRenderNode::preprocess() |
125 | { |
126 | QMutexLocker locker(m_nodeMutex.data()); |
127 | |
128 | if (!m_controller) |
129 | return; |
130 | |
131 | QOpenGLFramebufferObject *targetFBO; |
132 | if (m_samples > 0) |
133 | targetFBO = m_multisampledFBO; |
134 | else |
135 | targetFBO = m_fbo; |
136 | |
137 | m_declarative->activateOpenGLContext(window: m_window); |
138 | |
139 | targetFBO->bind(); |
140 | // Render scene here |
141 | m_controller->render(defaultFboHandle: targetFBO->handle()); |
142 | |
143 | targetFBO->release(); |
144 | |
145 | if (m_samples > 0) |
146 | QOpenGLFramebufferObject::blitFramebuffer(target: m_fbo, source: m_multisampledFBO); |
147 | |
148 | m_declarative->doneOpenGLContext(window: m_window); |
149 | } |
150 | |
151 | // This function is called within m_nodeMutex lock |
152 | void DeclarativeRenderNode::handleControllerDestroyed() |
153 | { |
154 | m_controller = 0; |
155 | } |
156 | |
157 | QT_END_NAMESPACE |
158 | |