@@ -118,28 +118,17 @@ start_capture() {
118118 if [ -n " $hud_xid " ]; then
119119 log " composite: cs2 present-hook + HUD overlay (xid=$hud_xid , hud=${hud_fps} fps)"
120120 # sink_0 = cs2 (base), sink_1 = HUD on top. The HUD ximagesrc MUST carry alpha
121- # (BGRA) or it paints opaque over cs2.
122- local cs2_src hud_src outchain
123- if _gpu_compositor_ok " $codec " ; then
124- # GPU HUD blend: upload both legs to CUDA and let cudacompositor alpha-blend
125- # on the GPU, then cudaconvertscale -> nvenc, all GPU-resident. Keeps the
126- # 1080p60 blend off the 2 capture CPU cores (the software compositor's cost).
127- # Opt-in (GS_GPU_COMPOSITOR=1); dies-on-spawn falls back to ximagesrc below.
128- log " composite: GPU HUD blend (cudacompositor) — alpha-blend off the capture CPU"
129- cs2_src=" appsrc name=vksrc ! queue ! videorate ! video/x-raw,framerate=$fps /1 ! cudaupload ! comp.sink_0"
130- hud_src=" ximagesrc xid=$hud_xid use-damage=0 show-pointer=false ! video/x-raw,framerate=$hud_fps /1 ! videoconvert ! video/x-raw,format=BGRA ! cudaupload ! queue leaky=downstream max-size-buffers=2 ! comp.sink_1"
131- outchain=" cudacompositor name=comp background=black ! cudaconvertscale ! video/x-raw(memory:CUDAMemory),format=NV12,width=$out_w ,height=$out_h ,framerate=$fps /1 ! $enc ! $parse "
132- else
133- # Software compositor (default): CPU alpha-blend on the capture cores.
134- cs2_src=" appsrc name=vksrc ! queue ! videorate ! video/x-raw,framerate=$fps /1 ! comp.sink_0"
135- # leaky=downstream: a slow/blocked HUD grab drops its own frames instead of
136- # back-pressuring the compositor (which would stall the cs2 leg too).
137- hud_src=" ximagesrc xid=$hud_xid use-damage=0 show-pointer=false ! video/x-raw,framerate=$hud_fps /1 ! videoconvert ! video/x-raw,format=BGRA ! queue leaky=downstream max-size-buffers=2 ! comp.sink_1"
138- # queue after the compositor = a thread boundary so the software blend and the
139- # upload/encode run on separate cores (else they serialize on one). Bounded by
140- # buffer count — raw frames are big, so the default byte cap would throttle.
141- outchain=" compositor name=comp background=black ! queue max-size-buffers=8 max-size-bytes=0 max-size-time=0 ! $convert ! $enc ! $parse "
142- fi
121+ # (BGRA) or it paints opaque over cs2 — verify this on-node first. The software
122+ # compositor stays: LIVE-DIAG measured the capture at ~1.1 of its 2 cores, so the
123+ # blend is NOT CPU-bound and GPU compositing would buy nothing here.
124+ local cs2_src=" appsrc name=vksrc ! queue ! videorate ! video/x-raw,framerate=$fps /1 ! comp.sink_0"
125+ # leaky=downstream: a slow/blocked HUD grab drops its own frames instead of
126+ # back-pressuring the compositor (which would stall the cs2 leg too).
127+ local hud_src=" ximagesrc xid=$hud_xid use-damage=0 show-pointer=false ! video/x-raw,framerate=$hud_fps /1 ! videoconvert ! video/x-raw,format=BGRA ! queue leaky=downstream max-size-buffers=2 ! comp.sink_1"
128+ # queue after the compositor = a thread boundary so the software blend and the
129+ # upload/encode run on separate cores (else they serialize on one). Bounded by
130+ # buffer count — raw frames are big, so the default byte cap would throttle.
131+ local outchain=" compositor name=comp background=black ! queue max-size-buffers=8 max-size-bytes=0 max-size-time=0 ! $convert ! $enc ! $parse "
143132 local pipeline
144133 if [ " $audio " = 1 ]; then
145134 pipeline=" $outchain ! queue ! mux. \
@@ -153,6 +142,12 @@ $cs2_src \
153142$hud_src "
154143 fi
155144 export VKCAP_FPS=" $fps "
145+ # With LIVE-DIAG on, also have the consumer log presents/s — present-locked,
146+ # so presents/s == cs2's REAL render fps feeding the stream. This is the signal
147+ # LIVE-DIAG lacked: presents/s consistently ≥ fps ⇒ the stream is true CFR and
148+ # any "not 60" feel is the camera switching or viewer-side; presents/s dipping
149+ # below fps ⇒ cs2 isn't holding the rate under live load (videorate then dups).
150+ [ " ${GS_LIVE_DIAG:- 1} " = " 1" ] && export VKCAP_DEBUG=" ${VKCAP_DEBUG:- 1} "
156151 # Zero-copy is clip-only: the software `compositor` here blends in system
157152 # memory and can't consume a device-local dmabuf. Force it off so a global
158153 # VKCAP_ZEROCOPY=1 can't push this path into the ximagesrc fallback.
0 commit comments