diff --git a/src/quick3d/qquick3dmodel.cpp b/src/quick3d/qquick3dmodel.cpp
index 5c72e203497ea2d134ad8bda1f526e6089288d61..8de06cb3b35868f4944b5367b0155a4cd7233b63 100644
--- a/src/quick3d/qquick3dmodel.cpp
+++ b/src/quick3d/qquick3dmodel.cpp
@@ -409,7 +409,7 @@ QSSGRenderGraphObject *QQuick3DModel::updateSpatialNode(QSSGRenderGraphObject *n
 
     auto modelNode = static_cast<QSSGRenderModel *>(node);
     if (m_dirtyAttributes & SourceDirty)
-        modelNode->meshPath = QSSGRenderMeshPath::create(translateSource());
+        modelNode->meshPath = QSSGRenderPath(translateSource());
     if (m_dirtyAttributes & TessellationModeDirty)
         modelNode->tessellationMode = TessellationModeValues(m_tessellationMode);
     if (m_dirtyAttributes & TessellationEdgeDirty)
diff --git a/src/runtimerender/graphobjects/qssgrendergeometry.cpp b/src/runtimerender/graphobjects/qssgrendergeometry.cpp
index dc0596a11d485f4145968281c86c721d2a154488..3f9e03fa15d8a2e54da447e997d48dedb2edfe9d 100644
--- a/src/runtimerender/graphobjects/qssgrendergeometry.cpp
+++ b/src/runtimerender/graphobjects/qssgrendergeometry.cpp
@@ -84,7 +84,7 @@ int QSSGRenderGeometry::stride() const
 
 QString QSSGRenderGeometry::path() const
 {
-    return m_meshPath.path;
+    return m_meshPath.path();
 }
 
 QSSGRenderGeometry::PrimitiveType QSSGRenderGeometry::primitiveType() const
@@ -158,7 +158,7 @@ void QSSGRenderGeometry::clearAttributes()
 
 void QSSGRenderGeometry::setPath(const QString &path)
 {
-    m_meshPath = QSSGRenderMeshPath::create(path);
+    m_meshPath = QSSGRenderPath(path);
     m_dirty = true;
 }
 
diff --git a/src/runtimerender/graphobjects/qssgrendergeometry_p.h b/src/runtimerender/graphobjects/qssgrendergeometry_p.h
index 369856a8b8465b07a7afff90a863db7e483a0e6b..7117907b1fa68e0d6eaccab9449c5579ce038e30 100644
--- a/src/runtimerender/graphobjects/qssgrendergeometry_p.h
+++ b/src/runtimerender/graphobjects/qssgrendergeometry_p.h
@@ -44,6 +44,7 @@
 #include <QtQuick3DRuntimeRender/private/qssgrendergraphobject_p.h>
 #include <QtQuick3DRuntimeRender/private/qssgrendernode_p.h>
 #include <QtQuick3DRuntimeRender/private/qssgrendermesh_p.h>
+#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
 #include <QtQuick3DAssetImport/private/qssgmeshutilities_p.h>
 
 #include <QtCore/qbytearray.h>
@@ -130,7 +131,7 @@ protected:
     Q_DISABLE_COPY(QSSGRenderGeometry)
 
     bool m_dirty = true;
-    QSSGRenderMeshPath m_meshPath;
+    QSSGRenderPath m_meshPath;
     QSSGMeshUtilities::MeshData m_meshData;
     QSSGRef<QSSGMeshUtilities::QSSGMeshBuilder> m_meshBuilder;
     QSSGBounds3 m_bounds;
diff --git a/src/runtimerender/graphobjects/qssgrendermodel_p.h b/src/runtimerender/graphobjects/qssgrendermodel_p.h
index 8d04e1957415ac3904cf20fb9e6c994a71da3d46..c995b0bdb3f0e513e35a8bdda7c7204f228ba4a1 100644
--- a/src/runtimerender/graphobjects/qssgrendermodel_p.h
+++ b/src/runtimerender/graphobjects/qssgrendermodel_p.h
@@ -61,7 +61,7 @@ struct Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRenderModel : public QSSGRenderNode
     //*not* relative to the presentation directory
     QVector<QSSGRenderGraphObject *> materials;
     QSSGRenderGeometry *geometry = nullptr;
-    QSSGRenderMeshPath meshPath;
+    QSSGRenderPath meshPath;
     float edgeTessellation = 1.0f;
     float innerTessellation = 1.0f;
     TessellationModeValues tessellationMode = TessellationModeValues::NoTessellation;
diff --git a/src/runtimerender/qssgrendererutil_p.h b/src/runtimerender/qssgrendererutil_p.h
index 6c742b864fea0ecdf01f18fa781f6a3113cf6800..c17f249f7cb631f9a267d3a5d7fa108eef5c398e 100644
--- a/src/runtimerender/qssgrendererutil_p.h
+++ b/src/runtimerender/qssgrendererutil_p.h
@@ -51,8 +51,34 @@ namespace QSSGRendererUtil
 inline constexpr quint32 nextMultipleOf4(quint32 value) {
     return (value + 3) & ~3;
 }
+}
+
+class QSSGRenderPath
+{
+public:
+    QSSGRenderPath() = default;
+    explicit inline QSSGRenderPath(const QString &p) noexcept
+        : m_path(p), m_key(qHash(p, qGlobalQHashSeed())) {}
+
+    inline bool isNull() const { return m_path.isNull(); }
+    QString path() const { return m_path; }
+private:
+    friend bool operator==(const QSSGRenderPath &, const QSSGRenderPath &);
+    friend size_t qHash(const QSSGRenderPath &, size_t) Q_DECL_NOTHROW;
+    QString m_path;
+    size_t m_key = 0;
 };
 
