COMPMID-1586: Add support for NHWC CLDeconvolutionLayer

COMPMID-1651: Fix QASYMM8 CLDeconvolutionLayer

This patch also extends the range of values used for testing Convolution and
Deconvolution to cover quantized [-1.0f, 1.0f].

Change-Id: I8b280669db67bb3ec25bf5d411c8f5954f5b0dab
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/149869
Reviewed-by: Michalis Spyrou <michalis.spyrou@arm.com>
Tested-by: bsgcomp <bsgcomp@arm.com>
diff --git a/src/core/CL/kernels/CLDeconvolutionLayerUpsampleKernel.cpp b/src/core/CL/kernels/CLDeconvolutionLayerUpsampleKernel.cpp
index be3a926..dd7d790 100644
--- a/src/core/CL/kernels/CLDeconvolutionLayerUpsampleKernel.cpp
+++ b/src/core/CL/kernels/CLDeconvolutionLayerUpsampleKernel.cpp
@@ -45,11 +45,19 @@
 
     ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::QASYMM8, DataType::F16, DataType::F32);
     ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
-    ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(0) == 0);
-    ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(1) == 0);
+
+    const DataLayout data_layout = input->data_layout();
+
+    const size_t idx_w = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
+    const size_t idx_h = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
+    const size_t idx_c = get_data_layout_dimension_index(data_layout, DataLayoutDimension::CHANNEL);
+
+    ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(idx_w) == 0);
+    ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(idx_h) == 0);
     ARM_COMPUTE_RETURN_ERROR_ON(!info.padding_is_symmetric());
 
-    for(size_t i = 2; i < Coordinates::num_max_dimensions; ++i)
+    ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(idx_c) != output->dimension(idx_c));
+    for(size_t i = 3; i < Coordinates::num_max_dimensions; ++i)
     {
         ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(i) != output->dimension(i));
     }
@@ -93,28 +101,61 @@
     ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
     ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(ICLKernel::window(), window);
 
+    const DataLayout data_layout = _input->info()->data_layout();
+
+    const size_t idx_w = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
+    const size_t idx_h = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
+
     const int out_start_x = _info.pad().first;
-    const int out_end_x   = _output->info()->dimension(0) - _inner_border.right - _info.pad().first + _info.stride().first - 1;
+    const int out_end_x   = _output->info()->dimension(idx_w) - _inner_border.right - _info.pad().first + _info.stride().first - 1;
     const int out_step_x  = _info.stride().first;
 
     const int out_start_y = _inner_border.top + _info.pad().second;
-    const int out_end_y   = _output->info()->dimension(1) - _info.pad().second + _info.stride().second - 1;
+    const int out_end_y   = _output->info()->dimension(idx_h) - _info.pad().second + _info.stride().second - 1;
     const int out_step_y  = _info.stride().second;
 
-    Window collapsed = window.collapse_if_possible(ICLKernel::window(), Window::DimZ);
-
-    Window slice_out = collapsed.first_slice_window_3D();
-    slice_out.set(Window::DimX, Window::Dimension(out_start_x, out_end_x, out_step_x));
-    slice_out.set(Window::DimY, Window::Dimension(out_start_y, out_end_y, out_step_y));
-
-    Window slice_in = collapsed.first_slice_window_3D();
-
-    do
+    switch(data_layout)
     {
-        unsigned int idx = 0;
-        add_3D_tensor_argument(idx, _input, slice_in);
-        add_3D_tensor_argument(idx, _output, slice_out);
-        enqueue(queue, *this, slice_out);
+        case DataLayout::NCHW:
+        {
+            Window collapsed = window.collapse_if_possible(ICLKernel::window(), Window::DimZ);
+
+            Window slice_out = collapsed.first_slice_window_3D();
+            slice_out.set(Window::DimX, Window::Dimension(out_start_x, out_end_x, out_step_x));
+            slice_out.set(Window::DimY, Window::Dimension(out_start_y, out_end_y, out_step_y));
+
+            Window slice_in = collapsed.first_slice_window_3D();
+
+            do
+            {
+                unsigned int idx = 0;
+                add_3D_tensor_argument(idx, _input, slice_in);
+                add_3D_tensor_argument(idx, _output, slice_out);
+                enqueue(queue, *this, slice_out);
+            }
+            while(collapsed.slide_window_slice_3D(slice_in) && collapsed.slide_window_slice_3D(slice_out));
+            break;
+        }
+        case DataLayout::NHWC:
+        {
+            // NOTE: not collapsing in NHWC
+            Window slice_out = window.first_slice_window_3D();
+            slice_out.set(Window::DimY, Window::Dimension(out_start_x, out_end_x, out_step_x));
+            slice_out.set(Window::DimZ, Window::Dimension(out_start_y, out_end_y, out_step_y));
+
+            Window slice_in = window.first_slice_window_3D();
+
+            do
+            {
+                unsigned int idx = 0;
+                add_3D_tensor_argument(idx, _input, slice_in);
+                add_3D_tensor_argument(idx, _output, slice_out);
+                enqueue(queue, *this, slice_out);
+            }
+            while(window.slide_window_slice_3D(slice_in) && window.slide_window_slice_3D(slice_out));
+            break;
+        }
+        default:
+            ARM_COMPUTE_ERROR("Unsupported data layout");
     }
-    while(collapsed.slide_window_slice_3D(slice_in) && collapsed.slide_window_slice_3D(slice_out));
 }