From 6e084ced8adf8cdb70d6d126f5701a4e6943f8d3 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 13 Feb 2020 14:58:44 +0000 Subject: Remove useless job Change-Id: Id17bfec0c6618ae0849df935f34322788f02aae3 Reviewed-by: Paul Lemire --- .../render/boundingsphere/tst_boundingsphere.cpp | 5 - tests/auto/render/opengl/renderer/tst_renderer.cpp | 3 - .../tst_pickboundingvolumejob.cpp | 5 - .../render/raycastingjob/tst_raycastingjob.cpp | 5 - tests/auto/render/render.pro | 1 - .../updatemeshtrianglelistjob/test_scene.qml | 102 ------ .../tst_updatemeshtrianglelistjob.cpp | 354 --------------------- .../updatemeshtrianglelistjob.pro | 18 -- .../updatemeshtrianglelistjob.qrc | 5 - 9 files changed, 498 deletions(-) delete mode 100644 tests/auto/render/updatemeshtrianglelistjob/test_scene.qml delete mode 100644 tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp delete mode 100644 tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro delete mode 100644 tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc (limited to 'tests') diff --git a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp index 2e3b498a6..7a05addcd 100644 --- a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp +++ b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -166,10 +165,6 @@ void runRequiredJobs(Qt3DRender::TestAspect *test) expandBVolume.setRoot(test->sceneRoot()); expandBVolume.setManagers(test->nodeManagers()); expandBVolume.run(); - - Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList; - updateTriangleList.setManagers(test->nodeManagers()); - updateTriangleList.run(); } } // anonymous diff --git a/tests/auto/render/opengl/renderer/tst_renderer.cpp b/tests/auto/render/opengl/renderer/tst_renderer.cpp index c602e7cf8..d0f1d5c17 100644 --- a/tests/auto/render/opengl/renderer/tst_renderer.cpp +++ b/tests/auto/render/opengl/renderer/tst_renderer.cpp @@ -161,7 +161,6 @@ private Q_SLOTS: 1 + // UpdateShaderDataTransform 1 + // ExpandBoundingVolumeJob 1 + // CalculateBoundingVolumeJob - 1 + // UpdateMeshTriangleListJob 1 + // updateSkinningPaletteJob 1 + // SyncLoadingJobs 1 + // updateLevelOfDetailJob @@ -289,7 +288,6 @@ private Q_SLOTS: 1 + // cleanupJob 1 + // VAOGatherer 1 + // CalculateBoundingVolumeJob - 1 + // UpdateMeshTriangleListJob 1 + // updateSkinningPaletteJob 1 + // SyncLoadingJobs 1 + // ExpandBoundingVolumeJob @@ -313,7 +311,6 @@ private Q_SLOTS: 1 + // updateSkinningPaletteJob 1 + // SyncLoadingJobs 1 + // CalculateBoundingVolumeJob - 1 + // UpdateMeshTriangleListJob 1 + // BufferGathererJob singleRenderViewJobCount); diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp index ea809cf50..cd984cfac 100644 --- a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp +++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -193,10 +192,6 @@ void runRequiredJobs(Qt3DRender::TestAspect *test) expandBVolume.setRoot(test->sceneRoot()); expandBVolume.setManagers(test->nodeManagers()); expandBVolume.run(); - - Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList; - updateTriangleList.setManagers(test->nodeManagers()); - updateTriangleList.run(); } void initializePickBoundingVolumeJob(Qt3DRender::Render::PickBoundingVolumeJob *job, Qt3DRender::TestAspect *test) diff --git a/tests/auto/render/raycastingjob/tst_raycastingjob.cpp b/tests/auto/render/raycastingjob/tst_raycastingjob.cpp index 2908842eb..61774b1bb 100644 --- a/tests/auto/render/raycastingjob/tst_raycastingjob.cpp +++ b/tests/auto/render/raycastingjob/tst_raycastingjob.cpp @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -189,10 +188,6 @@ void runRequiredJobs(Qt3DRender::TestAspect *test) expandBVolume.setRoot(test->sceneRoot()); expandBVolume.setManagers(test->nodeManagers()); expandBVolume.run(); - - Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList; - updateTriangleList.setManagers(test->nodeManagers()); - updateTriangleList.run(); } void initializeJob(Qt3DRender::Render::RayCastingJob *job, Qt3DRender::TestAspect *test) diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index d819cf543..9592b9f6c 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -134,7 +134,6 @@ qtConfig(qt3d-opengl-renderer):qtConfig(private_tests) { boundingsphere \ pickboundingvolumejob \ gltfplugins \ - updatemeshtrianglelistjob \ updateshaderdatatransformjob } diff --git a/tests/auto/render/updatemeshtrianglelistjob/test_scene.qml b/tests/auto/render/updatemeshtrianglelistjob/test_scene.qml deleted file mode 100644 index 35292967c..000000000 --- a/tests/auto/render/updatemeshtrianglelistjob/test_scene.qml +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import Qt3D.Core 2.0 -import Qt3D.Render 2.0 -import Qt3D.Extras 2.0 -import QtQuick.Window 2.0 - -Entity { - id: sceneRoot - - Window { - id: win - width: 800 - height: 800 - visible: true - } - - Camera { - id: camera - projectionType: CameraLens.PerspectiveProjection - fieldOfView: 45 - nearPlane : 0.1 - farPlane : 1000.0 - position: Qt.vector3d( 0.0, 0.0, -40.0 ) - upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) - viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) - } - - components: [ - RenderSettings { - Viewport { - normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0) - - RenderSurfaceSelector { - - surface: win - - ClearBuffers { - buffers : ClearBuffers.ColorDepthBuffer - NoDraw {} - } - - CameraSelector { - camera: camera - } - } - } - } - ] - - Entity { - components: GeometryRenderer { id: cubeMesh; view: CuboidMesh { } } - } -} diff --git a/tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp b/tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp deleted file mode 100644 index a0af5cea5..000000000 --- a/tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Paul Lemire -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qmlscenereader.h" - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { // Needs to be in that namespace to be friend with QRenderAspect - -QVector getNodesForCreation(Qt3DCore::QNode *root) -{ - using namespace Qt3DCore; - - QVector nodes; - Qt3DCore::QNodeVisitor visitor; - visitor.traverse(root, [&nodes](QNode *node) { - nodes.append(node); - - // Store the metaobject of the node in the QNode so that we have it available - // to us during destruction in the QNode destructor. This allows us to send - // the QNodeId and the metaobject as typeinfo to the backend aspects so they - // in turn can find the correct QBackendNodeMapper object to handle the destruction - // of the corresponding backend nodes. - QNodePrivate *d = QNodePrivate::get(node); - d->m_typeInfo = const_cast(QNodePrivate::findStaticMetaObject(node->metaObject())); - - // Mark this node as having been handled for creation so that it is picked up - d->m_hasBackendNode = true; - }); - - return nodes; -} - -QVector nodeTreeChangesForNodes(const QVector nodes) -{ - QVector nodeTreeChanges; - nodeTreeChanges.reserve(nodes.size()); - - for (Qt3DCore::QNode *n : nodes) { - nodeTreeChanges.push_back({ - n->id(), - Qt3DCore::QNodePrivate::get(n)->m_typeInfo, - Qt3DCore::NodeTreeChange::Added, - n - }); - } - - return nodeTreeChanges; -} - -class TestAspect : public Qt3DRender::QRenderAspect -{ -public: - TestAspect(Qt3DCore::QNode *root) - : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous) - , m_sceneRoot(nullptr) - { - Qt3DRender::QRenderAspect::onRegistered(); - - const QVector nodes = getNodesForCreation(root); - d_func()->setRootAndCreateNodes(qobject_cast(root), nodeTreeChangesForNodes(nodes)); - - Qt3DRender::Render::Entity *rootEntity = nodeManagers()->lookupResource(rootEntityId()); - Q_ASSERT(rootEntity); - m_sceneRoot = rootEntity; - } - - ~TestAspect() - { - QRenderAspect::onUnregistered(); - } - - void onRegistered() { Qt3DRender::QRenderAspect::onRegistered(); } - void onUnregistered() { Qt3DRender::QRenderAspect::onUnregistered(); } - - Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); } - Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); } - Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); } - Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; } - -private: - Qt3DRender::Render::Entity *m_sceneRoot; -}; - -} // Qt3DRender - -QT_END_NAMESPACE - -namespace { - -void runRequiredJobs(Qt3DRender::TestAspect *aspect) -{ - Qt3DRender::Render::GeometryRendererManager *geomRendererManager = aspect->nodeManagers()->geometryRendererManager(); - const QVector dirtyGeometryRenderers = geomRendererManager->dirtyGeometryRenderers(); - QVector dirtyGeometryRendererJobs; - dirtyGeometryRendererJobs.reserve(dirtyGeometryRenderers.size()); - - // Load Geometry - for (const Qt3DCore::QNodeId geoRendererId : dirtyGeometryRenderers) { - Qt3DRender::Render::HGeometryRenderer geometryRendererHandle = geomRendererManager->lookupHandle(geoRendererId); - if (!geometryRendererHandle.isNull()) { - auto job = Qt3DRender::Render::LoadGeometryJobPtr::create(geometryRendererHandle); - job->setNodeManagers(aspect->nodeManagers()); - dirtyGeometryRendererJobs.push_back(job); - } - } -} - -struct NodeCollection -{ - explicit NodeCollection(Qt3DRender::TestAspect *aspect, QObject *frontendRoot) - : geometryRenderers(frontendRoot->findChildren()) - , attributes(frontendRoot->findChildren()) - , buffers(frontendRoot->findChildren()) - { - // THEN - QCOMPARE(aspect->nodeManagers()->geometryManager()->activeHandles().size(), geometryRenderers.size()); - QCOMPARE(aspect->nodeManagers()->attributeManager()->activeHandles().size(), attributes.size()); - QCOMPARE(aspect->nodeManagers()->bufferManager()->activeHandles().size(), buffers.size()); - - for (const Qt3DRender::QGeometryRenderer *g : qAsConst(geometryRenderers)) { - Qt3DRender::Render::GeometryRenderer *backend = aspect->nodeManagers()->geometryRendererManager()->lookupResource(g->id()); - QVERIFY(backend != nullptr); - backendGeometryRenderer.push_back(backend); - } - - for (const Qt3DCore::QAttribute *a : qAsConst(attributes)) { - Qt3DRender::Render::Attribute *backend = aspect->nodeManagers()->attributeManager()->lookupResource(a->id()); - QVERIFY(backend != nullptr); - backendAttributes.push_back(backend); - } - - for (const Qt3DCore::QBuffer *b : qAsConst(buffers)) { - Qt3DRender::Render::Buffer *backend = aspect->nodeManagers()->bufferManager()->lookupResource(b->id()); - QVERIFY(backend != nullptr); - backendBuffers.push_back(backend); - } - } - - QList geometryRenderers; - QList attributes; - QList buffers; - - QVector backendGeometryRenderer; - QVector backendAttributes; - QVector backendBuffers; -}; - - -} // anonymous - -class tst_UpdateMeshTriangleListJob : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkInitialState() - { - // GIVEN - Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob; - - // THEN - QVERIFY(backendUpdateMeshTriangleListJob.managers() == nullptr); - } - - void checkInitialize() - { - // GIVEN - Qt3DRender::Render::UpdateMeshTriangleListJob updateMeshTriangleListJob; - Qt3DRender::Render::NodeManagers managers; - - // WHEN - updateMeshTriangleListJob.setManagers(&managers); - - // THEN - QVERIFY(updateMeshTriangleListJob.managers() == &managers); - } - - void checkRunNoDirtyGeometryRenderNoDirtyAttributesNoDirtyBuffers() - { - // GIVEN - QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml")); - QScopedPointer root(qobject_cast(sceneReader.root())); - QVERIFY(root); - QScopedPointer test(new Qt3DRender::TestAspect(root.data())); - - // Run required jobs to load geometries and meshes - runRequiredJobs(test.data()); - - // WHEN - const NodeCollection collection(test.data(), root.data()); - - // THEN - QCOMPARE(collection.geometryRenderers.size(), 1); - QCOMPARE(collection.attributes.size(), 5); - QCOMPARE(collection.buffers.size(), 2); - - // WHEN - for (Qt3DRender::Render::GeometryRenderer *g : collection.backendGeometryRenderer) - g->unsetDirty(); - for (Qt3DRender::Render::Attribute *a : collection.backendAttributes) - a->unsetDirty(); - for (Qt3DRender::Render::Buffer *b : collection.backendBuffers) - b->unsetDirty(); - - Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob; - backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers()); - - backendUpdateMeshTriangleListJob.run(); - - // THEN - QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 0); - } - - void checkRunDirtyGeometryRenderNoDirtyAttributesNoDirtyBuffers() - { - // GIVEN - QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml")); - QScopedPointer root(qobject_cast(sceneReader.root())); - QVERIFY(root); - QScopedPointer test(new Qt3DRender::TestAspect(root.data())); - - // Run required jobs to load geometries and meshes - runRequiredJobs(test.data()); - - // WHEN - const NodeCollection collection(test.data(), root.data()); - - // THEN - QCOMPARE(collection.geometryRenderers.size(), 1); - QCOMPARE(collection.attributes.size(), 5); - QCOMPARE(collection.buffers.size(), 2); - - // WHEN - for (Qt3DRender::Render::Attribute *a : collection.backendAttributes) - a->unsetDirty(); - for (Qt3DRender::Render::Buffer *b : collection.backendBuffers) - b->unsetDirty(); - - Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob; - backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers()); - - backendUpdateMeshTriangleListJob.run(); - - // THEN - QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 1); - } - - void checkRunDirtyGeometryRenderDirtyAttributesNoDirtyBuffers() - { - // GIVEN - QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml")); - QScopedPointer root(qobject_cast(sceneReader.root())); - QVERIFY(root); - QScopedPointer test(new Qt3DRender::TestAspect(root.data())); - - // Run required jobs to load geometries and meshes - runRequiredJobs(test.data()); - - // WHEN - const NodeCollection collection(test.data(), root.data()); - - // THEN - QCOMPARE(collection.geometryRenderers.size(), 1); - QCOMPARE(collection.attributes.size(), 5); - QCOMPARE(collection.buffers.size(), 2); - - // WHEN - for (Qt3DRender::Render::Buffer *b : collection.backendBuffers) - b->unsetDirty(); - - Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob; - backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers()); - - backendUpdateMeshTriangleListJob.run(); - - // THEN - QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 1); - } - - void checkRunDirtyGeometryRenderDirtyAttributesDirtyBuffers() - { - // GIVEN - QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml")); - QScopedPointer root(qobject_cast(sceneReader.root())); - QVERIFY(root); - QScopedPointer test(new Qt3DRender::TestAspect(root.data())); - - // Run required jobs to load geometries and meshes - runRequiredJobs(test.data()); - - // WHEN - const NodeCollection collection(test.data(), root.data()); - - // THEN - QCOMPARE(collection.geometryRenderers.size(), 1); - QCOMPARE(collection.attributes.size(), 5); - QCOMPARE(collection.buffers.size(), 2); - - // WHEN - for (Qt3DRender::Render::Buffer *b : collection.backendBuffers) - b->unsetDirty(); - - Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob; - backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers()); - - backendUpdateMeshTriangleListJob.run(); - - // THEN - QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 1); - } - -}; - -QTEST_MAIN(tst_UpdateMeshTriangleListJob) - -#include "tst_updatemeshtrianglelistjob.moc" diff --git a/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro b/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro deleted file mode 100644 index 499f78c72..000000000 --- a/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro +++ /dev/null @@ -1,18 +0,0 @@ -TEMPLATE = app - -TARGET = tst_updatemeshtrianglelistjob - -QT += 3dcore 3dcore-private 3drender 3drender-private testlib - -CONFIG += testcase - -SOURCES += tst_updatemeshtrianglelistjob.cpp - -include(../../core/common/common.pri) -include(../commons/commons.pri) -include(../qmlscenereader/qmlscenereader.pri) -# Extra dependencies to build test scenes needed by the tests -QT += quick 3dquick 3dquick-private 3dextras 3dquickextras - -RESOURCES += \ - updatemeshtrianglelistjob.qrc diff --git a/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc b/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc deleted file mode 100644 index 6a6a0433e..000000000 --- a/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - test_scene.qml - - -- cgit v1.2.3