shapes: Privately expose the tringulator scale

For many typical uses in Qt Quick the hardcoded TRI_SCALE = 1 was
just fine. However, this is not quite sufficient for Qt Location's
purposes since the triangulator in QtGui may run out of precision
when zooming in a map and having to deal with large coordinates.

To overcome this one would pass in a transform with a < 1 scale
to the triangulator and then apply the same scaling in reverse
to the generated vertex positions (e.g. this is what the OpenGL
paint engine does). But to allow doing this, there needs to be
an internal way at least, so that one can send the desired scale
down to the default Shape rendering backend.

Pick-to: 6.5
Change-Id: I4e7f72b79d317ebc31e9d661f4a93723854e3504
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Laszlo Agocs 2022-12-14 19:01:18 +01:00
parent 6ac764a4d9
commit bcfcaeb87b
4 changed files with 40 additions and 20 deletions

View File

@ -1003,6 +1003,7 @@ void QQuickShapePrivate::sync()
const int count = sp.size();
bool countChanged = false;
renderer->beginSync(count, &countChanged);
renderer->setTriangulationScale(triangulationScale);
for (int i = 0; i < count; ++i) {
QQuickShapePath *p = sp[i];

View File

@ -65,6 +65,7 @@ public:
virtual void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) = 0;
virtual void setFillGradient(int index, QQuickShapeGradient *gradient) = 0;
virtual void setTriangulationScale(qreal) { }
// Render thread, with gui blocked
virtual void updateNode() = 0;
@ -150,6 +151,7 @@ public:
bool async = false;
bool enableVendorExts = false;
bool syncTimingActive = false;
qreal triangulationScale = 1.0;
};
struct QQuickShapeGradientCacheKey

View File

