Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/qtdeclarative/src/qtdeclarative/src/quickshapes/qquickshapenvprrenderer.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 | - | |||||||||||||
49 | QT_BEGIN_NAMESPACE | - | ||||||||||||
50 | - | |||||||||||||
51 | void QQuickShapeNvprRenderer::beginSync(int totalCount) | - | ||||||||||||
52 | { | - | ||||||||||||
53 | if (m_sp.count() != totalCount) {
| 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 | - | |||||||||||||
59 | void 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 | - | |||||||||||||
67 | void 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 | - | |||||||||||||
75 | void 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 | - | |||||||||||||
83 | void 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 | - | |||||||||||||
91 | void 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 | - | |||||||||||||
99 | void 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 | - | |||||||||||||
108 | void 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 | - | |||||||||||||
116 | void 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 | - | |||||||||||||
127 | void QQuickShapeNvprRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) | - | ||||||||||||
128 | { | - | ||||||||||||
129 | ShapePathGuiData &d(m_sp[index]); | - | ||||||||||||
130 | if (gradient) {
| 0 | ||||||||||||
131 | d.fillGradient.stops = gradient->gradientStops(); // sorted | - | ||||||||||||
132 | d.fillGradient.spread = gradient->spread(); | - | ||||||||||||
133 | if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(gradient)) {
| 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
| 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
| 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 | - | |||||||||||||
157 | void QQuickShapeNvprRenderer::endSync(bool) | - | ||||||||||||
158 | { | - | ||||||||||||
159 | } | - | ||||||||||||
160 | - | |||||||||||||
161 | void QQuickShapeNvprRenderer::setNode(QQuickShapeNvprRenderNode *node) | - | ||||||||||||
162 | { | - | ||||||||||||
163 | if (m_node != node) {
| 0 | ||||||||||||
164 | m_node = node; | - | ||||||||||||
165 | m_accDirty |= DirtyList; | - | ||||||||||||
166 | } never executed: end of block | 0 | ||||||||||||
167 | } never executed: end of block | 0 | ||||||||||||
168 | - | |||||||||||||
169 | QDebug operator<<(QDebug debug, const QQuickShapeNvprRenderer::NvprPath &path) | - | ||||||||||||
170 | { | - | ||||||||||||
171 | QDebugStateSaver saver(debug); | - | ||||||||||||
172 | debug.space().noquote(); | - | ||||||||||||
173 | if (!path.str.isEmpty()) {
| 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) {
| 0 | ||||||||||||
191 | if (nameTab[i].cmd == cmd) {
| 0 | ||||||||||||
192 | QByteArray cs; | - | ||||||||||||
193 | for (int j = 0; j < nameTab[i].coordCount; ++j) {
| 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 | - | |||||||||||||
205 | static 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 | - | |||||||||||||
214 | static 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 | - | |||||||||||||
222 | static 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 | - | |||||||||||||
230 | static 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 | - | |||||||||||||
238 | void QQuickShapeNvprRenderer::convertPath(const QQuickPath *path, ShapePathGuiData *d) | - | ||||||||||||
239 | { | - | ||||||||||||
240 | d->path = NvprPath(); | - | ||||||||||||
241 | if (!path)
| 0 | ||||||||||||
242 | return; never executed: return; | 0 | ||||||||||||
243 | - | |||||||||||||
244 | const QList<QQuickPathElement *> &pp(QQuickPathPrivate::get(path)->_pathElements); | - | ||||||||||||
245 | if (pp.isEmpty())
| 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())) {
| 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)) {
| 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
| 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
| 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
| 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
| 0 | ||||||||||||
274 | const bool sweepFlag = o->direction() == QQuickPathArc::Clockwise; // maps to CCW, not a typo | - | ||||||||||||
275 | GLenum cmd; | - | ||||||||||||
276 | if (o->useLargeArc())
| 0 | ||||||||||||
277 | cmd = sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV; never executed: cmd = sweepFlag ? 0x16 : 0x18;
| 0 | ||||||||||||
278 | else | - | ||||||||||||
279 | cmd = sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV; never executed: cmd = sweepFlag ? 0x12 : 0x14;
| 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
| 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())
| 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
| 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())
| 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)
| 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 | - | |||||||||||||
329 | static 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 | - | |||||||||||||
335 | void 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)
| 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)
| 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) {
| 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)
| 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)
| 0 | ||||||||||||
362 | dst.source = src.path; never executed: dst.source = src.path; | 0 | ||||||||||||
363 | - | |||||||||||||
364 | if (dirty & DirtyStyle) {
| 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) {
| 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) {
| 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) {
| 0 | ||||||||||||
415 | if (src.dashPattern.isEmpty()) {
| 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)
| 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) {
| 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) {
| 0 | ||||||||||||
437 | dst.fillGradientActive = src.fillGradientActive; | - | ||||||||||||
438 | if (src.fillGradientActive)
| 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 | - | |||||||||||||
447 | bool QQuickShapeNvprRenderNode::nvprInited = false; | - | ||||||||||||
448 | QQuickNvprFunctions QQuickShapeNvprRenderNode::nvpr; | - | ||||||||||||
449 | QQuickNvprMaterialManager QQuickShapeNvprRenderNode::mtlmgr; | - | ||||||||||||
450 | - | |||||||||||||
451 | QQuickShapeNvprRenderNode::~QQuickShapeNvprRenderNode() | - | ||||||||||||
452 | { | - | ||||||||||||
453 | releaseResources(); | - | ||||||||||||
454 | } never executed: end of block | 0 | ||||||||||||
455 | - | |||||||||||||
456 | void QQuickShapeNvprRenderNode::releaseResources() | - | ||||||||||||
457 | { | - | ||||||||||||
458 | for (ShapePathRenderData &d : m_sp) { | - | ||||||||||||
459 | if (d.path) {
| 0 | ||||||||||||
460 | nvpr.deletePaths(d.path, 1); | - | ||||||||||||
461 | d.path = 0; | - | ||||||||||||
462 | } never executed: end of block | 0 | ||||||||||||
463 | if (d.fallbackFbo) {
| 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 | - | |||||||||||||
472 | void QQuickNvprMaterialManager::create(QQuickNvprFunctions *nvpr) | - | ||||||||||||
473 | { | - | ||||||||||||
474 | m_nvpr = nvpr; | - | ||||||||||||
475 | } never executed: end of block | 0 | ||||||||||||
476 | - | |||||||||||||
477 | void QQuickNvprMaterialManager::releaseResources() | - | ||||||||||||
478 | { | - | ||||||||||||
479 | QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); | - | ||||||||||||
480 | for (MaterialDesc &mtl : m_materials) { | - | ||||||||||||
481 | if (mtl.ppl) {
| 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 | - | |||||||||||||
488 | QQuickNvprMaterialManager::MaterialDesc *QQuickNvprMaterialManager::activateMaterial(Material m) | - | ||||||||||||
489 | { | - | ||||||||||||
490 | QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); | - | ||||||||||||
491 | MaterialDesc &mtl(m_materials[m]); | - | ||||||||||||
492 | - | |||||||||||||
493 | if (!mtl.ppl) {
| 0 | ||||||||||||
494 | if (m == MatSolid) {
| 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)) {
| 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
| 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)) {
| 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
| 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)) {
| 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
| 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)) {
| 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 | - | |||||||||||||
623 | void QQuickShapeNvprRenderNode::updatePath(ShapePathRenderData *d) | - | ||||||||||||
624 | { | - | ||||||||||||
625 | if (d->dirty & QQuickShapeNvprRenderer::DirtyPath) {
| 0 | ||||||||||||
626 | if (!d->path) {
| 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()) {
| 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) {
| 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) {
| 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)
| 0 | ||||||||||||
653 | d->fallbackValid = false; never executed: d->fallbackValid = false; | 0 | ||||||||||||
654 | } never executed: end of block | 0 | ||||||||||||
655 | - | |||||||||||||
656 | void 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 | - | |||||||||||||
666 | void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d) | - | ||||||||||||
667 | { | - | ||||||||||||
668 | QQuickNvprMaterialManager::MaterialDesc *mtl = nullptr; | - | ||||||||||||
669 | if (d->fillGradientActive) {
| 0 | ||||||||||||
670 | QQuickShapeGradient::SpreadMode spread = d->fillGradient.spread; | - | ||||||||||||
671 | if (d->fillGradientActive == QQuickAbstractPathRenderer::LinearGradient) {
| 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
| 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
| 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 | - | |||||||||||||
729 | void QQuickShapeNvprRenderNode::renderOffscreenFill(ShapePathRenderData *d) | - | ||||||||||||
730 | { | - | ||||||||||||
731 | if (d->fallbackValid && d->fallbackFbo)
| 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) {
| 0 | ||||||||||||
741 | delete d->fallbackFbo; | - | ||||||||||||
742 | d->fallbackFbo = nullptr; | - | ||||||||||||
743 | } never executed: end of block | 0 | ||||||||||||
744 | if (!d->fallbackFbo)
| 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())
| 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 | - | |||||||||||||
776 | void QQuickShapeNvprRenderNode::setupStencilForCover(bool stencilClip, int sv) | - | ||||||||||||
777 | { | - | ||||||||||||
778 | if (!stencilClip) {
| 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 | - | |||||||||||||
789 | void QQuickShapeNvprRenderNode::render(const RenderState *state) | - | ||||||||||||
790 | { | - | ||||||||||||
791 | f = QOpenGLContext::currentContext()->extraFunctions(); | - | ||||||||||||
792 | - | |||||||||||||
793 | if (!nvprInited) {
| 0 | ||||||||||||
794 | if (!nvpr.create()) {
| 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) {
| 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) {
| 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)
| 0 | ||||||||||||
835 | f->glDisable(GL_SCISSOR_TEST); never executed: f->glDisable( 0x0C11 ); | 0 | ||||||||||||
836 | renderOffscreenFill(&d); | - | ||||||||||||
837 | reloadMatrices = true; | - | ||||||||||||
838 | if (hasScissor)
| 0 | ||||||||||||
839 | f->glEnable(GL_SCISSOR_TEST); never executed: f->glEnable( 0x0C11 ); | 0 | ||||||||||||
840 | } never executed: end of block | 0 | ||||||||||||
841 | - | |||||||||||||
842 | if (reloadMatrices) {
| 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) {
| 0 | ||||||||||||
850 | if (!stencilClip) {
| 0 | ||||||||||||
851 | setupStencilForCover(false, 0); | - | ||||||||||||
852 | renderFill(&d); | - | ||||||||||||
853 | } else { never executed: end of block | 0 | ||||||||||||
854 | if (!m_fallbackBlitter.isCreated())
| 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) {
| 0 | ||||||||||||
868 | const int strokeStencilValue = 0x80; | - | ||||||||||||
869 | const int writeMask = 0x80; | - | ||||||||||||
870 | - | |||||||||||||
871 | setupStencilForCover(stencilClip, sv); | - | ||||||||||||
872 | if (stencilClip) {
| 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)
| 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)
| 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 | - | |||||||||||||
893 | QSGRenderNode::StateFlags QQuickShapeNvprRenderNode::changedStates() const | - | ||||||||||||
894 | { | - | ||||||||||||
895 | return BlendState | StencilState | DepthState | ScissorState; never executed: return BlendState | StencilState | DepthState | ScissorState; | 0 | ||||||||||||
896 | } | - | ||||||||||||
897 | - | |||||||||||||
898 | QSGRenderNode::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 | - | |||||||||||||
903 | bool 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:
| 166 | ||||||||||||
907 | } | - | ||||||||||||
908 | - | |||||||||||||
909 | bool QQuickNvprBlitter::create() | - | ||||||||||||
910 | { | - | ||||||||||||
911 | if (isCreated())
| 0 | ||||||||||||
912 | destroy(); never executed: destroy(); | 0 | ||||||||||||
913 | - | |||||||||||||
914 | m_program = new QOpenGLShaderProgram; | - | ||||||||||||
915 | if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) {
| 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())
| 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())
| 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 | - | |||||||||||||
940 | void QQuickNvprBlitter::destroy() | - | ||||||||||||
941 | { | - | ||||||||||||
942 | if (m_program) {
| 0 | ||||||||||||
943 | delete m_program; | - | ||||||||||||
944 | m_program = nullptr; | - | ||||||||||||
945 | } never executed: end of block | 0 | ||||||||||||
946 | if (m_buffer) {
| 0 | ||||||||||||
947 | delete m_buffer; | - | ||||||||||||
948 | m_buffer = nullptr; | - | ||||||||||||
949 | } never executed: end of block | 0 | ||||||||||||
950 | } never executed: end of block | 0 | ||||||||||||
951 | - | |||||||||||||
952 | void 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) {
| 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 | - | |||||||||||||
1001 | QT_END_NAMESPACE | - | ||||||||||||
Source code | Switch to Preprocessed file |