| 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 |