diff --git a/ogre/src/OgreCamera.cc b/ogre/src/OgreCamera.cc index fafc217a8..76ec94698 100644 --- a/ogre/src/OgreCamera.cc +++ b/ogre/src/OgreCamera.cc @@ -44,6 +44,12 @@ void OgreCamera::Destroy() if (!this->ogreCamera) return; + if (this->renderTexture) + { + this->renderTexture->Destroy(); + this->renderTexture = nullptr; + } + Ogre::SceneManager *ogreSceneManager; ogreSceneManager = this->scene->OgreSceneManager(); if (ogreSceneManager == nullptr) diff --git a/ogre/src/OgreDepthCamera.cc b/ogre/src/OgreDepthCamera.cc index b4b92d248..b6139696d 100644 --- a/ogre/src/OgreDepthCamera.cc +++ b/ogre/src/OgreDepthCamera.cc @@ -39,9 +39,6 @@ class gz::rendering::OgreDepthCameraPrivate /// \brief Point cloud xyz data buffer public: float *pcdBuffer = nullptr; - /// \brief Point cloud view port - public: Ogre::Viewport *pcdViewport = nullptr; - /// \brief Point cloud material public: MaterialPtr pcdMaterial = nullptr; @@ -110,6 +107,18 @@ void OgreDepthCamera::Destroy() this->dataPtr->colorBuffer = nullptr; } + if (this->dataPtr->pcdTexture) + { + this->dataPtr->pcdTexture->Destroy(); + this->dataPtr->pcdTexture.reset(); + } + + if (this->dataPtr->colorTexture) + { + this->dataPtr->colorTexture->Destroy(); + this->dataPtr->colorTexture.reset(); + } + if (!this->ogreCamera || !this->scene->IsInitialized()) return; diff --git a/ogre/src/OgreGpuRays.cc b/ogre/src/OgreGpuRays.cc index be5faa945..717ef8b7d 100644 --- a/ogre/src/OgreGpuRays.cc +++ b/ogre/src/OgreGpuRays.cc @@ -16,7 +16,6 @@ */ #include -#include #include #include @@ -203,6 +202,12 @@ void OgreGpuRays::Destroy() this->dataPtr->orthoCam = nullptr; } + if (this->dataPtr->undistMesh) + { + delete this->dataPtr->undistMesh; + this->dataPtr->undistMesh = nullptr; + } + this->dataPtr->visual.reset(); this->dataPtr->texIdx.clear(); this->dataPtr->texCount = 0u; @@ -886,8 +891,6 @@ void OgreGpuRays::CreateMesh() mesh->AddSubMesh(*submesh); this->dataPtr->undistMesh = mesh; - - common::MeshManager::Instance()->AddMesh(this->dataPtr->undistMesh); } ///////////////////////////////////////////////// diff --git a/ogre/src/OgreRenderTarget.cc b/ogre/src/OgreRenderTarget.cc index d7ed64af8..de9261b9f 100644 --- a/ogre/src/OgreRenderTarget.cc +++ b/ogre/src/OgreRenderTarget.cc @@ -61,10 +61,7 @@ OgreRenderTarget::OgreRenderTarget() ////////////////////////////////////////////////// OgreRenderTarget::~OgreRenderTarget() { - // TODO(anyone): clean up check null - - OgreRTShaderSystem::Instance()->DetachViewport(this->ogreViewport, - this->scene); + GZ_ASSERT(this->ogreViewport == nullptr, "Destroy() not called!"); } ////////////////////////////////////////////////// @@ -339,6 +336,8 @@ void OgreRenderTexture::DestroyTarget() if (nullptr == this->ogreTexture) return; + this->materialApplicator.reset(); + OgreRTShaderSystem::Instance()->DetachViewport(this->ogreViewport, this->scene); @@ -351,6 +350,7 @@ void OgreRenderTexture::DestroyTarget() auto engine = OgreRenderEngine::Instance(); engine->OgreRoot()->getRenderSystem()->_cleanupDepthBuffers(false); + this->ogreViewport = nullptr; this->ogreTexture = nullptr; } diff --git a/ogre/src/OgreThermalCamera.cc b/ogre/src/OgreThermalCamera.cc index d5f7551fb..19be05445 100644 --- a/ogre/src/OgreThermalCamera.cc +++ b/ogre/src/OgreThermalCamera.cc @@ -104,9 +104,6 @@ class gz::rendering::OgreThermalCameraPrivate /// \brief Dummy texture public: OgreRenderTexturePtr thermalTexture; - /// \brief Point cloud texture - public: OgreRenderTexturePtr colorTexture; - /// \brief Lens distortion compositor public: Ogre::CompositorInstance *thermalInstance = nullptr; @@ -294,6 +291,12 @@ void OgreThermalCamera::Destroy() this->dataPtr->thermalImage = nullptr; } + if (this->dataPtr->thermalTexture) + { + this->dataPtr->thermalTexture->Destroy(); + this->dataPtr->thermalTexture = nullptr; + } + if (!this->ogreCamera || !this->scene->IsInitialized()) return; diff --git a/ogre/src/OgreWideAngleCamera.cc b/ogre/src/OgreWideAngleCamera.cc index 860dd2c19..856e244ef 100644 --- a/ogre/src/OgreWideAngleCamera.cc +++ b/ogre/src/OgreWideAngleCamera.cc @@ -156,6 +156,12 @@ void OgreWideAngleCamera::Destroy() this->dataPtr->wideAngleImage = nullptr; } + if (this->dataPtr->wideAngleTexture) + { + this->dataPtr->wideAngleTexture->Destroy(); + this->dataPtr->wideAngleTexture = nullptr; + } + for (unsigned int i = 0u; i < this->dataPtr->kEnvCameraCount; ++i) { if (this->dataPtr->envRenderTargets[i]) diff --git a/test/common_test/CommonRenderingTest.hh b/test/common_test/CommonRenderingTest.hh index ed4bf3f3f..8af2265f0 100644 --- a/test/common_test/CommonRenderingTest.hh +++ b/test/common_test/CommonRenderingTest.hh @@ -41,13 +41,41 @@ static std::tuple GetTestParams() if (gz::utils::env(kEngineToTestEnv, engine)) { - gz::utils::env(kEngineBackend, backend); - gz::utils::env(kEngineHeadless, headless); - } + gzdbg << "Read GZ_ENGINE_TO_TEST=" << engine << std::endl; + if (gz::utils::env(kEngineBackend, backend)) + { + gzdbg << "Read GZ_ENGINE_BACKEND=" << backend << std::endl; + } + if (gz::utils::env(kEngineHeadless, headless)) + { + gzdbg << "Read GZ_ENGINE_HEADLESS=" << headless << std::endl; + } + } return {engine, backend, headless}; } +static std::map +GetEngineParams(const std::string &_engine, const std::string &_backend, const std::string &_headless) +{ + std::map engineParams; + if (_engine == "ogre2" && _backend == "vulkan") + { + gzdbg << "Using OGRE2-VULKAN backend to test" << std::endl; + engineParams["vulkan"] = "1"; + } + else if (_engine == "ogre2" && _backend == "metal") + { + gzdbg << "Using OGRE2-METAL backend to test" << std::endl; + engineParams["metal"] = "1"; + } + if (!_headless.empty()) + { + engineParams["headless"] = "1"; + } + return engineParams; +} + /// \brief Common test fixture for all rendering tests /// This allows for the engine, backend, and headless parameters /// to be controlled via environment variables @@ -59,38 +87,22 @@ class CommonRenderingTest: public testing::Test gz::common::Console::SetVerbosity(4); auto [envEngine, envBackend, envHeadless] = GetTestParams(); + if (envEngine.empty()) { GTEST_SKIP() << kEngineToTestEnv << " environment not set"; } - std::map engineParams; - - if (envEngine == "ogre2" && envBackend == "vulkan") - { - gzdbg << "Using OGRE2-VULKAN backend to test" << std::endl; - engineParams["vulkan"] = "1"; - } - else if (envEngine == "ogre2" && envBackend == "metal") - { - gzdbg << "Using OGRE2-METAL backend to test" << std::endl; - engineParams["metal"] = "1"; - } - - if (!envHeadless.empty()) - { - engineParams["headless"] = "1"; - } - + auto engineParams = GetEngineParams(envEngine, envBackend, envHeadless); this->engineToTest = envEngine; engine = gz::rendering::engine(this->engineToTest, engineParams); if (!engine) { - GTEST_FAIL() << "Engine '" << this->engineToTest << "' could not be loaded" << std::endl; + GTEST_SKIP() << "Engine '" << this->engineToTest << "' could not be loaded" << std::endl; } } - /// \brief Tear down the test case + /// \brief Tear down the test case public: void TearDown() override { if(engine) @@ -99,17 +111,17 @@ class CommonRenderingTest: public testing::Test } } - /// \brief String name of the engine to test + /// \brief String name of the engine to test public: std::string engineToTest; - /// \brief Pointer to the rendering engine to test + /// \brief Pointer to the rendering engine to test public: gz::rendering::RenderEngine *engine = nullptr; }; /// \brief Check that the current engine being tested is supported. /// If the engine is not in the set of passed arguments, the test is skipped -/// Example: +/// Example: /// Skip test if engine is not ogre or ogre2 /// CHECK_SUPPORTED_ENGINE("ogre", "ogre2"); #define CHECK_SUPPORTED_ENGINE(...) \ @@ -118,7 +130,7 @@ if(std::unordered_set({__VA_ARGS__}).count(this->engineToTest) == 0 /// \brief Check that the current engine being tested is unsupported /// If the engine is in the set of passed arguments, the test is skipped -/// Example: +/// Example: /// Skip test if engine is ogre2 /// CHECK_UNSUPPORTED_ENGINE("ogre"); #define CHECK_UNSUPPORTED_ENGINE(...) \ diff --git a/test/common_test/Material_TEST.cc b/test/common_test/Material_TEST.cc index 654865905..9bc1f0bb0 100644 --- a/test/common_test/Material_TEST.cc +++ b/test/common_test/Material_TEST.cc @@ -27,6 +27,8 @@ #include "gz/rendering/ShaderType.hh" #include "gz/rendering/Scene.hh" +#include + using namespace gz; using namespace rendering; @@ -332,7 +334,7 @@ TEST_F(MaterialTest, MaterialProperties) } ///////////////////////////////////////////////// -TEST_F(MaterialTest, Copy) +TEST_F(MaterialTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(Copy)) { ScenePtr scene = engine->CreateScene("copy_scene"); ASSERT_NE(nullptr, scene); diff --git a/test/regression/CMakeLists.txt b/test/regression/CMakeLists.txt index aac9ecda7..b432e487b 100644 --- a/test/regression/CMakeLists.txt +++ b/test/regression/CMakeLists.txt @@ -1,8 +1,11 @@ set(TEST_TYPE "REGRESSION") -set(tests +gz_rendering_test( + TYPE ${TEST_TYPE} + SOURCE reload_engine + LIB_DEPS + gz-plugin${GZ_PLUGIN_VER}::loader + gz-common${GZ_COMMON_VER}::gz-common${GZ_COMMON_VER} + ${PROJECT_LIBRARY_TARGET_NAME} ) -link_directories(${PROJECT_BINARY_DIR}/test) - -gz_build_tests(TYPE REGRESSION SOURCES ${tests}) diff --git a/test/regression/reload_engine.cc b/test/regression/reload_engine.cc new file mode 100644 index 000000000..7aa30f9c0 --- /dev/null +++ b/test/regression/reload_engine.cc @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2017 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include + +#include "CommonRenderingTest.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +constexpr auto kNumRetries = 3; + +/// \brief Test fixture for reloading engines. +/// Since the CommonRenderingTest loads an engine by default, +/// we are doing a custom implementation here. +class ReloadEngineTest: public ::testing::Test +{ + /// \brief Set up the test fixture + public: void SetUp() override + { + gz::common::Console::SetVerbosity(4); + auto [envEngine, envBackend, envHeadless] = GetTestParams(); + if (envEngine.empty()) + { + GTEST_SKIP() << kEngineToTestEnv << " environment not set"; + } + + this->engineToTest = envEngine; + this->engineParams = GetEngineParams(envEngine, envBackend, envHeadless); + } + + /// \brief Load the configured engine and run a series of rendering commands + /// \param[in] _exec Function to execute on loaded engine + public: void Run(std::function _exec) + { + for (size_t ii = 0; ii < kNumRetries; ++ii) + { + auto engine = gz::rendering::engine(this->engineToTest, + this->engineParams); + ASSERT_NE(nullptr, engine); + _exec(engine); + ASSERT_TRUE(gz::rendering::unloadEngine(this->engineToTest)); + } + } + + /// \brief Engine under test + protected: std::string engineToTest; + + /// \brief Parameters for spawning rendering engine + protected: std::map engineParams; +}; + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, Empty) +{ + // Noop test + this->Run([](auto){}); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, Scene) +{ + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, BoundingBoxCamera) +{ + CHECK_SUPPORTED_ENGINE("ogre2"); + + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto camera = scene->CreateBoundingBoxCamera("camera"); + ASSERT_NE(nullptr, camera); + camera->SetImageWidth(500); + camera->SetImageHeight(500); + root->AddChild(camera); + + camera->Update(); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(Camera)) +{ + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto camera = scene->CreateCamera("camera"); + ASSERT_NE(nullptr, camera); + camera->SetImageWidth(500); + camera->SetImageHeight(500); + root->AddChild(camera); + + camera->Update(); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(DepthCamera)) +{ + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto camera = scene->CreateDepthCamera("camera"); + ASSERT_NE(nullptr, camera); + camera->SetImageWidth(500); + camera->SetImageHeight(500); + root->AddChild(camera); + + camera->Update(); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(GpuRays)) +{ + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto gpuRays = scene->CreateGpuRays("gpu_rays"); + ASSERT_NE(nullptr, gpuRays); + gpuRays->SetAngleMin(-1.0); + gpuRays->SetAngleMax(1.0); + gpuRays->SetRayCount(1000); + gpuRays->SetVerticalRayCount(1); + root->AddChild(gpuRays); + + gpuRays->Update(); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, SegmentationCamera) +{ + CHECK_SUPPORTED_ENGINE("ogre2"); + + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto camera = scene->CreateSegmentationCamera("camera"); + ASSERT_NE(nullptr, camera); + camera->SetImageWidth(500); + camera->SetImageHeight(500); + root->AddChild(camera); + + camera->Update(); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(ThermalCamera)) +{ + CHECK_SUPPORTED_ENGINE("ogre", "ogre2"); + + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto camera = scene->CreateThermalCamera("camera"); + ASSERT_NE(nullptr, camera); + camera->SetImageWidth(500); + camera->SetImageHeight(500); + root->AddChild(camera); + + camera->Update(); + engine->DestroyScene(scene); + }); +} + +///////////////////////////////////////////////// +TEST_F(ReloadEngineTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(WideAngleCamera)) +{ + CHECK_SUPPORTED_ENGINE("ogre"); + + this->Run([](auto engine){ + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + auto root = scene->RootVisual(); + ASSERT_NE(nullptr, root); + + auto camera = scene->CreateWideAngleCamera("camera"); + ASSERT_NE(nullptr, camera); + camera->SetImageWidth(500); + camera->SetImageHeight(500); + root->AddChild(camera); + + camera->Update(); + engine->DestroyScene(scene); + }); +}