OpenCoverage

qquickshapenvprrenderer.cpp

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/qtdeclarative/src/qtdeclarative/src/quickshapes/qquickshapenvprrenderer.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
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 "qquickshapenvprrenderer_p.h"-
41#include <QOpenGLExtraFunctions>-
42#include <QOpenGLFramebufferObject>-
43#include <QOpenGLShaderProgram>-
44#include <QOpenGLBuffer>-
45#include <qmath.h>-
46#include <private/qpainterpath_p.h>-
47#include <private/qquickpath_p_p.h>-
48-
49QT_BEGIN_NAMESPACE-
50-
51void QQuickShapeNvprRenderer::beginSync(int totalCount)-
52{-
53 if (m_sp.count() != totalCount) {
m_sp.count() != totalCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
54 m_sp.resize(totalCount);-
55 m_accDirty |= DirtyList;-
56 }
never executed: end of block
0
57}
never executed: end of block
0
58-
59void QQuickShapeNvprRenderer::setPath(int index, const QQuickPath *path)-
60{-
61 ShapePathGuiData &d(m_sp[index]);-
62 convertPath(path, &d);-
63 d.dirty |= DirtyPath;-
64 m_accDirty |= DirtyPath;-
65}
never executed: end of block
0
66-
67void QQuickShapeNvprRenderer::setStrokeColor(int index, const QColor &color)-
68{-
69 ShapePathGuiData &d(m_sp[index]);-
70 d.strokeColor = color;-
71 d.dirty |= DirtyStyle;-
72 m_accDirty |= DirtyStyle;-
73}
never executed: end of block
0
74-
75void QQuickShapeNvprRenderer::setStrokeWidth(int index, qreal w)-
76{-
77 ShapePathGuiData &d(m_sp[index]);-
78 d.strokeWidth = w;-
79 d.dirty |= DirtyStyle;-
80 m_accDirty |= DirtyStyle;-
81}
never executed: end of block
0
82-
83void QQuickShapeNvprRenderer::setFillColor(int index, const QColor &color)-
84{-
85 ShapePathGuiData &d(m_sp[index]);-
86 d.fillColor = color;-
87 d.dirty |= DirtyStyle;-
88 m_accDirty |= DirtyStyle;-
89}
never executed: end of block
0
90-
91void QQuickShapeNvprRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule)-
92{-
93 ShapePathGuiData &d(m_sp[index]);-
94 d.fillRule = fillRule;-
95 d.dirty |= DirtyFillRule;-
96 m_accDirty |= DirtyFillRule;-
97}
never executed: end of block
0
98-
99void QQuickShapeNvprRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit)-
100{-
101 ShapePathGuiData &d(m_sp[index]);-
102 d.joinStyle = joinStyle;-
103 d.miterLimit = miterLimit;-
104 d.dirty |= DirtyStyle;-
105 m_accDirty |= DirtyStyle;-
106}
never executed: end of block
0
107-
108void QQuickShapeNvprRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle)-
109{-
110 ShapePathGuiData &d(m_sp[index]);-
111 d.capStyle = capStyle;-
112 d.dirty |= DirtyStyle;-
113 m_accDirty |= DirtyStyle;-
114}
never executed: end of block
0
115-
116void QQuickShapeNvprRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,-
117 qreal dashOffset, const QVector<qreal> &dashPattern)-
118{-
119 ShapePathGuiData &d(m_sp[index]);-
120 d.dashActive = strokeStyle == QQuickShapePath::DashLine;-
121 d.dashOffset = dashOffset;-
122 d.dashPattern = dashPattern;-
123 d.dirty |= DirtyDash;-
124 m_accDirty |= DirtyDash;-
125}
never executed: end of block
0
126-
127void QQuickShapeNvprRenderer::setFillGradient(int index, QQuickShapeGradient *gradient)-
128{-
129 ShapePathGuiData &d(m_sp[index]);-
130 if (gradient) {
gradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
131 d.fillGradient.stops = gradient->gradientStops(); // sorted-
132 d.fillGradient.spread = gradient->spread();-
133 if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(gradient)) {
QQuickShapeLin...t *>(gradient)Description
TRUEnever evaluated
FALSEnever evaluated
0
134 d.fillGradientActive = LinearGradient;-
135 d.fillGradient.a = QPointF(g->x1(), g->y1());-
136 d.fillGradient.b = QPointF(g->x2(), g->y2());-
137 } else if (QQuickShapeRadialGradient *g = qobject_cast<QQuickShapeRadialGradient *>(gradient)) {
never executed: end of block
QQuickShapeRad...t *>(gradient)Description
TRUEnever evaluated
FALSEnever evaluated
0
138 d.fillGradientActive = RadialGradient;-
139 d.fillGradient.a = QPointF(g->centerX(), g->centerY());-
140 d.fillGradient.b = QPointF(g->focalX(), g->focalY());-
141 d.fillGradient.v0 = g->centerRadius();-
142 d.fillGradient.v1 = g->focalRadius();-
143 } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(gradient)) {
never executed: end of block
QQuickShapeCon...t *>(gradient)Description
TRUEnever evaluated
FALSEnever evaluated
0
144 d.fillGradientActive = ConicalGradient;-
145 d.fillGradient.a = QPointF(g->centerX(), g->centerY());-
146 d.fillGradient.v0 = g->angle();-
147 } else {
never executed: end of block
0
148 Q_UNREACHABLE();-
149 }
never executed: end of block
0
150 } else {-
151 d.fillGradientActive = NoGradient;-
152 }
never executed: end of block
0
153 d.dirty |= DirtyFillGradient;-
154 m_accDirty |= DirtyFillGradient;-
155}
never executed: end of block
0
156-
157void QQuickShapeNvprRenderer::endSync(bool)-
158{-
159}-
160-
161void QQuickShapeNvprRenderer::setNode(QQuickShapeNvprRenderNode *node)-
162{-
163 if (m_node != node) {
m_node != nodeDescription
TRUEnever evaluated
FALSEnever evaluated
0
164 m_node = node;-
165 m_accDirty |= DirtyList;-
166 }
never executed: end of block
0
167}
never executed: end of block
0
168-
169QDebug operator<<(QDebug debug, const QQuickShapeNvprRenderer::NvprPath &path)-
170{-
171 QDebugStateSaver saver(debug);-
172 debug.space().noquote();-
173 if (!path.str.isEmpty()) {
!path.str.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
174 debug << "Path with SVG string" << path.str;-
175 return debug;
never executed: return debug;
0
176 }-
177 debug << "Path with" << path.cmd.count() << "commands";-
178 int ci = 0;-
179 for (GLubyte cmd : path.cmd) {-
180 static struct { GLubyte cmd; const char *s; int coordCount; } nameTab[] = {-
181 { GL_MOVE_TO_NV, "moveTo", 2 },-
182 { GL_LINE_TO_NV, "lineTo", 2 },-
183 { GL_QUADRATIC_CURVE_TO_NV, "quadTo", 4 },-
184 { GL_CUBIC_CURVE_TO_NV, "cubicTo", 6 },-
185 { GL_LARGE_CW_ARC_TO_NV, "arcTo-large-CW", 5 },-
186 { GL_LARGE_CCW_ARC_TO_NV, "arcTo-large-CCW", 5 },-
187 { GL_SMALL_CW_ARC_TO_NV, "arcTo-small-CW", 5 },-
188 { GL_SMALL_CCW_ARC_TO_NV, "arcTo-small-CCW", 5 },-
189 { GL_CLOSE_PATH_NV, "closePath", 0 } };-
190 for (size_t i = 0; i < sizeof(nameTab) / sizeof(nameTab[0]); ++i) {
i < sizeof(nam...of(nameTab[0])Description
TRUEnever evaluated
FALSEnever evaluated
0
191 if (nameTab[i].cmd == cmd) {
nameTab[i].cmd == cmdDescription
TRUEnever evaluated
FALSEnever evaluated
0
192 QByteArray cs;-
193 for (int j = 0; j < nameTab[i].coordCount; ++j) {
j < nameTab[i].coordCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
194 cs.append(QByteArray::number(path.coord[ci++]));-
195 cs.append(' ');-
196 }
never executed: end of block
0
197 debug << "\n " << nameTab[i].s << " " << cs;-
198 break;
never executed: break;
0
199 }-
200 }
never executed: end of block
0
201 }
never executed: end of block
0
202 return debug;
never executed: return debug;
0
203}-
204-
205static inline void appendCoords(QVector<GLfloat> *v, QQuickCurve *c, QPointF *pos)-
206{-
207 QPointF p(c->hasRelativeX() ? pos->x() + c->relativeX() : c->x(),-
208 c->hasRelativeY() ? pos->y() + c->relativeY() : c->y());-
209 v->append(p.x());-
210 v->append(p.y());-
211 *pos = p;-
212}
never executed: end of block
0
213-
214static inline void appendControlCoords(QVector<GLfloat> *v, QQuickPathQuad *c, const QPointF &pos)-
215{-
216 QPointF p(c->hasRelativeControlX() ? pos.x() + c->relativeControlX() : c->controlX(),-
217 c->hasRelativeControlY() ? pos.y() + c->relativeControlY() : c->controlY());-
218 v->append(p.x());-
219 v->append(p.y());-
220}
never executed: end of block
0
221-
222static inline void appendControl1Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos)-
223{-
224 QPointF p(c->hasRelativeControl1X() ? pos.x() + c->relativeControl1X() : c->control1X(),-
225 c->hasRelativeControl1Y() ? pos.y() + c->relativeControl1Y() : c->control1Y());-
226 v->append(p.x());-
227 v->append(p.y());-
228}
never executed: end of block
0
229-
230static inline void appendControl2Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos)-
231{-
232 QPointF p(c->hasRelativeControl2X() ? pos.x() + c->relativeControl2X() : c->control2X(),-
233 c->hasRelativeControl2Y() ? pos.y() + c->relativeControl2Y() : c->control2Y());-
234 v->append(p.x());-
235 v->append(p.y());-
236}
never executed: end of block
0
237-
238void QQuickShapeNvprRenderer::convertPath(const QQuickPath *path, ShapePathGuiData *d)-
239{-
240 d->path = NvprPath();-
241 if (!path)
!pathDescription
TRUEnever evaluated
FALSEnever evaluated
0
242 return;
never executed: return;
0
243-
244 const QList<QQuickPathElement *> &pp(QQuickPathPrivate::get(path)->_pathElements);-
245 if (pp.isEmpty())
pp.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
246 return;
never executed: return;
0
247-
248 QPointF startPos(path->startX(), path->startY());-
249 QPointF pos(startPos);-
250 if (!qFuzzyIsNull(pos.x()) || !qFuzzyIsNull(pos.y())) {
!qFuzzyIsNull(pos.x())Description
TRUEnever evaluated
FALSEnever evaluated
!qFuzzyIsNull(pos.y())Description
TRUEnever evaluated
FALSEnever evaluated
0
251 d->path.cmd.append(GL_MOVE_TO_NV);-
252 d->path.coord.append(pos.x());-
253 d->path.coord.append(pos.y());-
254 }
never executed: end of block
0
255-
256 for (QQuickPathElement *e : pp) {-
257 if (QQuickPathMove *o = qobject_cast<QQuickPathMove *>(e)) {
QQuickPathMove...PathMove *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
258 d->path.cmd.append(GL_MOVE_TO_NV);-
259 appendCoords(&d->path.coord, o, &pos);-
260 startPos = pos;-
261 } else if (QQuickPathLine *o = qobject_cast<QQuickPathLine *>(e)) {
never executed: end of block
QQuickPathLine...PathLine *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
262 d->path.cmd.append(GL_LINE_TO_NV);-
263 appendCoords(&d->path.coord, o, &pos);-
264 } else if (QQuickPathQuad *o = qobject_cast<QQuickPathQuad *>(e)) {
never executed: end of block
QQuickPathQuad...PathQuad *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
265 d->path.cmd.append(GL_QUADRATIC_CURVE_TO_NV);-
266 appendControlCoords(&d->path.coord, o, pos);-
267 appendCoords(&d->path.coord, o, &pos);-
268 } else if (QQuickPathCubic *o = qobject_cast<QQuickPathCubic *>(e)) {
never executed: end of block
QQuickPathCubi...athCubic *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
269 d->path.cmd.append(GL_CUBIC_CURVE_TO_NV);-
270 appendControl1Coords(&d->path.coord, o, pos);-
271 appendControl2Coords(&d->path.coord, o, pos);-
272 appendCoords(&d->path.coord, o, &pos);-
273 } else if (QQuickPathArc *o = qobject_cast<QQuickPathArc *>(e)) {
never executed: end of block
QQuickPathArc ...kPathArc *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
274 const bool sweepFlag = o->direction() == QQuickPathArc::Clockwise; // maps to CCW, not a typo-
275 GLenum cmd;-
276 if (o->useLargeArc())
o->useLargeArc()Description
TRUEnever evaluated
FALSEnever evaluated
0
277 cmd = sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV;
never executed: cmd = sweepFlag ? 0x16 : 0x18;
sweepFlagDescription
TRUEnever evaluated
FALSEnever evaluated
0
278 else-
279 cmd = sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV;
never executed: cmd = sweepFlag ? 0x12 : 0x14;
sweepFlagDescription
TRUEnever evaluated
FALSEnever evaluated
0
280 d->path.cmd.append(cmd);-
281 d->path.coord.append(o->radiusX());-
282 d->path.coord.append(o->radiusY());-
283 d->path.coord.append(o->xAxisRotation());-
284 appendCoords(&d->path.coord, o, &pos);-
285 } else if (QQuickPathSvg *o = qobject_cast<QQuickPathSvg *>(e)) {
never executed: end of block
QQuickPathSvg ...kPathSvg *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
286 // PathSvg cannot be combined with other elements. But take at-
287 // least startX and startY into account.-
288 if (d->path.str.isEmpty())
d->path.str.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
289 d->path.str = QString(QStringLiteral("M %1 %2 ")).arg(pos.x()).arg(pos.y()).toUtf8();
never executed: d->path.str = QString(([]() noexcept -> QString { enum { Size = sizeof(u"" "M %1 %2 ")/2 - 1 }; static const QStaticStringData<Size> qstring_literal = { { { { -1 } }, Size, 0, 0, sizeof(QStringData) }, u"" "M %1 %2 " }; QStringDataPtr holder = { qstring_literal.data_ptr() }; const QString qstring_literal_temp(holder); return qstring_literal_temp; }())).arg(pos.x()).arg(pos.y()).toUtf8();
never executed: return qstring_literal_temp;
0
290 d->path.str.append(o->path().toUtf8());-
291 } else if (QQuickPathAngleArc *o = qobject_cast<QQuickPathAngleArc *>(e)) {
never executed: end of block
QQuickPathAngl...AngleArc *>(e)Description
TRUEnever evaluated
FALSEnever evaluated
0
292 QRectF rect(o->centerX() - o->radiusX(), o->centerY() - o->radiusY(), o->radiusX() * 2, o->radiusY() * 2);-
293 QPointF startPoint;-
294 QPointF endPoint;-
295 qt_find_ellipse_coords(rect, o->startAngle(), -o->sweepAngle(), &startPoint, &endPoint);-
296-
297 // get to our starting position-
298 if (o->moveToStart())
o->moveToStart()Description
TRUEnever evaluated
FALSEnever evaluated
0
299 d->path.cmd.append(GL_MOVE_TO_NV);
never executed: d->path.cmd.append(0x02);
0
300 else-
301 d->path.cmd.append(GL_LINE_TO_NV); // ### should we check if startPoint == pos?
never executed: d->path.cmd.append(0x04);
0
302 d->path.coord.append(startPoint.x());-
303 d->path.coord.append(startPoint.y());-
304-
305 const bool sweepFlag = o->sweepAngle() > 0; // maps to CCW, not a typo-
306 d->path.cmd.append(qAbs(o->sweepAngle()) > 180.0-
307 ? (sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV)-
308 : (sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV));-
309 d->path.coord.append(o->radiusX());-
310 d->path.coord.append(o->radiusY());-
311 d->path.coord.append(0); // xAxisRotation-
312 d->path.coord.append(endPoint.x());-
313 d->path.coord.append(endPoint.y());-
314 pos = endPoint;-
315 } else {
never executed: end of block
0
316 qWarning() << "Shape/NVPR: unsupported Path element" << e;-
317 }
never executed: end of block
0
318 }-
319-
320 // For compatibility with QTriangulatingStroker. SVG and others would not-
321 // implicitly close the path when end_pos == start_pos (start_pos being the-
322 // last moveTo pos); that would still need an explicit 'z' or similar. We-
323 // don't have an explicit close command, so just fake a close when the-
324 // positions match.-
325 if (pos == startPos)
pos == startPosDescription
TRUEnever evaluated
FALSEnever evaluated
0
326 d->path.cmd.append(GL_CLOSE_PATH_NV);
never executed: d->path.cmd.append(0x00);
0
327}
never executed: end of block
0
328-
329static inline QVector4D qsg_premultiply(const QColor &c, float globalOpacity)-
330{-
331 const float o = c.alphaF() * globalOpacity;-
332 return QVector4D(c.redF() * o, c.greenF() * o, c.blueF() * o, o);
never executed: return QVector4D(c.redF() * o, c.greenF() * o, c.blueF() * o, o);
0
333}-
334-
335void QQuickShapeNvprRenderer::updateNode()-
336{-
337 // Called on the render thread with gui blocked -> update the node with its-
338 // own copy of all relevant data.-
339-
340 if (!m_accDirty)
!m_accDirtyDescription
TRUEnever evaluated
FALSEnever evaluated
0
341 return;
never executed: return;
0
342-
343 const int count = m_sp.count();-
344 const bool listChanged = m_accDirty & DirtyList;-
345 if (listChanged)
listChangedDescription
TRUEnever evaluated
FALSEnever evaluated
0
346 m_node->m_sp.resize(count);
never executed: m_node->m_sp.resize(count);
0
347-
348 for (int i = 0; i < count; ++i) {
i < countDescription
TRUEnever evaluated
FALSEnever evaluated
0
349 ShapePathGuiData &src(m_sp[i]);-
350 QQuickShapeNvprRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]);-
351-
352 int dirty = src.dirty;-
353 src.dirty = 0;-
354 if (listChanged)
listChangedDescription
TRUEnever evaluated
FALSEnever evaluated
0
355 dirty |= DirtyPath | DirtyStyle | DirtyFillRule | DirtyDash | DirtyFillGradient;
never executed: dirty |= DirtyPath | DirtyStyle | DirtyFillRule | DirtyDash | DirtyFillGradient;
0
356-
357 // updateNode() can be called several times with different dirty-
358 // states before render() gets invoked. So accumulate.-
359 dst.dirty |= dirty;-
360-
361 if (dirty & DirtyPath)
dirty & DirtyPathDescription
TRUEnever evaluated
FALSEnever evaluated
0
362 dst.source = src.path;
never executed: dst.source = src.path;
0
363-
364 if (dirty & DirtyStyle) {
dirty & DirtyStyleDescription
TRUEnever evaluated
FALSEnever evaluated
0
365 dst.strokeWidth = src.strokeWidth;-
366 dst.strokeColor = qsg_premultiply(src.strokeColor, 1.0f);-
367 dst.fillColor = qsg_premultiply(src.fillColor, 1.0f);-
368 switch (src.joinStyle) {-
369 case QQuickShapePath::MiterJoin:
never executed: case QQuickShapePath::MiterJoin:
0
370 dst.joinStyle = GL_MITER_TRUNCATE_NV;-
371 break;
never executed: break;
0
372 case QQuickShapePath::BevelJoin:
never executed: case QQuickShapePath::BevelJoin:
0
373 dst.joinStyle = GL_BEVEL_NV;-
374 break;
never executed: break;
0
375 case QQuickShapePath::RoundJoin:
never executed: case QQuickShapePath::RoundJoin:
0
376 dst.joinStyle = GL_ROUND_NV;-
377 break;
never executed: break;
0
378 default:
never executed: default:
0
379 Q_UNREACHABLE();-
380 }
never executed: end of block
0
381 dst.miterLimit = src.miterLimit;-
382 switch (src.capStyle) {-
383 case QQuickShapePath::FlatCap:
never executed: case QQuickShapePath::FlatCap:
0
384 dst.capStyle = GL_FLAT;-
385 break;
never executed: break;
0
386 case QQuickShapePath::SquareCap:
never executed: case QQuickShapePath::SquareCap:
0
387 dst.capStyle = GL_SQUARE_NV;-
388 break;
never executed: break;
0
389 case QQuickShapePath::RoundCap:
never executed: case QQuickShapePath::RoundCap:
0
390 dst.capStyle = GL_ROUND_NV;-
391 break;
never executed: break;
0
392 default:
never executed: default:
0
393 Q_UNREACHABLE();-
394 }
never executed: end of block
0
395 }-
396-
397 if (dirty & DirtyFillRule) {
dirty & DirtyFillRuleDescription
TRUEnever evaluated
FALSEnever evaluated
0
398 switch (src.fillRule) {-
399 case QQuickShapePath::OddEvenFill:
never executed: case QQuickShapePath::OddEvenFill:
0
400 dst.fillRule = GL_INVERT;-
401 break;
never executed: break;
0
402 case QQuickShapePath::WindingFill:
never executed: case QQuickShapePath::WindingFill:
0
403 dst.fillRule = GL_COUNT_UP_NV;-
404 break;
never executed: break;
0
405 default:
never executed: default:
0
406 Q_UNREACHABLE();-
407 }
never executed: end of block
0
408 }-
409-
410 if (dirty & DirtyDash) {
dirty & DirtyDashDescription
TRUEnever evaluated
FALSEnever evaluated
0
411 // Multiply by strokeWidth because the Shape API follows QPen-
412 // meaning the input dash pattern and dash offset here are in width units.-
413 dst.dashOffset = src.dashOffset * src.strokeWidth;-
414 if (src.dashActive) {
src.dashActiveDescription
TRUEnever evaluated
FALSEnever evaluated
0
415 if (src.dashPattern.isEmpty()) {
src.dashPattern.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
416 // default values for DashLine as defined in qpen.cpp-
417 dst.dashPattern.resize(2);-
418 dst.dashPattern[0] = 4 * src.strokeWidth; // dash-
419 dst.dashPattern[1] = 2 * src.strokeWidth; // space-
420 } else {
never executed: end of block
0
421 dst.dashPattern.resize(src.dashPattern.count());-
422 for (int i = 0; i < src.dashPattern.count(); ++i)
i < src.dashPattern.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
423 dst.dashPattern[i] = GLfloat(src.dashPattern[i]) * src.strokeWidth;
never executed: dst.dashPattern[i] = GLfloat(src.dashPattern[i]) * src.strokeWidth;
0
424-
425 // QPen expects a dash pattern of even length and so should we-
426 if (src.dashPattern.count() % 2 != 0) {
src.dashPatter...unt() % 2 != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
427 qWarning("QQuickShapeNvprRenderNode: dash pattern not of even length");-
428 dst.dashPattern << src.strokeWidth;-
429 }
never executed: end of block
0
430 }
never executed: end of block
0
431 } else {-
432 dst.dashPattern.clear();-
433 }
never executed: end of block
0
434 }-
435-
436 if (dirty & DirtyFillGradient) {
dirty & DirtyFillGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
437 dst.fillGradientActive = src.fillGradientActive;-
438 if (src.fillGradientActive)
src.fillGradientActiveDescription
TRUEnever evaluated
FALSEnever evaluated
0
439 dst.fillGradient = src.fillGradient;
never executed: dst.fillGradient = src.fillGradient;
0
440 }
never executed: end of block
0
441 }
never executed: end of block
0
442-
443 m_node->markDirty(QSGNode::DirtyMaterial);-
444 m_accDirty = 0;-
445}
never executed: end of block
0
446-
447bool QQuickShapeNvprRenderNode::nvprInited = false;-
448QQuickNvprFunctions QQuickShapeNvprRenderNode::nvpr;-
449QQuickNvprMaterialManager QQuickShapeNvprRenderNode::mtlmgr;-
450-
451QQuickShapeNvprRenderNode::~QQuickShapeNvprRenderNode()-
452{-
453 releaseResources();-
454}
never executed: end of block
0
455-
456void QQuickShapeNvprRenderNode::releaseResources()-
457{-
458 for (ShapePathRenderData &d : m_sp) {-
459 if (d.path) {
d.pathDescription
TRUEnever evaluated
FALSEnever evaluated
0
460 nvpr.deletePaths(d.path, 1);-
461 d.path = 0;-
462 }
never executed: end of block
0
463 if (d.fallbackFbo) {
d.fallbackFboDescription
TRUEnever evaluated
FALSEnever evaluated
0
464 delete d.fallbackFbo;-
465 d.fallbackFbo = nullptr;-
466 }
never executed: end of block
0
467 }
never executed: end of block
0
468-
469 m_fallbackBlitter.destroy();-
470}
never executed: end of block
0
471-
472void QQuickNvprMaterialManager::create(QQuickNvprFunctions *nvpr)-
473{-
474 m_nvpr = nvpr;-
475}
never executed: end of block
0
476-
477void QQuickNvprMaterialManager::releaseResources()-
478{-
479 QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();-
480 for (MaterialDesc &mtl : m_materials) {-
481 if (mtl.ppl) {
mtl.pplDescription
TRUEnever evaluated
FALSEnever evaluated
0
482 f->glDeleteProgramPipelines(1, &mtl.ppl);-
483 mtl = MaterialDesc();-
484 }
never executed: end of block
0
485 }
never executed: end of block
0
486}
never executed: end of block
0
487-
488QQuickNvprMaterialManager::MaterialDesc *QQuickNvprMaterialManager::activateMaterial(Material m)-
489{-
490 QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();-
491 MaterialDesc &mtl(m_materials[m]);-
492-
493 if (!mtl.ppl) {
!mtl.pplDescription
TRUEnever evaluated
FALSEnever evaluated
0
494 if (m == MatSolid) {
m == MatSolidDescription
TRUEnever evaluated
FALSEnever evaluated
0
495 static const char *fragSrc =-
496 "#version 310 es\n"-
497 "precision highp float;\n"-
498 "out vec4 fragColor;\n"-
499 "uniform vec4 color;\n"-
500 "uniform float opacity;\n"-
501 "void main() {\n"-
502 " fragColor = color * opacity;\n"-
503 "}\n";-
504 if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
!m_nvpr->creat...ppl, &mtl.prg)Description
TRUEnever evaluated
FALSEnever evaluated
0
505 qWarning("NVPR: Failed to create shader pipeline for solid fill");-
506 return nullptr;
never executed: return nullptr;
0
507 }-
508 Q_ASSERT(mtl.ppl && mtl.prg);-
509 mtl.uniLoc[0] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "color");-
510 Q_ASSERT(mtl.uniLoc[0] >= 0);-
511 mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");-
512 Q_ASSERT(mtl.uniLoc[1] >= 0);-
513 } else if (m == MatLinearGradient) {
never executed: end of block
m == MatLinearGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
514 static const char *fragSrc =-
515 "#version 310 es\n"-
516 "precision highp float;\n"-
517 "layout(location = 0) in vec2 uv;"-
518 "uniform float opacity;\n"-
519 "uniform sampler2D gradTab;\n"-
520 "uniform vec2 gradStart;\n"-
521 "uniform vec2 gradEnd;\n"-
522 "out vec4 fragColor;\n"-
523 "void main() {\n"-
524 " vec2 gradVec = gradEnd - gradStart;\n"-
525 " float gradTabIndex = dot(gradVec, uv - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);\n"-
526 " fragColor = texture(gradTab, vec2(gradTabIndex, 0.5)) * opacity;\n"-
527 "}\n";-
528 if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
!m_nvpr->creat...ppl, &mtl.prg)Description
TRUEnever evaluated
FALSEnever evaluated
0
529 qWarning("NVPR: Failed to create shader pipeline for linear gradient");-
530 return nullptr;
never executed: return nullptr;
0
531 }-
532 Q_ASSERT(mtl.ppl && mtl.prg);-
533 mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");-
534 Q_ASSERT(mtl.uniLoc[1] >= 0);-
535 mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradStart");-
536 Q_ASSERT(mtl.uniLoc[2] >= 0);-
537 mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradEnd");-
538 Q_ASSERT(mtl.uniLoc[3] >= 0);-
539 } else if (m == MatRadialGradient) {
never executed: end of block
m == MatRadialGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
540 static const char *fragSrc =-
541 "#version 310 es\n"-
542 "precision highp float;\n"-
543 "uniform sampler2D gradTab;\n"-
544 "uniform float opacity;\n"-
545 "uniform vec2 focalToCenter;\n"-
546 "uniform float centerRadius;\n"-
547 "uniform float focalRadius;\n"-
548 "uniform vec2 translationPoint;\n"-
549 "layout(location = 0) in vec2 uv;\n"-
550 "out vec4 fragColor;\n"-
551 "void main() {\n"-
552 " vec2 coord = uv - translationPoint;\n"-
553 " float rd = centerRadius - focalRadius;\n"-
554 " float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter));\n"-
555 " float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd;\n"-
556 " float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2);\n"-
557 " float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord));\n"-
558 " vec4 result = vec4(0.0);\n"-
559 " if (det >= 0.0) {\n"-
560 " float detSqrt = sqrt(det);\n"-
561 " float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2);\n"-
562 " if (focalRadius + w * (centerRadius - focalRadius) >= 0.0)\n"-
563 " result = texture(gradTab, vec2(w, 0.5)) * opacity;\n"-
564 " }\n"-
565 " fragColor = result;\n"-
566 "}\n";-
567 if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
!m_nvpr->creat...ppl, &mtl.prg)Description
TRUEnever evaluated
FALSEnever evaluated
0
568 qWarning("NVPR: Failed to create shader pipeline for radial gradient");-
569 return nullptr;
never executed: return nullptr;
0
570 }-
571 Q_ASSERT(mtl.ppl && mtl.prg);-
572 mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");-
573 Q_ASSERT(mtl.uniLoc[1] >= 0);-
574 mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "focalToCenter");-
575 Q_ASSERT(mtl.uniLoc[2] >= 0);-
576 mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "centerRadius");-
577 Q_ASSERT(mtl.uniLoc[3] >= 0);-
578 mtl.uniLoc[4] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "focalRadius");-
579 Q_ASSERT(mtl.uniLoc[4] >= 0);-
580 mtl.uniLoc[5] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint");-
581 Q_ASSERT(mtl.uniLoc[5] >= 0);-
582 } else if (m == MatConicalGradient) {
never executed: end of block
m == MatConicalGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
583 static const char *fragSrc =-
584 "#version 310 es\n"-
585 "precision highp float;\n"-
586 "#define INVERSE_2PI 0.1591549430918953358\n"-
587 "uniform sampler2D gradTab;\n"-
588 "uniform float opacity;\n"-
589 "uniform float angle;\n"-
590 "uniform vec2 translationPoint;\n"-
591 "layout(location = 0) in vec2 uv;\n"-
592 "out vec4 fragColor;\n"-
593 "void main() {\n"-
594 " vec2 coord = uv - translationPoint;\n"-
595 " float t;\n"-
596 " if (abs(coord.y) == abs(coord.x))\n"-
597 " t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI;\n"-
598 " else\n"-
599 " t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI;\n"-
600 " fragColor = texture(gradTab, vec2(t - floor(t), 0.5)) * opacity;\n"-
601 "}\n";-
602 if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
!m_nvpr->creat...ppl, &mtl.prg)Description
TRUEnever evaluated
FALSEnever evaluated
0
603 qWarning("NVPR: Failed to create shader pipeline for conical gradient");-
604 return nullptr;
never executed: return nullptr;
0
605 }-
606 Q_ASSERT(mtl.ppl && mtl.prg);-
607 mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");-
608 Q_ASSERT(mtl.uniLoc[1] >= 0);-
609 mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "angle");-
610 Q_ASSERT(mtl.uniLoc[2] >= 0);-
611 mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint");-
612 Q_ASSERT(mtl.uniLoc[3] >= 0);-
613 } else {
never executed: end of block
0
614 Q_UNREACHABLE();-
615 }
never executed: end of block
0
616 }-
617-
618 f->glBindProgramPipeline(mtl.ppl);-
619-
620 return &mtl;
never executed: return &mtl;
0
621}-
622-
623void QQuickShapeNvprRenderNode::updatePath(ShapePathRenderData *d)-
624{-
625 if (d->dirty & QQuickShapeNvprRenderer::DirtyPath) {
d->dirty & QQu...rer::DirtyPathDescription
TRUEnever evaluated
FALSEnever evaluated
0
626 if (!d->path) {
!d->pathDescription
TRUEnever evaluated
FALSEnever evaluated
0
627 d->path = nvpr.genPaths(1);-
628 Q_ASSERT(d->path != 0);-
629 }
never executed: end of block
0
630 if (d->source.str.isEmpty()) {
d->source.str.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
631 nvpr.pathCommands(d->path, d->source.cmd.count(), d->source.cmd.constData(),-
632 d->source.coord.count(), GL_FLOAT, d->source.coord.constData());-
633 } else {
never executed: end of block
0
634 nvpr.pathString(d->path, GL_PATH_FORMAT_SVG_NV, d->source.str.count(), d->source.str.constData());-
635 }
never executed: end of block
0
636 }-
637-
638 if (d->dirty & QQuickShapeNvprRenderer::DirtyStyle) {
d->dirty & QQu...er::DirtyStyleDescription
TRUEnever evaluated
FALSEnever evaluated
0
639 nvpr.pathParameterf(d->path, GL_PATH_STROKE_WIDTH_NV, d->strokeWidth);-
640 nvpr.pathParameteri(d->path, GL_PATH_JOIN_STYLE_NV, d->joinStyle);-
641 nvpr.pathParameteri(d->path, GL_PATH_MITER_LIMIT_NV, d->miterLimit);-
642 nvpr.pathParameteri(d->path, GL_PATH_END_CAPS_NV, d->capStyle);-
643 nvpr.pathParameteri(d->path, GL_PATH_DASH_CAPS_NV, d->capStyle);-
644 }
never executed: end of block
0
645-
646 if (d->dirty & QQuickShapeNvprRenderer::DirtyDash) {
d->dirty & QQu...rer::DirtyDashDescription
TRUEnever evaluated
FALSEnever evaluated
0
647 nvpr.pathParameterf(d->path, GL_PATH_DASH_OFFSET_NV, d->dashOffset);-
648 // count == 0 -> no dash-
649 nvpr.pathDashArray(d->path, d->dashPattern.count(), d->dashPattern.constData());-
650 }
never executed: end of block
0
651-
652 if (d->dirty)
d->dirtyDescription
TRUEnever evaluated
FALSEnever evaluated
0
653 d->fallbackValid = false;
never executed: d->fallbackValid = false;
0
654}
never executed: end of block
0
655-
656void QQuickShapeNvprRenderNode::renderStroke(ShapePathRenderData *d, int strokeStencilValue, int writeMask)-
657{-
658 QQuickNvprMaterialManager::MaterialDesc *mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);-
659 f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],-
660 d->strokeColor.x(), d->strokeColor.y(), d->strokeColor.z(), d->strokeColor.w());-
661 f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity());-
662-
663 nvpr.stencilThenCoverStrokePath(d->path, strokeStencilValue, writeMask, GL_CONVEX_HULL_NV);-
664}
never executed: end of block
0
665-
666void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d)-
667{-
668 QQuickNvprMaterialManager::MaterialDesc *mtl = nullptr;-
669 if (d->fillGradientActive) {
d->fillGradientActiveDescription
TRUEnever evaluated
FALSEnever evaluated
0
670 QQuickShapeGradient::SpreadMode spread = d->fillGradient.spread;-
671 if (d->fillGradientActive == QQuickAbstractPathRenderer::LinearGradient) {
d->fillGradien...LinearGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
672 mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient);-
673 // uv = vec2(coeff[0] * x + coeff[1] * y + coeff[2], coeff[3] * x + coeff[4] * y + coeff[5])-
674 // where x and y are in path coordinate space, which is just what-
675 // we need since the gradient's start and stop are in that space too.-
676 GLfloat coeff[6] = { 1, 0, 0,-
677 0, 1, 0 };-
678 nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff);-
679 f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], d->fillGradient.a.x(), d->fillGradient.a.y());-
680 f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], d->fillGradient.b.x(), d->fillGradient.b.y());-
681 } else if (d->fillGradientActive == QQuickAbstractPathRenderer::RadialGradient) {
never executed: end of block
d->fillGradien...RadialGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
682 mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatRadialGradient);-
683 // simply drive uv (location 0) with x and y, just like for the linear gradient-
684 GLfloat coeff[6] = { 1, 0, 0,-
685 0, 1, 0 };-
686 nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff);-
687-
688 const QPointF centerPoint = d->fillGradient.a;-
689 const QPointF focalPoint = d->fillGradient.b;-
690 const QPointF focalToCenter = centerPoint - focalPoint;-
691 const GLfloat centerRadius = d->fillGradient.v0;-
692 const GLfloat focalRadius = d->fillGradient.v1;-
693-
694 f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], focalToCenter.x(), focalToCenter.y());-
695 f->glProgramUniform1f(mtl->prg, mtl->uniLoc[3], centerRadius);-
696 f->glProgramUniform1f(mtl->prg, mtl->uniLoc[4], focalRadius);-
697 f->glProgramUniform2f(mtl->prg, mtl->uniLoc[5], focalPoint.x(), focalPoint.y());-
698 } else if (d->fillGradientActive == QQuickAbstractPathRenderer::ConicalGradient) {
never executed: end of block
d->fillGradien...onicalGradientDescription
TRUEnever evaluated
FALSEnever evaluated
0
699 mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatConicalGradient);-
700 // same old-
701 GLfloat coeff[6] = { 1, 0, 0,-
702 0, 1, 0 };-
703 nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff);-
704-
705 const QPointF centerPoint = d->fillGradient.a;-
706 const GLfloat angle = -qDegreesToRadians(d->fillGradient.v0);-
707-
708 f->glProgramUniform1f(mtl->prg, mtl->uniLoc[2], angle);-
709 f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], centerPoint.x(), centerPoint.y());-
710-
711 spread = QQuickShapeGradient::RepeatSpread;-
712 } else {
never executed: end of block
0
713 Q_UNREACHABLE();-
714 }
never executed: end of block
0
715 const QQuickShapeGradientCache::Key cacheKey(d->fillGradient.stops, spread);-
716 QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);-
717 tx->bind();-
718 } else {
never executed: end of block
0
719 mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);-
720 f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],-
721 d->fillColor.x(), d->fillColor.y(), d->fillColor.z(), d->fillColor.w());-
722 }
never executed: end of block
0
723 f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity());-
724-
725 const int writeMask = 0xFF;-
726 nvpr.stencilThenCoverFillPath(d->path, d->fillRule, writeMask, GL_BOUNDING_BOX_NV);-
727}
never executed: end of block
0
728-
729void QQuickShapeNvprRenderNode::renderOffscreenFill(ShapePathRenderData *d)-
730{-
731 if (d->fallbackValid && d->fallbackFbo)
d->fallbackValidDescription
TRUEnever evaluated
FALSEnever evaluated
d->fallbackFboDescription
TRUEnever evaluated
FALSEnever evaluated
0
732 return;
never executed: return;
0
733-
734 GLfloat bb[4];-
735 nvpr.getPathParameterfv(d->path, GL_PATH_STROKE_BOUNDING_BOX_NV, bb);-
736 QSize sz = QSizeF(bb[2] - bb[0] + 1, bb[3] - bb[1] + 1).toSize();-
737 d->fallbackSize = QSize(qMax(32, sz.width()), qMax(32, sz.height()));-
738 d->fallbackTopLeft = QPointF(bb[0], bb[1]);-
739-
740 if (d->fallbackFbo && d->fallbackFbo->size() != d->fallbackSize) {
d->fallbackFboDescription
TRUEnever evaluated
FALSEnever evaluated
d->fallbackFbo...->fallbackSizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
741 delete d->fallbackFbo;-
742 d->fallbackFbo = nullptr;-
743 }
never executed: end of block
0
744 if (!d->fallbackFbo)
!d->fallbackFboDescription
TRUEnever evaluated
FALSEnever evaluated
0
745 d->fallbackFbo = new QOpenGLFramebufferObject(d->fallbackSize, QOpenGLFramebufferObject::CombinedDepthStencil);
never executed: d->fallbackFbo = new QOpenGLFramebufferObject(d->fallbackSize, QOpenGLFramebufferObject::CombinedDepthStencil);
0
746 if (!d->fallbackFbo->bind())
!d->fallbackFbo->bind()Description
TRUEnever evaluated
FALSEnever evaluated
0
747 return;
never executed: return;
0
748-
749 GLint prevViewport[4];-
750 f->glGetIntegerv(GL_VIEWPORT, prevViewport);-
751-
752 f->glViewport(0, 0, d->fallbackSize.width(), d->fallbackSize.height());-
753 f->glDisable(GL_DEPTH_TEST);-
754 f->glClearColor(0, 0, 0, 0);-
755 f->glClearStencil(0);-
756 f->glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);-
757 f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF);-
758 f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);-
759-
760 QMatrix4x4 mv;-
761 mv.translate(-d->fallbackTopLeft.x(), -d->fallbackTopLeft.y());-
762 nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, mv.constData());-
763 QMatrix4x4 proj;-
764 proj.ortho(0, d->fallbackSize.width(), d->fallbackSize.height(), 0, 1, -1);-
765 nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, proj.constData());-
766-
767 renderFill(d);-
768-
769 d->fallbackFbo->release();-
770 f->glEnable(GL_DEPTH_TEST);-
771 f->glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]);-
772-
773 d->fallbackValid = true;-
774}
never executed: end of block
0
775-
776void QQuickShapeNvprRenderNode::setupStencilForCover(bool stencilClip, int sv)-
777{-
778 if (!stencilClip) {
!stencilClipDescription
TRUEnever evaluated
FALSEnever evaluated
0
779 // Assume stencil buffer is cleared to 0 for each frame.-
780 // Within the frame dppass=GL_ZERO for glStencilOp ensures stencil is reset and so no need to clear.-
781 f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF);-
782 f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);-
783 } else {
never executed: end of block
0
784 f->glStencilFunc(GL_LESS, sv, 0xFF); // pass if (sv & 0xFF) < (stencil_value & 0xFF)-
785 f->glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // dppass: replace with the original value (clip's stencil ref value)-
786 }
never executed: end of block
0
787}-
788-
789void QQuickShapeNvprRenderNode::render(const RenderState *state)-
790{-
791 f = QOpenGLContext::currentContext()->extraFunctions();-
792-
793 if (!nvprInited) {
!nvprInitedDescription
TRUEnever evaluated
FALSEnever evaluated
0
794 if (!nvpr.create()) {
!nvpr.create()Description
TRUEnever evaluated
FALSEnever evaluated
0
795 qWarning("NVPR init failed");-
796 return;
never executed: return;
0
797 }-
798 mtlmgr.create(&nvpr);-
799 nvprInited = true;-
800 }
never executed: end of block
0
801-
802 f->glUseProgram(0);-
803 f->glStencilMask(~0);-
804 f->glEnable(GL_STENCIL_TEST);-
805-
806 const bool stencilClip = state->stencilEnabled();-
807 // when true, the stencil buffer already has a clip path with a ref value of sv-
808 const int sv = state->stencilValue();-
809 const bool hasScissor = state->scissorEnabled();-
810-
811 if (hasScissor) {
hasScissorDescription
TRUEnever evaluated
FALSEnever evaluated
0
812 // scissor rect is already set, just enable scissoring-
813 f->glEnable(GL_SCISSOR_TEST);-
814 }
never executed: end of block
0
815-
816 // Depth test against the opaque batches rendered before.-
817 f->glEnable(GL_DEPTH_TEST);-
818 f->glDepthFunc(GL_LESS);-
819 nvpr.pathCoverDepthFunc(GL_LESS);-
820 nvpr.pathStencilDepthOffset(-0.05f, -1);-
821-
822 bool reloadMatrices = true;-
823-
824 for (ShapePathRenderData &d : m_sp) {-
825 updatePath(&d);-
826-
827 const bool hasFill = d.hasFill();-
828 const bool hasStroke = d.hasStroke();-
829-
830 if (hasFill && stencilClip) {
hasFillDescription
TRUEnever evaluated
FALSEnever evaluated
stencilClipDescription
TRUEnever evaluated
FALSEnever evaluated
0
831 // Fall back to a texture when complex clipping is in use and we have-
832 // to fill. Reconciling glStencilFillPath's and the scenegraph's clip-
833 // stencil semantics has not succeeded so far...-
834 if (hasScissor)
hasScissorDescription
TRUEnever evaluated
FALSEnever evaluated
0
835 f->glDisable(GL_SCISSOR_TEST);
never executed: f->glDisable( 0x0C11 );
0
836 renderOffscreenFill(&d);-
837 reloadMatrices = true;-
838 if (hasScissor)
hasScissorDescription
TRUEnever evaluated
FALSEnever evaluated
0
839 f->glEnable(GL_SCISSOR_TEST);
never executed: f->glEnable( 0x0C11 );
0
840 }
never executed: end of block
0
841-
842 if (reloadMatrices) {
reloadMatricesDescription
TRUEnever evaluated
FALSEnever evaluated
0
843 reloadMatrices = false;-
844 nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData());-
845 nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData());-
846 }
never executed: end of block
0
847-
848 // Fill!-
849 if (hasFill) {
hasFillDescription
TRUEnever evaluated
FALSEnever evaluated
0
850 if (!stencilClip) {
!stencilClipDescription
TRUEnever evaluated
FALSEnever evaluated
0
851 setupStencilForCover(false, 0);-
852 renderFill(&d);-
853 } else {
never executed: end of block
0
854 if (!m_fallbackBlitter.isCreated())
!m_fallbackBlitter.isCreated()Description
TRUEnever evaluated
FALSEnever evaluated
0
855 m_fallbackBlitter.create();
never executed: m_fallbackBlitter.create();
0
856 f->glStencilFunc(GL_EQUAL, sv, 0xFF);-
857 f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);-
858 QMatrix4x4 mv = *matrix();-
859 mv.translate(d.fallbackTopLeft.x(), d.fallbackTopLeft.y());-
860 m_fallbackBlitter.texturedQuad(d.fallbackFbo->texture(), d.fallbackFbo->size(),-
861 *state->projectionMatrix(), mv,-
862 inheritedOpacity());-
863 }
never executed: end of block
0
864 }-
865-
866 // Stroke!-
867 if (hasStroke) {
hasStrokeDescription
TRUEnever evaluated
FALSEnever evaluated
0
868 const int strokeStencilValue = 0x80;-
869 const int writeMask = 0x80;-
870-
871 setupStencilForCover(stencilClip, sv);-
872 if (stencilClip) {
stencilClipDescription
TRUEnever evaluated
FALSEnever evaluated
0
873 // for the stencil step (eff. read mask == 0xFF & ~writeMask)-
874 nvpr.pathStencilFunc(GL_EQUAL, sv, 0xFF);-
875 // With stencilCLip == true the read mask for the stencil test before the stencil step is 0x7F.-
876 // This assumes the clip stencil value is <= 127.-
877 if (sv >= strokeStencilValue)
sv >= strokeStencilValueDescription
TRUEnever evaluated
FALSEnever evaluated
0
878 qWarning("Shape/NVPR: stencil clip ref value %d too large; expect rendering errors", sv);
never executed: QMessageLogger(__FILE__, 878, __PRETTY_FUNCTION__).warning("Shape/NVPR: stencil clip ref value %d too large; expect rendering errors", sv);
0
879 }
never executed: end of block
0
880-
881 renderStroke(&d, strokeStencilValue, writeMask);-
882 }
never executed: end of block
0
883-
884 if (stencilClip)
stencilClipDescription
TRUEnever evaluated
FALSEnever evaluated
0
885 nvpr.pathStencilFunc(GL_ALWAYS, 0, ~0);
never executed: nvpr.pathStencilFunc( 0x0207 , 0, ~0);
0
886-
887 d.dirty = 0;-
888 }
never executed: end of block
0
889-
890 f->glBindProgramPipeline(0);-
891}
never executed: end of block
0
892-
893QSGRenderNode::StateFlags QQuickShapeNvprRenderNode::changedStates() const-
894{-
895 return BlendState | StencilState | DepthState | ScissorState;
never executed: return BlendState | StencilState | DepthState | ScissorState;
0
896}-
897-
898QSGRenderNode::RenderingFlags QQuickShapeNvprRenderNode::flags() const-
899{-
900 return DepthAwareRendering; // avoid hitting the less optimal no-opaque-batch path in the renderer
never executed: return DepthAwareRendering;
0
901}-
902-
903bool QQuickShapeNvprRenderNode::isSupported()-
904{-
905 static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0;-
906 return !nvprDisabled && QQuickNvprFunctions::isSupported();
executed 166 times by 1 test: return !nvprDisabled && QQuickNvprFunctions::isSupported();
Executed by:
  • tst_examples
166
907}-
908-
909bool QQuickNvprBlitter::create()-
910{-
911 if (isCreated())
isCreated()Description
TRUEnever evaluated
FALSEnever evaluated
0
912 destroy();
never executed: destroy();
0
913-
914 m_program = new QOpenGLShaderProgram;-
915 if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) {
QOpenGLContext...t::CoreProfileDescription
TRUEnever evaluated
FALSEnever evaluated
0
916 m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/shapes/shaders/blit_core.vert"));
never executed: return qstring_literal_temp;
0
917 m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/shapes/shaders/blit_core.frag"));
never executed: return qstring_literal_temp;
0
918 } else {
never executed: end of block
0
919 m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/shapes/shaders/blit.vert"));
never executed: return qstring_literal_temp;
0
920 m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/shapes/shaders/blit.frag"));
never executed: return qstring_literal_temp;
0
921 }
never executed: end of block
0
922 m_program->bindAttributeLocation("qt_Vertex", 0);-
923 m_program->bindAttributeLocation("qt_MultiTexCoord0", 1);-
924 if (!m_program->link())
!m_program->link()Description
TRUEnever evaluated
FALSEnever evaluated
0
925 return false;
never executed: return false;
0
926-
927 m_matrixLoc = m_program->uniformLocation("qt_Matrix");-
928 m_opacityLoc = m_program->uniformLocation("qt_Opacity");-
929-
930 m_buffer = new QOpenGLBuffer;-
931 if (!m_buffer->create())
!m_buffer->create()Description
TRUEnever evaluated
FALSEnever evaluated
0
932 return false;
never executed: return false;
0
933 m_buffer->bind();-
934 m_buffer->allocate(4 * sizeof(GLfloat) * 6);-
935 m_buffer->release();-
936-
937 return true;
never executed: return true;
0
938}-
939-
940void QQuickNvprBlitter::destroy()-
941{-
942 if (m_program) {
m_programDescription
TRUEnever evaluated
FALSEnever evaluated
0
943 delete m_program;-
944 m_program = nullptr;-
945 }
never executed: end of block
0
946 if (m_buffer) {
m_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
947 delete m_buffer;-
948 m_buffer = nullptr;-
949 }
never executed: end of block
0
950}
never executed: end of block
0
951-
952void QQuickNvprBlitter::texturedQuad(GLuint textureId, const QSize &size,-
953 const QMatrix4x4 &proj, const QMatrix4x4 &modelview,-
954 float opacity)-
955{-
956 QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();-
957-
958 m_program->bind();-
959-
960 QMatrix4x4 m = proj * modelview;-
961 m_program->setUniformValue(m_matrixLoc, m);-
962 m_program->setUniformValue(m_opacityLoc, opacity);-
963-
964 m_buffer->bind();-
965-
966 if (size != m_prevSize) {
size != m_prevSizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
967 m_prevSize = size;-
968-
969 QPointF p0(size.width() - 1, size.height() - 1);-
970 QPointF p1(0, 0);-
971 QPointF p2(0, size.height() - 1);-
972 QPointF p3(size.width() - 1, 0);-
973-
974 GLfloat vertices[6 * 4] = {-
975 GLfloat(p0.x()), GLfloat(p0.y()), 1, 0,-
976 GLfloat(p1.x()), GLfloat(p1.y()), 0, 1,-
977 GLfloat(p2.x()), GLfloat(p2.y()), 0, 0,-
978-
979 GLfloat(p0.x()), GLfloat(p0.y()), 1, 0,-
980 GLfloat(p3.x()), GLfloat(p3.y()), 1, 1,-
981 GLfloat(p1.x()), GLfloat(p1.y()), 0, 1,-
982 };-
983-
984 m_buffer->write(0, vertices, sizeof(vertices));-
985 }
never executed: end of block
0
986-
987 m_program->enableAttributeArray(0);-
988 m_program->enableAttributeArray(1);-
989 f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);-
990 f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (const void *) (2 * sizeof(GLfloat)));-
991-
992 f->glBindTexture(GL_TEXTURE_2D, textureId);-
993-
994 f->glDrawArrays(GL_TRIANGLES, 0, 6);-
995-
996 f->glBindTexture(GL_TEXTURE_2D, 0);-
997 m_buffer->release();-
998 m_program->release();-
999}
never executed: end of block
0
1000-
1001QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.2.0