Skip to content

Two-pass superblock partition search - #5253

Merged
urvangjoshi merged 1 commit into
AOMediaCodec:av2-encfrom
yeqing-wu:sb_two_pass_partition_merge
Aug 18, 2026
Merged

Two-pass superblock partition search#5253
urvangjoshi merged 1 commit into
AOMediaCodec:av2-encfrom
yeqing-wu:sb_two_pass_partition_merge

Conversation

@yeqing-wu

@yeqing-wu yeqing-wu commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Speed up the partition search by splitting it into two passes over each superblock.

The first pass (the "dry" pass) works out a rough partition shape. It runs mode search with a reduced set of tools, because it only has to rank shapes against each other, not produce the final coding decision. It stops at 16x16.

The second pass (the "wet" pass) codes the superblock for real, with the full set of tools. It keeps the first pass's shape for blocks of 32x32 and larger and searches the smaller blocks again, since that is where the first pass is least reliable. Large blocks the first pass left unsplit are also searched again, because a reduced tool set tends to under-split them, and trusting that would leave the block over-merged with no way to recover. That re-search is limited to blocks up to 128 and stops at 8x8, which keeps most of the time saved.

STATS_CHANGED

Anchor: commit 5b32726
Speed 4 (cpu-used=4): FG16 CTC (33 frames, class A1 and A2, RA)
Speed 3 (cpu-used=3): FG16 CTC (33 frames, class A1 and A2, RA)
Speed 2 (cpu-used=2): FG16 CTC (33 frames, class A1 and A2, RA)

    1) Speed 4 (cpu-used=4)
      +------------+-------+-------+-------+-------+------+------+
      | Class      |     Y |    Cb |    Cr |  wAvg | Enc% | Dec% |
      +------------+-------+-------+-------+-------+------+------+
      | A1         | -0.09 | -2.32 | -2.75 | -0.35 |   86 |   86 |
      | A2         |  0.78 |  0.86 |  1.13 |  0.80 |   73 |   95 |
      | Avg w/o B2 |  0.52 | -0.08 | -0.02 |  0.46 |   77 |   93 |
      +------------+-------+-------+-------+-------+------+------+
    
    2) Speed 3 (cpu-used=3)
      +------------+-------+-------+-------+-------+------+------+
      | Class      |     Y |    Cb |    Cr |  wAvg | Enc% | Dec% |
      +------------+-------+-------+-------+-------+------+------+
      | A1         | -0.03 | -2.27 | -2.79 | -0.29 |   93 |   88 |
      | A2         |  0.81 |  0.98 |  1.82 |  0.87 |   73 |   96 |
      | Avg w/o B2 |  0.56 |  0.02 |  0.45 |  0.53 |   79 |   94 |
      +------------+-------+-------+-------+-------+------+------+
    
    3) Speed 2 (cpu-used=2): Not satisfied: Score = 24.7
      +------------+-------+-------+-------+-------+------+------+
      | Class      |     Y |    Cb |    Cr |  wAvg | Enc% | Dec% |
      +------------+-------+-------+-------+-------+------+------+
      | A1         |  0.39 | -1.90 | -2.76 |  0.11 |   94 |   89 |
      | A2         |  0.94 |  2.07 |  2.25 |  1.05 |   76 |   96 |
      | Avg w/o B2 |  0.77 |  0.89 |  0.77 |  0.77 |   81 |   94 |
      +------------+-------+-------+-------+-------+------+------+

Thus, it is only enabled for speed >= 3 in the current stage.

Comment thread av2/encoder/speed_features.h Outdated
Comment thread av2/encoder/encoder_utils.h
Comment thread av2/encoder/speed_features.h Outdated
Comment thread av2/encoder/encodeframe.c
@yeqing-wu
yeqing-wu force-pushed the sb_two_pass_partition_merge branch from b631696 to 52eebe0 Compare August 13, 2026 16:30
@yeqing-wu

Copy link
Copy Markdown
Contributor Author

@urvangjoshi and @leolzhao,

