//! Native Vulkan Video H.264 decode for the clients — M2 of the native-decode program
//! (design/client-native-decode.md §3.2).
//!
//! This crate sits between [`pf_bitstream`]'s per-AU planning and Vulkan Video
//! submission.
//!
//! WP-A — the CPU-testable half, everything runs without a GPU:
//!
//! - [`params`]: the vendored parser's `Sps`/`Pps` converted into the
//!   `StdVideoH264*ParameterSet` structs session parameters are created from, behind
//!   owning wrappers ([`OwnedStdSps`]/[`OwnedStdPps`]) because the Std structs embed
//!   raw pointers.
//! - [`slots`]: [`SlotMap`], the hardware DPB slot ledger keyed by
//!   [`pf_bitstream::h264::PicId`]. pf-bitstream's DPB decides what lives and dies;
//!   this map only translates ids to slot indices and refuses to guess.
//! - [`pic`]: [`plan_to_vk`], one [`pf_bitstream::h264::AuPlan`] converted into the
//!   `StdVideoDecodeH264PictureInfo`/`StdVideoDecodeH264ReferenceInfo` set plus slice
//!   offsets and slot bindings a `vkCmdDecodeVideoKHR` call wants.
//!
//! WP-B — the GPU half, built ON the borrowed presenter device (this crate never
//! creates or destroys a VkDevice) with the decision logic split out pure so it
//! stays CPU-testable:
//!
//! - [`device`]: [`DeviceHandles`] (the borrowed handle bundle + its liveness
//!   contract), the [`QueueLock`] trait every submit runs under, [`DecodeDevice`].
//! - [`caps`]: one thin driver query + [`derive_caps`], the pure
//!   coincide/distinct/layered decision table ([`DecodeCaps`]).
//! - [`session`]: `VkVideoSessionKHR` + versioned session parameters (pure ledger
//!   decides Add-vs-Recreate; extent/DPB renegotiation rebuilds the session).
//! - [`images`]: the picture pool DECOUPLED from DPB slots (the zero-copy FFmpeg
//!   pool model — a re-activated slot binds a fresh free image, so delivered
//!   pictures are never decode targets), per-image timeline semaphores with the
//!   presenter `value+1` write-back, per-plane views, [`HOLD_HEADROOM`] sizing.
//! - [`ring`]: the host-visible bitstream upload ring (pure alignment/growth
//!   math) — SLICE NALUs only (feeding a whole AU hangs VCN firmware).
//! - [`decoder`]: [`VkH264Decoder`] — plan → convert → upload → record → submit,
//!   with a per-op `RESULT_STATUS_ONLY` query ([`VkH264Decoder::poll_status`]) so
//!   driver-reported corruption is finally observable (the Ally X class) —
//!   caps-gated per queue family: where `queryResultStatusSupport` is absent
//!   (RADV), verdicts degrade to timeline completion, FFmpeg parity.
//!
//! M3 (HEVC) — the CPU half, over [`pf_bitstream::h265`]'s WP-1 planner:
//!
//! - [`params_h265`]: VPS/SPS/PPS into the `StdVideoH265*ParameterSet` structs
//!   behind owning wrappers ([`OwnedStdH265Vps`]/[`OwnedStdH265Sps`]/
//!   [`OwnedStdH265Pps`]) — Main/Main10/4:4:4 RExt fidelity carried through, the
//!   rest of the envelope rejected typed.
//! - [`pic_h265`]: [`plan_to_vk_h265`], one [`pf_bitstream::h265::AuPlan`] into
//!   `StdVideoDecodeH265PictureInfo`/`StdVideoDecodeH265ReferenceInfo` plus the
//!   RPS index arrays, slice offsets and slot bindings — over the SAME
//!   [`SlotMap`] (H.265's DPB ceiling is H.264's: 16 references + 1 setup).
//!
//! M3 (HEVC) — the GPU half, sharing every codec-agnostic piece with H.264
//! (picture pool, bitstream ring, op ring, DPB settling, frame delivery) rather
//! than re-implementing them:
//!
//! - [`caps_h265`]: [`H265ProfileKey`] (the stream's profile idc, chroma format
//!   and bit depths, which Vulkan wants stated on every object) and
//!   [`derive_caps_h265`] — Main → NV12, Main 10 → P010, RExt 4:4:4 → the
//!   two-plane 4:4:4 formats, with a device that cannot host the combination
//!   refused BEFORE a session exists ([`CapsError::NoFormat`]).
//! - [`session_h265`]: the H.265 session and its THREE-array parameters ledger —
//!   VPS included, with [`fallback_vps_from_sps`] standing in (and deduping
//!   correctly) for streams joined after their VPS NALU.
//! - [`decoder_h265`]: [`VkH265Decoder`], mirroring [`VkH264Decoder`]'s public
//!   surface method-for-method. Codec DISPATCH is the client wiring's job.
//!
//! M7 (AV1) — the CPU half, over [`pf_bitstream::av1`]'s planner:
//!
//! - [`params_av1`]: the sequence header into `StdVideoAV1SequenceHeader` behind an
//!   owning wrapper ([`OwnedStdAv1SequenceHeader`]) — the ONE parameter set AV1 has.
//! - [`pic_av1`]: [`plan_to_vk_av1`], one [`pf_bitstream::av1::AuPlan`] into
//!   `StdVideoDecodeAV1PictureInfo` and its eight per-frame sub-blocks, plus the
//!   per-reference-NAME DPB SLOT table, the tile-group ranges and the slot bindings
//!   — over the SAME [`SlotMap`] (AV1's ceiling is eight references + one setup).
//!
//! M7 (AV1) — the GPU half, sharing every codec-agnostic piece with the other two
//! (picture pool, bitstream ring, op ring, frame delivery, DPB settling) rather
//! than re-implementing them:
//!
//! - [`caps_av1`]: [`Av1ProfileKey`] — Std profile, sampling, bit depth AND the
//!   sequence's film-grain flag, because `filmGrainSupport` is part of the Vulkan
//!   decode PROFILE — and [`derive_caps_av1`]: 4:2:0 8-bit → NV12, 10-bit → P010,
//!   4:4:4 → the two-plane 4:4:4 pair, with a device that cannot host the
//!   combination (film grain very much included) refused BEFORE a session exists.
//! - [`session_av1`]: the AV1 session and its ONE-set parameters ledger — no PPS,
//!   no VPS, no update path at all, so a changed sequence header RECREATES.
//! - [`decoder_av1`]: [`VkAv1Decoder`], mirroring [`VkH265Decoder`]'s public
//!   surface method-for-method, over temporal units that may carry several frames.
//!
//! M4 (status and telemetry) — three pure modules turning the signals above into
//! something a session, a user and a support engineer can act on:
//!
//! - [`recovery`]: [`RecoveryWatch`], the recovery point SEI folded into a
//!   per-picture "the stream healed HERE" mark ([`RecoveryMark`], carried on
//!   [`DecodedVkFrame::recovery`]). The only clean point an intra-refresh session
//!   has — its wave emits no IDR — so without it a client freezes for its full
//!   backstop and then forces the very IDR the wave exists to avoid.
//! - [`integrity`]: [`is_integrity_warning`] / [`is_integrity_warning_h265`] /
//!   [`is_integrity_warning_av1`], the one list of warnings that mean the PICTURE
//!   is damaged. Here rather than in the client so the fault harness asserts
//!   against the predicate production conceals on.
//! - [`fault`]: [`AuFault`], deliberate decoder-input corruption
//!   (`PUNKTFUNK_AU_FAULT`), inert unless armed. A detector nobody can fire is
//!   exactly as trustworthy as no detector at all.
//!
//! Plus [`VkH264Decoder::status_queries`] / [`VkH265Decoder::status_queries`]: does
//! this device answer per-op `RESULT_STATUS` at all? Without that fact a clean
//! integrity report cannot be told apart from an unmeasured one — which is the
//! precise failure the program exists to end.
//!
//! Unsafe posture: unlike pf-bitstream (which forbids unsafe outright), this crate
//! cannot — the `ash::vk::native` bindgen structs are zero-initialized the way the
//! encode side does it (`pf-encode/src/enc/linux/vk_build.rs`), and the GPU half is
//! Vulkan FFI. Every unsafe block therefore carries a written `// SAFETY:` proof — enforced by
//! the workspace `[workspace.lints]` tables, and (unlike the encoder) with NO file-level
//! `unsafe_op_in_unsafe_fn` exemption: every operation is individually fenced.

