Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsgsoftwarerenderablenode.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
12#if QT_CONFIG(quick_sprite)
14#endif
15
16#include <qsgsimplerectnode.h>
18#include <private/qsgrendernode_p.h>
19#include <private/qsgplaintexture_p.h>
20
21#include <qmath.h>
22
23Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable")
24
26
27// Largest subrectangle with integer coordinates
28inline QRect toRectMin(const QRectF & r)
29{
30 int x1 = qCeil(r.left());
31 int x2 = qFloor(r.right());
32 int y1 = qCeil(r.top());
33 int y2 = qFloor(r.bottom());
34 return QRect(x1, y1, x2 - x1, y2 - y1);
35}
36
37// Smallest superrectangle with integer coordinates
38inline QRect toRectMax(const QRectF & r)
39{
40 return r.toAlignedRect();
41}
42
44 : m_nodeType(type)
45 , m_isOpaque(true)
46 , m_isDirty(true)
47 , m_hasClipRegion(false)
48 , m_opacity(1.0f)
49{
50 switch (m_nodeType) {
52 m_handle.simpleRectNode = static_cast<QSGSimpleRectNode*>(node);
53 break;
55 m_handle.simpleTextureNode = static_cast<QSGSimpleTextureNode*>(node);
56 break;
58 m_handle.imageNode = static_cast<QSGSoftwareInternalImageNode*>(node);
59 break;
61 m_handle.painterNode = static_cast<QSGSoftwarePainterNode*>(node);
62 break;
64 m_handle.rectangleNode = static_cast<QSGSoftwareInternalRectangleNode*>(node);
65 break;
67 m_handle.glpyhNode = static_cast<QSGSoftwareGlyphNode*>(node);
68 break;
70 m_handle.ninePatchNode = static_cast<QSGSoftwareNinePatchNode*>(node);
71 break;
73 m_handle.simpleRectangleNode = static_cast<QSGRectangleNode*>(node);
74 break;
76 m_handle.simpleImageNode = static_cast<QSGImageNode*>(node);
77 break;
78#if QT_CONFIG(quick_sprite)
79 case QSGSoftwareRenderableNode::SpriteNode:
80 m_handle.spriteNode = static_cast<QSGSoftwareSpriteNode*>(node);
81 break;
82#endif
84 m_handle.renderNode = static_cast<QSGRenderNode*>(node);
85 break;
87 m_handle.simpleRectNode = nullptr;
88 break;
89 }
90}
91
96
98{
99 // Update the Node properties
100 m_isDirty = true;
101 m_isOpaque = false;
102
104
105 switch (m_nodeType) {
107 if (m_handle.simpleRectNode->color().alpha() == 255)
108 m_isOpaque = true;
109
110 boundingRect = m_handle.simpleRectNode->rect();
111 break;
113 if (!m_handle.simpleTextureNode->texture()->hasAlphaChannel())
114 m_isOpaque = true;
115
116 boundingRect = m_handle.simpleTextureNode->rect();
117 break;
119 m_isOpaque = !m_handle.imageNode->pixmap().hasAlphaChannel();
120
121 boundingRect = m_handle.imageNode->rect().toRect();
122 break;
124 if (m_handle.painterNode->opaquePainting())
125 m_isOpaque = true;
126
127 boundingRect = QRectF(0, 0, m_handle.painterNode->size().width(), m_handle.painterNode->size().height());
128 break;
130 if (m_handle.rectangleNode->isOpaque())
131 m_isOpaque = true;
132
133 boundingRect = m_handle.rectangleNode->rect();
134 break;
136 // Always has alpha
137 boundingRect = m_handle.glpyhNode->boundingRect();
138 break;
140 m_isOpaque = m_handle.ninePatchNode->isOpaque();
141
142 boundingRect = m_handle.ninePatchNode->bounds();
143 break;
145 if (m_handle.simpleRectangleNode->color().alpha() == 255)
146 m_isOpaque = true;
147
148 boundingRect = m_handle.simpleRectangleNode->rect();
149 break;
151 if (!m_handle.simpleImageNode->texture()->hasAlphaChannel())
152 m_isOpaque = true;
153
154 boundingRect = m_handle.simpleImageNode->rect();
155 break;
156#if QT_CONFIG(quick_sprite)
157 case QSGSoftwareRenderableNode::SpriteNode:
158 m_isOpaque = m_handle.spriteNode->isOpaque();
159 boundingRect = m_handle.spriteNode->rect();
160 break;
161#endif
163 if (m_handle.renderNode->flags().testFlag(QSGRenderNode::OpaqueRendering))
164 m_isOpaque = true;
165
166 boundingRect = m_handle.renderNode->rect();
167 break;
168 default:
169 break;
170 }
171
172 if (m_transform.isRotating())
173 m_isOpaque = false;
174
175 const QRectF transformedRect = m_transform.mapRect(boundingRect);
176 m_boundingRectMin = toRectMin(transformedRect);
177 m_boundingRectMax = toRectMax(transformedRect);
178
179 if (m_hasClipRegion && m_clipRegion.rectCount() <= 1) {
180 // If there is a clipRegion, and it is empty, the item wont be rendered
181 if (m_clipRegion.isEmpty()) {
182 m_boundingRectMin = QRect();
183 m_boundingRectMax = QRect();
184 } else {
185 const auto rects = m_clipRegion.begin();
186 m_boundingRectMin = m_boundingRectMin.intersected(rects[0]);
187 m_boundingRectMax = m_boundingRectMax.intersected(rects[0]);
188 }
189 }
190
191 // Overrides
192 if (m_opacity < 1.0f)
193 m_isOpaque = false;
194
195 m_dirtyRegion = QRegion(m_boundingRectMax);
196}
197
199{
200 const QMatrix4x4 *projectionMatrix() const override { return &ident; }
201 QRect scissorRect() const override { return QRect(); }
202 bool scissorEnabled() const override { return false; }
203 int stencilValue() const override { return 0; }
204 bool stencilEnabled() const override { return false; }
205 const QRegion *clipRegion() const override { return &cr; }
208};
209
211{
213
214 // Check for don't paint conditions
215 if (m_nodeType != RenderNode) {
216 if (!m_isDirty || qFuzzyIsNull(m_opacity) || m_dirtyRegion.isEmpty()) {
217 m_isDirty = false;
218 m_dirtyRegion = QRegion();
219 return QRegion();
220 }
221 } else {
222 if (!m_isDirty || qFuzzyIsNull(m_opacity)) {
223 m_isDirty = false;
224 m_dirtyRegion = QRegion();
225 return QRegion();
226 } else {
227 QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(m_handle.renderNode);
228 rd->m_localMatrix = m_transform;
229 rd->m_matrix = &rd->m_localMatrix;
230 rd->m_opacity = m_opacity;
231
232 // all the clip region below is in world coordinates, taking m_transform into account already
233 QRegion cr = m_dirtyRegion;
234 if (m_clipRegion.rectCount() > 1)
235 cr &= m_clipRegion;
236
237 painter->save();
239 rs.cr = cr;
240 m_handle.renderNode->render(&rs);
241 painter->restore();
242
243 const QRect br = m_handle.renderNode->flags().testFlag(QSGRenderNode::BoundedRectRendering)
244 ? m_boundingRectMax // already mapped to world
245 : QRect(0, 0, painter->device()->width(), painter->device()->height());
246 m_previousDirtyRegion = QRegion(br);
247 m_isDirty = false;
248 m_dirtyRegion = QRegion();
249 return br;
250 }
251 }
252
253 painter->save();
254 painter->setOpacity(m_opacity);
255
256 // Set clipRegion to m_dirtyRegion (in world coordinates, so must be done before the setTransform below)
257 // as m_dirtyRegion already accounts for clipRegion
258 painter->setClipRegion(m_dirtyRegion, Qt::ReplaceClip);
259 if (m_clipRegion.rectCount() > 1)
261
262 painter->setTransform(m_transform, false); //precalculated worldTransform
263 if (forceOpaquePainting || m_isOpaque)
265
266 switch (m_nodeType) {
268 painter->fillRect(m_handle.simpleRectNode->rect(), m_handle.simpleRectNode->color());
269 break;
271 {
272 QSGTexture *texture = m_handle.simpleTextureNode->texture();
273 if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(texture)) {
274 const QPixmap &pm = pt->pixmap();
275 painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, m_handle.simpleTextureNode->sourceRect());
276 } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(texture)) {
277 const QImage &im = pt->image();
278 painter->drawImage(m_handle.simpleTextureNode->rect(), im, m_handle.simpleTextureNode->sourceRect());
279 }
280 }
281 break;
283 m_handle.imageNode->paint(painter);
284 break;
286 m_handle.painterNode->paint(painter);
287 break;
289 m_handle.rectangleNode->paint(painter);
290 break;
292 m_handle.glpyhNode->paint(painter);
293 break;
295 m_handle.ninePatchNode->paint(painter);
296 break;
298 static_cast<QSGSoftwareRectangleNode *>(m_handle.simpleRectangleNode)->paint(painter);
299 break;
301 static_cast<QSGSoftwareImageNode *>(m_handle.simpleImageNode)->paint(painter);
302 break;
303#if QT_CONFIG(quick_sprite)
304 case QSGSoftwareRenderableNode::SpriteNode:
305 static_cast<QSGSoftwareSpriteNode *>(m_handle.spriteNode)->paint(painter);
306 break;
307#endif
308 default:
309 break;
310 }
311
312 painter->restore();
313
314 QRegion areaToBeFlushed = m_dirtyRegion;
315 m_previousDirtyRegion = QRegion(m_boundingRectMax);
316 m_isDirty = false;
317 m_dirtyRegion = QRegion();
318
319 return areaToBeFlushed;
320}
321
323{
324 return m_dirtyRegion.isEmpty();
325}
326
328{
329 if (m_transform == transform)
330 return;
331 m_transform = transform;
332 update();
333}
334
335void QSGSoftwareRenderableNode::setClipRegion(const QRegion &clipRect, bool hasClipRegion)
336{
337 if (m_clipRegion == clipRect && m_hasClipRegion == hasClipRegion)
338 return;
339
340 m_clipRegion = clipRect;
341 m_hasClipRegion = hasClipRegion;
342 update();
343}
344
346{
347 if (qFuzzyCompare(m_opacity, opacity))
348 return;
349
350 m_opacity = opacity;
351 update();
352}
353
358
363
364void QSGSoftwareRenderableNode::addDirtyRegion(const QRegion &dirtyRegion, bool forceDirty)
365{
366 // Check if the dirty region applies to this node
367 QRegion prev = m_dirtyRegion;
368 if (dirtyRegion.intersects(m_boundingRectMax)) {
369 if (forceDirty)
370 m_isDirty = true;
371 m_dirtyRegion += dirtyRegion.intersected(m_boundingRectMax);
372 }
373 qCDebug(lcRenderable) << "addDirtyRegion: " << dirtyRegion << "old dirtyRegion: " << prev << "new dirtyRegion: " << m_dirtyRegion;
374}
375
377{
378 QRegion prev = m_dirtyRegion;
379 if (m_isDirty) {
380 // Check if this rect concerns us
381 if (dirtyRegion.intersects(m_boundingRectMax)) {
382 m_dirtyRegion -= dirtyRegion;
383 if (m_dirtyRegion.isEmpty())
384 m_isDirty = false;
385 }
386 }
387 qCDebug(lcRenderable) << "subtractDirtyRegion: " << dirtyRegion << "old dirtyRegion" << prev << "new dirtyRegion: " << m_dirtyRegion;
388}
389
391{
392 // When removing a node, the boundingRect shouldn't be subtracted
393 // because a deleted node has no valid boundingRect
394 if (wasRemoved)
395 return m_previousDirtyRegion;
396
397 return m_previousDirtyRegion.subtracted(QRegion(m_boundingRectMax));
398}
399
401{
402 return m_dirtyRegion;
403}
404
int alpha() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1466
\inmodule QtGui
Definition qimage.h:37
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
int width() const
int height() const
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
void restore()
Restores the current painter state (pops a saved state off the stack).
void setOpacity(qreal opacity)
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
void save()
Saves the current painter state (pushes the state onto a stack).
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Draws the rectangular portion source of the given image into the target rectangle in the paint device...
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
@ CompositionMode_Source
Definition qpainter.h:101
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
void setClipRegion(const QRegion &, Qt::ClipOperation op=Qt::ReplaceClip)
Sets the clip region to the given region using the specified clip operation.
void setTransform(const QTransform &transform, bool combine=false)
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
bool hasAlphaChannel() const
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr QRect toRect() const noexcept
Returns a QRect based on the values of this rectangle.
Definition qrect.h:859
\inmodule QtCore\reentrant
Definition qrect.h:30
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
int rectCount() const noexcept
bool intersects(const QRegion &r) const
Definition qregion.cpp:613
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
const_iterator begin() const noexcept
QRegion intersected(const QRegion &r) const
QRegion subtracted(const QRegion &r) const
virtual QRectF boundingRect() const
The QSGImageNode class is provided for convenience to easily draw textured content using the QML scen...
virtual QRectF rect() const =0
Returns the target rect of this image node.
virtual QSGTexture * texture() const =0
Returns the texture for this image node.
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
The QSGRectangleNode class is a convenience class for drawing solid filled rectangles using scenegrap...
virtual QRectF rect() const =0
Returns the rectangle that this rect node covers.
virtual QColor color() const =0
Returns the color of this rectangle.
static QSGRenderNodePrivate * get(QSGRenderNode *node)
The QSGRenderNode class represents a set of custom rendering commands targeting the graphics API that...
virtual void render(const RenderState *state)=0
This function is called by the renderer and should paint this node with directly invoking commands in...
virtual RenderingFlags flags() const
virtual QRectF rect() const
The QSGSimpleRectNode class is a convenience class for drawing solid filled rectangles using scenegra...
QRectF rect() const
Returns the rectangle that this rect node covers.
QColor color() const
Returns the color of this rectangle.
The QSGSimpleTextureNode class is provided for convenience to easily draw textured content using the ...
QSGTexture * texture() const
Returns the texture for this texture node.
QRectF rect() const
Returns the target rect of this texture node.
QRectF sourceRect() const
Returns the source rect of this texture node.
void paint(QPainter *painter)
void paint(QPainter *painter)
void setClipRegion(const QRegion &clipRegion, bool hasClipRegion=true)
void setTransform(const QTransform &transform)
QSGSoftwareRenderableNode(NodeType type, QSGNode *node)
void subtractDirtyRegion(const QRegion &dirtyRegion)
QRegion renderNode(QPainter *painter, bool forceOpaquePainting=false)
QRegion previousDirtyRegion(bool wasRemoved=false) const
void addDirtyRegion(const QRegion &dirtyRegion, bool forceDirty=true)
\inmodule QtQuick
Definition qsgtexture.h:20
virtual bool hasAlphaChannel() const =0
Returns true if the texture data contains an alpha channel.
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
bool isRotating() const
Returns true if the matrix represents some kind of a rotating transformation, otherwise returns false...
Definition qtransform.h:183
QRect mapRect(const QRect &) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QPainter paint
Combined button and popup list for selecting options.
@ ReplaceClip
@ IntersectClip
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
int qFloor(T v)
Definition qmath.h:42
int qCeil(T v)
Definition qmath.h:36
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLboolean r
[2]
GLuint GLfloat GLfloat GLfloat x1
GLenum type
GLenum GLuint texture
GLuint GLenum GLenum transform
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
static const QRectF boundingRect(const QPointF *points, int pointCount)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE QRect toRectMin(const QRectF &r)
QRect toRectMax(const QRectF &r)
QRandomGenerator64 rd
[10]
QPainter painter(this)
[7]
const QRegion * clipRegion() const override
bool scissorEnabled() const override
const QMatrix4x4 * projectionMatrix() const override
bool stencilEnabled() const override
QRect scissorRect() const override
int stencilValue() const override