Add support for CLVK

This patch enables CLVK through the graph API and inside the
CLScheduler. By default the Native platform is selected.
Selecting CLVK can be done via --target=clvk.

Resolves COMPMID-4205 and COMPMID-4206

Change-Id: Ic60744980c6b8a60e776627ea677ed46be88f656
Signed-off-by: Michalis Spyrou <michalis.spyrou@arm.com>
Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/5475
Tested-by: Arm Jenkins <bsgcomp@arm.com>
Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
diff --git a/src/runtime/CL/CLHelpers.cpp b/src/runtime/CL/CLHelpers.cpp
index 5f1842f7..5b4bbbc 100644
--- a/src/runtime/CL/CLHelpers.cpp
+++ b/src/runtime/CL/CLHelpers.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 Arm Limited.
+ * Copyright (c) 2019-2021 Arm Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -85,14 +85,48 @@
 
 namespace arm_compute
 {
-std::tuple<cl::Context, cl::Device, cl_int>
-create_opencl_context_and_device()
+cl::Platform select_preferable_platform(CLBackendType cl_backend_type)
 {
-    ARM_COMPUTE_ERROR_ON(!opencl_is_available());
     std::vector<cl::Platform> platforms;
     cl::Platform::get(&platforms);
     ARM_COMPUTE_ERROR_ON_MSG(platforms.size() == 0, "Couldn't find any OpenCL platform");
-    cl::Platform            p = platforms[0];
+
+    cl::Platform selected_platform{ nullptr };
+
+    // If the user has selected the Native platform, return the first available.
+    switch(cl_backend_type)
+    {
+        case CLBackendType::Native:
+            selected_platform = platforms[0];
+            break;
+        case CLBackendType::Clvk:
+            for(auto p : platforms)
+            {
+                std::string res = p.getInfo<CL_PLATFORM_NAME>();
+                if(res.find("clvk") != std::string::npos)
+                {
+                    selected_platform = p;
+                    break;
+                }
+            }
+            break;
+        default:
+            ARM_COMPUTE_ERROR("Unsupported backend type");
+    }
+
+    if(!selected_platform())
+    {
+        ARM_COMPUTE_ERROR("No valid platform found");
+    }
+
+    return selected_platform;
+}
+
+std::tuple<cl::Context, cl::Device, cl_int>
+create_opencl_context_and_device(CLBackendType cl_backend_type)
+{
+    ARM_COMPUTE_ERROR_ON(!opencl_is_available());
+    cl::Platform            p = select_preferable_platform(cl_backend_type);
     cl::Device              device;
     std::vector<cl::Device> platform_devices;
     p.getDevices(CL_DEVICE_TYPE_DEFAULT, &platform_devices);
diff --git a/src/runtime/CL/CLRuntimeContext.cpp b/src/runtime/CL/CLRuntimeContext.cpp
index 9d46126..0c1d011 100644
--- a/src/runtime/CL/CLRuntimeContext.cpp
+++ b/src/runtime/CL/CLRuntimeContext.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 Arm Limited.
+ * Copyright (c) 2019-2021 Arm Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -29,10 +29,10 @@
 namespace arm_compute
 {
 CLRuntimeContext::CLRuntimeContext()
-    : _gpu_owned_scheduler(std::make_unique<CLScheduler>()), _gpu_scheduler(_gpu_owned_scheduler.get()), _symbols(), _core_context()
+    : _gpu_owned_scheduler(std::make_unique<CLScheduler>()), _gpu_scheduler(_gpu_owned_scheduler.get()), _symbols(), _core_context(), _backend_type()
 {
     _symbols.load_default();
-    auto ctx_dev_err = create_opencl_context_and_device();
+    auto ctx_dev_err = create_opencl_context_and_device(_backend_type);
     ARM_COMPUTE_ERROR_ON_MSG(std::get<2>(ctx_dev_err) != CL_SUCCESS, "Failed to create OpenCL context");
     auto             ctx   = std::get<0>(ctx_dev_err);
     auto             dev   = std::get<1>(ctx_dev_err);
diff --git a/src/runtime/CL/CLScheduler.cpp b/src/runtime/CL/CLScheduler.cpp
index f228cf6..cb5f04c 100644
--- a/src/runtime/CL/CLScheduler.cpp
+++ b/src/runtime/CL/CLScheduler.cpp
@@ -24,7 +24,6 @@
 #include "arm_compute/runtime/CL/CLScheduler.h"
 
 #include "arm_compute/core/CL/CLKernelLibrary.h"
-#include "arm_compute/runtime/CL/CLHelpers.h"
 #include "arm_compute/runtime/CL/CLTuner.h"
 #include "src/core/CL/ICLKernel.h"
 
@@ -96,7 +95,7 @@
 std::once_flag CLScheduler::_initialize_symbols;
 
 CLScheduler::CLScheduler()
-    : _context(), _queue(), _target(GPUTarget::MIDGARD), _is_initialised(false), _cl_tuner(nullptr), _gemm_heuristics(nullptr)
+    : _context(), _queue(), _target(GPUTarget::MIDGARD), _is_initialised(false), _cl_tuner(nullptr), _gemm_heuristics(nullptr), _backend_type(CLBackendType::Native)
 {
 }
 
@@ -119,14 +118,14 @@
     }
 }
 
-void CLScheduler::default_init(ICLTuner *cl_tuner, CLGEMMHeuristicsHandle *gemm_h)
+void CLScheduler::default_init(ICLTuner *cl_tuner, CLGEMMHeuristicsHandle *gemm_h, CLBackendType cl_backend_type)
 {
     if(!_is_initialised)
     {
         cl::Context ctx;
         cl::Device  dev;
         cl_int      err;
-        std::tie(ctx, dev, err) = create_opencl_context_and_device();
+        std::tie(ctx, dev, err) = create_opencl_context_and_device(cl_backend_type);
         ARM_COMPUTE_ERROR_ON_MSG(err != CL_SUCCESS, "Failed to create OpenCL context");
         cl::CommandQueue queue = cl::CommandQueue(ctx, dev);
         CLKernelLibrary::get().init("./cl_kernels/", ctx, dev);
@@ -143,7 +142,7 @@
     CLKernelLibrary::get().set_context(_context);
 }
 
-void CLScheduler::init(cl::Context context, cl::CommandQueue queue, const cl::Device &device, ICLTuner *cl_tuner, CLGEMMHeuristicsHandle *gemm_h)
+void CLScheduler::init(cl::Context context, cl::CommandQueue queue, const cl::Device &device, ICLTuner *cl_tuner, CLGEMMHeuristicsHandle *gemm_h, CLBackendType cl_backend_type)
 {
     set_context(std::move(context));
     _queue           = std::move(queue);
@@ -151,6 +150,7 @@
     _is_initialised  = true;
     _cl_tuner        = cl_tuner;
     _gemm_heuristics = gemm_h;
+    _backend_type    = cl_backend_type;
 }
 
 void CLScheduler::enqueue_common(ICLKernel &kernel, ITensorPack &tensors, bool flush)