This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 720bc0b916c0396ada52490cc75c652d42ccf9c7
Author:     Lynne <[email protected]>
AuthorDate: Sun Jul 5 16:30:36 2026 +0900
Commit:     Lynne <[email protected]>
CommitDate: Sun Jul 12 13:34:57 2026 +0900

    vulkan/seg_gather: avoid scratch spills and serial prefix summing
    
    Compilers lowered the funnel indexer to scratch (spilling the data),
    during the tight copy loop into something that spills every load.
    Just use a case to select from the 2 source vectors.
    
    Summing the offsets at the end took far longer than expected and
    blocked all invocs. Just use a trivial subgroup add + atomic add
    to finish the sum quickly and with less contention.
---
 libavcodec/vulkan/seg_gather.comp.glsl | 49 +++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/libavcodec/vulkan/seg_gather.comp.glsl 
b/libavcodec/vulkan/seg_gather.comp.glsl
index 772f0200ff..5ee28097d6 100644
--- a/libavcodec/vulkan/seg_gather.comp.glsl
+++ b/libavcodec/vulkan/seg_gather.comp.glsl
@@ -21,6 +21,7 @@
 #version 460
 #pragma shader_stage(compute)
 #extension GL_GOOGLE_include_directive : require
+#extension GL_KHR_shader_subgroup_arithmetic : require
 
 #include "common.glsl"
 
@@ -31,8 +32,8 @@
  * FFv1 slice, ...) into its own fixed-stride, device-local slot, because no
  * encoder workgroup knows the others' final sizes. Run afterwards, this
  * shader prefix-sums the per-segment sizes and packs the segments back to
- * back into one contiguous, host-visible buffer -- so the device->host
- * transfer is a single coalesced stream rather than a scattered dribble.
+ * back into one contiguous buffer -- so the device->host transfer is a
+ * single coalesced stream rather than a scattered dribble.
  *
  * One workgroup per segment. Inputs: the sparse slot buffer, the per-segment
  * sizes, and the slot stride.
@@ -43,9 +44,9 @@ layout (set = 0, binding = 0, scalar) readonly buffer 
sizes_buf {
 };
 
 layout (push_constant, scalar) uniform pushConstants {
-    u8buf sparse;       /* device-local: one slot per segment */
-    u8buf compacted;    /* host-visible: contiguous output    */
-    uint  slot_size;    /* stride between sparse slots         */
+    u8buf sparse;       /* one slot per segment       */
+    u8buf compacted;    /* contiguous output          */
+    uint  slot_size;    /* stride between sparse slots */
 };
 
 shared uint s_dst_off;
@@ -60,17 +61,24 @@ u32vec4 funnel(u32vec4 lo, u32vec4 hi, uint sh)
     if (sh == 0u)
         return lo;
 
-    uint s[8] = uint[8](lo.x, lo.y, lo.z, lo.w, hi.x, hi.y, hi.z, hi.w);
     uint uw = sh >> 2u;             /* whole uints into the window       */
     uint bb = (sh & 3u) << 3u;      /* remaining sub-uint shift, in bits  */
 
+    /* s[uw..uw+3] and s[uw+1..uw+4] of the concatenated (lo, hi) pair,
+     * selected via uniform branches; a dynamically indexed local array
+     * would get spilled to scratch memory. */
+    u32vec4 a, c;
+    switch (uw) {
+    case 0u: a = lo;                     c = u32vec4(lo.yzw, hi.x); break;
+    case 1u: a = u32vec4(lo.yzw, hi.x);  c = u32vec4(lo.zw, hi.xy); break;
+    case 2u: a = u32vec4(lo.zw, hi.xy);  c = u32vec4(lo.w, hi.xyz); break;
+    default: a = u32vec4(lo.w, hi.xyz);  c = hi;                    break;
+    }
+
     if (bb == 0u)
-        return u32vec4(s[uw], s[uw + 1u], s[uw + 2u], s[uw + 3u]);
+        return a;
 
-    return u32vec4((s[uw     ] >> bb) | (s[uw + 1u] << (32u - bb)),
-                   (s[uw + 1u] >> bb) | (s[uw + 2u] << (32u - bb)),
-                   (s[uw + 2u] >> bb) | (s[uw + 3u] << (32u - bb)),
-                   (s[uw + 3u] >> bb) | (s[uw + 4u] << (32u - bb)));
+    return (a >> bb) | (c << (32u - bb));
 }
 
 void main(void)
@@ -82,14 +90,19 @@ void main(void)
     /*
      * Destination offset: the sum of all preceding segment sizes. The output
      * is packed tight -- segments back to back -- so it is usable directly as
-     * the assembled bitstream.
+     * the assembled bitstream. Reduced by the whole workgroup; a serial loop
+     * on one thread leaves 255 idle and is latency-bound on the reads.
      */
-    if (b == 0u) {
-        uint o = 0u;
-        for (uint i = 0u; i < seg; i++)
-            o += seg_sizes[i];
-        s_dst_off = o;
-    }
+    if (b == 0u)
+        s_dst_off = 0u;
+    barrier();
+
+    uint acc = 0u;
+    for (uint i = b; i < seg; i += wg)
+        acc += seg_sizes[i];
+    acc = subgroupAdd(acc);
+    if (subgroupElect() && acc != 0u)
+        atomicAdd(s_dst_off, acc);
     barrier();
 
     const uint n = seg_sizes[seg];

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to