COMPMID-979: Add NHWC data layout to the tensor's metadata

Change-Id: I89bdab7dc63a437eb7d60c0ae652c53c3875e503
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/122524
Tested-by: Jenkins <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Reviewed-by: Pablo Tello <pablo.tello@arm.com>
diff --git a/arm_compute/core/Helpers.h b/arm_compute/core/Helpers.h
index 63fad1d..c91299f 100644
--- a/arm_compute/core/Helpers.h
+++ b/arm_compute/core/Helpers.h
@@ -588,6 +588,16 @@
  */
 bool set_data_type_if_unknown(ITensorInfo &info, DataType data_type);
 
+/* Set the data layout to the specified value if
+ * the current data layout is unknown.
+ *
+ * @param[in,out] info        Tensor info used to check and assign.
+ * @param[in]     data_layout New data layout.
+ *
+ * @return True if the data type has been changed.
+ */
+bool set_data_layout_if_unknown(ITensorInfo &info, DataLayout data_layout);
+
 /* Set the fixed point position to the specified value if
  * the current fixed point position is 0 and the data type is QS8 or QS16
  *
@@ -637,6 +647,15 @@
  * @return linead index
  */
 inline int coords2index(const TensorShape &shape, const Coordinates &coord);
+
+/* Get the index of the given dimension.
+ *
+ * @param[in] info        Tensor info used to check and assign.
+ * @param[in] data_layout New data layout.
+ *
+ * @return The int conversion of the requested data layout index.
+ */
+inline int get_data_layout_dimension_index(const ITensorInfo &info, const DataLayoutDimension data_layout_dimension);
 } // namespace arm_compute
 
 #include "arm_compute/core/Helpers.inl"
diff --git a/arm_compute/core/Helpers.inl b/arm_compute/core/Helpers.inl
index 8b86c22..ff85773 100644
--- a/arm_compute/core/Helpers.inl
+++ b/arm_compute/core/Helpers.inl
@@ -227,6 +227,7 @@
         info_sink.set_tensor_shape(info_source.tensor_shape());
         info_sink.set_fixed_point_position(info_source.fixed_point_position());
         info_sink.set_quantization_info(info_source.quantization_info());
+        info_sink.set_data_layout(info_source.data_layout());
         return true;
     }
 
@@ -266,6 +267,17 @@
     return false;
 }
 
+inline bool set_data_layout_if_unknown(ITensorInfo &info, DataLayout data_layout)
+{
+    if(info.data_layout() == DataLayout::UNKNOWN)
+    {
+        info.set_data_layout(data_layout);
+        return true;
+    }
+
+    return false;
+}
+
 inline bool set_fixed_point_position_if_zero(ITensorInfo &info, int fixed_point_position)
 {
     if(info.fixed_point_position() == 0 && (info.data_type() == DataType::QS8 || info.data_type() == DataType::QS16))
@@ -357,4 +369,33 @@
 
     return index;
 }
+
+inline int get_data_layout_dimension_index(const ITensorInfo &info, const DataLayoutDimension data_layout_dimension)
+{
+    ARM_COMPUTE_ERROR_ON_MSG(info.data_layout() == DataLayout::UNKNOWN, "Cannot retrieve the dimension index for an unknown layout!");
+
+    /* Return the index based on the data layout
+     * [N C H W]
+     * [3 2 1 0]
+     * [N H W C]
+    */
+    switch(data_layout_dimension)
+    {
+        case DataLayoutDimension::CHANNEL:
+            return (info.data_layout() == DataLayout::NCHW) ? 2 : 0;
+            break;
+        case DataLayoutDimension::HEIGHT:
+            return (info.data_layout() == DataLayout::NCHW) ? 1 : 2;
+            break;
+        case DataLayoutDimension::WIDTH:
+            return (info.data_layout() == DataLayout::NCHW) ? 0 : 1;
+            break;
+        case DataLayoutDimension::BATCHES:
+            return 3;
+            break;
+        default:
+            ARM_COMPUTE_ERROR("Data layout index not supported!");
+            break;
+    }
+}
 } // namespace arm_compute
diff --git a/arm_compute/core/ITensorInfo.h b/arm_compute/core/ITensorInfo.h
index b5677df..50a1eb2 100644
--- a/arm_compute/core/ITensorInfo.h
+++ b/arm_compute/core/ITensorInfo.h
@@ -97,6 +97,13 @@
      * @return Reference to this ITensorInfo object
      */
     virtual ITensorInfo &set_quantization_info(const QuantizationInfo &quantization_info) = 0;
+    /** Set the data layout of the tensor.
+     *
+     * @param[in] data_layout DataLayout containing the layout data information.
+     *
+     * @return Reference to this ITensorInfo object
+     */
+    virtual ITensorInfo &set_data_layout(const DataLayout &data_layout) = 0;
     /** Resets the padding settings of the tensor.
     *
     * @return Reference to this ITensorInfo object
@@ -222,6 +229,11 @@
     * @return A QuantizationInfo containing the scale and offset.
     */
     virtual QuantizationInfo quantization_info() const = 0;
+    /** Get the data layout of the tensor.
+    *
+    * @return A DataLayout containing the layout data information.
+    */
+    virtual DataLayout data_layout() const = 0;
 
     /** If infos are broadcast compatible tensor info's, return the broadcasted shape and the intersection of
      * the broadcasted valid regions of the tensors.
diff --git a/arm_compute/core/SubTensorInfo.h b/arm_compute/core/SubTensorInfo.h
index 7f4239d..f9ed99b 100644
--- a/arm_compute/core/SubTensorInfo.h
+++ b/arm_compute/core/SubTensorInfo.h
@@ -80,6 +80,12 @@
         _parent->set_data_type(data_type);
         return *this;
     };
+    ITensorInfo &set_data_layout(const DataLayout &data_layout) override
+    {
+        ARM_COMPUTE_ERROR_ON(_parent == nullptr);
+        _parent->set_data_layout(data_layout);
+        return *this;
+    };
     ITensorInfo &set_num_channels(int num_channels) override
     {
         ARM_COMPUTE_ERROR_ON(_parent == nullptr);
@@ -211,6 +217,11 @@
         ARM_COMPUTE_ERROR_ON(_parent == nullptr);
         return _parent->quantization_info();
     }
+    DataLayout data_layout() const override
+    {
+        ARM_COMPUTE_ERROR_ON(_parent == nullptr);
+        return _parent->data_layout();
+    }
 
 private:
     ITensorInfo *_parent;
diff --git a/arm_compute/core/TensorInfo.h b/arm_compute/core/TensorInfo.h
index 0b8989f..27cf5ba 100644
--- a/arm_compute/core/TensorInfo.h
+++ b/arm_compute/core/TensorInfo.h
@@ -220,6 +220,7 @@
     ITensorInfo &set_tensor_shape(const TensorShape &shape) override;
     ITensorInfo &set_fixed_point_position(int fixed_point_position) override;
     ITensorInfo &set_quantization_info(const QuantizationInfo &quantization_info) override;
+    ITensorInfo &set_data_layout(const DataLayout &data_layout) override;
     ITensorInfo &reset_padding() override;
     bool         auto_padding() override;
     bool extend_padding(const PaddingSize &padding) override;
@@ -297,6 +298,10 @@
     {
         return _quantization_info;
     }
+    DataLayout data_layout() const override
+    {
+        return _data_layout;
+    }
 
 private:
     /** Calculates strides, offset and total size resulting from the specified padding around the XY plane.
@@ -317,6 +322,7 @@
     ValidRegion      _valid_region;
     PaddingSize      _padding;
     QuantizationInfo _quantization_info;
+    DataLayout       _data_layout;
 };
 }
 #endif /*__ARM_COMPUTE_TENSORINFO_H__ */
diff --git a/arm_compute/core/Types.h b/arm_compute/core/Types.h
index 24c73ca..143ee02 100644
--- a/arm_compute/core/Types.h
+++ b/arm_compute/core/Types.h
@@ -109,10 +109,20 @@
 /** Supported tensor data layouts */
 enum class DataLayout
 {
+    UNKNOWN,
     NCHW,
     NHWC
 };
 
+/** Supported tensor data layout dimensions */
+enum class DataLayoutDimension
+{
+    CHANNEL,
+    HEIGHT,
+    WIDTH,
+    BATCHES
+};
+
 /** Quantization settings (used for QASYMM8 data type) */
 struct QuantizationInfo
 {
diff --git a/src/core/TensorInfo.cpp b/src/core/TensorInfo.cpp
index bd0c85f..2190e34 100644
--- a/src/core/TensorInfo.cpp
+++ b/src/core/TensorInfo.cpp
@@ -34,7 +34,7 @@
 
 TensorInfo::TensorInfo()
     : _total_size(0), _fixed_point_position(0), _offset_first_element_in_bytes(0), _strides_in_bytes(), _num_channels(0), _tensor_shape(), _data_type(DataType::UNKNOWN), _format(Format::UNKNOWN),
-      _is_resizable{ true }, _valid_region{ Coordinates(), _tensor_shape }, _padding{ 0 }, _quantization_info()
+      _is_resizable{ true }, _valid_region{ Coordinates(), _tensor_shape }, _padding{ 0 }, _quantization_info(), _data_layout(DataLayout::NCHW)
 {
 }
 
@@ -53,6 +53,7 @@
     _valid_region                  = info.valid_region();
     _padding                       = info.padding();
     _quantization_info             = info.quantization_info();
+    _data_layout                   = info.data_layout();
 }
 
 TensorInfo::TensorInfo(Format format)
@@ -384,6 +385,12 @@
     return *this;
 }
 
+ITensorInfo &TensorInfo::set_data_layout(const DataLayout &data_layout)
+{
+    _data_layout = data_layout;
+    return *this;
+}
+
 ITensorInfo &TensorInfo::reset_padding()
 {
     _padding = PaddingSize();