fix(ci): windows clippy + rustfmt debt from the D3D11VA push
apple / swift (push) Successful in 1m16s
windows-host / package (push) Successful in 8m34s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m49s
release / apple (push) Successful in 9m12s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m45s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 1m22s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 1m49s
apple / screenshots (push) Successful in 5m42s
android / android (push) Successful in 4m53s
arch / build-publish (push) Successful in 7m9s
ci / web (push) Successful in 1m9s
ci / docs-site (push) Successful in 1m12s
ci / rust (push) Successful in 5m28s
deb / build-publish (push) Successful in 4m9s
decky / build-publish (push) Successful in 15s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
ci / bench (push) Successful in 6m13s
flatpak / build-publish (push) Failing after 5m1s
docker / deploy-docs (push) Successful in 16s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 12m30s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 12m36s

The windows workflow has been red since a69a83b5: clippy 1.96 rejects the two
field-reassign-with-default view-desc initializers in video_d3d11.rs (now struct
literals), and with clippy failing first, the rustfmt step never ran — cargo fmt
--all had genuine misses queued up in video_d3d11.rs / pf-presenter d3d11.rs +
vk.rs / core abr.rs + client.rs (plus this session's config.rs). Formatting only
beyond the two initializers; no behaviour change.

Verified: clippy -p pf-client-core --all-targets -D warnings clean on the RTX
Windows box, cargo fmt --all --check clean, core lib tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 11:47:06 +02:00
parent d0f68cbbcd
commit 4839c0e6f6
6 changed files with 76 additions and 34 deletions
+40 -23
View File
@@ -41,12 +41,11 @@ use windows::Win32::Foundation::HANDLE;
use windows::Win32::Graphics::Direct3D::{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1}; use windows::Win32::Graphics::Direct3D::{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1};
use windows::Win32::Graphics::Direct3D11::{ use windows::Win32::Graphics::Direct3D11::{
D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Multithread, ID3D11Texture2D, D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Multithread, ID3D11Texture2D,
ID3D11VideoContext1, ID3D11VideoDevice, ID3D11VideoProcessor, ID3D11VideoContext1, ID3D11VideoDevice, ID3D11VideoProcessor, ID3D11VideoProcessorEnumerator,
ID3D11VideoProcessorEnumerator, ID3D11VideoProcessorOutputView, D3D11_BIND_RENDER_TARGET, ID3D11VideoProcessorOutputView, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE,
D3D11_BIND_SHADER_RESOURCE, D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
D3D11_CREATE_DEVICE_VIDEO_SUPPORT, D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX, D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX, D3D11_RESOURCE_MISC_SHARED_NTHANDLE, D3D11_SDK_VERSION,
D3D11_RESOURCE_MISC_SHARED_NTHANDLE, D3D11_SDK_VERSION, D3D11_TEXTURE2D_DESC, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,
D3D11_USAGE_DEFAULT, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,
D3D11_VIDEO_PROCESSOR_CONTENT_DESC, D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC, D3D11_VIDEO_PROCESSOR_CONTENT_DESC, D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC,
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC, D3D11_VIDEO_PROCESSOR_STREAM, D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC, D3D11_VIDEO_PROCESSOR_STREAM,
D3D11_VIDEO_USAGE_PLAYBACK_NORMAL, D3D11_VPIV_DIMENSION_TEXTURE2D, D3D11_VIDEO_USAGE_PLAYBACK_NORMAL, D3D11_VPIV_DIMENSION_TEXTURE2D,
@@ -262,7 +261,9 @@ fn create_device(luid: Option<[u8; 8]>) -> Result<(ID3D11Device, ID3D11DeviceCon
} }
} }
if chosen.is_none() && luid.is_some() && fallback.is_some() { if chosen.is_none() && luid.is_some() && fallback.is_some() {
tracing::warn!("no DXGI adapter matches the Vulkan device LUID — using the first hardware adapter"); tracing::warn!(
"no DXGI adapter matches the Vulkan device LUID — using the first hardware adapter"
);
} }
let adapter = chosen let adapter = chosen
.or(fallback) .or(fallback)
@@ -384,8 +385,10 @@ impl SharedRing {
unsafe { device.CreateTexture2D(&desc, None, Some(&mut tex)) } unsafe { device.CreateTexture2D(&desc, None, Some(&mut tex)) }
.context("create shared hand-off texture")?; .context("create shared hand-off texture")?;
let tex: ID3D11Texture2D = tex.expect("CreateTexture2D succeeded"); let tex: ID3D11Texture2D = tex.expect("CreateTexture2D succeeded");
let mutex: IDXGIKeyedMutex = tex.cast().context("shared texture lacks IDXGIKeyedMutex")?; let mutex: IDXGIKeyedMutex =
let resource: IDXGIResource1 = tex.cast().context("shared texture lacks IDXGIResource1")?; tex.cast().context("shared texture lacks IDXGIKeyedMutex")?;
let resource: IDXGIResource1 =
tex.cast().context("shared texture lacks IDXGIResource1")?;
let handle = unsafe { let handle = unsafe {
resource.CreateSharedHandle( resource.CreateSharedHandle(
None, None,
@@ -394,9 +397,11 @@ impl SharedRing {
) )
} }
.context("CreateSharedHandle")?; .context("CreateSharedHandle")?;
let mut ov_desc = D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC::default(); let ov_desc = D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC {
ov_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; ViewDimension: D3D11_VPOV_DIMENSION_TEXTURE2D,
ov_desc.Anonymous.Texture2D.MipSlice = 0; // Anonymous.Texture2D.MipSlice = 0 — the zeroed default.
..Default::default()
};
let mut out_view = None; let mut out_view = None;
unsafe { unsafe {
video_device.CreateVideoProcessorOutputView( video_device.CreateVideoProcessorOutputView(
@@ -415,8 +420,13 @@ impl SharedRing {
out_view, out_view,
}); });
} }
tracing::info!(width, height, slots = RING_SLOTS, generation, tracing::info!(
"D3D11 shared hand-off ring built (VideoProcessor → BGRA8)"); width,
height,
slots = RING_SLOTS,
generation,
"D3D11 shared hand-off ring built (VideoProcessor → BGRA8)"
);
Ok(SharedRing { Ok(SharedRing {
slots, slots,
vp, vp,
@@ -449,7 +459,10 @@ pub(crate) struct D3d11vaDecoder {
unsafe impl Send for D3d11vaDecoder {} unsafe impl Send for D3d11vaDecoder {}
impl D3d11vaDecoder { impl D3d11vaDecoder {
pub(crate) fn new(codec_id: ffmpeg::codec::Id, luid: Option<[u8; 8]>) -> Result<D3d11vaDecoder> { pub(crate) fn new(
codec_id: ffmpeg::codec::Id,
luid: Option<[u8; 8]>,
) -> Result<D3d11vaDecoder> {
use ffmpeg::ffi; use ffmpeg::ffi;
let (device, context) = create_device(luid)?; let (device, context) = create_device(luid)?;
// The adapter must expose the codec's DXVA profile — checked here, not at the first AU. // The adapter must expose the codec's DXVA profile — checked here, not at the first AU.
@@ -498,8 +511,8 @@ impl D3d11vaDecoder {
(*ctx).get_format = Some(get_format_d3d11); (*ctx).get_format = Some(get_format_d3d11);
(*ctx).flags |= ffi::AV_CODEC_FLAG_LOW_DELAY as i32; (*ctx).flags |= ffi::AV_CODEC_FLAG_LOW_DELAY as i32;
(*ctx).thread_count = 1; // hwaccel: threads only add latency (*ctx).thread_count = 1; // hwaccel: threads only add latency
// On top of the DPB-based pool libavcodec sizes: margin for the frames briefly held // On top of the DPB-based pool libavcodec sizes: margin for the frames briefly held
// between decode and the ring copy (the copy runs immediately, so this is small). // between decode and the ring copy (the copy runs immediately, so this is small).
(*ctx).extra_hw_frames = 4; (*ctx).extra_hw_frames = 4;
let r = ffi::avcodec_open2(ctx, codec, ptr::null_mut()); let r = ffi::avcodec_open2(ctx, codec, ptr::null_mut());
if r < 0 { if r < 0 {
@@ -601,10 +614,12 @@ impl D3d11vaDecoder {
let index = (*self.frame).data[1] as usize as u32; let index = (*self.frame).data[1] as usize as u32;
// Input view over THIS slice of the decode array (cheap per-frame object). // Input view over THIS slice of the decode array (cheap per-frame object).
let mut iv_desc = D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC::default(); let mut iv_desc = D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC {
iv_desc.FourCC = 0; // surface format speaks for itself FourCC: 0, // surface format speaks for itself
iv_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; ViewDimension: D3D11_VPIV_DIMENSION_TEXTURE2D,
iv_desc.Anonymous.Texture2D.MipSlice = 0; // Anonymous.Texture2D zeroed (MipSlice 0); ArraySlice is per-frame below.
..Default::default()
};
iv_desc.Anonymous.Texture2D.ArraySlice = index; iv_desc.Anonymous.Texture2D.ArraySlice = index;
let mut in_view = None; let mut in_view = None;
video_device video_device
@@ -621,8 +636,10 @@ impl D3d11vaDecoder {
_ => DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709, _ => DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709,
}; };
video_context1.VideoProcessorSetStreamColorSpace1(&ring.vp, 0, in_cs); video_context1.VideoProcessorSetStreamColorSpace1(&ring.vp, 0, in_cs);
video_context1 video_context1.VideoProcessorSetOutputColorSpace1(
.VideoProcessorSetOutputColorSpace1(&ring.vp, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); &ring.vp,
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709,
);
let stream = D3D11_VIDEO_PROCESSOR_STREAM { let stream = D3D11_VIDEO_PROCESSOR_STREAM {
Enable: true.into(), Enable: true.into(),
+6 -1
View File
@@ -125,7 +125,12 @@ pub fn import(
None, None,
) )
} }
.with_context(|| format!("create {}x{} {mp_format:?} external image", frame.width, frame.height))?; .with_context(|| {
format!(
"create {}x{} {mp_format:?} external image",
frame.width, frame.height
)
})?;
let result = (|| { let result = (|| {
// The handle's importable memory types, intersected with the image's requirement. // The handle's importable memory types, intersected with the image's requirement.
+5 -3
View File
@@ -55,7 +55,6 @@ struct HwCtxWin {
ext_mem_win32: ash::khr::external_memory_win32::Device, ext_mem_win32: ash::khr::external_memory_win32::Device,
} }
/// A submitted hardware frame parked until the in-flight fence proves the GPU reads /// A submitted hardware frame parked until the in-flight fence proves the GPU reads
/// done: imported dmabuf planes, or a Vulkan-Video frame (FFmpeg's image — we own only /// done: imported dmabuf planes, or a Vulkan-Video frame (FFmpeg's image — we own only
/// the plane views; dropping the frame's guard releases the AVFrame back to the pool). /// the plane views; dropping the frame's guard releases the AVFrame back to the pool).
@@ -666,8 +665,11 @@ impl Presenter {
} }
#[cfg(windows)] #[cfg(windows)]
if win_capable { if win_capable {
device_extensions device_extensions.extend(
.extend(crate::d3d11::DEVICE_EXTENSIONS.iter().map(|n| CString::from(*n))); crate::d3d11::DEVICE_EXTENSIONS
.iter()
.map(|n| CString::from(*n)),
);
} }
if has_hdr_metadata { if has_hdr_metadata {
device_extensions.push(CString::from(ash::ext::hdr_metadata::NAME)); device_extensions.push(CString::from(ash::ext::hdr_metadata::NAME));
+20 -5
View File
@@ -210,7 +210,10 @@ mod tests {
// One bad window is a blip — no reaction. // One bad window is a blip — no reaction.
assert_eq!(c.on_window(ticks(start, 0), 1, 0, None, false), None); assert_eq!(c.on_window(ticks(start, 0), 1, 0, None, false), None);
// The second consecutive bad window backs off ×0.7. // The second consecutive bad window backs off ×0.7.
assert_eq!(c.on_window(ticks(start, 1), 1, 0, None, false), Some(14_000)); assert_eq!(
c.on_window(ticks(start, 1), 1, 0, None, false),
Some(14_000)
);
c.on_ack(14_000); c.on_ack(14_000);
// Still bad after the cooldown → another ×0.7 step from the ACKED rate. // Still bad after the cooldown → another ×0.7 step from the ACKED rate.
assert_eq!(c.on_window(ticks(start, 6), 1, 0, None, false), None); // bad #1 again assert_eq!(c.on_window(ticks(start, 6), 1, 0, None, false), None); // bad #1 again
@@ -222,7 +225,10 @@ mod tests {
let mut c = BitrateController::new(20_000); let mut c = BitrateController::new(20_000);
let start = Instant::now(); let start = Instant::now();
assert_eq!(c.on_window(ticks(start, 0), 1, 0, None, false), None); assert_eq!(c.on_window(ticks(start, 0), 1, 0, None, false), None);
assert_eq!(c.on_window(ticks(start, 1), 1, 0, None, false), Some(14_000)); assert_eq!(
c.on_window(ticks(start, 1), 1, 0, None, false),
Some(14_000)
);
c.on_ack(14_000); c.on_ack(14_000);
// Two more bad windows land INSIDE the 3 s cooldown (ticks 2,3 = 1.5/2.25 s) → held. // Two more bad windows land INSIDE the 3 s cooldown (ticks 2,3 = 1.5/2.25 s) → held.
assert_eq!(c.on_window(ticks(start, 2), 1, 0, None, false), None); assert_eq!(c.on_window(ticks(start, 2), 1, 0, None, false), None);
@@ -247,7 +253,10 @@ mod tests {
let mut c = BitrateController::new(20_000); let mut c = BitrateController::new(20_000);
let start = Instant::now(); let start = Instant::now();
assert_eq!(c.on_window(ticks(start, 0), 1, 0, None, false), None); assert_eq!(c.on_window(ticks(start, 0), 1, 0, None, false), None);
assert_eq!(c.on_window(ticks(start, 1), 1, 0, None, false), Some(14_000)); assert_eq!(
c.on_window(ticks(start, 1), 1, 0, None, false),
Some(14_000)
);
c.on_ack(14_000); c.on_ack(14_000);
// 13 clean windows → one additive step up (14000 + 14000/16 + 1 = 14876). // 13 clean windows → one additive step up (14000 + 14000/16 + 1 = 14876).
let up = run_clean(&mut c, start, 2, 13); let up = run_clean(&mut c, start, 2, 13);
@@ -264,10 +273,16 @@ mod tests {
let start = Instant::now(); let start = Instant::now();
// Establish a ~10 ms baseline over a few clean windows. // Establish a ~10 ms baseline over a few clean windows.
for i in 0..4 { for i in 0..4 {
assert_eq!(c.on_window(ticks(start, i), 0, 0, Some(10_000), false), None); assert_eq!(
c.on_window(ticks(start, i), 0, 0, Some(10_000), false),
None
);
} }
// Delay climbs 40 ms above baseline with ZERO loss — bufferbloat. Two windows → back off. // Delay climbs 40 ms above baseline with ZERO loss — bufferbloat. Two windows → back off.
assert_eq!(c.on_window(ticks(start, 4), 0, 0, Some(50_000), false), None); assert_eq!(
c.on_window(ticks(start, 4), 0, 0, Some(50_000), false),
None
);
assert_eq!( assert_eq!(
c.on_window(ticks(start, 5), 0, 0, Some(52_000), false), c.on_window(ticks(start, 5), 0, 0, Some(52_000), false),
Some(14_000) Some(14_000)
+1 -1
View File
@@ -11,11 +11,11 @@
//! invariant) plus a blocking data-plane pump; frames cross to the embedder over a bounded //! invariant) plus a blocking data-plane pump; frames cross to the embedder over a bounded
//! channel. All methods are safe to call from any single embedder thread. //! channel. All methods are safe to call from any single embedder thread.
use crate::abr::BitrateController;
use crate::config::{CompositorPref, GamepadPref, Mode, Role}; use crate::config::{CompositorPref, GamepadPref, Mode, Role};
use crate::error::{PunktfunkError, Result}; use crate::error::{PunktfunkError, Result};
use crate::input::InputEvent; use crate::input::InputEvent;
use crate::packet::FLAG_PROBE; use crate::packet::FLAG_PROBE;
use crate::abr::BitrateController;
use crate::quic::{ use crate::quic::{
endpoint, io, window_loss_ppm, BitrateChanged, ColorInfo, HdrMeta, Hello, HidOutput, endpoint, io, window_loss_ppm, BitrateChanged, ColorInfo, HdrMeta, Hello, HidOutput,
LossReport, ProbeRequest, ProbeResult, Reconfigure, Reconfigured, RequestKeyframe, RichInput, LossReport, ProbeRequest, ProbeResult, Reconfigure, Reconfigured, RequestKeyframe, RichInput,
+4 -1
View File
@@ -453,7 +453,10 @@ mod tests {
assert_eq!(p % 2, 0, "FEC requires even shards"); assert_eq!(p % 2, 0, "FEC requires even shards");
assert!(p <= max_shard_payload()); assert!(p <= max_shard_payload());
let wire = HEADER_LEN + p + CRYPTO_OVERHEAD; let wire = HEADER_LEN + p + CRYPTO_OVERHEAD;
assert!(wire <= 1452, "sealed datagram {wire} B exceeds a 1500-MTU IPv6 hop"); assert!(
wire <= 1452,
"sealed datagram {wire} B exceeds a 1500-MTU IPv6 hop"
);
assert!(HEADER_LEN + (p + 2) + CRYPTO_OVERHEAD > 1452, "not maximal"); assert!(HEADER_LEN + (p + 2) + CRYPTO_OVERHEAD > 1452, "not maximal");
} }