# mediaway-encoder-vulkan — roadmap
Cross-platform Vulkan Video encode backend (`VK_KHR_video_encode_queue`).
Facade: [`mediaway-encoder`](../../mediaway-encoder/docs/roadmap.md).
Platform order: Windows → Web → Linux → other. Workspace index:
[`docs/roadmap.md`](../../../docs/roadmap.md). Sibling vendor/framework-axis
crates: `mediaway-encoder-nvenc`, `mediaway-encoder-quicksync`,
`mediaway-encoder-amf` (all ADR-only, not yet implemented).
## Stages
### 0 — Scaffold + capability probe (this change)
- [x] Workspace member + docs / ADR surface
- [x] `ash` dependency review + ADR ([0001](../adr/0001-vulkan-video-encode-ash-probe.md))
- [x] Real instance + physical-device + queue-family probe
(`probe::probe_video_encode_queue_families`): reports which queue
families advertise `VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR` /
`..._H265_BIT_KHR` per device
- [x] **Compiled / run** — hardware-verified same-day follow-up (ADR-0001
§ "Verification update"): found + fixed one real bug (`VK_KHR_video_queue`
is a device extension, not an instance one), then confirmed against real
hardware — RTX 4090 reports H.264/H.265 encode queue family `4`; Intel
UHD 770's Windows Vulkan driver reports no encode queue at all (genuine
finding, not a bug). `cargo test`/`clippy -D warnings`/`fmt --check` all
clean.
### 1 — H.264 encode session — hardware-verified 2026-07-29 (see ADR-0001 § Stage 1 addendum)
- [x] `vkGetPhysicalDeviceVideoCapabilitiesKHR` (profile-chain query: picture
layout, extent/alignment limits, DPB slot limits) — deeper than the
Stage 0 queue-family flag check (`session.rs::query_capabilities`)
- [x] `VkVideoSessionCreateInfoKHR` + memory binding
(`vkGetVideoSessionMemoryRequirementsKHR` /
`vkBindVideoSessionMemoryKHR`) — `session_encode.rs::create_video_session`
- [x] `VkVideoSessionParametersCreateInfoKHR` +
`VkVideoEncodeH264SessionParametersAddInfoKHR` (real SPS/PPS) —
`h264_params.rs` + `session_encode.rs::create_session_parameters`
- [x] DPB image (`VkVideoPictureResourceInfoKHR` /
`VkVideoReferenceSlotInfoKHR`) — single-slot/IDR-only, mirroring
`mediaway-encoder-linux`'s "every frame independent IDR" stage
- [x] CPU-upload input path (`session_encode.rs::synthetic_gray_nv12` +
`create_host_buffer`/`upload_to_host_memory` — a `copy`-class path, no
Zero-Copy claim; real cost-disclosure naming deferred to a
`mediaway_encoder::VideoEncoder` impl, not this diagnostic entry point)
- [x] `vkCmdBeginVideoCodingKHR` → `vkCmdEncodeVideoKHR` → `vkCmdEndVideoCodingKHR`
command submission + fence wait — `session_command.rs`
- [x] Bitstream readback (mapped output buffer → Annex-B bytes) —
`session_command.rs::submit_and_readback`; verified real (not just
"has start codes") via independent system FFmpeg oracle: `ffprobe`
parses `H.264 Baseline, 160x64, key_frame=1, level=10`; `ffmpeg` decodes
with no errors to a pixel-exact match of the synthetic gray input
- [x] `impl mediaway_encoder::VideoEncoder for VulkanVideoEncoder` —
**hardware-verified 2026-07-29** (see ADR-0001 § "VideoEncoder impl +
HEVC addendum"): `encoder.rs`, a real, reusable, multi-frame session
(instance/device/video session/session parameters/images/buffers/
command pool/fence/query pool all persist across `push_frame` calls —
only upload/record/submit/readback repeats per frame, mirroring
`mediaway-encoder-windows`'s `D3d12VideoEncoder`). Real per-frame
compressed-byte-count query (`VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR`)
closes [`encode_synthetic_intra_frame`]'s old "whole zero-padded
buffer" scope cut — packets are now byte-exact.
Real session shape (types, ownership) mostly follows ADR-0001's original
design sketch, minus the `VideoSession<S>` typestate (deferred — see the
ADR's Stage 1 addendum "Deliberate scope cuts").
### 2 — GOP / rate control (deferred)
- [ ] P-frame reference picture management, multi-slot DPB
- [ ] Rate control modes beyond fixed QP
### 3 — Zero-Copy GPU input (deferred)
- [ ] Windows: `VK_KHR_external_memory_win32` import of a
`GpuBufferHandle::DirectX11` (`ID3D11Texture2D`) as a Vulkan image
- [ ] Linux: `VK_KHR_external_memory_fd` (DMA-BUF) import
- [ ] `GpuBufferHandle::Vulkan` as Mediaway's own native path (no cross-API
import needed when the caller is already Vulkan-native)
### 4 — Multi-codec
- [x] HEVC via `VK_KHR_video_encode_h265` — **hardware-verified 2026-07-29**:
`hevc_params.rs` (`StdVideoH265*` VPS/SPS/PPS + picture-info/
slice-segment-header builders), `session_command_hevc.rs` (per-frame
recording — the one piece that couldn't share H.264's code, since the
picture-info `pNext` payload type differs). Real finding:
`picture_access_granularity` is **32x32** for HEVC on this driver, not
16x16 like H.264 — the two must never be assumed equal.
- [x] AV1 via `VK_KHR_video_encode_av1` — implemented (`av1_params.rs`,
`session_command_av1.rs`, `EncodeProfile::Av1`), migrated the crate from
`ash` (no AV1 bindings) to `vulkanalia` to unlock it (see
`adr/0001`'s migration addendum). **Blocked on this crate's reference
RTX 4090, hardware-verified 2026-07-29** (see `adr/0001`'s AV1
addendum): device/session/session-parameters/sequence-header all real
and hardware-verified, but every `vkCmdEncodeVideoKHR` frame's own
output is not a valid OBU stream — independently confirmed to be a
driver-maturity limitation, not this crate's bug (`ffmpeg -c:v
av1_vulkan` on the same machine produces AV1 output `dav1d` itself
rejects). `push_three_av1_frames_or_skip` self-documents this and skips
rather than hard-fails. Re-verify on a newer NVIDIA driver before
assuming this is still broken.