| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-FileCopyrightText: 2024 - 2026 Arm Limited and/or its affiliates <open-source-office@arm.com> | ||
| 2 | // | ||
| 3 | // SPDX-License-Identifier: Apache-2.0 | ||
| 4 | |||
| 5 | #ifndef KLEIDICV_WORKSPACE_BLUR_AND_DOWNSAMPLE_WS_H | ||
| 6 | #define KLEIDICV_WORKSPACE_BLUR_AND_DOWNSAMPLE_WS_H | ||
| 7 | |||
| 8 | #include "separable.h" | ||
| 9 | |||
| 10 | namespace KLEIDICV_TARGET_NAMESPACE { | ||
| 11 | |||
| 12 | // Alter SeparableFilterWorkspace's behavior to only process elements in even | ||
| 13 | // rows and columns | ||
| 14 | class BlurAndDownsampleFilterWorkspace final : public SeparableFilterWorkspace { | ||
| 15 | public: | ||
| 16 | // Only constructible with create(). | ||
| 17 | BlurAndDownsampleFilterWorkspace() = delete; | ||
| 18 | |||
| 19 | static std::variant<BlurAndDownsampleFilterWorkspace, kleidicv_error_t> | ||
| 20 | 552 | create(Rectangle rect, size_t channels, | |
| 21 | size_t intermediate_size) KLEIDICV_STREAMING { | ||
| 22 | 1104 | auto [allocation, buffer_rows_stride] = | |
| 23 | 552 | allocate(rect, channels, intermediate_size); | |
| 24 | |||
| 25 |
2/2✓ Branch 0 taken 548 times.
✓ Branch 1 taken 4 times.
|
552 | if (!allocation) { |
| 26 | 4 | return KLEIDICV_ERROR_ALLOCATION; | |
| 27 | } | ||
| 28 | |||
| 29 | 1096 | return BlurAndDownsampleFilterWorkspace{rect, channels, allocation, | |
| 30 | 548 | buffer_rows_stride}; | |
| 31 | 552 | } | |
| 32 | |||
| 33 | private: | ||
| 34 | 548 | BlurAndDownsampleFilterWorkspace(Rectangle rect, size_t channels, | |
| 35 | uint8_t *allocation, | ||
| 36 | size_t buffer_rows_stride) KLEIDICV_STREAMING | ||
| 37 | 1096 | : SeparableFilterWorkspace(rect, channels, allocation, | |
| 38 | 1096 | buffer_rows_stride) {} | |
| 39 | |||
| 40 | public: | ||
| 41 | template <typename FilterType> | ||
| 42 | 548 | void process(size_t y_begin, size_t y_end, | |
| 43 | Rows<const typename FilterType::SourceType> src_rows, | ||
| 44 | Rows<typename FilterType::DestinationType> dst_rows, | ||
| 45 | typename FilterType::BorderType border_type, | ||
| 46 | FilterType filter) KLEIDICV_STREAMING { | ||
| 47 | // Border helper which calculates border offsets. | ||
| 48 | 1096 | typename FilterType::BorderInfoType vertical_border{rect_.height(), | |
| 49 | 548 | border_type}; | |
| 50 | 1096 | typename FilterType::BorderInfoType horizontal_border{rect_.width(), | |
| 51 | 548 | border_type}; | |
| 52 | |||
| 53 | // Buffer rows which hold intermediate widened data. | ||
| 54 | 548 | auto buffer_rows = | |
| 55 | 1096 | Rows{reinterpret_cast<typename FilterType::BufferType *>(buffer_.get()), | |
| 56 | 548 | buffer_rows_stride_, channels_}; | |
| 57 | |||
| 58 | // Vertical processing loop. | ||
| 59 |
2/2✓ Branch 0 taken 548 times.
✓ Branch 1 taken 10044 times.
|
10592 | for (size_t vertical_index = align_up(y_begin, 2); vertical_index < y_end; |
| 60 | 10044 | vertical_index += 2) { | |
| 61 | // Recalculate vertical border offsets. | ||
| 62 | 10044 | auto offsets = vertical_border.offsets_with_border(vertical_index); | |
| 63 | // Process in the vertical direction first. | ||
| 64 | 20088 | filter.process_vertical(rect_.width(), src_rows.at(vertical_index), | |
| 65 | 10044 | buffer_rows, offsets); | |
| 66 | // Process in the horizontal direction last. | ||
| 67 | 20088 | process_horizontal(rect_.width(), buffer_rows, | |
| 68 | 10044 | dst_rows.at(vertical_index / 2), filter, | |
| 69 | 10044 | horizontal_border); | |
| 70 | 10044 | } | |
| 71 | 548 | } | |
| 72 | |||
| 73 | private: | ||
| 74 | template <typename FilterType> | ||
| 75 | 10044 | void process_horizontal(size_t width, | |
| 76 | Rows<typename FilterType::BufferType> buffer_rows, | ||
| 77 | Rows<typename FilterType::DestinationType> dst_rows, | ||
| 78 | FilterType filter, | ||
| 79 | typename FilterType::BorderInfoType horizontal_border) | ||
| 80 | KLEIDICV_STREAMING { | ||
| 81 | // Margin associated with the filter. | ||
| 82 | 10044 | constexpr size_t margin = filter.margin; | |
| 83 | |||
| 84 | // Process data affected by left border. | ||
| 85 | KLEIDICV_FORCE_LOOP_UNROLL | ||
| 86 |
2/2✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 10044 times.
|
20088 | for (size_t horizontal_index = 0; horizontal_index < margin; |
| 87 | 10044 | horizontal_index += 2) { | |
| 88 | 10044 | auto offsets = | |
| 89 | 10044 | horizontal_border.offsets_with_left_border(horizontal_index); | |
| 90 | 20088 | filter.process_horizontal_borders(buffer_rows.at(0, horizontal_index), | |
| 91 | 10044 | dst_rows.at(0, horizontal_index / 2), | |
| 92 | 10044 | offsets); | |
| 93 | 10044 | } | |
| 94 | |||
| 95 | // Process data which is not affected by any borders in bulk. | ||
| 96 | { | ||
| 97 | 10044 | size_t width_without_borders = width - (2 * margin); | |
| 98 | 10044 | auto offsets = horizontal_border.offsets_without_border(); | |
| 99 | 10044 | size_t start = align_up(margin, 2); | |
| 100 | 20088 | filter.process_horizontal(width_without_borders, buffer_rows.at(0, start), | |
| 101 | 10044 | dst_rows.at(0, start / 2), offsets); | |
| 102 | 10044 | } | |
| 103 | |||
| 104 | // Process data affected by right border. | ||
| 105 |
2/2✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 10044 times.
|
20088 | for (size_t index = align_up(width - margin, 2); index < width; |
| 106 | 10044 | index += 2) { | |
| 107 | 10044 | auto offsets = horizontal_border.offsets_with_right_border(index); | |
| 108 | 20088 | filter.process_horizontal_borders(buffer_rows.at(0, index), | |
| 109 | 10044 | dst_rows.at(0, index / 2), offsets); | |
| 110 | 10044 | } | |
| 111 | 10044 | } | |
| 112 | }; // end of class BlurAndDownsampleFilterWorkspace | ||
| 113 | |||
| 114 | } // namespace KLEIDICV_TARGET_NAMESPACE | ||
| 115 | |||
| 116 | #endif // KLEIDICV_WORKSPACE_BLUR_AND_DOWNSAMPLE_WS_H | ||
| 117 |