I have unified part_sf.two_pass_partition_search and part_sf.two_pass_partition_search_sb_level with a single levelled speed feature part_sf.two_pass_partition_search with the enum type, I think this design is better and clean.

      TWO_PASS_PART_OFF          (0)
      TWO_PASS_PART_CONSERVATIVE (1)  full-tool dry pass, trust unsplit shapes
      TWO_PASS_PART_FAST         (2)  reduced-tool dry pass, re-split unsplit

Thanks
Yeqing

Comment thread av2/encoder/partition_search.c
Comment thread av2/encoder/rdopt.c
@yeqing-wu
yeqing-wu force-pushed the sb_two_pass_partition_merge branch 5 times, most recently from 3f5f26b to 608db83 Compare August 14, 2026 18:30
@yeqing-wu

Copy link
Copy Markdown
Contributor Author

Hi All,

Since it has passed all tests, could you please help review the code? If there is no issue, could you please help approve it?

Thanks
Yeqing

@urvangjoshi

Copy link
Copy Markdown
Contributor

@yeqing-wu : thanks for the updates. My main overall concern is the mix of gains (on A1) and losses (A2 and lower) -- but the speed-up is indeed very good.

Let me carefully review today / Monday to see if there is some issue / something where we can improve etc.

@yeqing-wu

Copy link
Copy Markdown
Contributor Author

Thanks @urvangjoshi , there are still lots of things we can improve for two pass partitions. We can do that step by step. And we can have different tunes for different speeds.

@yeqing-wu

Copy link
Copy Markdown
Contributor Author

Hi All,

Any comments on this PR? I'm currently working on per-QP and per-speed-preset configuration for two-pass partition which can achieve much better tradeoff, and in parallel I'm improving the two-pass partition structure to recover some of the coding gain (Already observed -0.13% gain with minor encoding time saving). Both of those build on this change, so I'd like to get it merged to continue with the next steps.

Thanks
Yeqing

@leolzhao

Copy link
Copy Markdown
Contributor

This MR looks good to me. @yeqing-wu

@yeqing-wu

Copy link
Copy Markdown
Contributor Author

This MR looks good to me. @yeqing-wu

Thanks very much @leolzhao for helping review the PR.

@urvangjoshi urvangjoshi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have had significant PRs for speed >= 3 recently. Could you rerun the tests to see the latest results with your PR?

If results same as before, I'm slightly leaning towards enabling this for 4K resolution only for now -- and enable for others later after we tune it more.

I'll let others chime in as well though, and we can make a collective decision.

Some comments from partial review.

Comment thread av2/encoder/encoder_utils.c
Comment thread av2/encoder/interp_search.h
Comment thread av2/encoder/partition_search.c
@yeqing-wu

yeqing-wu commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

We have had significant PRs for speed >= 3 recently. Could you rerun the tests to see the latest results with your PR?

If results same as before, I'm slightly leaning towards enabling this for 4K resolution only for now -- and enable for others later after we tune it more.

I'll let others chime in as well though, and we can make a collective decision.

Some comments from partial review.

image

This is the results from latest tests, including CCSO etc. speed up. (without including the improvement I listed below)

Is there a particular reason we're enabling this only for 4K? From what I can see, it also achieves a very good tradeoff at 2K, the ratio is higher than the minimum bar, should we also enable it for 2k? Please let me know if I'm missing something.

On my side, I'm continuing to improve two-pass partition and have already achieved
image

@urvangjoshi

Copy link
Copy Markdown
Contributor

We have had significant PRs for speed >= 3 recently. Could you rerun the tests to see the latest results with your PR?
If results same as before, I'm slightly leaning towards enabling this for 4K resolution only for now -- and enable for others later after we tune it more.
I'll let others chime in as well though, and we can make a collective decision.
Some comments from partial review.

image This is the results from latest tests, including CCSO etc. speed up. (without including the improvement I listed below)

Can you update MR description with this?
I was curious if there was a different result especially after 283b7ca and 7f268de.

I feel that this can have a large impact on the results.

