IVGCVSW-6163 Add Conv3d FrontEnd and Ref Implementation

 * Added front-end
 * Added Reference workload
 * Added Serializer & Deserializer support
 * Added unit tests
 * Added NDHWC DataLayout

Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: Iec4d39e7433b5334d52fa44cf8efc6bcd39319d8
diff --git a/include/armnn/BackendHelper.hpp b/include/armnn/BackendHelper.hpp
index e3478a7..80676de 100644
--- a/include/armnn/BackendHelper.hpp
+++ b/include/armnn/BackendHelper.hpp
@@ -108,6 +108,13 @@
                                   const Optional<TensorInfo>& biases,
                                   Optional<std::string&> reasonIfUnsupported = EmptyOptional());
 
+    bool IsConvolution3dSupported(const TensorInfo& input,
+                                  const TensorInfo& output,
+                                  const Convolution3dDescriptor& descriptor,
+                                  const TensorInfo& weights,
+                                  const Optional<TensorInfo>& biases,
+                                  Optional<std::string&> reasonIfUnsupported = EmptyOptional());
+
     bool IsDebugSupported(const TensorInfo& input,
                           const TensorInfo& output,
                           Optional<std::string&> reasonIfUnsupported = EmptyOptional());
diff --git a/include/armnn/Descriptors.hpp b/include/armnn/Descriptors.hpp
index d571f22..9a5128a 100644
--- a/include/armnn/Descriptors.hpp
+++ b/include/armnn/Descriptors.hpp
@@ -468,6 +468,74 @@
     DataLayout           m_DataLayout;
 };
 
+/// A Convolution3dDescriptor for the Convolution3dLayer.
+struct Convolution3dDescriptor : BaseDescriptor
+{
+    Convolution3dDescriptor()
+        : m_PadLeft(0)
+        , m_PadRight(0)
+        , m_PadTop(0)
+        , m_PadBottom(0)
+        , m_PadFront(0)
+        , m_PadBack(0)
+        , m_StrideX(1)
+        , m_StrideY(1)
+        , m_StrideZ(1)
+        , m_DilationX(1)
+        , m_DilationY(1)
+        , m_DilationZ(1)
+        , m_BiasEnabled(false)
+        , m_DataLayout(DataLayout::NDHWC)
+    {}
+
+    bool operator ==(const Convolution3dDescriptor& rhs) const
+    {
+        return m_PadLeft     == rhs.m_PadLeft &&
+               m_PadRight    == rhs.m_PadRight &&
+               m_PadTop      == rhs.m_PadTop &&
+               m_PadBottom   == rhs.m_PadBottom &&
+               m_PadFront    == rhs.m_PadFront &&
+               m_PadBack     == rhs.m_PadBack &&
+               m_StrideX     == rhs.m_StrideX &&
+               m_StrideY     == rhs.m_StrideY &&
+               m_StrideZ     == rhs.m_StrideZ &&
+               m_DilationX   == rhs.m_DilationX &&
+               m_DilationY   == rhs.m_DilationY &&
+               m_DilationZ   == rhs.m_DilationZ &&
+               m_BiasEnabled == rhs.m_BiasEnabled &&
+               m_DataLayout  == rhs.m_DataLayout;
+    }
+
+    /// Padding left value in the width dimension.
+    uint32_t             m_PadLeft;
+    /// Padding right value in the width dimension.
+    uint32_t             m_PadRight;
+    /// Padding top value in the height dimension.
+    uint32_t             m_PadTop;
+    /// Padding bottom value in the height dimension.
+    uint32_t             m_PadBottom;
+    /// Padding front value in the depth dimension.
+    uint32_t             m_PadFront;
+    /// Padding back value in the depth dimension.
+    uint32_t             m_PadBack;
+    /// Stride value when proceeding through input for the width dimension.
+    uint32_t             m_StrideX;
+    /// Stride value when proceeding through input for the height dimension.
+    uint32_t             m_StrideY;
+    /// Stride value when proceeding through input for the depth dimension.
+    uint32_t             m_StrideZ;
+    /// Dilation along x axis
+    uint32_t             m_DilationX;
+    /// Dilation along y axis
+    uint32_t             m_DilationY;
+    /// Dilation along z axis
+    uint32_t             m_DilationZ;
+    /// Enable/disable bias.
+    bool                 m_BiasEnabled;
+    /// The data layout to be used (NDHWC).
+    DataLayout           m_DataLayout;
+};
+
 /// A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
 struct DepthwiseConvolution2dDescriptor : BaseDescriptor
 {
diff --git a/include/armnn/DescriptorsFwd.hpp b/include/armnn/DescriptorsFwd.hpp
index 396b728..5c4615d 100644
--- a/include/armnn/DescriptorsFwd.hpp
+++ b/include/armnn/DescriptorsFwd.hpp
@@ -16,6 +16,7 @@
 struct ChannelShuffleDescriptor;
 struct ComparisonDescriptor;
 struct Convolution2dDescriptor;
+struct Convolution3dDescriptor;
 struct DepthwiseConvolution2dDescriptor;
 struct DetectionPostProcessDescriptor;
 struct ElementwiseUnaryDescriptor;
diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp
index 37aeaf4..8ec8de0 100644
--- a/include/armnn/INetwork.hpp
+++ b/include/armnn/INetwork.hpp
@@ -241,6 +241,17 @@
                                              const ConstTensor& biases,
                                              const char* name = nullptr);
 
