Commit a1679b5c85 for ffmpeg

commit a1679b5c850c027fab5930aea25dbd2948297c5f
Author: Lynne <dev@lynne.ee>
Date:   Sun Sep 27 01:20:26 2026 +0900

    ffv1enc_vulkan: code each symbol in code specialised for its exponent

    A symbol was coded by loops over its unary prefix and its mantissa,
    reading every state from its invocation just before its decision and
    updating it right after.

    Each exponent now has its own straight-line code, reached through a
    small branch tree, which reads all the states the symbol uses from
    their invocations up front, so the chain of decisions never waits on
    them. Once the symbol is coded, all invocations adapt their state at
    once, from masks of the states the symbol used and of the decisions
    that were ones. Escaped symbols adapt the two states they repeat in
    scalar registers. The renormalisation check stays a branch instead of
    being turned into selects.

    The output is unchanged. Encoding a 6464x4852 16-bit RGB frame with
    1024 slices on an RX 6900 XT, with the frame in VRAM, goes from
    170.1/144.8 ms to 126.6/101.6 ms with context model 1/0.

diff --git a/libavcodec/vulkan/ffv1_enc.comp.glsl b/libavcodec/vulkan/ffv1_enc.comp.glsl
index 050a45efef..3e46a7f838 100644
--- a/libavcodec/vulkan/ffv1_enc.comp.glsl
+++ b/libavcodec/vulkan/ffv1_enc.comp.glsl
@@ -114,11 +114,26 @@ void encode_line(in SliceContext sc, readonly uimage2D img, uint state_off,

         d[1] = fold(d[1], bits);

-        uint rc_off = state_off + CONTEXT_SIZE*d[0] + gl_LocalInvocationID.x;
-
+        uint lane = gl_SubgroupInvocationID;
+        uint rc_off = state_off + CONTEXT_SIZE*d[0] + lane;
         uint st = slice_rc_state[rc_off];
-        put_isymbol(st, d[1]);
-        slice_rc_state[rc_off] = uint8_t(st);
+
+        uint ad = abs(d[1]);
+        int e = findMSB(ad);
+        int ec = clamp(e, 0, 9);
+        int es = 11 + min(e, 10);
+        uint used = d[1] == 0 ? 1u : 1u | ((4u << ec) - 2u) | (((1u << ec) - 1u) << 22) | (1u << es);
+        uint ones = d[1] == 0 ? 1u : ((2u << ec) - 2u) | ((ad & ((1u << ec) - 1u)) << 22) |
+                                     (uint(d[1] < 0) << es);
+        uint nst = zero_one_state[(bitfieldExtract(ones, int(lane), 1) << 8) + st];
+
+        uint s10, s31;
+        put_isymbol(st, d[1], s10, s31);
+
+        uint adapted = bitfieldExtract(used, int(lane), 1) != 0 ? nst : st;
+        if (ad >= 1024)
+            adapted = lane == 10 ? s10 : lane == 31 ? s31 : adapted;
+        slice_rc_state[rc_off] = uint8_t(adapted);
         linecache_next(cur);
         if (rc_nev > 42)
             rac_emit();
diff --git a/libavcodec/vulkan/rangecoder_subgroup.glsl b/libavcodec/vulkan/rangecoder_subgroup.glsl
index 94406bbea9..c9ccaf74ce 100644
--- a/libavcodec/vulkan/rangecoder_subgroup.glsl
+++ b/libavcodec/vulkan/rangecoder_subgroup.glsl
@@ -143,7 +143,7 @@ void put_rac_range1(uint range1, bool bit)
 {
     rc_top = bit ? rc_top : rc_top - range1;
     rc.range = bit ? range1 : rc.range - range1;
-    if (rc.range < 0x100)
+    [[dont_flatten]] if (rc.range < 0x100)
         rac_renorm_enc();
 }

@@ -181,43 +181,114 @@ uint rac_terminate(void)
     return rc.bs_off - rc.bs_start;
 }

-void put_rac_state(inout uint st, uint i, bool bit)
+void put_isymbol_tail(int e, uint st24, uint a, bool neg)
 {
-    uint s = subgroupBroadcast(st, i);
-    put_rac(s << 24, bit);
-    uint ns = uint(zero_one_state[(uint(bit) << 8) + s]);
-    st = gl_SubgroupInvocationID == i ? ns : st;
+    uint s[21];
+    [[unroll]] for (int i = 0; i < 11; i++)
+        if (i <= e + 1)
+            s[i] = subgroupBroadcast(st24, i);
+    [[unroll]] for (int i = 0; i < 9; i++)
+        if (i < e)
+            s[11 + i] = subgroupBroadcast(st24, 22 + i);
+    s[20] = subgroupBroadcast(st24, 11 + e);
+
+    put_rac(s[0], false);
+    [[unroll]] for (int i = 0; i < 9; i++)
+        if (i < e)
+            put_rac(s[1 + i], true);
+    put_rac(s[1 + e], false);
+    [[unroll]] for (int i = 8; i >= 0; i--)
+        if (i < e)
+            put_rac(s[11 + i], bitfieldExtract(a, i, 1) != 0);
+    put_rac(s[20], neg);
 }

