IVGCVSW-4212 Example of standalone dynamic reference backend

 * Add example to build dynamic reference backend
 * Add functions to clear dynamic backends
 * Fix the error when dynamic backend is not deregistered
 * Add DYARMNN_DYNAMIC_BACKEND_ENABLED to check disable empty
   dynamic backend when dynamic backend is enabled

Signed-off-by: Narumol Prangnawarat <narumol.prangnawarat@arm.com>
Change-Id: I1ef3a3f10ed6ca5ec18d0af04b007fc3bc71a3cb
diff --git a/cmake/GlobalConfig.cmake b/cmake/GlobalConfig.cmake
index 191cd9d..51a7efd 100644
--- a/cmake/GlobalConfig.cmake
+++ b/cmake/GlobalConfig.cmake
@@ -302,6 +302,11 @@
     add_definitions(-DARMNNREF_ENABLED)
 endif()
 
+# ArmNN dynamic backend
+if(DYNAMIC_BACKEND_PATHS)
+    add_definitions(-DARMNN_DYNAMIC_BACKEND_ENABLED)
+endif()
+
 # Streamline annotate
 if(PROFILING_BACKEND_STREAMLINE)
     include_directories("${GATOR_ROOT}/annotate")
diff --git a/include/armnn/BackendRegistry.hpp b/include/armnn/BackendRegistry.hpp
index 82e59d9..a0cfee9 100644
--- a/include/armnn/BackendRegistry.hpp
+++ b/include/armnn/BackendRegistry.hpp
@@ -43,6 +43,8 @@
         }
     };
 
+    void Deregister(const BackendId& id);
+
 protected:
     using FactoryStorage = std::unordered_map<BackendId, FactoryFunction>;
 
diff --git a/src/armnn/BackendRegistry.cpp b/src/armnn/BackendRegistry.cpp
index 45f73b8..dc3e2bc 100644
--- a/src/armnn/BackendRegistry.cpp
+++ b/src/armnn/BackendRegistry.cpp
@@ -27,6 +27,11 @@
     m_Factories[id] = factory;
 }
 
+void BackendRegistry::Deregister(const BackendId& id)
+{
+    m_Factories.erase(id);
+}
+
 bool BackendRegistry::IsBackendRegistered(const BackendId& id) const
 {
     return (m_Factories.find(id) != m_Factories.end());
diff --git a/src/armnn/DeviceSpec.hpp b/src/armnn/DeviceSpec.hpp
index 3226470..703a4b1 100644
--- a/src/armnn/DeviceSpec.hpp
+++ b/src/armnn/DeviceSpec.hpp
@@ -24,14 +24,33 @@
         return m_SupportedBackends;
     }
 
-    void AddSupportedBackends(const BackendIdSet& backendIds)
+    void AddSupportedBackends(const BackendIdSet& backendIds, bool isDynamic = false)
     {
         m_SupportedBackends.insert(backendIds.begin(), backendIds.end());
+        if (isDynamic)
+        {
+            m_DynamicBackends.insert(backendIds.begin(), backendIds.end());
+        }
+    }
+
+    void ClearDynamicBackends()
+    {
+        for (const auto& id : m_DynamicBackends)
+        {
+            m_SupportedBackends.erase(id);
+        }
+        m_DynamicBackends.clear();
+    }
+
+    const BackendIdSet& GetDynamicBackends() const
+    {
+        return m_DynamicBackends;
     }
 
 private:
     DeviceSpec() = delete;
     BackendIdSet m_SupportedBackends;
+    BackendIdSet m_DynamicBackends;
 };
 
 } // namespace armnn
diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp
index 9b0ce1a..4ad6fa5 100644
--- a/src/armnn/Runtime.cpp
+++ b/src/armnn/Runtime.cpp
@@ -214,6 +214,10 @@
                       << std::endl;
         }
     }
