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(); const int count = sp.size();
bool countChanged = false; bool countChanged = false;
renderer->beginSync(count, &countChanged); renderer->beginSync(count, &countChanged);
renderer->setTriangulationScale(triangulationScale);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
QQuickShapePath *p = sp[i]; QQuickShapePath *p = sp[i];

View File

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

View File

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

View File

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