Is there a particular reason we're enabling this only for 4K? From what I can see, it also achieves a very good tradeoff at 2K, the ratio is higher than the minimum bar, should we also enable it for 2k? Please let me know if I'm missing something.

My thinking was:

  • For 4K, there's both gain and speed-up. So, it's obvious that we should turn on this feature -- and that way, your code also gets merged. [Turning speed feature on/off for other resolutions is easy later on].
  • For 2K and lower resolutions, (a) The absolute loss is a bit on the higher side, but (b) the ratio is good. So, I'd like @yunqingwang1 @leolzhao to chime in and decide what we want to do.

On my side, I'm continuing to improve two-pass partition and have already achieved image

Can you explain these results? Which anchor are they based on: this PR as anchor, or the baseline commit of this PR as anchor?
In other words, what will be the combined result of the 2 PRs?

@yeqing-wu

Copy link
Copy Markdown
Contributor Author

Can you update MR description with this?
I was curious if there was a different result especially after 283b7ca and 7f268de.

The results I've attached are already based on last Friday's commit. I can run a test with today's TCQ PR as well. But I'd like to raise a concern: should we generally avoid asking the proponents of earlier PRs to re-run tests against PRs submitted several days later? If we ask for re-runs every time an incoming PR might impact others, the process could become open-ended, since most PRs have some overlap and their bases can differ significantly.

