This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 1250049b6f14d06c318f89a6c6d857591649accd Author: Philip Langdale <[email protected]> AuthorDate: Sat Aug 15 11:13:29 2026 -0700 Commit: Philip Langdale <[email protected]> CommitDate: Sat Aug 29 16:38:05 2026 -0700 avfilter/fruc_vulkan: don't recalculate warping for every plane The warp calculation is currently done for every plane, but doesn't depend on the plane contents, just the dimensions; so this is wasted work when plane sizes don't vary (eg: RGB, 4:4:4 YUV). This will not have a visible impact on performance at realistic interpolation rates as the optical flow generation is the limiting factor until you are doing something silly like 30->900fps. But wasted work is wasted work, so best to stop doing it. --- libavfilter/vulkan/fruc_interpolate.comp.glsl | 63 +++++++++++++++++---------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/libavfilter/vulkan/fruc_interpolate.comp.glsl b/libavfilter/vulkan/fruc_interpolate.comp.glsl index b682be5568..35cc399f28 100644 --- a/libavfilter/vulkan/fruc_interpolate.comp.glsl +++ b/libavfilter/vulkan/fruc_interpolate.comp.glsl @@ -88,6 +88,15 @@ void main() { ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + /* The warp positions and the guard weight only depend on plane size. So + * we cache these values and re-use them if the next plane is the same + * size. In practice, we won't see plane sizes change and then change back + * to some previous dimension, so a single cached value is optimal. */ + vec2 cached_size = vec2(0.0); + vec2 s0 = vec2(0.0); + vec2 s1 = vec2(0.0); + float guard = 0.0; + for (int i = 0; i < planes; i++) { /* Bound the pass by the visible extent, not by either image's allocation: * a padded source would let invocations run past the end of a visible @@ -99,13 +108,35 @@ void main() vec2 base = (vec2(pos) + 0.5) / size; - /* The flow is anchored on the f0/f1 grids, not the intermediate frame. - * Recover the source position on each grid by Picard iteration. */ - vec2 s0 = base; - vec2 s1 = base; - for (int k = 0; k < PICARD_ITERS; k++) { - s0 = mix(s0, base - t * flow_at_fwd(s0), PICARD_OMEGA); - s1 = mix(s1, base - (1.0 - t) * flow_at_bwd(s1), PICARD_OMEGA); + if (size != cached_size) { + cached_size = size; + + /* The flow is anchored on the f0/f1 grids, not the intermediate frame. + * Recover the source position on each grid by Picard iteration. */ + s0 = base; + s1 = base; + for (int k = 0; k < PICARD_ITERS; k++) { + s0 = mix(s0, base - t * flow_at_fwd(s0), PICARD_OMEGA); + s1 = mix(s1, base - (1.0 - t) * flow_at_bwd(s1), PICARD_OMEGA); + } + + /* Key staticness off the same weighted luma the grayscale pass feeds the + * flow engine. */ + float l0 = 0.0, l1 = 0.0; + for (int q = 0; q < planes; q++) { + l0 += dot(texture(f0_img[q], f0_uv(base, q)), luma_weights[q]); + l1 += dot(texture(f1_img[q], f1_uv(base, q)), luma_weights[q]); + } + float lz = abs(l0 - l1); + float staticness = exp(-(lz * lz) / (STATIC_LUMA_SIGMA * STATIC_LUMA_SIGMA)); + + float disp = max(length((s0 - base) * luma_size), + length((s1 - base) * luma_size)); + /* smoothstep is used to transition between the two thresholds and avoid + * abrupt changes at the boundary. */ + float reach = smoothstep(WARP_NEAR_PX, WARP_FAR_PX, disp * WARP_REACH_SCALE); + + guard = staticness * reach; } vec4 c0 = texture(f0_img[i], f0_uv(s0, i)); @@ -118,23 +149,7 @@ void main() vec4 z1 = texture(f1_img[i], f1_uv(base, i)); vec4 stat = mix(z0, z1, t); - /* Key staticness off the same weighted luma the grayscale pass feeds the - * flow engine. */ - float l0 = 0.0, l1 = 0.0; - for (int q = 0; q < planes; q++) { - l0 += dot(texture(f0_img[q], f0_uv(base, q)), luma_weights[q]); - l1 += dot(texture(f1_img[q], f1_uv(base, q)), luma_weights[q]); - } - float lz = abs(l0 - l1); - float staticness = exp(-(lz * lz) / (STATIC_LUMA_SIGMA * STATIC_LUMA_SIGMA)); - - float disp = max(length((s0 - base) * luma_size), - length((s1 - base) * luma_size)); - /* smoothstep is used to transition between the two thresholds and avoid - * abrupt changes at the boundary. */ - float reach = smoothstep(WARP_NEAR_PX, WARP_FAR_PX, disp * WARP_REACH_SCALE); - - vec4 result = mix(warped, stat, staticness * reach); + vec4 result = mix(warped, stat, guard); imageStore(out_img[i], pos, result); } -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