+    /// Adds a 3D convolution layer to the network.
+    /// @param convolution3dDescriptor - Description of the 3D convolution layer.
+    /// @param weights - Tensor for the weights data.
+    /// @param biases - Optional tensor for the bias data. If specified, must match the output tensor shape.
+    /// @param name - Optional name for the layer.
+    /// @return - Interface for configuring the layer.
+    IConnectableLayer* AddConvolution3dLayer(const Convolution3dDescriptor& convolution3dDescriptor,
+                                             const ConstTensor& weights,
+                                             const Optional<ConstTensor>& biases,
+                                             const char* name = nullptr);
+
     /// Adds a depth to space layer to the network.
     /// @param depthToSpaceDescriptor - Parameters for the depth to space operation.
     /// @param name - Optional name for the layer.
diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp
index 2fab6b4..ef52368 100644
--- a/include/armnn/Types.hpp
+++ b/include/armnn/Types.hpp
@@ -53,7 +53,8 @@
 enum class DataLayout
 {
     NCHW = 1,
-    NHWC = 2
+    NHWC = 2,
+    NDHWC = 3
 };
 
 /// Define the behaviour of the internal profiler when outputting network details
@@ -422,6 +423,8 @@
     X(Shape) \
     X(UnidirectionalSequenceLstm) \
     X(ChannelShuffle) \
+    X(Convolution3d) \
+
 // New layers should be added at last to minimize instability.
 
 /// When adding a new layer, adapt also the LastLayer enum value in the
diff --git a/include/armnn/TypesUtils.hpp b/include/armnn/TypesUtils.hpp
index 20fcbbd..b644daa 100644
--- a/include/armnn/TypesUtils.hpp
+++ b/include/armnn/TypesUtils.hpp
@@ -218,9 +218,10 @@
 {
     switch (dataLayout)
     {
-        case DataLayout::NCHW: return "NCHW";
-        case DataLayout::NHWC: return "NHWC";
-        default:               return "Unknown";
+        case DataLayout::NCHW:  return "NCHW";
+        case DataLayout::NHWC:  return "NHWC";
+        case DataLayout::NDHWC: return "NDHWC";
+        default:                return "Unknown";
     }
 }
 
diff --git a/include/armnn/backends/ILayerSupport.hpp b/include/armnn/backends/ILayerSupport.hpp
index f511ee4..3744f31 100644
--- a/include/armnn/backends/ILayerSupport.hpp
+++ b/include/armnn/backends/ILayerSupport.hpp
@@ -106,6 +106,13 @@
                                           const Optional<TensorInfo>& biases,
                                           Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const = 0;
 
+    virtual bool IsConvolution3dSupported(const TensorInfo& input,
+                                          const TensorInfo& output,
+                                          const Convolution3dDescriptor& descriptor,
+                                          const TensorInfo& weights,
+                                          const Optional<TensorInfo>& biases,
+                                          Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const = 0;
+
     virtual bool IsDebugSupported(const TensorInfo& input,
                                   const TensorInfo& output,
                                   Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const = 0;
diff --git a/include/armnnUtils/DataLayoutIndexed.hpp b/include/armnnUtils/DataLayoutIndexed.hpp
index b26f220..163d34b 100644
--- a/include/armnnUtils/DataLayoutIndexed.hpp
+++ b/include/armnnUtils/DataLayoutIndexed.hpp
@@ -23,6 +23,7 @@
     unsigned int      GetChannelsIndex() const { return m_ChannelsIndex; }
     unsigned int      GetHeightIndex()   const { return m_HeightIndex; }
     unsigned int      GetWidthIndex()    const { return m_WidthIndex; }
+    unsigned int      GetDepthIndex()    const { return m_DepthIndex; }
 
     inline unsigned int GetIndex(const armnn::TensorShape& shape,
                                  unsigned int batchIndex, unsigned int channelIndex,
@@ -63,6 +64,7 @@
     unsigned int      m_ChannelsIndex;
     unsigned int      m_HeightIndex;
     unsigned int      m_WidthIndex;
+    unsigned int      m_DepthIndex;
 };
 
 /// Equality methods