fix(client/d3d11va): green bar at the bottom — clamp the blit to the frame
ci / web (push) Successful in 47s
ci / docs-site (push) Successful in 1m8s
apple / swift (push) Successful in 1m18s
decky / build-publish (push) Successful in 23s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 6m49s
ci / bench (push) Successful in 7m2s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 5m4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
apple / screenshots (push) Successful in 6m12s
deb / build-publish (push) Successful in 9m49s
android / android (push) Successful in 13m29s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 6m53s
docker / deploy-docs (push) Successful in 27s
flatpak / build-publish (push) Successful in 6m32s
deb / build-publish-host (push) Successful in 13m26s
arch / build-publish (push) Successful in 17m13s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 8m0s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m10s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 21m2s
ci / rust (push) Successful in 28m51s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 9m0s
ci / web (push) Successful in 47s
ci / docs-site (push) Successful in 1m8s
apple / swift (push) Successful in 1m18s
decky / build-publish (push) Successful in 23s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 6m49s
ci / bench (push) Successful in 7m2s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 5m4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
apple / screenshots (push) Successful in 6m12s
deb / build-publish (push) Successful in 9m49s
android / android (push) Successful in 13m29s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 6m53s
docker / deploy-docs (push) Successful in 27s
flatpak / build-publish (push) Successful in 6m32s
deb / build-publish-host (push) Successful in 13m26s
arch / build-publish (push) Successful in 17m13s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 8m0s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m10s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 21m2s
ci / rust (push) Successful in 28m51s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 9m0s
The decode surface is DXVA-aligned (height rounded up to the profile's
alignment, 128 for HEVC/AV1), so it is taller than the frame: a 2400-line
stream decodes into a 2432-line texture. VideoProcessorBlt was called with
no stream source rect, so it blitted the WHOLE surface — the uninitialized
padding rows (NV12 Y=0,U=V=0, which converts to vivid green) landed at the
bottom of the output and the picture was squashed to fit. Set the source
rect to the real frame.
Pre-existing on this backend, but 40030e90 made D3D11VA auto's first choice
on Intel, so it went from a corner case to what every Intel user sees — a
~32 px green bar at 3840x2400, reported on glass within the hour.
Also dedupe the Settings GPU picker by description: that string IS the
identity downstream (persisted as Settings::adapter, matched by name as
PUNKTFUNK_VK_ADAPTER), so repeated enumerations of one adapter offered the
user the same choice twice — live on an Intel Arc laptop, whose Vulkan ICD
also enumerates the single physical iGPU twice. Both paths now log their
raw enumeration (decode texture dims; DXGI name/LUID/ids) for the next
report.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+35
-10
@@ -41,16 +41,41 @@ fn all_adapters() -> Vec<IDXGIAdapter> {
|
||||
|
||||
/// Descriptions of the real (hardware, non-WARP) GPUs — the Settings GPU picker's option list.
|
||||
/// The picker only shows when this has more than one entry.
|
||||
///
|
||||
/// **Deduplicated by description**, because the description IS the identity everywhere
|
||||
/// downstream: the pick is persisted as that string (`Settings::adapter`) and matched by
|
||||
/// name in the session binary (`PUNKTFUNK_VK_ADAPTER`). So two entries with the same name
|
||||
/// are one selectable choice however many times DXGI enumerates them — listing it twice
|
||||
/// only offers the user a meaningless coin flip. Seen live on an Intel Arc laptop
|
||||
/// (2026-07-19), whose Vulkan ICD likewise enumerates the one physical iGPU twice.
|
||||
pub fn adapter_names() -> Vec<String> {
|
||||
const DXGI_ADAPTER_FLAG_SOFTWARE: u32 = 2; // dxgi.h; not in this windows-rs feature set
|
||||
all_adapters()
|
||||
.iter()
|
||||
.filter(|a| {
|
||||
a.cast::<windows::Win32::Graphics::Dxgi::IDXGIAdapter1>()
|
||||
.and_then(|a1| unsafe { a1.GetDesc1() })
|
||||
.map(|d| d.Flags & DXGI_ADAPTER_FLAG_SOFTWARE == 0)
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(adapter_name)
|
||||
.collect()
|
||||
let mut names: Vec<String> = Vec::new();
|
||||
for a in all_adapters() {
|
||||
let desc1 = a
|
||||
.cast::<windows::Win32::Graphics::Dxgi::IDXGIAdapter1>()
|
||||
.and_then(|a1| unsafe { a1.GetDesc1() })
|
||||
.ok();
|
||||
let name = adapter_name(&a);
|
||||
// Forensics for the next duplicate/oddity report — which adapters DXGI actually
|
||||
// returned, and whether the repeats share a LUID (one adapter enumerated twice)
|
||||
// or are distinct devices that merely present the same description.
|
||||
if let Some(d) = &desc1 {
|
||||
tracing::debug!(
|
||||
name = %name,
|
||||
luid = format!("{:08x}-{:08x}", d.AdapterLuid.HighPart, d.AdapterLuid.LowPart),
|
||||
vendor = format_args!("{:#06x}", d.VendorId),
|
||||
device = format_args!("{:#06x}", d.DeviceId),
|
||||
flags = d.Flags,
|
||||
"DXGI adapter"
|
||||
);
|
||||
}
|
||||
if desc1.is_some_and(|d| d.Flags & DXGI_ADAPTER_FLAG_SOFTWARE != 0) {
|
||||
continue; // WARP / software renderer — never a streaming target
|
||||
}
|
||||
if !names.contains(&name) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
names
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ use ffmpeg_next as ffmpeg;
|
||||
use std::ffi::c_void;
|
||||
use std::ptr;
|
||||
use windows::core::{Interface, GUID};
|
||||
use windows::Win32::Foundation::HANDLE;
|
||||
use windows::Win32::Foundation::{HANDLE, RECT};
|
||||
use windows::Win32::Graphics::Direct3D::{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1};
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Multithread, ID3D11Texture2D,
|
||||
@@ -678,6 +678,25 @@ impl D3d11vaDecoder {
|
||||
(_, _, true) => DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709,
|
||||
_ => DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709,
|
||||
};
|
||||
// The DECODE surface is DXVA-aligned (height rounded up to the profile's
|
||||
// macroblock/tile alignment — 128 for HEVC/AV1), so it is TALLER than the
|
||||
// frame: a 2400-line stream decodes into a 2432-line texture. Without an
|
||||
// explicit source rect the processor blits the WHOLE surface — the padding
|
||||
// rows (uninitialized NV12: Y=0,U=V=0, which converts to vivid green) land at
|
||||
// the bottom of the output and the picture is squashed to fit. Clamp the
|
||||
// source to the real frame; the dest stays the whole (frame-sized) slot.
|
||||
// Live-hit on Intel 3840x2400 as a ~32 px green bar (2026-07-19).
|
||||
video_context1.VideoProcessorSetStreamSourceRect(
|
||||
&ring.vp,
|
||||
0,
|
||||
true,
|
||||
Some(&RECT {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: width as i32,
|
||||
bottom: height as i32,
|
||||
}),
|
||||
);
|
||||
video_context1.VideoProcessorSetStreamColorSpace1(&ring.vp, 0, in_cs);
|
||||
video_context1.VideoProcessorSetOutputColorSpace1(
|
||||
&ring.vp,
|
||||
@@ -722,7 +741,16 @@ impl D3d11vaDecoder {
|
||||
// completion, and an unflushed deferred batch would add a driver-decided delay.
|
||||
context.Flush();
|
||||
|
||||
log_layout_once(width, height, index, color.is_pq());
|
||||
let mut src_desc = D3D11_TEXTURE2D_DESC::default();
|
||||
src.GetDesc(&mut src_desc);
|
||||
log_layout_once(
|
||||
width,
|
||||
height,
|
||||
src_desc.Width,
|
||||
src_desc.Height,
|
||||
index,
|
||||
color.is_pq(),
|
||||
);
|
||||
Ok(D3d11Frame {
|
||||
width,
|
||||
height,
|
||||
@@ -770,10 +798,20 @@ impl Drop for D3d11vaDecoder {
|
||||
}
|
||||
|
||||
/// One-time dump of the first decoded surface's layout — the forensics for a new GPU/driver.
|
||||
fn log_layout_once(width: u32, height: u32, index: u32, pq: bool) {
|
||||
/// `tex_*` is the DXVA-aligned decode surface (>= the frame); the gap is the padding the
|
||||
/// stream source rect excludes.
|
||||
fn log_layout_once(width: u32, height: u32, tex_w: u32, tex_h: u32, index: u32, pq: bool) {
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
static ONCE: AtomicBool = AtomicBool::new(true);
|
||||
if ONCE.swap(false, Ordering::Relaxed) {
|
||||
tracing::info!(width, height, slice = index, pq, "D3D11VA first frame");
|
||||
tracing::info!(
|
||||
width,
|
||||
height,
|
||||
tex_w,
|
||||
tex_h,
|
||||
slice = index,
|
||||
pq,
|
||||
"D3D11VA first frame"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user