COMPMID-424 Implemented reference implementation and validation tests (NEON and CL) for Warp Perspective

Changed the behaviour in NEWarpKernel for border mode replicate and constant to stick with the VX specs.
When the new coords are out of the valid region, the output will be computed using the values from the border.
In the validation tests the validate will be called with tolerance_value 1 and tolerance_number 0.2%, due to some float arithmetic related mismatches.

Change-Id: Id4f9d0ef87178f8f8fd38ee17fee0e6f4beb85cd
Reviewed-on: http://mpd-gerrit.cambridge.arm.com/80283
Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
Reviewed-by: Moritz Pflanzer <moritz.pflanzer@arm.com>
Reviewed-by: Steven Niu <steven.niu@arm.com>
diff --git a/tests/validation/Validation.cpp b/tests/validation/Validation.cpp
index eac4105..868bbaa 100644
--- a/tests/validation/Validation.cpp
+++ b/tests/validation/Validation.cpp
@@ -193,7 +193,6 @@
             BOOST_TEST_INFO("reference = " << std::setprecision(5) << ref);
             BOOST_TEST_INFO("target = " << std::setprecision(5) << target);
             BOOST_TEST_WARN(equal);
-
             ++num_mismatches;
         }
         ++num_elements;
@@ -264,6 +263,39 @@
                << "%) mismatched (maximum tolerated " << std::setprecision(2) << tolerance_number << "%)");
 }
 
+void validate(const IAccessor &tensor, const RawTensor &reference, const RawTensor &valid_mask, float tolerance_value, float tolerance_number, uint64_t wrap_range)
+{
+    int64_t num_mismatches = 0;
+    int64_t num_elements   = 0;
+
+    BOOST_TEST(tensor.element_size() == reference.element_size());
+    BOOST_TEST(tensor.format() == reference.format());
+    BOOST_TEST(tensor.data_type() == reference.data_type());
+    BOOST_TEST(tensor.num_channels() == reference.num_channels());
+    BOOST_TEST(compare_dimensions(tensor.shape(), reference.shape()));
+
+    const int    min_elements = std::min(tensor.num_elements(), reference.num_elements());
+    const int    min_channels = std::min(tensor.num_channels(), reference.num_channels());
+    const size_t channel_size = element_size_from_data_type(reference.data_type());
+
+    // Iterate over all elements within valid region, e.g. U8, S16, RGB888, ...
+    for(int element_idx = 0; element_idx < min_elements; ++element_idx)
+    {
+        const Coordinates id = index2coord(reference.shape(), element_idx);
+        if(valid_mask[element_idx] == 1)
+        {
+            check_single_element(id, tensor, reference, tolerance_value, wrap_range, min_channels, channel_size, num_mismatches, num_elements);
+        }
+    }
+
+    const int64_t absolute_tolerance_number = tolerance_number * num_elements;
+    const float   percent_mismatches        = static_cast<float>(num_mismatches) / num_elements * 100.f;
+
+    BOOST_TEST(num_mismatches <= absolute_tolerance_number,
+               num_mismatches << " values (" << std::setprecision(2) << percent_mismatches
+               << "%) mismatched (maximum tolerated " << std::setprecision(2) << tolerance_number << "%)");
+}
+
 void validate(const IAccessor &tensor, const void *reference_value)
 {
     BOOST_TEST_REQUIRE((reference_value != nullptr));