Regarding the gain shown in the table below, it is measured on top of the two-pass partitioning in this PR (already rebased on last Friday's ToT). The change uses the winning MV from the dry (first) pass as the starting MV for the wet pass, giving the wet pass a better starting point.

image

As I recall, we agreed in the FG16 group meeting that we should avoid bundling significant code changes into a single PR. Since the two-pass partitioning strategy is still evolving, I'd suggest we keep these changes in separate PRs rather than merging them together. Please let me know your thoughts.

@urvangjoshi

Copy link
Copy Markdown
Contributor

Can you update MR description with this?
I was curious if there was a different result especially after 283b7ca and 7f268de.

The results I've attached are already based on last Friday's commit. I can run a test with today's TCQ PR as well. But I'd like to raise a concern: should we generally avoid asking the proponents of earlier PRs to re-run tests against PRs submitted several days later? If we ask for re-runs every time an incoming PR might impact others, the process could become open-ended, since most PRs have some overlap and their bases can differ significantly.

@yeqing-wu : That's a fair point and agree that we should not ask for newer results in general.

My intention here of asking for newer results, was in fact to help with results from this PR.
My hope/wish was that you see even better results now that some unhelpful / buggy speed features have been disabled at speed 3+. (And it's possible that those were hurting your PR as well).

Regarding the gain shown in the table below, it is measured on top of the two-pass partitioning in this PR (already rebased on last Friday's ToT). The change uses the winning MV from the dry (first) pass as the starting MV for the wet pass, giving the wet pass a better starting point.

image As I recall, we agreed in the FG16 group meeting that we should avoid bundling significant code changes into a single PR. Since the two-pass partitioning strategy is still evolving, I'd suggest we keep these changes in separate PRs rather than merging them together. Please let me know your thoughts.

To clarify:

  • Yes, MRs should remain separate
  • The reason for clarifying the combined result was to see what to expect in the upcoming PR.

Now, IIUC, the combined result from 2 PRs for A2 set will be 0.62% loss with 73% enc-time in RA. Is that correct?

If so, I'm fine to go ahead with this if others are ok. @yunqingwang1 @leolzhao .

@yeqing-wu

Copy link
Copy Markdown
Contributor Author

Now, IIUC, the combined result from 2 PRs for A2 set will be 0.62% loss with 73% enc-time in RA. Is that correct?

I haven’t tested their combination, but the gain (the MV from the dry pass as the starting MV for the wet pass) is within this fast two-pass partition, and saves very minor encoding time. Therefore, if we consider only the additive effect, the loss of A2 would decrease from 0.71% to (0.71% - 0.18%) = 0.53%. The encoding time savings should remain the same, even though the new changes would add 0.5% saving.

@yeqing-wu

Copy link
Copy Markdown
Contributor Author

If this two-pass partition fails to function as intended in the future, I would be more than willing to assist in removing the code responsible for it.

@urvangjoshi

Copy link
Copy Markdown
Contributor

Now, IIUC, the combined result from 2 PRs for A2 set will be 0.62% loss with 73% enc-time in RA. Is that correct?

I haven’t tested their combination, but the gain (the MV from the dry pass as the starting MV for the wet pass) is within this fast two-pass partition, and saves very minor encoding time. Therefore, if we consider only the additive effect, the loss of A2 would decrease from 0.71% to (0.71% - 0.18%) = 0.53%. The encoding time savings should remain the same, even though the new changes would add 0.5% saving.

Thanks, that sounds like a good trade-off indeed.

Speed up the partition search by splitting it into two passes over each
superblock.

The first pass (the "dry" pass) works out a rough partition shape. It runs
mode search with a reduced set of tools, because it only has to rank shapes
against each other, not produce the final coding decision. It stops at 16x16.

The second pass (the "wet" pass) codes the superblock for real, with the full
set of tools. It keeps the first pass's shape for blocks of 32x32 and larger
and searches the smaller blocks again, since that is where the first pass is
least reliable. Large blocks the first pass left unsplit are also searched
again, because a reduced tool set tends to under-split them, and trusting
that would leave the block over-merged with no way to recover. That re-search
is limited to blocks up to 128 and stops at 8x8, which keeps most of the time
saved.

STATS_CHANGED

Anchor: commit 5b32726
Speed 4 (cpu-used=4): FG16 CTC (33 frames, class A1 and A2, RA)
Speed 3 (cpu-used=3): FG16 CTC (33 frames, class A1 and A2, RA)
Speed 2 (cpu-used=2): FG16 CTC (33 frames, class A1 and A2, RA)

1) Speed 4 (cpu-used=4)
  +------------+-------+-------+-------+-------+------+------+
  | Class      |     Y |    Cb |    Cr |  wAvg | Enc% | Dec% |
  +------------+-------+-------+-------+-------+------+------+
  | A1         | -0.09 | -2.32 | -2.75 | -0.35 |   86 |   86 |
  | A2         |  0.78 |  0.86 |  1.13 |  0.80 |   73 |   95 |
  | Avg w/o B2 |  0.52 | -0.08 | -0.02 |  0.46 |   77 |   93 |
  +------------+-------+-------+-------+-------+------+------+

2) Speed 3 (cpu-used=3)
  +------------+-------+-------+-------+-------+------+------+
  | Class      |     Y |    Cb |    Cr |  wAvg | Enc% | Dec% |
  +------------+-------+-------+-------+-------+------+------+
  | A1         | -0.03 | -2.27 | -2.79 | -0.29 |   93 |   88 |
  | A2         |  0.81 |  0.98 |  1.82 |  0.87 |   73 |   96 |
  | Avg w/o B2 |  0.56 |  0.02 |  0.45 |  0.53 |   79 |   94 |
  +------------+-------+-------+-------+-------+------+------+

3) Speed 2 (cpu-used=2): Not satisfied: Score = 24.7
  +------------+-------+-------+-------+-------+------+------+
  | Class      |     Y |    Cb |    Cr |  wAvg | Enc% | Dec% |
  +------------+-------+-------+-------+-------+------+------+
  | A1         |  0.39 | -1.90 | -2.76 |  0.11 |   94 |   89 |
  | A2         |  0.94 |  2.07 |  2.25 |  1.05 |   76 |   96 |
  | Avg w/o B2 |  0.77 |  0.89 |  0.77 |  0.77 |   81 |   94 |
  +------------+-------+-------+-------+-------+------+------+
@urvangjoshi
urvangjoshi force-pushed the sb_two_pass_partition_merge branch from 608db83 to da9df0b Compare August 17, 2026 22:48
@urvangjoshi
urvangjoshi enabled auto-merge (squash) August 17, 2026 23:05
@urvangjoshi
urvangjoshi merged commit 45dc128 into AOMediaCodec:av2-enc Aug 18, 2026
109 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants