1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/post_filter.h"
16
17 #include <algorithm>
18 #include <atomic>
19 #include <cassert>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23
24 #include "src/dsp/constants.h"
25 #include "src/dsp/dsp.h"
26 #include "src/utils/array_2d.h"
27 #include "src/utils/blocking_counter.h"
28 #include "src/utils/common.h"
29 #include "src/utils/constants.h"
30 #include "src/utils/memory.h"
31 #include "src/utils/types.h"
32
33 namespace libgav1 {
34 namespace {
35
36 // Import all the constants in the anonymous namespace.
37 #include "src/post_filter/deblock_thresholds.inc"
38
39 // Row indices of loop restoration border. This is used to populate the
40 // |loop_restoration_border_| when either cdef is on or multithreading is
41 // enabled. The dimension is subsampling_y.
42 constexpr int kLoopRestorationBorderRows[2] = {54, 26};
43
44 } // namespace
45
46 // The following example illustrates how ExtendFrame() extends a frame.
47 // Suppose the frame width is 8 and height is 4, and left, right, top, and
48 // bottom are all equal to 3.
49 //
50 // Before:
51 //
52 // ABCDEFGH
53 // IJKLMNOP
54 // QRSTUVWX
55 // YZabcdef
56 //
57 // After:
58 //
59 // AAA|ABCDEFGH|HHH [3]
60 // AAA|ABCDEFGH|HHH
61 // AAA|ABCDEFGH|HHH
62 // ---+--------+---
63 // AAA|ABCDEFGH|HHH [1]
64 // III|IJKLMNOP|PPP
65 // QQQ|QRSTUVWX|XXX
66 // YYY|YZabcdef|fff
67 // ---+--------+---
68 // YYY|YZabcdef|fff [2]
69 // YYY|YZabcdef|fff
70 // YYY|YZabcdef|fff
71 //
72 // ExtendFrame() first extends the rows to the left and to the right[1]. Then
73 // it copies the extended last row to the bottom borders[2]. Finally it copies
74 // the extended first row to the top borders[3].
75 // static
76 template <typename Pixel>
ExtendFrame(Pixel * const frame_start,const int width,const int height,const ptrdiff_t stride,const int left,const int right,const int top,const int bottom)77 void PostFilter::ExtendFrame(Pixel* const frame_start, const int width,
78 const int height, const ptrdiff_t stride,
79 const int left, const int right, const int top,
80 const int bottom) {
81 Pixel* src = frame_start;
82 // Copy to left and right borders.
83 int y = height;
84 do {
85 ExtendLine<Pixel>(src, width, left, right);
86 src += stride;
87 } while (--y != 0);
88 // Copy to bottom borders. For performance we copy |stride| pixels
89 // (including some padding pixels potentially) in each row, ending at the
90 // bottom right border pixel. In the diagram the asterisks indicate padding
91 // pixels.
92 //
93 // |<--- stride --->|
94 // **YYY|YZabcdef|fff <-- Copy from the extended last row.
95 // -----+--------+---
96 // **YYY|YZabcdef|fff
97 // **YYY|YZabcdef|fff
98 // **YYY|YZabcdef|fff <-- bottom right border pixel
99 assert(src == frame_start + height * stride);
100 Pixel* dst = src - left;
101 src = dst - stride;
102 for (int y = 0; y < bottom; ++y) {
103 memcpy(dst, src, sizeof(Pixel) * stride);
104 dst += stride;
105 }
106 // Copy to top borders. For performance we copy |stride| pixels (including
107 // some padding pixels potentially) in each row, starting from the top left
108 // border pixel. In the diagram the asterisks indicate padding pixels.
109 //
110 // +-- top left border pixel
111 // |
112 // v
113 // AAA|ABCDEFGH|HHH**
114 // AAA|ABCDEFGH|HHH**
115 // AAA|ABCDEFGH|HHH**
116 // ---+--------+-----
117 // AAA|ABCDEFGH|HHH** <-- Copy from the extended first row.
118 // |<--- stride --->|
119 src = frame_start - left;
120 dst = frame_start - left - top * stride;
121 for (int y = 0; y < top; ++y) {
122 memcpy(dst, src, sizeof(Pixel) * stride);
123 dst += stride;
124 }
125 }
126
127 template void PostFilter::ExtendFrame<uint8_t>(uint8_t* const frame_start,
128 const int width,
129 const int height,
130 const ptrdiff_t stride,
131 const int left, const int right,
132 const int top, const int bottom);
133
134 #if LIBGAV1_MAX_BITDEPTH >= 10
135 template void PostFilter::ExtendFrame<uint16_t>(
136 uint16_t* const frame_start, const int width, const int height,
137 const ptrdiff_t stride, const int left, const int right, const int top,
138 const int bottom);
139 #endif
140
PostFilter(const ObuFrameHeader & frame_header,const ObuSequenceHeader & sequence_header,FrameScratchBuffer * const frame_scratch_buffer,YuvBuffer * const frame_buffer,const dsp::Dsp * dsp,int do_post_filter_mask)141 PostFilter::PostFilter(const ObuFrameHeader& frame_header,
142 const ObuSequenceHeader& sequence_header,
143 FrameScratchBuffer* const frame_scratch_buffer,
144 YuvBuffer* const frame_buffer, const dsp::Dsp* dsp,
145 int do_post_filter_mask)
146 : frame_header_(frame_header),
147 loop_restoration_(frame_header.loop_restoration),
148 dsp_(*dsp),
149 // Deblocking filter always uses 64x64 as step size.
150 num_64x64_blocks_per_row_(DivideBy64(frame_header.width + 63)),
151 upscaled_width_(frame_header.upscaled_width),
152 width_(frame_header.width),
153 height_(frame_header.height),
154 bitdepth_(sequence_header.color_config.bitdepth),
155 subsampling_x_{0, sequence_header.color_config.subsampling_x,
156 sequence_header.color_config.subsampling_x},
157 subsampling_y_{0, sequence_header.color_config.subsampling_y,
158 sequence_header.color_config.subsampling_y},
159 planes_(sequence_header.color_config.is_monochrome ? kMaxPlanesMonochrome
160 : kMaxPlanes),
161 pixel_size_log2_(static_cast<int>((bitdepth_ == 8) ? sizeof(uint8_t)
162 : sizeof(uint16_t)) -
163 1),
164 inner_thresh_(kInnerThresh[frame_header.loop_filter.sharpness]),
165 outer_thresh_(kOuterThresh[frame_header.loop_filter.sharpness]),
166 needs_chroma_deblock_(frame_header.loop_filter.level[kPlaneU + 1] != 0 ||
167 frame_header.loop_filter.level[kPlaneV + 1] != 0),
168 cdef_index_(frame_scratch_buffer->cdef_index),
169 inter_transform_sizes_(frame_scratch_buffer->inter_transform_sizes),
170 restoration_info_(&frame_scratch_buffer->loop_restoration_info),
171 superres_coefficients_{
172 frame_scratch_buffer->superres_coefficients[kPlaneTypeY].get(),
173 frame_scratch_buffer
174 ->superres_coefficients
175 [(sequence_header.color_config.is_monochrome ||
176 sequence_header.color_config.subsampling_x == 0)
177 ? kPlaneTypeY
178 : kPlaneTypeUV]
179 .get()},
180 superres_line_buffer_(frame_scratch_buffer->superres_line_buffer),
181 block_parameters_(frame_scratch_buffer->block_parameters_holder),
182 frame_buffer_(*frame_buffer),
183 cdef_border_(frame_scratch_buffer->cdef_border),
184 loop_restoration_border_(frame_scratch_buffer->loop_restoration_border),
185 do_post_filter_mask_(do_post_filter_mask),
186 thread_pool_(
187 frame_scratch_buffer->threading_strategy.post_filter_thread_pool()) {
188 const int8_t zero_delta_lf[kFrameLfCount] = {};
189 ComputeDeblockFilterLevels(zero_delta_lf, deblock_filter_levels_);
190 if (DoSuperRes()) {
191 int plane = kPlaneY;
192 do {
193 const int downscaled_width =
194 SubsampledValue(width_, subsampling_x_[plane]);
195 const int upscaled_width =
196 SubsampledValue(upscaled_width_, subsampling_x_[plane]);
197 const int superres_width = downscaled_width << kSuperResScaleBits;
198 super_res_info_[plane].step =
199 (superres_width + upscaled_width / 2) / upscaled_width;
200 const int error =
201 super_res_info_[plane].step * upscaled_width - superres_width;
202 super_res_info_[plane].initial_subpixel_x =
203 ((-((upscaled_width - downscaled_width) << (kSuperResScaleBits - 1)) +
204 DivideBy2(upscaled_width)) /
205 upscaled_width +
206 (1 << (kSuperResExtraBits - 1)) - error / 2) &
207 kSuperResScaleMask;
208 super_res_info_[plane].upscaled_width = upscaled_width;
209 } while (++plane < planes_);
210 if (dsp->super_res_coefficients != nullptr) {
211 int plane = kPlaneY;
212 const int number_loops = (superres_coefficients_[kPlaneTypeY] ==
213 superres_coefficients_[kPlaneTypeUV])
214 ? kMaxPlanesMonochrome
215 : static_cast<int>(kNumPlaneTypes);
216 do {
217 dsp->super_res_coefficients(
218 SubsampledValue(upscaled_width_, subsampling_x_[plane]),
219 super_res_info_[plane].initial_subpixel_x,
220 super_res_info_[plane].step, superres_coefficients_[plane]);
221 } while (++plane < number_loops);
222 }
223 }
224 int plane = kPlaneY;
225 do {
226 loop_restoration_buffer_[plane] = frame_buffer_.data(plane);
227 cdef_buffer_[plane] = frame_buffer_.data(plane);
228 superres_buffer_[plane] = frame_buffer_.data(plane);
229 source_buffer_[plane] = frame_buffer_.data(plane);
230 } while (++plane < planes_);
231 if (DoCdef() || DoRestoration() || DoSuperRes()) {
232 plane = kPlaneY;
233 const int pixel_size_log2 = pixel_size_log2_;
234 do {
235 int horizontal_shift = 0;
236 int vertical_shift = 0;
237 if (DoRestoration() &&
238 loop_restoration_.type[plane] != kLoopRestorationTypeNone) {
239 horizontal_shift += frame_buffer_.alignment();
240 if (!DoCdef() && thread_pool_ == nullptr) {
241 vertical_shift += kRestorationVerticalBorder;
242 }
243 superres_buffer_[plane] +=
244 vertical_shift * frame_buffer_.stride(plane) +
245 (horizontal_shift << pixel_size_log2);
246 }
247 if (DoSuperRes()) {
248 vertical_shift += kSuperResVerticalBorder;
249 }
250 cdef_buffer_[plane] += vertical_shift * frame_buffer_.stride(plane) +
251 (horizontal_shift << pixel_size_log2);
252 if (DoCdef() && thread_pool_ == nullptr) {
253 horizontal_shift += frame_buffer_.alignment();
254 vertical_shift += kCdefBorder;
255 }
256 assert(horizontal_shift <= frame_buffer_.right_border(plane));
257 assert(vertical_shift <= frame_buffer_.bottom_border(plane));
258 source_buffer_[plane] += vertical_shift * frame_buffer_.stride(plane) +
259 (horizontal_shift << pixel_size_log2);
260 } while (++plane < planes_);
261 }
262 }
263
ExtendFrameBoundary(uint8_t * const frame_start,const int width,const int height,const ptrdiff_t stride,const int left,const int right,const int top,const int bottom) const264 void PostFilter::ExtendFrameBoundary(uint8_t* const frame_start,
265 const int width, const int height,
266 const ptrdiff_t stride, const int left,
267 const int right, const int top,
268 const int bottom) const {
269 #if LIBGAV1_MAX_BITDEPTH >= 10
270 if (bitdepth_ >= 10) {
271 ExtendFrame<uint16_t>(reinterpret_cast<uint16_t*>(frame_start), width,
272 height, stride / sizeof(uint16_t), left, right, top,
273 bottom);
274 return;
275 }
276 #endif
277 ExtendFrame<uint8_t>(frame_start, width, height, stride, left, right, top,
278 bottom);
279 }
280
ExtendBordersForReferenceFrame()281 void PostFilter::ExtendBordersForReferenceFrame() {
282 if (frame_header_.refresh_frame_flags == 0) return;
283 int plane = kPlaneY;
284 do {
285 const int plane_width =
286 SubsampledValue(upscaled_width_, subsampling_x_[plane]);
287 const int plane_height = SubsampledValue(height_, subsampling_y_[plane]);
288 assert(frame_buffer_.left_border(plane) >= kMinLeftBorderPixels &&
289 frame_buffer_.right_border(plane) >= kMinRightBorderPixels &&
290 frame_buffer_.top_border(plane) >= kMinTopBorderPixels &&
291 frame_buffer_.bottom_border(plane) >= kMinBottomBorderPixels);
292 // plane subsampling_x_ left_border
293 // Y N/A 64, 48
294 // U,V 0 64, 48
295 // U,V 1 32, 16
296 assert(frame_buffer_.left_border(plane) >= 16);
297 // The |left| argument to ExtendFrameBoundary() must be at least
298 // kMinLeftBorderPixels (13) for warp.
299 static_assert(16 >= kMinLeftBorderPixels, "");
300 ExtendFrameBoundary(
301 frame_buffer_.data(plane), plane_width, plane_height,
302 frame_buffer_.stride(plane), frame_buffer_.left_border(plane),
303 frame_buffer_.right_border(plane), frame_buffer_.top_border(plane),
304 frame_buffer_.bottom_border(plane));
305 } while (++plane < planes_);
306 }
307
CopyDeblockedPixels(Plane plane,int row4x4)308 void PostFilter::CopyDeblockedPixels(Plane plane, int row4x4) {
309 const ptrdiff_t src_stride = frame_buffer_.stride(plane);
310 const uint8_t* const src = GetSourceBuffer(plane, row4x4, 0);
311 const int row_offset = DivideBy4(row4x4);
312 const ptrdiff_t dst_stride = loop_restoration_border_.stride(plane);
313 uint8_t* dst = loop_restoration_border_.data(plane) + row_offset * dst_stride;
314 const int num_pixels = SubsampledValue(MultiplyBy4(frame_header_.columns4x4),
315 subsampling_x_[plane]);
316 const int row_width = num_pixels << pixel_size_log2_;
317 int last_valid_row = -1;
318 const int plane_height =
319 SubsampledValue(frame_header_.height, subsampling_y_[plane]);
320 int row = kLoopRestorationBorderRows[subsampling_y_[plane]];
321 const int absolute_row = (MultiplyBy4(row4x4) >> subsampling_y_[plane]) + row;
322 for (int i = 0; i < 4; ++i, ++row) {
323 if (absolute_row + i >= plane_height) {
324 if (last_valid_row == -1) break;
325 // If we run out of rows, copy the last valid row (mimics the bottom
326 // border extension).
327 row = last_valid_row;
328 }
329 memcpy(dst, src + row * src_stride, row_width);
330 last_valid_row = row;
331 dst += dst_stride;
332 }
333 }
334
CopyBordersForOneSuperBlockRow(int row4x4,int sb4x4,bool for_loop_restoration)335 void PostFilter::CopyBordersForOneSuperBlockRow(int row4x4, int sb4x4,
336 bool for_loop_restoration) {
337 // Number of rows to be subtracted from the start position described by
338 // row4x4. We always lag by 8 rows (to account for in-loop post filters).
339 const int row_offset = (row4x4 == 0) ? 0 : 8;
340 // Number of rows to be subtracted from the height described by sb4x4.
341 const int height_offset = (row4x4 == 0) ? 8 : 0;
342 // If cdef is off and post filter multithreading is off, then loop restoration
343 // needs 2 extra rows for the bottom border in each plane.
344 const int extra_rows =
345 (for_loop_restoration && thread_pool_ == nullptr && !DoCdef()) ? 2 : 0;
346 int plane = kPlaneY;
347 do {
348 const int plane_width =
349 SubsampledValue(upscaled_width_, subsampling_x_[plane]);
350 const int plane_height = SubsampledValue(height_, subsampling_y_[plane]);
351 const int row = (MultiplyBy4(row4x4) - row_offset) >> subsampling_y_[plane];
352 assert(row >= 0);
353 if (row >= plane_height) break;
354 const int num_rows =
355 std::min(SubsampledValue(MultiplyBy4(sb4x4) - height_offset,
356 subsampling_y_[plane]) +
357 extra_rows,
358 plane_height - row);
359 // We only need to track the progress of the Y plane since the progress of
360 // the U and V planes will be inferred from the progress of the Y plane.
361 if (!for_loop_restoration && plane == kPlaneY) {
362 progress_row_ = row + num_rows;
363 }
364 const bool copy_bottom = row + num_rows == plane_height;
365 const int stride = frame_buffer_.stride(plane);
366 uint8_t* const start = (for_loop_restoration ? superres_buffer_[plane]
367 : frame_buffer_.data(plane)) +
368 row * stride;
369 const int left_border = for_loop_restoration
370 ? kRestorationHorizontalBorder
371 : frame_buffer_.left_border(plane);
372 const int right_border = for_loop_restoration
373 ? kRestorationHorizontalBorder
374 : frame_buffer_.right_border(plane);
375 const int top_border =
376 (row == 0) ? (for_loop_restoration ? kRestorationVerticalBorder
377 : frame_buffer_.top_border(plane))
378 : 0;
379 const int bottom_border =
380 copy_bottom
381 ? (for_loop_restoration ? kRestorationVerticalBorder
382 : frame_buffer_.bottom_border(plane))
383 : 0;
384 ExtendFrameBoundary(start, plane_width, num_rows, stride, left_border,
385 right_border, top_border, bottom_border);
386 } while (++plane < planes_);
387 }
388
SetupLoopRestorationBorder(const int row4x4)389 void PostFilter::SetupLoopRestorationBorder(const int row4x4) {
390 assert(row4x4 >= 0);
391 assert(!DoCdef());
392 assert(DoRestoration());
393 int plane = kPlaneY;
394 do {
395 if (loop_restoration_.type[plane] == kLoopRestorationTypeNone) {
396 continue;
397 }
398 const int row_offset = DivideBy4(row4x4);
399 const int num_pixels =
400 SubsampledValue(upscaled_width_, subsampling_x_[plane]);
401 const int row_width = num_pixels << pixel_size_log2_;
402 const int plane_height = SubsampledValue(height_, subsampling_y_[plane]);
403 const int row = kLoopRestorationBorderRows[subsampling_y_[plane]];
404 const int absolute_row =
405 (MultiplyBy4(row4x4) >> subsampling_y_[plane]) + row;
406 const ptrdiff_t src_stride = frame_buffer_.stride(plane);
407 const uint8_t* src =
408 GetSuperResBuffer(static_cast<Plane>(plane), row4x4, 0) +
409 row * src_stride;
410 const ptrdiff_t dst_stride = loop_restoration_border_.stride(plane);
411 uint8_t* dst =
412 loop_restoration_border_.data(plane) + row_offset * dst_stride;
413 for (int i = 0; i < 4; ++i) {
414 memcpy(dst, src, row_width);
415 #if LIBGAV1_MAX_BITDEPTH >= 10
416 if (bitdepth_ >= 10) {
417 ExtendLine<uint16_t>(dst, num_pixels, kRestorationHorizontalBorder,
418 kRestorationHorizontalBorder);
419 } else // NOLINT.
420 #endif
421 ExtendLine<uint8_t>(dst, num_pixels, kRestorationHorizontalBorder,
422 kRestorationHorizontalBorder);
423 // If we run out of rows, copy the last valid row (mimics the bottom
424 // border extension).
425 if (absolute_row + i < plane_height - 1) src += src_stride;
426 dst += dst_stride;
427 }
428 } while (++plane < planes_);
429 }
430
SetupLoopRestorationBorder(int row4x4_start,int sb4x4)431 void PostFilter::SetupLoopRestorationBorder(int row4x4_start, int sb4x4) {
432 assert(row4x4_start >= 0);
433 assert(DoCdef());
434 assert(DoRestoration());
435 for (int sb_y = 0; sb_y < sb4x4; sb_y += 16) {
436 const int row4x4 = row4x4_start + sb_y;
437 const int row_offset_start = DivideBy4(row4x4);
438 const std::array<uint8_t*, kMaxPlanes> dst = {
439 loop_restoration_border_.data(kPlaneY) +
440 row_offset_start * loop_restoration_border_.stride(kPlaneY),
441 loop_restoration_border_.data(kPlaneU) +
442 row_offset_start * loop_restoration_border_.stride(kPlaneU),
443 loop_restoration_border_.data(kPlaneV) +
444 row_offset_start * loop_restoration_border_.stride(kPlaneV)};
445 // If SuperRes is enabled, then we apply SuperRes for the rows to be copied
446 // directly with |loop_restoration_border_| as the destination. Otherwise,
447 // we simply copy the rows.
448 if (DoSuperRes()) {
449 std::array<uint8_t*, kMaxPlanes> src;
450 std::array<int, kMaxPlanes> rows;
451 int plane = kPlaneY;
452 do {
453 if (loop_restoration_.type[plane] == kLoopRestorationTypeNone) {
454 rows[plane] = 0;
455 continue;
456 }
457 const int plane_height =
458 SubsampledValue(frame_header_.height, subsampling_y_[plane]);
459 const int row = kLoopRestorationBorderRows[subsampling_y_[plane]];
460 const int absolute_row =
461 (MultiplyBy4(row4x4) >> subsampling_y_[plane]) + row;
462 src[plane] = GetSourceBuffer(static_cast<Plane>(plane), row4x4, 0) +
463 row * frame_buffer_.stride(plane);
464 rows[plane] = Clip3(plane_height - absolute_row, 0, 4);
465 } while (++plane < planes_);
466 ApplySuperRes(src, rows, /*line_buffer_row=*/-1, dst,
467 /*dst_is_loop_restoration_border=*/true);
468 // If we run out of rows, copy the last valid row (mimics the bottom
469 // border extension).
470 plane = kPlaneY;
471 do {
472 if (rows[plane] == 0 || rows[plane] >= 4) continue;
473 const ptrdiff_t stride = loop_restoration_border_.stride(plane);
474 uint8_t* dst_line = dst[plane] + rows[plane] * stride;
475 const uint8_t* const src_line = dst_line - stride;
476 const int upscaled_width = super_res_info_[plane].upscaled_width
477 << pixel_size_log2_;
478 for (int i = rows[plane]; i < 4; ++i) {
479 memcpy(dst_line, src_line, upscaled_width);
480 dst_line += stride;
481 }
482 } while (++plane < planes_);
483 } else {
484 int plane = kPlaneY;
485 do {
486 CopyDeblockedPixels(static_cast<Plane>(plane), row4x4);
487 } while (++plane < planes_);
488 }
489 // Extend the left and right boundaries needed for loop restoration.
490 int plane = kPlaneY;
491 do {
492 if (loop_restoration_.type[plane] == kLoopRestorationTypeNone) {
493 continue;
494 }
495 uint8_t* dst_line = dst[plane];
496 const int plane_width =
497 SubsampledValue(upscaled_width_, subsampling_x_[plane]);
498 for (int i = 0; i < 4; ++i) {
499 #if LIBGAV1_MAX_BITDEPTH >= 10
500 if (bitdepth_ >= 10) {
501 ExtendLine<uint16_t>(dst_line, plane_width,
502 kRestorationHorizontalBorder,
503 kRestorationHorizontalBorder);
504 } else // NOLINT.
505 #endif
506 {
507 ExtendLine<uint8_t>(dst_line, plane_width,
508 kRestorationHorizontalBorder,
509 kRestorationHorizontalBorder);
510 }
511 dst_line += loop_restoration_border_.stride(plane);
512 }
513 } while (++plane < planes_);
514 }
515 }
516
RunJobs(WorkerFunction worker)517 void PostFilter::RunJobs(WorkerFunction worker) {
518 std::atomic<int> row4x4(0);
519 const int num_workers = thread_pool_->num_threads();
520 BlockingCounter pending_workers(num_workers);
521 for (int i = 0; i < num_workers; ++i) {
522 thread_pool_->Schedule([this, &row4x4, &pending_workers, worker]() {
523 (this->*worker)(&row4x4);
524 pending_workers.Decrement();
525 });
526 }
527 // Run the jobs on the current thread.
528 (this->*worker)(&row4x4);
529 // Wait for the threadpool jobs to finish.
530 pending_workers.Wait();
531 }
532
ApplyFilteringThreaded()533 void PostFilter::ApplyFilteringThreaded() {
534 if (DoDeblock()) {
535 RunJobs(&PostFilter::DeblockFilterWorker<kLoopFilterTypeVertical>);
536 RunJobs(&PostFilter::DeblockFilterWorker<kLoopFilterTypeHorizontal>);
537 }
538 if (DoCdef() && DoRestoration()) {
539 for (int row4x4 = 0; row4x4 < frame_header_.rows4x4;
540 row4x4 += kNum4x4InLoopFilterUnit) {
541 SetupLoopRestorationBorder(row4x4, kNum4x4InLoopFilterUnit);
542 }
543 }
544 if (DoCdef()) {
545 for (int row4x4 = 0; row4x4 < frame_header_.rows4x4;
546 row4x4 += kNum4x4InLoopFilterUnit) {
547 SetupCdefBorder(row4x4);
548 }
549 RunJobs(&PostFilter::ApplyCdefWorker);
550 }
551 if (DoSuperRes()) ApplySuperResThreaded();
552 if (DoRestoration()) {
553 if (!DoCdef()) {
554 int row4x4 = 0;
555 do {
556 SetupLoopRestorationBorder(row4x4);
557 row4x4 += kNum4x4InLoopFilterUnit;
558 } while (row4x4 < frame_header_.rows4x4);
559 }
560 RunJobs(&PostFilter::ApplyLoopRestorationWorker);
561 }
562 ExtendBordersForReferenceFrame();
563 }
564
ApplyFilteringForOneSuperBlockRow(int row4x4,int sb4x4,bool is_last_row,bool do_deblock)565 int PostFilter::ApplyFilteringForOneSuperBlockRow(int row4x4, int sb4x4,
566 bool is_last_row,
567 bool do_deblock) {
568 if (row4x4 < 0) return -1;
569 if (DoDeblock() && do_deblock) {
570 ApplyDeblockFilterForOneSuperBlockRow(row4x4, sb4x4);
571 }
572 if (DoRestoration() && DoCdef()) {
573 SetupLoopRestorationBorder(row4x4, sb4x4);
574 }
575 if (DoCdef()) {
576 ApplyCdefForOneSuperBlockRow(row4x4, sb4x4, is_last_row);
577 }
578 if (DoSuperRes()) {
579 ApplySuperResForOneSuperBlockRow(row4x4, sb4x4, is_last_row);
580 }
581 if (DoRestoration()) {
582 CopyBordersForOneSuperBlockRow(row4x4, sb4x4, true);
583 ApplyLoopRestoration(row4x4, sb4x4);
584 if (is_last_row) {
585 // Loop restoration operates with a lag of 8 rows. So make sure to cover
586 // all the rows of the last superblock row.
587 CopyBordersForOneSuperBlockRow(row4x4 + sb4x4, 16, true);
588 ApplyLoopRestoration(row4x4 + sb4x4, 16);
589 }
590 }
591 if (frame_header_.refresh_frame_flags != 0 && DoBorderExtensionInLoop()) {
592 CopyBordersForOneSuperBlockRow(row4x4, sb4x4, false);
593 if (is_last_row) {
594 CopyBordersForOneSuperBlockRow(row4x4 + sb4x4, 16, false);
595 }
596 }
597 if (is_last_row && !DoBorderExtensionInLoop()) {
598 ExtendBordersForReferenceFrame();
599 }
600 return is_last_row ? height_ : progress_row_;
601 }
602
603 } // namespace libgav1
604