pub mod caps;
pub mod caps_av1;
pub mod caps_h265;
pub mod decoder;
pub mod decoder_av1;
pub mod decoder_h265;
pub mod device;
pub mod fault;
pub mod images;
pub mod integrity;
pub mod params;
pub mod params_av1;
pub mod params_h265;
pub mod pic;
pub mod pic_av1;
pub mod pic_h265;
pub mod probe;
pub mod recovery;
pub mod ring;
pub mod session;
pub mod session_av1;
pub mod session_h265;
pub mod slots;

/// Re-exported for the integration layer (WP-C): [`DecodedVkFrame`]'s handle fields are
/// ash types, and the consumer (pf-client-core, whose own `ash` is optional/feature-gated)
/// flattens them to raw `u64`s through `ash::vk::Handle` — via THIS instance of ash, so
/// the versions can never skew.
pub use ash;
// The pf-bitstream types a [`DecodedVkFrame`] consumer names, re-exported so it
// doesn't grow a pf-bitstream dependency of its own:
/// [`VkAv1Decoder::take_warnings`]'s warning type — the AV1 twin of
/// [`PlanWarning`], renamed for the same reason [`H265PlanWarning`] is: the three
/// enums are genuinely different (AV1 has `MissingShowExisting`, and its
/// `MissingReference` needs no interpretation because no AV1 process empties a
/// reference slot behind the stream's back) and a consumer dispatching per codec
/// must be able to name all three.
pub use pf_bitstream::av1::PlanWarning as Av1PlanWarning;
/// [`DecodedVkFrame::colour`]'s type.
pub use pf_bitstream::h264::ColourDescription;
/// [`DecodedVkFrame::crop`]'s type.
pub use pf_bitstream::h264::DisplayCrop;
/// [`VkH264Decoder::take_warnings`]'s warning type.
pub use pf_bitstream::h264::PlanWarning;
/// [`VkH265Decoder::take_warnings`]'s warning type — the H.265 twin of
/// [`PlanWarning`], renamed rather than shadowed because the two enums are
/// genuinely different (H.264 has `FrameNumGap`/`Mmco5Rebase`, H.265 has
/// `NonZeroReorder`) and a consumer dispatching per codec must be able to name
/// BOTH. Without it the client could only render warnings as strings — and it has
/// to BRANCH on them: `NonZeroReorder` and `Mmco5Rebase` are spec-legal facts the
/// planner planned in full, not concealment, and dropping their frames would cost
/// a visible hitch at every SPS activation.
pub use pf_bitstream::h265::PlanWarning as H265PlanWarning;