-void put_isymbol(inout uint st, int v)
+void put_isymbol_esc(int e, uint st, uint a, bool neg, out uint s10, out uint s31)
 {
-    put_rac_state(st, 0, v == 0);
-    if (v == 0)
-        return;
-
-    uint a = abs(v);
-    int e = findMSB(a);
+    uint st24 = st << 24;
+    uint s[10];
+    [[unroll]] for (int i = 0; i < 10; i++)
+        s[i] = subgroupBroadcast(st24, i);
+    s10 = subgroupBroadcast(st, 10);
+    s31 = subgroupBroadcast(st, 31);
+    put_rac(s[0], false);
+    [[unroll]] for (int i = 1; i < 10; i++)
+        put_rac(s[i], true);
+    if (rc_nev > 40)
+        rac_emit();

-    for (int i = 0; i < min(e, 9); i++)
-        put_rac_state(st, 1 + i, true);
     for (int i = 9; i < e; i++) {
-        put_rac_state(st, 10, true);
+        uint nx = rangecoder_state[256 + s10];
+        put_rac(s10 << 24, true);
         if (rc_nev > 60)
             rac_emit();
+        s10 = nx;
     }
-    put_rac_state(st, 1 + min(e, 9), false);
+    uint nx = rangecoder_state[s10];
+    put_rac(s10 << 24, false);
+    s10 = nx;

     for (int i = e - 1; i >= 9; i--) {
-        put_rac_state(st, 31, bitfieldExtract(a, i, 1) != 0);
+        bool b = bitfieldExtract(a, i, 1) != 0;
+        uint n0 = rangecoder_state[s31];
+        uint n1 = rangecoder_state[256 + s31];
+        put_rac(s31 << 24, b);
         if (rc_nev > 60)
             rac_emit();
+        s31 = b ? n1 : n0;
     }
-    if (e > 9 && rc_nev > 50)
+    if (rc_nev > 50)
         rac_emit();
-    for (int i = min(e, 9) - 1; i >= 0; i--)
-        put_rac_state(st, 22 + i, bitfieldExtract(a, i, 1) != 0);

-    put_rac_state(st, 11 + min(e, 10), v < 0);
+    [[unroll]] for (int i = 8; i >= 0; i--)
+        s[i] = subgroupBroadcast(st24, 22 + i);
+    uint ss = subgroupBroadcast(st24, 21);
+    [[unroll]] for (int i = 8; i >= 0; i--)
+        put_rac(s[i], bitfieldExtract(a, i, 1) != 0);
+    put_rac(ss, neg);
+}
+
+void put_isymbol(uint st, int v, out uint s10, out uint s31)
+{
+    uint st24 = st << 24;
+    uint a = abs(v);
+    int e = findMSB(a);
+    bool neg = v < 0;
+    s10 = 0;
+    s31 = 0;
+
+    if (v != 0) {
+        if (e < 4) {
+            if (e < 2) {
+                if (e == 1)
+                    put_isymbol_tail(1, st24, a, neg);
+                else
+                    put_isymbol_tail(0, st24, a, neg);
+            } else if (e == 3) {
+                put_isymbol_tail(3, st24, a, neg);
+            } else {
+                put_isymbol_tail(2, st24, a, neg);
+            }
+        } else if (e < 7) {
+            if (e == 4)
+                put_isymbol_tail(4, st24, a, neg);
+            else if (e == 5)
+                put_isymbol_tail(5, st24, a, neg);
+            else
+                put_isymbol_tail(6, st24, a, neg);
+        } else if (e < 10) {
+            if (e == 7)
+                put_isymbol_tail(7, st24, a, neg);
+            else if (e == 8)
+                put_isymbol_tail(8, st24, a, neg);
+            else
+                put_isymbol_tail(9, st24, a, neg);
+        } else {
+            put_isymbol_esc(e, st, a, neg, s10, s31);
+        }
+    } else {
+        put_rac(subgroupBroadcast(st24, 0), true);
+    }
 }
 #endif