Line | Branch | Exec | Source |
---|---|---|---|
1 | // SPDX-FileCopyrightText: 2024 - 2025 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 | template <typename FilterType> | ||
17 | 129 | void process(Rectangle rect, size_t y_begin, size_t y_end, | |
18 | Rows<const typename FilterType::SourceType> src_rows, | ||
19 | Rows<typename FilterType::DestinationType> dst_rows, | ||
20 | size_t channels, typename FilterType::BorderType border_type, | ||
21 | FilterType filter) KLEIDICV_STREAMING { | ||
22 | // Border helper which calculates border offsets. | ||
23 | 258 | typename FilterType::BorderInfoType vertical_border{rect.height(), | |
24 | 129 | border_type}; | |
25 | 258 | typename FilterType::BorderInfoType horizontal_border{rect.width(), | |
26 | 129 | border_type}; | |
27 | |||
28 | // Buffer rows which hold intermediate widened data. | ||
29 | 258 | auto buffer_rows = Rows{reinterpret_cast<typename FilterType::BufferType *>( | |
30 | 129 | &data_[buffer_rows_offset_]), | |
31 | 129 | buffer_rows_stride_, channels}; | |
32 | |||
33 | // Vertical processing loop. | ||
34 |
2/2✓ Branch 0 taken 129 times.
✓ Branch 1 taken 1281 times.
|
1410 | for (size_t vertical_index = y_begin; vertical_index < y_end; |
35 | 1281 | vertical_index += 2) { | |
36 | // Recalculate vertical border offsets. | ||
37 | 1281 | auto offsets = vertical_border.offsets_with_border(vertical_index); | |
38 | // Process in the vertical direction first. | ||
39 | 2562 | filter.process_vertical(rect.width(), src_rows.at(vertical_index), | |
40 | 1281 | buffer_rows, offsets); | |
41 | // Process in the horizontal direction last. | ||
42 | 2562 | process_horizontal(rect.width(), buffer_rows, | |
43 | 1281 | dst_rows.at(vertical_index / 2), filter, | |
44 | 1281 | horizontal_border); | |
45 | 1281 | } | |
46 | 129 | } | |
47 | |||
48 | private: | ||
49 | template <typename FilterType> | ||
50 | 1281 | void process_horizontal(size_t width, | |
51 | Rows<typename FilterType::BufferType> buffer_rows, | ||
52 | Rows<typename FilterType::DestinationType> dst_rows, | ||
53 | FilterType filter, | ||
54 | typename FilterType::BorderInfoType horizontal_border) | ||
55 | KLEIDICV_STREAMING { | ||
56 | // Margin associated with the filter. | ||
57 | 1281 | constexpr size_t margin = filter.margin; | |
58 | |||
59 | // Process data affected by left border. | ||
60 | KLEIDICV_FORCE_LOOP_UNROLL | ||
61 |
2/2✓ Branch 0 taken 1281 times.
✓ Branch 1 taken 1281 times.
|
2562 | for (size_t horizontal_index = 0; horizontal_index < margin; |
62 | 1281 | horizontal_index += 2) { | |
63 | 1281 | auto offsets = | |
64 | 1281 | horizontal_border.offsets_with_left_border(horizontal_index); | |
65 | 2562 | filter.process_horizontal_borders(buffer_rows.at(0, horizontal_index), | |
66 | 1281 | dst_rows.at(0, horizontal_index / 2), | |
67 | 1281 | offsets); | |
68 | 1281 | } | |
69 | |||
70 | // Process data which is not affected by any borders in bulk. | ||
71 | { | ||
72 | 1281 | size_t width_without_borders = width - (2 * margin); | |
73 | 1281 | auto offsets = horizontal_border.offsets_without_border(); | |
74 | 1281 | size_t start = align_up(margin, 2); | |
75 | 2562 | filter.process_horizontal(width_without_borders, buffer_rows.at(0, start), | |
76 | 1281 | dst_rows.at(0, start / 2), offsets); | |
77 | 1281 | } | |
78 | |||
79 | // Process data affected by right border. | ||
80 |
2/2✓ Branch 0 taken 1281 times.
✓ Branch 1 taken 1281 times.
|
2562 | for (size_t index = align_up(width - margin, 2); index < width; |
81 | 1281 | index += 2) { | |
82 | 1281 | auto offsets = horizontal_border.offsets_with_right_border(index); | |
83 | 2562 | filter.process_horizontal_borders(buffer_rows.at(0, index), | |
84 | 1281 | dst_rows.at(0, index / 2), offsets); | |
85 | 1281 | } | |
86 | 1281 | } | |
87 | }; // end of class BlurAndDownsampleFilterWorkspace | ||
88 | |||
89 | // BlurAndDownsampleFilterWorkspace and SeparableFilterWorkspace must have the | ||
90 | // same size because through the API of this library only | ||
91 | // SeparableFilterWorkspace can be created. So, child classes of | ||
92 | // SeparableFilterWorkspace can only add functionality but cannot add member | ||
93 | // variables. | ||
94 | static_assert(sizeof(BlurAndDownsampleFilterWorkspace) == | ||
95 | sizeof(SeparableFilterWorkspace)); | ||
96 | |||
97 | } // namespace KLEIDICV_TARGET_NAMESPACE | ||
98 | |||
99 | #endif // KLEIDICV_WORKSPACE_BLUR_AND_DOWNSAMPLE_WS_H | ||
100 |