hasvk: Add open-loop CBR and VBR rate control for gen7.

Only constant QP was offered.  Add the two bitrate modes, with the quantizer
derived once per picture from the requested bitrate and frame rate.

There is no closed loop and there cannot be one here: a picture's size is
known only after the GPU encodes it, and vkCmdEncodeVideoKHR merely records
commands.  The VA-API encoder for this hardware runs its bit rate control
after each frame completes, which that API's synchronisation allows and this
one does not, and gen7 has no macroblock-level rate control the hardware
drives on its own -- the VA-API driver leaves those MFX_AVC_IMG_STATE fields
zero on this generation.  Vulkan defines rate control as best effort, and
this is the effort.

The quantizer comes from a measured curve rather than a guess: sweeping QP 14
to 50 over a 176x144 clip gives 361 bits per macroblock at QP 26 for an I
picture and 166 for a P one, halving every 12.5 steps of the quantizer for I
and every 10.3 for P.  Measured against the target across a 15x range of
bitrates, I pictures land between 0.82x and 1.30x, P pictures between 0.59x
and 1.56x -- the spread on P is content dependent and nothing open loop can
narrow it.  A target below about 90 bits per macroblock cannot be met at all,
since that is where the curve flattens.

dEQP-VK.video.encode.h264 goes from 84 to 92 of 120 with no failures.  The
remaining 28 are quantization maps, which gen7 has no hardware path for, and
B frames.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
elwrclandClaude Opus 5 committed 2026-08-21 08:21:15 +03:00
1 parent e7142772a7
commit f68161c313
3 files changed
+124 -6

No files matched your search

+9 -3
View File
@@ -215,11 +215,17 @@ anv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_CAPABILITIES_KHR);
if (enc_caps) {
enc_caps->flags = 0;
/* Constant QP only; no CBR/VBR rate control. */
/* CBR and VBR are open loop: the quantizer is derived from the
* bitrate target once per picture and nothing measures the result,
* so both behave the same and neither tracks the target closely.
* See anv_video_rate_control_qp(). */
enc_caps->rateControlModes =
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR;
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR |
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR |
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR;
enc_caps->maxRateControlLayers = 1;
enc_caps->maxBitrate = 0;
/* Level 4.1's ceiling, the highest level the encoder reports. */
enc_caps->maxBitrate = 62500000;
enc_caps->maxQualityLevels = 1;
enc_caps->encodeInputPictureGranularity.width = ANV_MB_WIDTH;
enc_caps->encodeInputPictureGranularity.height = ANV_MB_HEIGHT;