IVGCVSW-3883 Add frontend for DepthToSpace layer

Signed-off-by: Aron Virginas-Tar <Aron.Virginas-Tar@arm.com>
Change-Id: I18d957af6e988ffb6b9ee46ac836d1f38600e10b
diff --git a/src/backends/backendsCommon/LayerSupportBase.cpp b/src/backends/backendsCommon/LayerSupportBase.cpp
index 7f1fd10..656407d 100644
--- a/src/backends/backendsCommon/LayerSupportBase.cpp
+++ b/src/backends/backendsCommon/LayerSupportBase.cpp
@@ -129,6 +129,14 @@
     return DefaultLayerSupport(__func__, __FILE__, __LINE__, reasonIfUnsupported);
 }
 
+bool LayerSupportBase::IsDepthToSpaceSupported(const TensorInfo& input,
+                                               const TensorInfo& output,
+                                               const DepthToSpaceDescriptor& descriptor,
+                                               Optional<std::string&> reasonIfUnsupported) const
+{
+    return DefaultLayerSupport(__func__, __FILE__, __LINE__, reasonIfUnsupported);
+}
+
 bool LayerSupportBase::IsDepthwiseConvolutionSupported(const TensorInfo& input,
                                                        const TensorInfo& output,
                                                        const DepthwiseConvolution2dDescriptor& descriptor,
diff --git a/src/backends/backendsCommon/LayerSupportBase.hpp b/src/backends/backendsCommon/LayerSupportBase.hpp
index 8df1f8d..c3875e6 100644
--- a/src/backends/backendsCommon/LayerSupportBase.hpp
+++ b/src/backends/backendsCommon/LayerSupportBase.hpp
@@ -74,6 +74,11 @@
                           const TensorInfo& output,
                           Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override;
 
+    bool IsDepthToSpaceSupported(const TensorInfo& input,
+                                 const TensorInfo& output,
+                                 const DepthToSpaceDescriptor& descriptor,
+                                 Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override;
+
     bool IsDepthwiseConvolutionSupported(const TensorInfo& input,
                                          const TensorInfo& output,
                                          const DepthwiseConvolution2dDescriptor& descriptor,
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index c8c4f9a..52d1409 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -2642,4 +2642,55 @@
     }
 }
 
+void DepthToSpaceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
+{
+    const std::string descriptorName{"DepthToSpaceQueueDescriptor"};
+
+    ValidateNumInputs(workloadInfo,  descriptorName, 1);
+    ValidateNumOutputs(workloadInfo, descriptorName, 1);
+
+    const TensorInfo& inputInfo  = workloadInfo.m_InputTensorInfos[0];
+    const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0];
+
+    ValidateTensorNumDimensions(inputInfo,  descriptorName, 4, "input");
+    ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output");
+
+    std::vector<DataType> supportedTypes =
+    {
+        DataType::Float32,
+        DataType::Float16,
+        DataType::QuantisedAsymm8,
+        DataType::QuantisedSymm16
+    };
+
+    ValidateDataTypes(inputInfo,  supportedTypes, descriptorName);
+    ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
+
+    ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output");
+
+    if (m_Parameters.m_BlockSize == 0)
+    {
+        throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
+    }
+
+    DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
+    const unsigned int wIndex = dimensionIndices.GetWidthIndex();
+    const unsigned int hIndex = dimensionIndices.GetHeightIndex();
+    const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
+
+    const TensorShape& outputShape = outputInfo.GetShape();
+    if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex]  % m_Parameters.m_BlockSize != 0)
+    {
+        throw InvalidArgumentException(descriptorName + ": Output width and height shape"
+                                       "must be divisible by block size.");
+    }
+
+    const TensorShape& inputShape = inputInfo.GetShape();
+    if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
+    {
+        throw InvalidArgumentException(descriptorName + ": The depth of the input tensor"
+                                       "must be divisible by the square of block size." );
+    }
+}
+
 } // namespace armnn
diff --git a/src/backends/backendsCommon/WorkloadData.hpp b/src/backends/backendsCommon/WorkloadData.hpp
index 1e49243..177bfb7 100644
--- a/src/backends/backendsCommon/WorkloadData.hpp
+++ b/src/backends/backendsCommon/WorkloadData.hpp
@@ -538,4 +538,9 @@
     void Validate(const WorkloadInfo& workloadInfo) const;
 };
 
+struct DepthToSpaceQueueDescriptor : QueueDescriptorWithParameters<DepthToSpaceDescriptor>
+{
+    void Validate(const WorkloadInfo& workloadInfo) const;
+};
+
 } // namespace armnn
diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp
index 9d6b2bd..44888b3 100644
--- a/src/backends/backendsCommon/WorkloadFactory.cpp
+++ b/src/backends/backendsCommon/WorkloadFactory.cpp
@@ -206,6 +206,19 @@
                                                           reason);
             break;
         }
+        case LayerType::DepthToSpace:
+        {
+            auto cLayer = boost::polymorphic_downcast<const DepthToSpaceLayer*>(&layer);
+
+            const TensorInfo& input  = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
+            const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
+
+            result = layerSupportObject->IsDepthToSpaceSupported(OverrideDataType(input, dataType),
+                                                                 OverrideDataType(output, dataType),
+                                                                 cLayer->GetParameters(),
+                                                                 reason);
+            break;
+        }
         case LayerType::DepthwiseConvolution2d:
         {
             auto cLayer = boost::polymorphic_downcast<const DepthwiseConvolution2dLayer*>(&layer);
@@ -1060,6 +1073,12 @@
     return std::unique_ptr<IWorkload>();
 }
 
+std::unique_ptr<IWorkload> IWorkloadFactory::CreateDepthToSpace(const DepthToSpaceQueueDescriptor& descriptor,
+                                                                const WorkloadInfo& info) const
+{
+    return std::unique_ptr<IWorkload>();
+}
+
 std::unique_ptr<IWorkload> IWorkloadFactory::CreateDepthwiseConvolution2d(
     const DepthwiseConvolution2dQueueDescriptor& descriptor, const WorkloadInfo& info) const
 {
diff --git a/src/backends/backendsCommon/WorkloadFactory.hpp b/src/backends/backendsCommon/WorkloadFactory.hpp
index 91cf2c7..29ebe2a 100644
--- a/src/backends/backendsCommon/WorkloadFactory.hpp
+++ b/src/backends/backendsCommon/WorkloadFactory.hpp
@@ -85,6 +85,9 @@
     virtual std::unique_ptr<IWorkload> CreateDebug(const DebugQueueDescriptor& descriptor,
                                                    const WorkloadInfo& info) const;
 
+    virtual std::unique_ptr<IWorkload> CreateDepthToSpace(const DepthToSpaceQueueDescriptor& descriptor,
+                                                          const WorkloadInfo& info) const;
+
     virtual std::unique_ptr<IWorkload> CreateDepthwiseConvolution2d(
         const DepthwiseConvolution2dQueueDescriptor& descriptor, const WorkloadInfo& info) const;
 
diff --git a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp
index 17b7934..e492cd6 100644
--- a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp
+++ b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp
@@ -413,6 +413,8 @@
 
 DECLARE_LAYER_POLICY_1_PARAM(Debug)
 
+DECLARE_LAYER_POLICY_2_PARAM(DepthToSpace)
+
 DECLARE_LAYER_POLICY_2_PARAM(DepthwiseConvolution2d)
 
 DECLARE_LAYER_POLICY_1_PARAM(Dequantize)