pub use caps::derive_caps;
pub use caps::plane_formats;
pub use caps::CapsError;
pub use caps::DecodeCaps;
pub use caps::MaxLevelIdc;
pub use caps::RawH264Caps;
pub use caps::VideoFormat;
pub use caps::NV12;
pub use caps::OUTPUT_FORMATS;
pub use caps::P010;
pub use caps::YUV444_10;
pub use caps::YUV444_8;
pub use caps_av1::derive_caps_av1;
pub use caps_av1::Av1ProfileKey;
pub use caps_av1::RawAv1Caps;
pub use caps_h265::derive_caps_h265;
pub use caps_h265::output_format_for;
pub use caps_h265::H265ProfileKey;
pub use caps_h265::RawH265Caps;
pub use decoder::DecodeStatus;
pub use decoder::DecodedVkFrame;
pub use decoder::VkDecodeError;
pub use decoder::VkH264Decoder;
pub use decoder_av1::plan_bitstream;
pub use decoder_av1::Av1Bitstream;
pub use decoder_av1::Av1TileError;
pub use decoder_av1::VkAv1Decoder;
pub use decoder_h265::VkH265Decoder;
pub use device::DecodeDevice;
pub use device::DeviceHandles;
pub use device::NoopQueueLock;
pub use device::QueueLock;
pub use device::QueueSubmitGuard;
pub use fault::AuFault;
pub use fault::FaultAction;
pub use fault::FaultMode;
pub use fault::DEFAULT_FAULT_PERIOD;
pub use images::plan_pools;
pub use images::PoolPlan;
pub use images::HOLD_HEADROOM;
pub use integrity::is_integrity_warning;
pub use integrity::is_integrity_warning_av1;
pub use integrity::is_integrity_warning_h265;
pub use params::pps_to_std;
pub use params::sps_to_std;
pub use params::OwnedStdPps;
pub use params::OwnedStdSps;
pub use params::ParamsError;
pub use params_av1::sequence_to_std;
pub use params_av1::OwnedStdAv1SequenceHeader;
pub use params_av1::ParamsAv1Error;
pub use params_h265::fallback_vps_from_sps;
pub use params_h265::pps_to_std_h265;
pub use params_h265::sps_to_std_h265;
pub use params_h265::vps_to_std_h265;
pub use params_h265::H265ParamsError;
pub use params_h265::OwnedStdH265Pps;
pub use params_h265::OwnedStdH265Sps;
pub use params_h265::OwnedStdH265Vps;
pub use pic::plan_to_vk;
pub use pic::DecodePlanVk;
pub use pic::PlanToVkError;
pub use pic::VkRef;
pub use pic_av1::plan_to_vk_av1;
pub use pic_av1::DecodePlanVkAv1;
pub use pic_av1::OwnedStdAv1PictureInfo;
pub use pic_av1::PlanToVkAv1Error;
pub use pic_av1::VkRefAv1;
pub use pic_av1::REFERENCE_NAME_UNUSED;
pub use pic_h265::plan_to_vk_h265;
pub use pic_h265::DecodePlanVkH265;
pub use pic_h265::PlanToVkH265Error;
pub use pic_h265::VkRefH265;
pub use pic_h265::H265_RPS_LIST_SIZE;
pub use recovery::RecoveryMark;
pub use recovery::RecoveryWatch;
pub use ring::RingLayout;
pub use session::ParamsAction;
pub use session::SessionConfig;
pub use session_av1::ParamsActionAv1;
pub use session_av1::SessionConfigAv1;
pub use session_h265::ParamsActionH265;
pub use session_h265::SessionConfigH265;
pub use slots::SlotError;
pub use slots::SlotMap;
