Commit 4a8ea86713 for aom
commit 4a8ea86713ded9624a0632c8644370cef4b6ef21
Author: Ihor Buhaiov <freedbrt@gmail.com>
Date: Sat Oct 10 19:42:31 2026 +0200
Remove the per SB exit check in loop filter rows
In the horizontal pass, av1_thread_loop_filter_rows() locked the shared
job_mutex for every superblock only to read lf_mt_exit. With row
multithreading every worker takes that lock thousands of times per frame
and the workers wait on each other.
On error, av1_set_vert_loop_filter_done() now writes LF_SYNC_EXIT into
the column counter of every row, under the row mutex, and wakes the
waiting workers. sync_read() already holds that mutex, so it reports
the exit and the horizontal pass stops. sync_write() keeps the larger
value, so the exit value stays.
This applies to every multithreaded loop filter run, in the encoder and
the decoder. The output does not change.
Encode time saved, screen recordings at RT speed 11 with 64x64
superblocks, aq mode 0 and the loop filter on every frame, median of
paired runs. 0.0% is within the noise. With the default 128x128
superblocks or when cyclic refresh turns the loop filter off, the
change is much smaller.
2 thr 4 thr 8 thr 12 thr
Apple M3 Pro, macOS
2560x1440, active map 0.0% 8.3% 10.7% 7.1%
2559x1372, active map 3.5% 6.5% 8.1% 6.9%
2560x1440, no map 0.0% 0.0% 4.1% 8.8%
2559x1372, no map 0.0% 0.0% 5.4% 8.5%
Ryzen 9 5900X, Windows
2560x1440, active map 0.0% 0.0% 4.2% 4.6%
2559x1372, active map 0.0% 0.0% 3.1% 3.9%
2560x1440, no map 0.0% 0.0% 3.5% 4.0%
2559x1372, no map 0.0% 0.0% 2.2% 2.4%
Change-Id: I7278541d130e13433ed7cdc2c931332fd183df20
diff --git a/av1/common/thread_common.c b/av1/common/thread_common.c
index dee45b44c2..975c0902f8 100644
--- a/av1/common/thread_common.c
+++ b/av1/common/thread_common.c
@@ -10,6 +10,7 @@
*/
#include <assert.h>
+#include <limits.h>
#include "aom/aom_image.h"
#include "config/aom_config.h"
@@ -204,8 +205,16 @@ static inline void cdef_row_mt_sync_write(AV1CdefSync *const cdef_sync,
#endif // CONFIG_MULTITHREAD
}
-static inline void sync_read(AV1LfSync *const lf_sync, int r, int c,
+// Value of cur_sb_col[plane][r] after a worker has encountered an error. It
+// wakes up the workers waiting in sync_read() and tells them to exit.
+#define LF_SYNC_EXIT INT_MAX
+
+// Returns true if the sync read is successful and the caller can continue.
+// Returns false if the caller should exit because a worker has encountered an
+// error.
+static inline bool sync_read(AV1LfSync *const lf_sync, int r, int c,
int plane) {
+ bool lf_mt_continue = true;
#if CONFIG_MULTITHREAD
const int nsync = lf_sync->sync_range;
@@ -216,6 +225,7 @@ static inline void sync_read(AV1LfSync *const lf_sync, int r, int c,
while (c > lf_sync->cur_sb_col[plane][r - 1] - nsync) {
pthread_cond_wait(&lf_sync->cond_[plane][r - 1], mutex);
}
+ lf_mt_continue = lf_sync->cur_sb_col[plane][r - 1] != LF_SYNC_EXIT;
pthread_mutex_unlock(mutex);
}
#else
@@ -224,6 +234,7 @@ static inline void sync_read(AV1LfSync *const lf_sync, int r, int c,
(void)c;
(void)plane;
#endif // CONFIG_MULTITHREAD
+ return lf_mt_continue;
}
static inline void sync_write(AV1LfSync *const lf_sync, int r, int c,
@@ -244,11 +255,9 @@ static inline void sync_write(AV1LfSync *const lf_sync, int r, int c,
if (sig) {
pthread_mutex_lock(&lf_sync->mutex_[plane][r]);
- // When a thread encounters an error, cur_sb_col[plane][r] is set to maximum
- // column number. In this case, the AOMMAX operation here ensures that
- // cur_sb_col[plane][r] is not overwritten with a smaller value thus
- // preventing the infinite waiting of threads in the relevant sync_read()
- // function.
+ // After an error cur_sb_col[plane][r] holds LF_SYNC_EXIT. AOMMAX keeps it
+ // from being lowered, so workers waiting in sync_read() still see it and
+ // exit.
lf_sync->cur_sb_col[plane][r] = AOMMAX(lf_sync->cur_sb_col[plane][r], cur);
pthread_cond_broadcast(&lf_sync->cond_[plane][r]);
@@ -313,22 +322,12 @@ void av1_thread_loop_filter_rows(
if (lf_sync != NULL) {
// Wait for vertical edge filtering of the top-right block to be
- // completed
- sync_read(lf_sync, r, c, plane);
+ // completed. Exit in case any worker has encountered an error.
+ if (!sync_read(lf_sync, r, c, plane)) return;
// Wait for vertical edge filtering of the right block to be completed
- sync_read(lf_sync, r + 1, c, plane);
- }
-
-#if CONFIG_MULTITHREAD
- if (lf_sync && lf_sync->num_workers > 1) {
- pthread_mutex_lock(lf_sync->job_mutex);
- const bool lf_mt_exit = lf_sync->lf_mt_exit;
- pthread_mutex_unlock(lf_sync->job_mutex);
- // Exit in case any worker has encountered an error.
- if (lf_mt_exit) return;
+ if (!sync_read(lf_sync, r + 1, c, plane)) return;
}
-#endif
av1_setup_dst_planes(planes, cm->seq_params->sb_size, frame_buffer,
mi_row, mi_col, plane, plane + num_planes);
@@ -352,20 +351,28 @@ void av1_thread_loop_filter_rows(
void av1_set_vert_loop_filter_done(AV1_COMMON *cm, AV1LfSync *lf_sync,
int num_mis_in_lpf_unit_height_log2) {
- int plane, sb_row;
- const int sb_cols =
- CEIL_POWER_OF_TWO(cm->mi_params.mi_cols, num_mis_in_lpf_unit_height_log2);
+#if CONFIG_MULTITHREAD
const int sb_rows =
CEIL_POWER_OF_TWO(cm->mi_params.mi_rows, num_mis_in_lpf_unit_height_log2);
// In case of loopfilter row-multithreading, the worker on an SB row waits for
// the vertical edge filtering of the right and top-right SBs. Hence, in case
- // a thread (main/worker) encounters an error, update that vertical
- // loopfiltering of every SB row in the frame is complete in order to avoid
- // dependent workers waiting indefinitely.
- for (sb_row = 0; sb_row < sb_rows; ++sb_row)
- for (plane = 0; plane < MAX_MB_PLANE; ++plane)
- sync_write(lf_sync, sb_row, sb_cols - 1, sb_cols, plane);
+ // a thread (main/worker) encounters an error, mark every SB row in the frame
+ // with LF_SYNC_EXIT. This avoids dependent workers waiting indefinitely and
+ // makes them exit instead of filtering.
+ for (int sb_row = 0; sb_row < sb_rows; ++sb_row) {
+ for (int plane = 0; plane < MAX_MB_PLANE; ++plane) {
+ pthread_mutex_lock(&lf_sync->mutex_[plane][sb_row]);
+ lf_sync->cur_sb_col[plane][sb_row] = LF_SYNC_EXIT;
+ pthread_cond_broadcast(&lf_sync->cond_[plane][sb_row]);
+ pthread_mutex_unlock(&lf_sync->mutex_[plane][sb_row]);
+ }
+ }
+#else
+ (void)cm;
+ (void)lf_sync;
+ (void)num_mis_in_lpf_unit_height_log2;
+#endif // CONFIG_MULTITHREAD
}
static inline void sync_lf_workers(AVxWorker *const workers,