349d16382e
The Vulkan path's receive_frame returns at SUBMISSION (~0.1 ms) — the hardware decodes asynchronously, so the decode stat was truthful but measured the wrong boundary. The pump now ships the frame to the presenter FIRST, then waits the frame's timeline fence (vkWaitSemaphores resolved through the shared device's proc chain) and stamps received→decode-COMPLETE — true NVDEC time at zero pipeline cost, since the presenter's own GPU wait is what actually gates sampling. Software/ VAAPI keep their synchronous stamps. Also: Alt+Enter joins F11 as the fullscreen toggle (some keyboards' Fn layer sends a media key for plain F11 — observed on glass as 'F11 only works with shift'); the shell's shortcuts panel lists both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
87 lines
4.1 KiB
Rust
87 lines
4.1 KiB
Rust
//! Generate bindings for `libavutil/hwcontext_vulkan.h` against the SYSTEM headers.
|
|
//!
|
|
//! ffmpeg-sys-next binds a curated header list that omits every hwcontext_*.h; the
|
|
//! Vulkan hwcontext structs (`AVVulkanDeviceContext`, `AVVkFrame`) are what let us run
|
|
//! FFmpeg's Vulkan Video decoder on the presenter's own VkDevice and read the decoded
|
|
//! VkImages back. Their layout depends on compile-time FF_API_* deprecation gates in
|
|
//! libavutil/version.h, so bindgen over the installed header is the only ABI-safe
|
|
//! source of truth — hand transcription would silently skew on the next FFmpeg bump.
|
|
//!
|
|
//! Non-Linux targets get an empty file: the workspace builds on macOS (clients/apple is
|
|
//! the client there), and this shim is Linux-client plumbing only.
|
|
|
|
use std::env;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=wrapper.h");
|
|
let out = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs");
|
|
|
|
if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("linux") {
|
|
std::fs::write(&out, "// pf-ffvk: Linux-only, empty on this target\n").unwrap();
|
|
return;
|
|
}
|
|
|
|
// Include paths from pkg-config (libavutil for the hwcontext header; the Vulkan
|
|
// headers usually live in /usr/include, but honor a registered vulkan.pc too).
|
|
// PF_FFVK_VULKAN_INCLUDE prepends an explicit Vulkan-Headers include dir — for
|
|
// cross builds and boxes without the system package.
|
|
println!("cargo:rerun-if-env-changed=PF_FFVK_VULKAN_INCLUDE");
|
|
let mut includes: Vec<PathBuf> = Vec::new();
|
|
if let Ok(dir) = env::var("PF_FFVK_VULKAN_INCLUDE") {
|
|
includes.push(PathBuf::from(dir));
|
|
}
|
|
let avutil = pkg_config::Config::new()
|
|
.cargo_metadata(false)
|
|
.probe("libavutil")
|
|
.expect("pkg-config: libavutil not found — install the FFmpeg dev package");
|
|
includes.extend(avutil.include_paths);
|
|
if let Ok(vk) = pkg_config::Config::new()
|
|
.cargo_metadata(false)
|
|
.probe("vulkan")
|
|
{
|
|
includes.extend(vk.include_paths);
|
|
}
|
|
|
|
let mut builder = bindgen::Builder::default()
|
|
.header("wrapper.h")
|
|
// The whole point of this crate: the Vulkan hwcontext surface…
|
|
.allowlist_type("AVVulkan.*")
|
|
.allowlist_type("AVVkFrame.*")
|
|
.allowlist_function("av_vk_frame_alloc")
|
|
.allowlist_function("av_vkfmt_from_pixfmt")
|
|
// The feature structs chained into AVVulkanDeviceContext.device_features (plain
|
|
// vulkan.h types; generating them here keeps the chain in one type system).
|
|
.allowlist_type("VkPhysicalDeviceVulkan11Features")
|
|
.allowlist_type("VkPhysicalDeviceVulkan12Features")
|
|
.allowlist_type("VkPhysicalDeviceVulkan13Features")
|
|
// AVVulkanFramesContext.img_flags values (plane views need MUTABLE_FORMAT).
|
|
.allowlist_type("VkImageCreateFlagBits")
|
|
// Timeline-semaphore wait — the pump measures true GPU decode completion.
|
|
.allowlist_type("VkSemaphoreWaitInfo")
|
|
.allowlist_type("PFN_vkWaitSemaphores")
|
|
.allowlist_type("PFN_vkGetDeviceProcAddr")
|
|
// …plus nothing else of FFmpeg: the core types these structs reference only
|
|
// ever appear behind pointers here, so keep them opaque instead of duplicating
|
|
// ffmpeg-sys-next's definitions (callers cast pointers between the crates).
|
|
.opaque_type("AVHWDeviceContext")
|
|
.opaque_type("AVHWFramesContext")
|
|
.opaque_type("AVBufferRef")
|
|
.opaque_type("AVFrame")
|
|
.derive_debug(false)
|
|
.layout_tests(true);
|
|
for dir in &includes {
|
|
builder = builder.clang_arg(format!("-I{}", dir.display()));
|
|
}
|
|
let bindings = builder.generate().expect(
|
|
"bindgen over libavutil/hwcontext_vulkan.h failed — is `vulkan-headers` installed? \
|
|
(the header includes <vulkan/vulkan.h>)",
|
|
);
|
|
bindings.write_to_file(&out).unwrap();
|
|
|
|
// The av_vk_* symbols live in libavutil, which ffmpeg-sys-next already links into
|
|
// every consumer of this crate; no extra link flags needed. Emitting the lib anyway
|
|
// keeps `cargo test -p pf-ffvk` linking standalone.
|
|
println!("cargo:rustc-link-lib=avutil");
|
|
}
|