+inline bool operator==(const QSSGRenderPath &p1, const QSSGRenderPath &p2)
+{
+    return (p1.m_key == p2.m_key) && (p1.m_path == p2.m_path);
+}
+
+inline size_t qHash(const QSSGRenderPath &path, size_t seed) Q_DECL_NOTHROW
+{
+    return (path.m_key) ? path.m_key : qHash(path.m_path, seed);
+}
+
 QT_END_NAMESPACE
 
 #endif
diff --git a/src/runtimerender/qssgrendermesh_p.h b/src/runtimerender/qssgrendermesh_p.h
index ca2b3b863c6d174a4e185738c2100e7d64183100..3de8cb288cf4f9be73a3d6c8a3d215c33e65b8ab 100644
--- a/src/runtimerender/qssgrendermesh_p.h
+++ b/src/runtimerender/qssgrendermesh_p.h
@@ -139,32 +139,6 @@ struct QSSGRenderSubset : public QSSGRenderSubsetBase
     }
 };
 
-struct QSSGRenderMeshPath
-{
-    QString path;
-    size_t key = 0;
-
-    inline bool isNull() const { return path.isNull(); }
-
-    static QSSGRenderMeshPath create(const QString &path)
-    {
-        QSSGRenderMeshPath p;
-        p.path = path;
-        p.key = qHash(path);
-        return p;
-    }
-};
-
-inline bool operator==(const QSSGRenderMeshPath &p1, const QSSGRenderMeshPath &p2)
-{
-    return (p1.path == p2.path);
-}
-
-inline size_t qHash(const QSSGRenderMeshPath &path, size_t seed) Q_DECL_NOTHROW
-{
-    return (path.key) ? path.key : qHash(path.path, seed);
-}
-
 struct QSSGRenderMesh
 {
     Q_DISABLE_COPY(QSSGRenderMesh)
diff --git a/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp b/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp
index ec6e6281fada3664ce1fc349e33e48ef5c695259..0795bb15ac5f8f83745fe011526d840d850b9d92 100644
--- a/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp
+++ b/src/runtimerender/resourcemanager/qssgrenderbuffermanager.cpp
@@ -772,7 +772,7 @@ QVector<QVector3D> QSSGBufferManager::createPackedPositionDataArray(
     return positions;
 }
 
-QSSGRenderMesh *QSSGBufferManager::getMesh(const QSSGRenderMeshPath &inSourcePath) const
+QSSGRenderMesh *QSSGBufferManager::getMesh(const QSSGRenderPath &inSourcePath) const
 {
     if (inSourcePath.isNull())
         return nullptr;
@@ -782,7 +782,7 @@ QSSGRenderMesh *QSSGBufferManager::getMesh(const QSSGRenderMeshPath &inSourcePat
 }
 
 QSSGRenderMesh *QSSGBufferManager::createRenderMesh(
-        const QSSGMeshUtilities::MultiLoadResult &result, const QSSGRenderMeshPath &inSourcePath)
+        const QSSGMeshUtilities::MultiLoadResult &result, const QSSGRenderPath &inSourcePath)
 {
     QSSGRenderMesh *newMesh = new QSSGRenderMesh(result.m_mesh->m_drawMode,
                                                  result.m_mesh->m_winding,
@@ -936,7 +936,7 @@ QSSGRenderMesh *QSSGBufferManager::createRenderMesh(
     return newMesh;
 }
 
-QSSGRenderMesh *QSSGBufferManager::loadMesh(const QSSGRenderMeshPath &inMeshPath)
+QSSGRenderMesh *QSSGBufferManager::loadMesh(const QSSGRenderPath &inMeshPath)
 {
     if (inMeshPath.isNull())
         return nullptr;
@@ -950,7 +950,7 @@ QSSGRenderMesh *QSSGBufferManager::loadMesh(const QSSGRenderMeshPath &inMeshPath
     QSSGMeshUtilities::MultiLoadResult result = loadMeshData(inMeshPath);
 
     if (result.m_mesh == nullptr) {
-        qCWarning(WARNING, "Failed to load mesh: %s", qPrintable(inMeshPath.path));
+        qCWarning(WARNING, "Failed to load mesh: %s", qPrintable(inMeshPath.path()));
         return nullptr;
     }
 
@@ -959,7 +959,7 @@ QSSGRenderMesh *QSSGBufferManager::loadMesh(const QSSGRenderMeshPath &inMeshPath
     return ret;
 }
 
-QSSGRenderMesh *QSSGBufferManager::loadCustomMesh(const QSSGRenderMeshPath &inSourcePath,
+QSSGRenderMesh *QSSGBufferManager::loadCustomMesh(const QSSGRenderPath &inSourcePath,
                                                   QSSGMeshUtilities::Mesh *mesh, bool update)
 {
     if (!inSourcePath.isNull() && mesh) {
@@ -979,13 +979,13 @@ QSSGRenderMesh *QSSGBufferManager::loadCustomMesh(const QSSGRenderMeshPath &inSo
     return nullptr;
 }
 
-QSSGMeshBVH *QSSGBufferManager::loadMeshBVH(const QSSGRenderMeshPath &inSourcePath)
+QSSGMeshBVH *QSSGBufferManager::loadMeshBVH(const QSSGRenderPath &inSourcePath)
 {
     // loading new mesh
     QSSGMeshUtilities::MultiLoadResult result = loadMeshData(inSourcePath);
 
     if (result.m_mesh == nullptr) {
-        qCWarning(WARNING, "Failed to load mesh: %s", qPrintable(inSourcePath.path));
+        qCWarning(WARNING, "Failed to load mesh: %s", qPrintable(inSourcePath.path()));
         return nullptr;
     }
 
@@ -997,18 +997,18 @@ QSSGMeshBVH *QSSGBufferManager::loadMeshBVH(const QSSGRenderMeshPath &inSourcePa
     return bvh;
 }
 
-QSSGMeshUtilities::MultiLoadResult QSSGBufferManager::loadMeshData(const QSSGRenderMeshPath &inMeshPath) const
+QSSGMeshUtilities::MultiLoadResult QSSGBufferManager::loadMeshData(const QSSGRenderPath &inMeshPath) const
 {
     // loading new mesh
     QSSGMeshUtilities::MultiLoadResult result;
 
     // check to see if this is a primitive mesh
-    if (inMeshPath.path.startsWith(QChar::fromLatin1('#')))
-        result = loadPrimitive(inMeshPath.path);
+    if (inMeshPath.path().startsWith(QChar::fromLatin1('#')))
+        result = loadPrimitive(inMeshPath.path());
 
     // Attempt a load from the filesystem if this mesh isn't a primitive.
     if (result.m_mesh == nullptr) {
-        QString pathBuilder = inMeshPath.path;
+        QString pathBuilder = inMeshPath.path();
         int poundIndex = pathBuilder.lastIndexOf(QChar::fromLatin1('#'));
         int id = 0;
         if (poundIndex != -1) {
diff --git a/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h b/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h
index 05153a53562fd6a3a6aba7c27ffd0c5632c6259c..eaf50f63a9dbbe81b98da57979b154be63c39a2d 100644
--- a/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h
+++ b/src/runtimerender/resourcemanager/qssgrenderbuffermanager_p.h
@@ -70,7 +70,7 @@ public:
 private:
     typedef QHash<QString, QSSGRenderImageTextureData> ImageMap;
     typedef QHash<QSGTexture *, QSSGRenderImageTextureData> QSGImageMap;
-    typedef QHash<QSSGRenderMeshPath, QSSGRenderMesh *> MeshMap;
+    typedef QHash<QSSGRenderPath, QSSGRenderMesh *> MeshMap;
 
     QSSGRef<QSSGRhiContext> context;
     QSSGRef<QSSGInputStreamFactory> inputStreamFactory;
@@ -104,16 +104,16 @@ public:
                                                  bool inForceScanForTransparency = false,
                                                  bool inBsdfMipmaps = false);
     QSSGRenderImageTextureData loadRenderImage(QSGTexture *qsgTexture);
-    QSSGRenderMesh *getMesh(const QSSGRenderMeshPath &inSourcePath) const;
-    QSSGRenderMesh *loadMesh(const QSSGRenderMeshPath &inSourcePath);
-    QSSGRenderMesh *loadCustomMesh(const QSSGRenderMeshPath &inSourcePath,
+    QSSGRenderMesh *getMesh(const QSSGRenderPath &inSourcePath) const;
+    QSSGRenderMesh *loadMesh(const QSSGRenderPath &inSourcePath);
+    QSSGRenderMesh *loadCustomMesh(const QSSGRenderPath &inSourcePath,
                                    QSSGMeshUtilities::Mesh *mesh,
                                    bool update = false);
-    QSSGMeshBVH *loadMeshBVH(const QSSGRenderMeshPath &inSourcePath);
-    QSSGMeshUtilities::MultiLoadResult loadMeshData(const QSSGRenderMeshPath &inSourcePath) const;
+    QSSGMeshBVH *loadMeshBVH(const QSSGRenderPath &inSourcePath);
+    QSSGMeshUtilities::MultiLoadResult loadMeshData(const QSSGRenderPath &inSourcePath) const;
 
     QSSGRenderMesh *createRenderMesh(const QSSGMeshUtilities::MultiLoadResult &result,
-                                     const QSSGRenderMeshPath &inSourcePath);
+                                     const QSSGRenderPath &inSourcePath);
 
     static QRhiTexture::Format toRhiFormat(const QSSGRenderTextureFormat format);
 
diff --git a/tests/auto/quick3d/qquick3dmodel/tst_qquick3dmodel.cpp b/tests/auto/quick3d/qquick3dmodel/tst_qquick3dmodel.cpp
index 147bf5f5ccefd4d59b2619b002047e9a6e2c389a..969a4a5c3c1541de7c3c8ca87ba8c591273181f8 100644
--- a/tests/auto/quick3d/qquick3dmodel/tst_qquick3dmodel.cpp
+++ b/tests/auto/quick3d/qquick3dmodel/tst_qquick3dmodel.cpp
@@ -112,7 +112,7 @@ void tst_QQuick3DModel::testProperties()
     QCOMPARE(spy.count(), 1);
     node = static_cast<QSSGRenderModel *>(model.updateSpatialNode(node));
     QCOMPARE(cubeUrl, model.source());
-    QCOMPARE(cubeUrl, node->meshPath.path);
+    QCOMPARE(cubeUrl, node->meshPath.path());
     QCOMPARE(originalNode, node);
 
     QQuick3DGeometry geometry;
diff --git a/tests/auto/quick3d/qquick3dtexture/tst_qquick3dtexture.cpp b/tests/auto/quick3d/qquick3dtexture/tst_qquick3dtexture.cpp
index 39c194f13dbd6811aa465a27b7aa4f076eb6ef1e..bbde7efa707d466c8123e84e1a13fc95fd2bccd8 100644
--- a/tests/auto/quick3d/qquick3dtexture/tst_qquick3dtexture.cpp
+++ b/tests/auto/quick3d/qquick3dtexture/tst_qquick3dtexture.cpp
@@ -70,7 +70,7 @@ void tst_QQuick3DTexture::testSetSource()
     const QString expectedPath {QString::fromLatin1("path/to/resource")};
     texture.setSource(fileWithScheme);
     node.reset(static_cast<QSSGRenderImage *>(texture.updateSpatialNode(nullptr)));
-    QCOMPARE(expectedPath, node->m_imagePath);
+    QCOMPARE(expectedPath, node->m_imagePath.path());
     QCOMPARE(spy.count(), 1);
 
     // Same url again
diff --git a/tests/auto/utils/picking/picking/tst_picking.cpp b/tests/auto/utils/picking/picking/tst_picking.cpp
index d871a909290344a55ccadc6e1279384faf0d6640..36755383aa4b3bb69afbc677c160ca5dfd9e41cb 100644
--- a/tests/auto/utils/picking/picking/tst_picking.cpp
+++ b/tests/auto/utils/picking/picking/tst_picking.cpp
@@ -80,7 +80,7 @@ void picking::test_picking()
     QSSGRenderModel model1, model2;
     model1.flags.setFlag(QSSGRenderNode::Flag::LocallyPickable, true);
     model2.flags.setFlag(QSSGRenderNode::Flag::LocallyPickable, true);
-    model1.meshPath = model2.meshPath = QSSGRenderMeshPath::create(QStringLiteral("#Cube"));
+    model1.meshPath = model2.meshPath = QSSGRenderPath(QStringLiteral("#Cube"));
     // Since we're using the same mesh for each model, we only need to call loadMesh() once.
     bufferManager->loadMesh(model1.meshPath);
 
diff --git a/tests/benchmarks/picking/picking/tst_picking.cpp b/tests/benchmarks/picking/picking/tst_picking.cpp
index 1c081428bcfe9e23becb9e8bb7a5b7881f9c82f7..5ebc6b0ebdaefe0cbff7a81044c2525f06b9ba67 100644
--- a/tests/benchmarks/picking/picking/tst_picking.cpp
+++ b/tests/benchmarks/picking/picking/tst_picking.cpp
@@ -112,7 +112,7 @@ void picking::benchImpl(int count, bool hit)
 
     QSSGRenderModel models[1000];
 
-    const auto cubeMeshPath = QSSGRenderMeshPath::create(QStringLiteral("#Cube"));
+    const auto cubeMeshPath = QSSGRenderPath(QStringLiteral("#Cube"));
 
     for (int i = 0; i != count; ++i) {
         auto &model = models[i];