@ -13,8 +13,6 @@
QT_BEGIN_NAMESPACE
static const qreal TRI_SCALE = 1;
struct ColoredVertex // must match QSGGeometry::ColoredPoint2D
{
float x, y;
@ -198,15 +196,22 @@ void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient
d.syncDirty |= DirtyFillGradient;
}
void QQuickShapeGenericRenderer::setTriangulationScale(qreal scale)
{
// No dirty, this is called at the start of every sync. Just store the value.
m_triangulationScale = scale;
}
void QQuickShapeFillRunnable::run()
{
QQuickShapeGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType, supportsElementIndexUint);
QQuickShapeGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType,
supportsElementIndexUint, triangulationScale);
emit done(this);
}
void QQuickShapeStrokeRunnable::run()
{
QQuickShapeGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize);
QQuickShapeGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize, triangulationScale);
emit done(this);
}
@ -286,6 +291,7 @@ void QQuickShapeGenericRenderer::endSync(bool async)
r->path = d.path;
r->fillColor = d.fillColor;
r->supportsElementIndexUint = supportsElementIndexUint;
r->triangulationScale = m_triangulationScale;
// Unlikely in practice but in theory m_sp could be
// resized. Therefore, capture 'i' instead of 'd'.
QObject::connect(r, &QQuickShapeFillRunnable::done, qApp, [this, i](QQuickShapeFillRunnable *r) {
@ -310,7 +316,9 @@ void QQuickShapeGenericRenderer::endSync(bool async)
pathWorkThreadPool->start(r);
#endif
} else {
triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType, supportsElementIndexUint);
triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType,
supportsElementIndexUint,
m_triangulationScale);
}
}
@ -325,6 +333,7 @@ void QQuickShapeGenericRenderer::endSync(bool async)
r->pen = d.pen;
r->strokeColor = d.strokeColor;
r->clipSize = QSize(m_item->width(), m_item->height());
r->triangulationScale = m_triangulationScale;
QObject::connect(r, &QQuickShapeStrokeRunnable::done, qApp, [this, i](QQuickShapeStrokeRunnable *r) {
if (!r->orphaned && i < m_sp.size()) {
ShapePathData &d(m_sp[i]);
@ -344,7 +353,7 @@ void QQuickShapeGenericRenderer::endSync(bool async)
#endif
} else {
triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices,
QSize(m_item->width(), m_item->height()));
QSize(m_item->width(), m_item->height()), m_triangulationScale);
}
}
}
@ -368,21 +377,22 @@ void QQuickShapeGenericRenderer::maybeUpdateAsyncItem()
// the stroke/fill triangulation functions may be invoked either on the gui
// thread or some worker thread and must thus be self-contained.
void QQuickShapeGenericRenderer::triangulateFill(const QPainterPath &path,
const Color4ub &fillColor,
VertexContainerType *fillVertices,
IndexContainerType *fillIndices,
QSGGeometry::Type *indexType,
bool supportsElementIndexUint)
const Color4ub &fillColor,
VertexContainerType *fillVertices,
IndexContainerType *fillIndices,
QSGGeometry::Type *indexType,
bool supportsElementIndexUint,
qreal triangulationScale)
{
const QVectorPath &vp = qtVectorPathForPath(path);
QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(TRI_SCALE, TRI_SCALE), 1, supportsElementIndexUint);
QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(triangulationScale, triangulationScale), 1, supportsElementIndexUint);
const int vertexCount = ts.vertices.size() / 2; // just a qreal vector with x,y hence the / 2
fillVertices->resize(vertexCount);
ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(fillVertices->data());
const qreal *vsrc = ts.vertices.constData();
for (int i = 0; i < vertexCount; ++i)
vdst[i].set(vsrc[i * 2] / TRI_SCALE, vsrc[i * 2 + 1] / TRI_SCALE, fillColor);
vdst[i].set(vsrc[i * 2] / triangulationScale, vsrc[i * 2 + 1] / triangulationScale, fillColor);
size_t indexByteSize;
if (ts.indices.type() == QVertexIndexVector::UnsignedShort) {
@ -400,14 +410,15 @@ void QQuickShapeGenericRenderer::triangulateFill(const QPainterPath &path,
}
void QQuickShapeGenericRenderer::triangulateStroke(const QPainterPath &path,
const QPen &pen,
const Color4ub &strokeColor,
VertexContainerType *strokeVertices,
const QSize &clipSize)
const QPen &pen,
const Color4ub &strokeColor,
VertexContainerType *strokeVertices,
const QSize &clipSize,
qreal triangulationScale)
{
const QVectorPath &vp = qtVectorPathForPath(path);
const QRectF clip(QPointF(0, 0), clipSize);
const qreal inverseScale = 1.0 / TRI_SCALE;
const qreal inverseScale = 1.0 / triangulationScale;
QTriangulatingStroker stroker;
stroker.setInvScale(inverseScale);

View File

@ -63,6 +63,7 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
void setTriangulationScale(qreal scale) override;
void endSync(bool async) override;
void setAsyncCallback(void (*)(void *), void *) override;
Flags flags() const override { return SupportsAsync; }
@ -80,12 +81,14 @@ public:
VertexContainerType *fillVertices,
IndexContainerType *fillIndices,
QSGGeometry::Type *indexType,
bool supportsElementIndexUint);
bool supportsElementIndexUint,
qreal triangulationScale);
static void triangulateStroke(const QPainterPath &path,
const QPen &pen,
const Color4ub &strokeColor,
VertexContainerType *strokeVertices,
const QSize &clipSize);
const QSize &clipSize,
qreal triangulationScale);
private:
void maybeUpdateAsyncItem();
@ -120,6 +123,7 @@ private:
int m_accDirty;
void (*m_asyncCallback)(void *);
void *m_asyncCallbackData;
float m_triangulationScale = 1.0;
};
class QQuickShapeFillRunnable : public QObject, public QRunnable
@ -135,6 +139,7 @@ public:
QPainterPath path;
QQuickShapeGenericRenderer::Color4ub fillColor;
bool supportsElementIndexUint;
qreal triangulationScale;
// output
QQuickShapeGenericRenderer::VertexContainerType fillVertices;
@ -159,6 +164,7 @@ public:
QPen pen;
QQuickShapeGenericRenderer::Color4ub strokeColor;
QSize clipSize;
qreal triangulationScale;
// output
QQuickShapeGenericRenderer::VertexContainerType strokeVertices;