IVGCVSW-7297 When creating multiple Executors only the last
 one works fine

 * Each CLBackend created its own ClContextControlWrapper which invalidated
   the OpenCL context's from all CLBackends that were created before that one.
 * Now CLBackends will keep a shared_ptr to a ClContextControlWrapper which
   more closely matches the functionality within ACL.

Signed-off-by: Mike Kelly <mike.kelly@arm.com>
Change-Id: I0744c2cb6a2f0d6b0c5fa54d786f88cf97775559
diff --git a/src/backends/cl/ClBackendContext.cpp b/src/backends/cl/ClBackendContext.cpp
index c63fb0c..62c6b03 100644
--- a/src/backends/cl/ClBackendContext.cpp
+++ b/src/backends/cl/ClBackendContext.cpp
@@ -20,11 +20,20 @@
 
 struct ClBackendContext::ClContextControlWrapper
 {
-    ClContextControlWrapper(arm_compute::CLTuner* tuner,
-                            arm_compute::CLGEMMHeuristicsHandle* heuristicsHandle,
-                            bool profilingEnabled)
-        : m_ClContextControl(tuner, heuristicsHandle, profilingEnabled)
-    {}
+    ClContextControlWrapper() {}
+
+    bool IsInitialised()
+    {
+        return m_Initialised;
+    }
+
+    void Init(arm_compute::CLTuner* tuner,
+              arm_compute::CLGEMMHeuristicsHandle* heuristicsHandle,
+              bool profilingEnabled)
+    {
+        m_ClContextControl = ClContextControl(tuner, heuristicsHandle, profilingEnabled);
+        m_Initialised = true;
+    }
 
     bool Sync()
     {
@@ -53,12 +62,28 @@
         {
             // There are no loaded networks left, so clear the CL cache to free up memory
             m_ClContextControl.ClearClCache();
+            m_Initialised = false;
         }
     }
 
+private:
+    bool m_Initialised;
     ClContextControl m_ClContextControl;
+
 };
 
+/**
+ * Returns a shared_ptr to the CLContextControlWrapper. This wraps the CLContextControl and ensures that we only create
+ * and use one at a time.
+ */
+std::shared_ptr<ClBackendContext::ClContextControlWrapper> ClBackendContext::Get()
+{
+    static std::shared_ptr<ClBackendContext::ClContextControlWrapper> instance
+            = std::make_shared<ClBackendContext::ClContextControlWrapper>();
+    // Instantiated on first use.
+    return instance;
+}
+
 std::string LowerString(std::string value)
 {
     std::transform(value.begin(), value.end(), value.begin(),
@@ -146,6 +171,7 @@
     arm_compute::CLTuner* tuner = nullptr;
     arm_compute::CLGEMMHeuristicsHandle* mlgoTuner = nullptr;
     bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
+
     if (useLegacyTunerAPI)
     {
         auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
@@ -246,11 +272,12 @@
         tuner = m_Tuner.get();
     }
 
-    m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
-            tuner,
-            mlgoTuner,
-            kernelProfiling
-    );
+    m_ClContextControlWrapper = Get();
+
+    if (!m_ClContextControlWrapper->IsInitialised())
+    {
+        m_ClContextControlWrapper->Init(tuner, mlgoTuner, kernelProfiling);
+    }
 }
 
 bool ClBackendContext::BeforeLoadNetwork(NetworkId)
diff --git a/src/backends/cl/ClBackendContext.hpp b/src/backends/cl/ClBackendContext.hpp
index 659d47b..2760677 100644
--- a/src/backends/cl/ClBackendContext.hpp
+++ b/src/backends/cl/ClBackendContext.hpp
@@ -31,8 +31,11 @@
 
 private:
     std::mutex m_Mutex;
+
     struct ClContextControlWrapper;
-    std::unique_ptr<ClContextControlWrapper> m_ClContextControlWrapper;
+    static std::shared_ptr<ClBackendContext::ClContextControlWrapper> Get();
+
+    std::shared_ptr<ClBackendContext::ClContextControlWrapper> m_ClContextControlWrapper;
 
     std::unordered_set<NetworkId> m_NetworkIds;