+
+    // Clear all dynamic backends.
+    DynamicBackendUtils::DeregisterDynamicBackends(m_DeviceSpec.GetDynamicBackends());
+    m_DeviceSpec.ClearDynamicBackends();
 }
 
 LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
@@ -273,7 +277,7 @@
     BackendIdSet registeredBackendIds = DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends);
 
     // Add the registered dynamic backend ids to the list of supported backends
-    m_DeviceSpec.AddSupportedBackends(registeredBackendIds);
+    m_DeviceSpec.AddSupportedBackends(registeredBackendIds, true);
 }
 
 } // namespace armnn
diff --git a/src/backends/backendsCommon/DynamicBackendUtils.cpp b/src/backends/backendsCommon/DynamicBackendUtils.cpp
index ab0006d..f893458 100644
--- a/src/backends/backendsCommon/DynamicBackendUtils.cpp
+++ b/src/backends/backendsCommon/DynamicBackendUtils.cpp
@@ -310,6 +310,18 @@
     return dynamicBackends;
 }
 
+void DynamicBackendUtils::DeregisterDynamicBackends(const BackendIdSet& dynamicBackends)
+{
+    // Get a reference of the backend registry
+    BackendRegistry& backendRegistry = BackendRegistryInstance();
+
+    for (const auto& id : dynamicBackends)
+    {
+        backendRegistry.Deregister(id);
+    }
+
+}
+
 BackendIdSet DynamicBackendUtils::RegisterDynamicBackends(const std::vector<DynamicBackendPtr>& dynamicBackends)
 {
     // Get a reference of the backend registry
diff --git a/src/backends/backendsCommon/DynamicBackendUtils.hpp b/src/backends/backendsCommon/DynamicBackendUtils.hpp
index 2763b9d..f4cdd4d 100644
--- a/src/backends/backendsCommon/DynamicBackendUtils.hpp
+++ b/src/backends/backendsCommon/DynamicBackendUtils.hpp
@@ -42,6 +42,7 @@
 
     static std::vector<DynamicBackendPtr> CreateDynamicBackends(const std::vector<std::string>& sharedObjects);
     static BackendIdSet RegisterDynamicBackends(const std::vector<DynamicBackendPtr>& dynamicBackends);
+    static void DeregisterDynamicBackends(const BackendIdSet& dynamicBackends);
 
 protected:
     /// Protected methods for testing purposes
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp
index c6606be..40e063d 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp
@@ -55,7 +55,9 @@
 ARMNN_SIMPLE_TEST_CASE(RegisterMultipleInvalidDynamicBackends, RegisterMultipleInvalidDynamicBackendsTestImpl);
 ARMNN_SIMPLE_TEST_CASE(RegisterMixedDynamicBackends, RegisterMixedDynamicBackendsTestImpl);
 
+#if !defined(ARMNN_DYNAMIC_BACKEND_ENABLED)
 ARMNN_SIMPLE_TEST_CASE(RuntimeEmpty, RuntimeEmptyTestImpl);
+#endif
 ARMNN_SIMPLE_TEST_CASE(RuntimeDynamicBackends, RuntimeDynamicBackendsTestImpl);
 ARMNN_SIMPLE_TEST_CASE(RuntimeDuplicateDynamicBackends, RuntimeDuplicateDynamicBackendsTestImpl);
 ARMNN_SIMPLE_TEST_CASE(RuntimeInvalidDynamicBackends, RuntimeInvalidDynamicBackendsTestImpl);
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
index 561578e..4238ef6 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
@@ -1198,6 +1198,8 @@
     }
 }
 
+#if !defined(ARMNN_DYNAMIC_BACKEND_ENABLED)
+
 void RuntimeEmptyTestImpl()
 {
     using namespace armnn;
@@ -1218,6 +1220,8 @@
     BOOST_TEST(backendRegistry.Size() == 0);
 }
 
