Adds CustomAllocator interface and Sample App

 * Updates the runtime options with a CustomAllocatorMap which allows to define a CustomAllocator for specific backends
 * Change IBackendInternal interface to use a shared pointer to a custom allocator
 * Update ClBackend.hpp/cpp to use the CustomAllocator
 * Adds an example application and unit test which uses a CustomAllocator for GpuAcc
 * Refactor of the interface to use MemorySource instead of the user Mapping cl_mem directly
 * Modify the BackendRegistry to also hold a registry of CustomAllocators
 * BackendRegistry Deregister will also deregister any allocators associated with that backend id
 * set_global_allocator within the BaseMemoryManager so that it always matches the currently used allocator

Signed-off-by: Jan Eilers <jan.eilers@arm.com>
Change-Id: I156d819686021865f4375e6cb7a5c5dec8fee9e8
Signed-off-by: David Monahan <david.monahan@arm.com>
diff --git a/include/armnn/BackendRegistry.hpp b/include/armnn/BackendRegistry.hpp
index fe6451c..c13aa9f 100644
--- a/include/armnn/BackendRegistry.hpp
+++ b/include/armnn/BackendRegistry.hpp
@@ -7,6 +7,7 @@
 #include <armnn/Types.hpp>
 #include <armnn/BackendId.hpp>
 #include <armnn/Optional.hpp>
+#include <armnn/backends/ICustomAllocator.hpp>
 
 #include <memory>
 #include <unordered_map>
@@ -35,6 +36,8 @@
     BackendIdSet GetBackendIds() const;
     std::string GetBackendIdsAsString() const;
     void SetProfilingService(armnn::Optional<profiling::ProfilingService&> profilingService);
+    void RegisterAllocator(const BackendId& id, std::shared_ptr<ICustomAllocator> alloc);
+    std::unordered_map<BackendId, std::shared_ptr<ICustomAllocator>> GetAllocators();
 
     BackendRegistry() {}
     virtual ~BackendRegistry() {}
@@ -50,6 +53,7 @@
     };
 
     void Deregister(const BackendId& id);
+    void DeregisterAllocator(const BackendId &id);
 
 protected:
     using FactoryStorage = std::unordered_map<BackendId, FactoryFunction>;
@@ -63,6 +67,7 @@
 
     FactoryStorage m_Factories;
     armnn::Optional<profiling::ProfilingService&> m_ProfilingService;
+    std::unordered_map<BackendId, std::shared_ptr<ICustomAllocator>> m_CustomMemoryAllocatorMap;
 };
 
 BackendRegistry& BackendRegistryInstance();
diff --git a/include/armnn/IRuntime.hpp b/include/armnn/IRuntime.hpp
index 8c269de..97a9c28 100644
--- a/include/armnn/IRuntime.hpp
+++ b/include/armnn/IRuntime.hpp
@@ -16,6 +16,7 @@
 
 #include <armnn/backends/ICustomAllocator.hpp>
 #include <memory>
+#include <map>
 
 namespace armnn
 {
@@ -103,8 +104,8 @@
             : m_GpuAccTunedParameters(nullptr)
             , m_EnableGpuProfiling(false)
             , m_DynamicBackendsPath("")
-            , m_CustomAllocator(nullptr)
             , m_ProtectedMode(false)
+            , m_CustomAllocatorMap()
         {}
 
         /// If set, uses the GpuAcc tuned parameters from the given object when executing GPU workloads.
@@ -118,17 +119,22 @@
         /// Only a single path is allowed for the override
         std::string m_DynamicBackendsPath;
 
-        /// A Custom Allocator used for allocation of working memory in the backends.
-        /// Set this for when you need to allocate Protected Working Memory, required for ProtectedMode
-        /// Only supported for GpuAcc
-        ICustomAllocator* m_CustomAllocator;
-
         /// Setting this flag will allow the user to create the Runtime in protected mode.
         /// It will run all the inferences on protected memory and will make sure that
         /// INetworkProperties::m_ImportEnabled set to true with MemorySource::DmaBufProtected option
-        /// This will use Protected Memory Allocator associated with the backend
+        /// This requires that the backend supports Protected Memory and has an allocator capable of
+        /// allocating Protected Memory associated with it.
         bool m_ProtectedMode;
 
+        /// @brief A map to define a custom memory allocator for specific backend Ids.
+        ///
+        /// @details  A Custom Allocator is used for allocation of working memory in the backends.
+        /// Set this if you need to take control of how memory is allocated on a backend. Required for
+        /// Protected Mode in order to correctly allocate Protected Memory
+        ///
+        /// @note Only supported for GpuAcc
+        std::map<BackendId, std::shared_ptr<ICustomAllocator>> m_CustomAllocatorMap;
+
         struct ExternalProfilingOptions
         {
             ExternalProfilingOptions()
diff --git a/include/armnn/backends/IBackendInternal.hpp b/include/armnn/backends/IBackendInternal.hpp
index 3b4ef95..6267464 100644
--- a/include/armnn/backends/IBackendInternal.hpp
+++ b/include/armnn/backends/IBackendInternal.hpp
@@ -199,10 +199,13 @@
 
     /// Signals the backend to use a custom memory allocator provided by the user
     ///
+    /// \param allocator - a pointer to the provided ICustomAllocator to use with this backend
     /// \param errMsg - Optional string variable to return error messages
     /// \return - Returns true if switching to custom allocator was successful
-    virtual bool UseCustomMemoryAllocator(armnn::Optional<std::string&> errMsg)
+    virtual bool UseCustomMemoryAllocator(std::shared_ptr<ICustomAllocator> allocator,
+                                          armnn::Optional<std::string&> errMsg)
     {
+        IgnoreUnused(allocator);
         if (errMsg)
         {
             std::stringstream message;
diff --git a/include/armnn/backends/ICustomAllocator.hpp b/include/armnn/backends/ICustomAllocator.hpp
index 1d4df0c..92cbcc2 100644
--- a/include/armnn/backends/ICustomAllocator.hpp
+++ b/include/armnn/backends/ICustomAllocator.hpp
@@ -7,6 +7,7 @@
 
 #include <cstddef>
 #include <memory>
+#include <armnn/MemorySources.hpp>
 
 namespace armnn
 {
@@ -23,13 +24,20 @@
      * @param[in] alignment Alignment that the returned pointer should comply with
      *
      * @return A pointer to the allocated memory
+     * The returned pointer must be host write accessible
      */
-    virtual void *allocate(size_t size, size_t alignment) = 0;
-    /** Interface to be implemented by the child class to free the allocated tensor */
-    virtual void free(void *ptr) = 0;
+    virtual void* allocate(size_t size, size_t alignment) = 0;
 
-    // Utility Function to define the Custom Memory Allocators capabilities
-    virtual bool SupportsProtectedMemory() = 0;
+    /** Interface to be implemented by the child class to free the allocated bytes */
+    virtual void free(void* ptr) = 0;
+
+    //  Used to specify what type of memory is being allocated by this allocator.
+    //  Supported types are:
+    //      MemorySource::Malloc
+    //  Unsupported types are:
+    //      MemorySource::DmaBuf
+    //      MemorySource::DmaBufProtected
+    virtual armnn::MemorySource GetMemorySourceType() = 0;
 
 };
 } // namespace armnn
\ No newline at end of file