aboutsummaryrefslogtreecommitdiff
path: root/arm_compute/core
diff options
context:
space:
mode:
authorIoan-Cristian Szabo <ioan-cristian.szabo@arm.com>2017-10-27 17:35:40 +0100
committerAnthony Barbier <anthony.barbier@arm.com>2018-11-02 16:47:18 +0000
commit9414f64c231a013664102e2c284b10266c6b4d4e (patch)
tree5a5ad6a525004634fe6b78cdfc8da71aae762d33 /arm_compute/core
parent6acc6add8412c6d3841a49684610fc5a6526312e (diff)
downloadComputeLibrary-9414f64c231a013664102e2c284b10266c6b4d4e.tar.gz
COMPMID-582: Add validation to channel_extract kernels.
Change-Id: I5022d02f06f9d849dad76e3d9b8e48632c236429 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/121191 Reviewed-by: Anthony Barbier <anthony.barbier@arm.com> Tested-by: Jenkins <bsgcomp@arm.com>
Diffstat (limited to 'arm_compute/core')
-rw-r--r--arm_compute/core/Utils.h225
-rw-r--r--arm_compute/core/Validate.h32
2 files changed, 257 insertions, 0 deletions
diff --git a/arm_compute/core/Utils.h b/arm_compute/core/Utils.h
index 111eac0e57..b3ebf5e25b 100644
--- a/arm_compute/core/Utils.h
+++ b/arm_compute/core/Utils.h
@@ -237,9 +237,25 @@ inline int plane_idx_from_channel(Format format, Channel channel)
{
switch(format)
{
+ // Single planar formats have a single plane
+ case Format::U8:
+ case Format::U16:
+ case Format::S16:
+ case Format::U32:
+ case Format::S32:
+ case Format::F16:
+ case Format::F32:
+ case Format::UV88:
+ case Format::RGB888:
+ case Format::RGBA8888:
+ case Format::YUYV422:
+ case Format::UYVY422:
+ return 0;
+ // Multi planar formats
case Format::NV12:
case Format::NV21:
{
+ // Channel U and V share the same plane of format UV88
switch(channel)
{
case Channel::Y:
@@ -274,6 +290,131 @@ inline int plane_idx_from_channel(Format format, Channel channel)
}
}
+/** Return the channel index of a given channel given an input format.
+ *
+ * @param[in] format Input format
+ * @param[in] channel Input channel
+ *
+ * @return The channel index of the specific channel of the specific format
+ */
+inline int channel_idx_from_format(Format format, Channel channel)
+{
+ switch(format)
+ {
+ case Format::RGB888:
+ {
+ switch(channel)
+ {
+ case Channel::R:
+ return 0;
+ case Channel::G:
+ return 1;
+ case Channel::B:
+ return 2;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ case Format::RGBA8888:
+ {
+ switch(channel)
+ {
+ case Channel::R:
+ return 0;
+ case Channel::G:
+ return 1;
+ case Channel::B:
+ return 2;
+ case Channel::A:
+ return 3;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ case Format::YUYV422:
+ {
+ switch(channel)
+ {
+ case Channel::Y:
+ return 0;
+ case Channel::U:
+ return 1;
+ case Channel::V:
+ return 3;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ case Format::UYVY422:
+ {
+ switch(channel)
+ {
+ case Channel::Y:
+ return 1;
+ case Channel::U:
+ return 0;
+ case Channel::V:
+ return 2;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ case Format::NV12:
+ {
+ switch(channel)
+ {
+ case Channel::Y:
+ return 0;
+ case Channel::U:
+ return 0;
+ case Channel::V:
+ return 1;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ case Format::NV21:
+ {
+ switch(channel)
+ {
+ case Channel::Y:
+ return 0;
+ case Channel::U:
+ return 1;
+ case Channel::V:
+ return 0;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ case Format::YUV444:
+ case Format::IYUV:
+ {
+ switch(channel)
+ {
+ case Channel::Y:
+ return 0;
+ case Channel::U:
+ return 0;
+ case Channel::V:
+ return 0;
+ default:
+ ARM_COMPUTE_ERROR("Not supported channel");
+ return 0;
+ }
+ }
+ default:
+ ARM_COMPUTE_ERROR("Not supported format");
+ return 0;
+ }
+}
+
/** Return the number of planes for a given format
*
* @param[in] format Input format
@@ -384,6 +525,28 @@ inline DataType get_promoted_data_type(DataType dt)
return DataType::UNKNOWN;
}
+/** Return true if the given format has horizontal subsampling.
+ *
+ * @param[in] format Format to determine subsampling.
+ *
+ * @return True if the format can be subsampled horizontaly.
+ */
+inline bool has_format_horizontal_subsampling(Format format)
+{
+ return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
+}
+
+/** Return true if the given format has vertical subsampling.
+ *
+ * @param[in] format Format to determine subsampling.
+ *
+ * @return True if the format can be subsampled verticaly.
+ */
+inline bool has_format_vertical_subsampling(Format format)
+{
+ return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
+}
+
/** Separate a 2D convolution into two 1D convolutions
*
* @param[in] conv 2D convolution
@@ -491,6 +654,68 @@ TensorShape calculate_depth_concatenate_shape(const std::vector<T *> &inputs_vec
return out_shape;
}
+/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
+ *
+ * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
+ * Android Source: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java
+ * WebM: https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM
+ * libYUV: https://bugs.chromium.org/p/libyuv/issues/detail?id=198&can=1&q=odd%20width
+ * YUVPlayer: https://sourceforge.net/p/raw-yuvplayer/bugs/1/
+ *
+ * @param[in, out] shape Tensor shape of 2D size
+ * @param[in] format Format of the tensor
+ *
+ */
+inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
+{
+ TensorShape output{ shape };
+
+ // Force width to be even for formats which require subsampling of the U and V channels
+ if(has_format_horizontal_subsampling(format))
+ {
+ output.set(0, output.x() & ~1U);
+ }
+
+ // Force height to be even for formats which require subsampling of the U and V channels
+ if(has_format_vertical_subsampling(format))
+ {
+ output.set(1, output.y() & ~1U);
+ }
+
+ return output;
+}
+
+/** Calculate subsampled shape for a given format and channel
+ *
+ * @param[in] shape Shape of the tensor to calculate the extracted channel.
+ * @param[in] format Format of the tensor.
+ * @param[in] channel Channel to create tensor shape to be extracted.
+ *
+ * @return The subsampled tensor shape.
+ */
+inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
+{
+ TensorShape output{ shape };
+
+ // Subsample shape only for U or V channel
+ if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
+ {
+ // Subsample width for the tensor shape when channel is U or V
+ if(has_format_horizontal_subsampling(format))
+ {
+ output.set(0, output.x() / 2U);
+ }
+
+ // Subsample height for the tensor shape when channel is U or V
+ if(has_format_vertical_subsampling(format))
+ {
+ output.set(1, output.y() / 2U);
+ }
+ }
+
+ return output;
+}
+
/** Calculate accurary required by the horizontal and vertical convolution computations
*
* @param[in] conv_col Pointer to the vertical vector of the separated convolution filter
diff --git a/arm_compute/core/Validate.h b/arm_compute/core/Validate.h
index 79e342c8ae..b04d293c4c 100644
--- a/arm_compute/core/Validate.h
+++ b/arm_compute/core/Validate.h
@@ -271,6 +271,38 @@ arm_compute::Status error_on_mismatching_dimensions(const char *function, const
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(...) \
ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_dimensions(__func__, __FILE__, __LINE__, __VA_ARGS__))
+/** Return an error if the passed tensor objects are not even.
+ *
+ * @param[in] function Function in which the error occurred.
+ * @param[in] file Name of the file where the error occurred.
+ * @param[in] line Line on which the error occurred.
+ * @param[in] format Format to check if odd shape is allowed
+ * @param[in] tensor1 The first object to be compared for odd shape.
+ * @param[in] tensors (Optional) Further allowed objects.
+ *
+ * @return Status
+ */
+template <typename... Ts>
+arm_compute::Status error_on_tensors_not_even(const char *function, const char *file, int line,
+ const Format &format, const ITensor *tensor1, Ts... tensors)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor1 == nullptr, function, file, line);
+ ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensors)...));
+ const std::array < const ITensor *, 1 + sizeof...(Ts) > tensors_info_array{ { tensor1, std::forward<Ts>(tensors)... } };
+ ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensors_info_array.cbegin(), tensors_info_array.cend(), [&](const ITensor * tensor)
+ {
+ const TensorShape correct_shape = adjust_odd_shape(tensor->info()->tensor_shape(), format);
+ return detail::have_different_dimensions(tensor->info()->tensor_shape(), correct_shape, 2);
+ }),
+ function, file, line, "Tensor shape has odd dimensions");
+ return arm_compute::Status{};
+}
+
+#define ARM_COMPUTE_ERROR_ON_TENSORS_NOT_EVEN(...) \
+ ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_tensors_not_even(__func__, __FILE__, __LINE__, __VA_ARGS__))
+#define ARM_COMPUTE_RETURN_ERROR_ON_TENSORS_NOT_EVEN(...) \
+ ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_tensors_not_even(__func__, __FILE__, __LINE__, __VA_ARGS__))
+
/** Return an error if the passed two tensor infos have different shapes from the given dimension
*
* @param[in] function Function in which the error occurred.