+#endif
+
 void RuntimeDynamicBackendsTestImpl()
 {
     using namespace armnn;
diff --git a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
index 5474f5d..639e1fd 100644
--- a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
@@ -25,14 +25,8 @@
         {
             case LayerType::Input:
                 ++m_inputLayerCount;
-                if (layer->GetGuid() == profiling::ProfilingGuid(0))
-                {
-                    BOOST_TEST(layer->GetName() == "inLayer0");
-                }
-                else if (layer->GetGuid() == profiling::ProfilingGuid(1))
-                {
-                    BOOST_TEST(layer->GetName() == "inLayer1");
-                }
+                BOOST_TEST((layer->GetName() == std::string("inLayer0") ||
+                            layer->GetName() == std::string("inLayer1")));
                 break;
             // The Addition layer should become a PreCompiled Layer after Optimisation
             case LayerType::PreCompiled:
diff --git a/src/dynamic/reference/CMakeLists.txt b/src/dynamic/reference/CMakeLists.txt
new file mode 100644
index 0000000..79bf7ec
--- /dev/null
+++ b/src/dynamic/reference/CMakeLists.txt
@@ -0,0 +1,35 @@
+#
+# Copyright © 2019 Arm Ltd. All rights reserved.
+# SPDX-License-Identifier: MIT
+#
+
+cmake_minimum_required (VERSION 3.0.2)
+
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+# File needed to wrap the existing backend into a dynamic one
+list(APPEND armnnRefDynamicBackend_sources
+    RefDynamicBackend.cpp
+    RefDynamicBackend.hpp
+)
+
+# Set the backend source path
+set(RefBackendPath ${PROJECT_SOURCE_DIR}/../../../src/backends/reference)
+
+# Source files of the backend, taken directly from the source tree
+file(GLOB RefBackendBaseFiles ${RefBackendPath}/*.cpp)
+file(GLOB RefBackendWorloadFiles ${RefBackendPath}/workloads/*.cpp)
+set(RefBackendFiles ${RefBackendBaseFiles} ${RefBackendWorloadFiles})
+
+# Remove the file that contains the static backend registration
+list(REMOVE_ITEM RefBackendFiles ${RefBackendPath}/RefRegistryInitializer.cpp)
+
+# Create the shared object
+add_library(Arm_CpuRef_backend MODULE ${armnnRefDynamicBackend_sources} ${RefBackendFiles})
+
+target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/../../../include)
+target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/../../../third-party) # for half
+target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/../../../src/armnn)
+target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/../../../src/armnnUtils)
+target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/../../../src/backends)
+target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/../../../src/profiling)
\ No newline at end of file
diff --git a/src/dynamic/reference/RefDynamicBackend.cpp b/src/dynamic/reference/RefDynamicBackend.cpp
new file mode 100644
index 0000000..f2ed0f6
--- /dev/null
+++ b/src/dynamic/reference/RefDynamicBackend.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "RefDynamicBackend.hpp"
+
+#include <reference/RefBackend.hpp>
+
+using namespace armnn;
+
+const char* GetBackendId()
+{
+    return RefBackend::GetIdStatic().Get().c_str();
+}
+
+void GetVersion(uint32_t* outMajor, uint32_t* outMinor)
+{
+    if (!outMajor || !outMinor)
+    {
+        return;
+    }
+
+    BackendVersion apiVersion = IBackendInternal::GetApiVersion();
+
+    *outMajor = apiVersion.m_Major;
+    *outMinor = apiVersion.m_Minor;
+}
+
+void* BackendFactory()
+{
+    return new RefBackend();
+}
diff --git a/src/dynamic/reference/RefDynamicBackend.hpp b/src/dynamic/reference/RefDynamicBackend.hpp
new file mode 100644
index 0000000..bc680a1
--- /dev/null
+++ b/src/dynamic/reference/RefDynamicBackend.hpp
@@ -0,0 +1,15 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstdint>
+
+extern "C"
+{
+const char* GetBackendId();
+void GetVersion(uint32_t* outMajor, uint32_t* outMinor);
+void* BackendFactory();
+}