1use std::ffi::c_void;
2
3use ash::vk;
4
5use crate::VulkanDecoderError;
6use crate::VulkanInitError;
7use crate::parameters::H264Profile;
8use crate::wrappers::*;
9
10pub(crate) fn query_video_format_properties<'a>(
11 device: vk::PhysicalDevice,
12 video_queue_instance_ext: &ash::khr::video_queue::Instance,
13 profile_info: &vk::VideoProfileInfoKHR<'_>,
14 image_usage: vk::ImageUsageFlags,
15) -> Result<Vec<vk::VideoFormatPropertiesKHR<'a>>, VulkanInitError> {
16 let mut profile_list_info =
17 vk::VideoProfileListInfoKHR::default().profiles(std::slice::from_ref(profile_info));
18
19 let format_info = vk::PhysicalDeviceVideoFormatInfoKHR::default()
20 .image_usage(image_usage)
21 .push_next(&mut profile_list_info);
22
23 let mut format_info_length = 0;
24
25 unsafe {
26 (video_queue_instance_ext
27 .fp()
28 .get_physical_device_video_format_properties_khr)(
29 device,
30 &format_info,
31 &mut format_info_length,
32 std::ptr::null_mut(),
33 )
34 .result()?;
35 }
36
37 let mut format_properties =
38 vec![vk::VideoFormatPropertiesKHR::default(); format_info_length as usize];
39
40 unsafe {
41 (video_queue_instance_ext
42 .fp()
43 .get_physical_device_video_format_properties_khr)(
44 device,
45 &format_info,
46 &mut format_info_length,
47 format_properties.as_mut_ptr(),
48 )
49 .result()?;
50 }
51
52 Ok(format_properties)
53}
54
55#[derive(Debug, Clone, Copy)]
57pub struct EncodeCapabilities {
58 pub h264: Option<EncodeH264Capabilities>,
59}
60
61#[derive(Debug, Clone, Copy)]
65pub struct EncodeH264Capabilities {
66 pub baseline_profile: Option<EncodeH264ProfileCapabilities>,
67 pub main_profile: Option<EncodeH264ProfileCapabilities>,
68 pub high_profile: Option<EncodeH264ProfileCapabilities>,
69}
70
71#[derive(Debug, Clone, Copy)]
73pub struct EncodeH264ProfileCapabilities {
74 pub min_width: u32,
76 pub max_width: u32,
78 pub min_height: u32,
80 pub max_height: u32,
82 pub supported_rate_control: vk::VideoEncodeRateControlModeFlagsKHR,
84 pub max_references: u32,
86 pub quality_levels: u32,
88}
89
90#[derive(Debug, Clone)]
91pub(crate) struct NativeEncodeCapabilities {
92 pub(crate) baseline: Option<NativeEncodeProfileCapabilities>,
93 pub(crate) main: Option<NativeEncodeProfileCapabilities>,
94 pub(crate) high: Option<NativeEncodeProfileCapabilities>,
95}
96
97impl NativeEncodeCapabilities {
98 pub(crate) fn user_facing(&self) -> EncodeH264Capabilities {
99 EncodeH264Capabilities {
100 baseline_profile: self
101 .baseline
102 .as_ref()
103 .map(NativeEncodeProfileCapabilities::user_facing),
104 main_profile: self
105 .main
106 .as_ref()
107 .map(NativeEncodeProfileCapabilities::user_facing),
108 high_profile: self
109 .high
110 .as_ref()
111 .map(NativeEncodeProfileCapabilities::user_facing),
112 }
113 }
114
115 pub(crate) fn query(instance: &Instance, device: vk::PhysicalDevice) -> Self {
116 let baseline = NativeEncodeProfileCapabilities::query(
117 instance,
118 device,
119 vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_BASELINE,
120 )
121 .ok();
122 let main = NativeEncodeProfileCapabilities::query(
123 instance,
124 device,
125 vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_MAIN,
126 )
127 .ok();
128 let high = NativeEncodeProfileCapabilities::query(
129 instance,
130 device,
131 vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_HIGH,
132 )
133 .ok();
134
135 Self {
136 baseline,
137 main,
138 high,
139 }
140 }
141
142 pub(crate) fn profile(&self, profile: H264Profile) -> Option<&NativeEncodeProfileCapabilities> {
143 match profile {
144 H264Profile::Baseline => self.baseline.as_ref(),
145 H264Profile::Main => self.main.as_ref(),
146 H264Profile::High => self.high.as_ref(),
147 }
148 }
149
150 pub(crate) fn max_profile(&self) -> H264Profile {
151 if self.high.is_some() {
152 H264Profile::High
153 } else if self.main.is_some() {
154 H264Profile::Main
155 } else {
156 H264Profile::Baseline
157 }
158 }
159}
160
161#[derive(Debug, Clone)]
162#[allow(dead_code)]
163pub(crate) struct NativeEncodeProfileCapabilities {
164 pub(crate) video_capabilities: vk::VideoCapabilitiesKHR<'static>,
165 pub(crate) encode_capabilities: vk::VideoEncodeCapabilitiesKHR<'static>,
166 pub(crate) h264_encode_capabilities: vk::VideoEncodeH264CapabilitiesKHR<'static>,
167 pub(crate) encode_dpb_properties: Vec<vk::VideoFormatPropertiesKHR<'static>>,
168 pub(crate) encode_src_properties: Vec<vk::VideoFormatPropertiesKHR<'static>>,
169 pub(crate) quality_level_properties: Vec<NativeEncodeQualityLevelProperties>,
170}
171
172impl NativeEncodeProfileCapabilities {
173 fn user_facing(&self) -> EncodeH264ProfileCapabilities {
174 EncodeH264ProfileCapabilities {
175 min_width: self.video_capabilities.min_coded_extent.width,
176 max_width: self.video_capabilities.max_coded_extent.width,
177 min_height: self.video_capabilities.min_coded_extent.height,
178 max_height: self.video_capabilities.max_coded_extent.height,
179 supported_rate_control: self.encode_capabilities.rate_control_modes,
180 max_references: self
181 .h264_encode_capabilities
182 .max_p_picture_l0_reference_count,
183 quality_levels: self.encode_capabilities.max_quality_levels,
184 }
185 }
186
187 fn query(
188 instance: &Instance,
189 device: vk::PhysicalDevice,
190 profile: vk::native::StdVideoH264ProfileIdc,
191 ) -> Result<Self, VulkanInitError> {
192 let mut h264_encode_profile_info =
193 vk::VideoEncodeH264ProfileInfoKHR::default().std_profile_idc(profile);
194
195 let encode_profile_info = vk::VideoProfileInfoKHR::default()
196 .video_codec_operation(vk::VideoCodecOperationFlagsKHR::ENCODE_H264)
197 .chroma_subsampling(vk::VideoChromaSubsamplingFlagsKHR::TYPE_420)
198 .luma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8)
199 .chroma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8)
200 .push_next(&mut h264_encode_profile_info);
201
202 let encode_dpb_properties = query_video_format_properties(
203 device,
204 &instance.video_queue_instance_ext,
205 &encode_profile_info,
206 vk::ImageUsageFlags::VIDEO_ENCODE_DPB_KHR,
207 )?;
208
209 let encode_src_properties = query_video_format_properties(
210 device,
211 &instance.video_queue_instance_ext,
212 &encode_profile_info,
213 vk::ImageUsageFlags::VIDEO_ENCODE_SRC_KHR,
214 )?;
215
216 let mut h264_encode_caps = vk::VideoEncodeH264CapabilitiesKHR::default();
217 let mut encode_caps = vk::VideoEncodeCapabilitiesKHR {
218 p_next: (&mut h264_encode_caps as *mut _) as *mut c_void,
219 ..Default::default()
220 };
221 let mut caps = vk::VideoCapabilitiesKHR::default().push_next(&mut encode_caps);
222
223 unsafe {
224 (instance
225 .video_queue_instance_ext
226 .fp()
227 .get_physical_device_video_capabilities_khr)(
228 device,
229 &encode_profile_info,
230 &mut caps,
231 )
232 .result()?;
233 }
234
235 let video_capabilities = vk::VideoCapabilitiesKHR::default()
236 .flags(caps.flags)
237 .min_bitstream_buffer_offset_alignment(caps.min_bitstream_buffer_offset_alignment)
238 .min_bitstream_buffer_size_alignment(caps.min_bitstream_buffer_size_alignment)
239 .picture_access_granularity(caps.picture_access_granularity)
240 .min_coded_extent(caps.min_coded_extent)
241 .max_coded_extent(caps.max_coded_extent)
242 .max_dpb_slots(caps.max_dpb_slots)
243 .max_active_reference_pictures(caps.max_active_reference_pictures)
244 .std_header_version(caps.std_header_version);
245
246 let encode_capabilities = vk::VideoEncodeCapabilitiesKHR::default()
247 .flags(encode_caps.flags)
248 .rate_control_modes(encode_caps.rate_control_modes)
249 .max_rate_control_layers(encode_caps.max_rate_control_layers)
250 .max_bitrate(encode_caps.max_bitrate)
251 .max_quality_levels(encode_caps.max_quality_levels)
252 .encode_input_picture_granularity(encode_caps.encode_input_picture_granularity)
253 .supported_encode_feedback_flags(encode_caps.supported_encode_feedback_flags);
254
255 let h264_encode_capabilities = vk::VideoEncodeH264CapabilitiesKHR::default()
256 .flags(h264_encode_caps.flags)
257 .max_level_idc(h264_encode_caps.max_level_idc)
258 .max_slice_count(h264_encode_caps.max_slice_count)
259 .max_p_picture_l0_reference_count(h264_encode_caps.max_p_picture_l0_reference_count)
260 .max_b_picture_l0_reference_count(h264_encode_caps.max_b_picture_l0_reference_count)
261 .max_l1_reference_count(h264_encode_caps.max_l1_reference_count)
262 .max_temporal_layer_count(h264_encode_caps.max_temporal_layer_count)
263 .expect_dyadic_temporal_layer_pattern(
264 h264_encode_caps.expect_dyadic_temporal_layer_pattern != 0,
265 )
266 .min_qp(h264_encode_caps.min_qp)
267 .max_qp(h264_encode_caps.max_qp)
268 .prefers_gop_remaining_frames(h264_encode_caps.prefers_gop_remaining_frames != 0)
269 .requires_gop_remaining_frames(h264_encode_caps.requires_gop_remaining_frames != 0)
270 .std_syntax_flags(h264_encode_caps.std_syntax_flags);
271
272 let mut quality_level_properties =
273 Vec::with_capacity(encode_capabilities.max_quality_levels as usize);
274
275 for i in 0..encode_capabilities.max_quality_levels {
276 if let Ok(qlp) =
277 NativeEncodeQualityLevelProperties::query(instance, device, &encode_profile_info, i)
278 {
279 quality_level_properties.push(qlp);
280 }
281 }
282
283 Ok(Self {
284 video_capabilities,
285 encode_capabilities,
286 h264_encode_capabilities,
287 encode_dpb_properties,
288 encode_src_properties,
289 quality_level_properties,
290 })
291 }
292}
293
294#[derive(Debug, Clone)]
295pub(crate) struct NativeEncodeQualityLevelProperties {
296 pub(crate) quality_level_properties: vk::VideoEncodeQualityLevelPropertiesKHR<'static>,
297 pub(crate) h264_quality_level_properties: vk::VideoEncodeH264QualityLevelPropertiesKHR<'static>,
298}
299
300impl NativeEncodeQualityLevelProperties {
301 fn query(
302 instance: &Instance,
303 device: vk::PhysicalDevice,
304 profile_info: &vk::VideoProfileInfoKHR<'_>,
305 quality_level: u32,
306 ) -> Result<Self, VulkanInitError> {
307 let quality_level_info = vk::PhysicalDeviceVideoEncodeQualityLevelInfoKHR::default()
308 .video_profile(profile_info)
309 .quality_level(quality_level);
310
311 let mut h264_qlp = vk::VideoEncodeH264QualityLevelPropertiesKHR::default();
312 let mut qlp = vk::VideoEncodeQualityLevelPropertiesKHR::default().push_next(&mut h264_qlp);
313
314 unsafe {
315 (instance
316 .video_encode_queue_instance_ext
317 .fp()
318 .get_physical_device_video_encode_quality_level_properties_khr)(
319 device,
320 &quality_level_info,
321 &mut qlp,
322 )
323 .result()?;
324 }
325
326 let quality_level_properties = vk::VideoEncodeQualityLevelPropertiesKHR::default()
327 .preferred_rate_control_mode(qlp.preferred_rate_control_mode)
328 .preferred_rate_control_layer_count(qlp.preferred_rate_control_layer_count);
329
330 let h264_quality_level_properties = vk::VideoEncodeH264QualityLevelPropertiesKHR::default()
331 .preferred_rate_control_flags(h264_qlp.preferred_rate_control_flags)
332 .preferred_gop_frame_count(h264_qlp.preferred_gop_frame_count)
333 .preferred_idr_period(h264_qlp.preferred_idr_period)
334 .preferred_consecutive_b_frame_count(h264_qlp.preferred_consecutive_b_frame_count)
335 .preferred_temporal_layer_count(h264_qlp.preferred_temporal_layer_count)
336 .preferred_constant_qp(h264_qlp.preferred_constant_qp)
337 .preferred_max_l0_reference_count(h264_qlp.preferred_max_l0_reference_count)
338 .preferred_max_l1_reference_count(h264_qlp.preferred_max_l1_reference_count)
339 .preferred_std_entropy_coding_mode_flag(
340 h264_qlp.preferred_std_entropy_coding_mode_flag != 0,
341 );
342
343 Ok(Self {
344 quality_level_properties,
345 h264_quality_level_properties,
346 })
347 }
348
349 pub(crate) fn zeroed(&self) -> bool {
350 self.quality_level_properties
352 .preferred_rate_control_mode
353 .as_raw()
354 == 0
355 && self
356 .quality_level_properties
357 .preferred_rate_control_layer_count
358 == 0
359 && self
360 .h264_quality_level_properties
361 .preferred_rate_control_flags
362 .as_raw()
363 == 0
364 && self.h264_quality_level_properties.preferred_gop_frame_count == 0
365 && self.h264_quality_level_properties.preferred_idr_period == 0
366 && self
367 .h264_quality_level_properties
368 .preferred_consecutive_b_frame_count
369 == 0
370 && self
371 .h264_quality_level_properties
372 .preferred_temporal_layer_count
373 == 0
374 && self
375 .h264_quality_level_properties
376 .preferred_constant_qp
377 .qp_i
378 == 0
379 && self
380 .h264_quality_level_properties
381 .preferred_constant_qp
382 .qp_p
383 == 0
384 && self
385 .h264_quality_level_properties
386 .preferred_constant_qp
387 .qp_b
388 == 0
389 && self
390 .h264_quality_level_properties
391 .preferred_max_l0_reference_count
392 == 0
393 && self
394 .h264_quality_level_properties
395 .preferred_max_l1_reference_count
396 == 0
397 && self
398 .h264_quality_level_properties
399 .preferred_std_entropy_coding_mode_flag
400 == 0
401 }
402}
403
404#[derive(Debug, Clone, Copy)]
406pub struct DecodeCapabilities {
407 pub h264: Option<DecodeH264Capabilities>,
408}
409
410#[derive(Debug, Clone, Copy)]
414pub struct DecodeH264Capabilities {
415 pub baseline_profile: Option<DecodeH264ProfileCapabilities>,
416 pub main_profile: Option<DecodeH264ProfileCapabilities>,
417 pub high_profile: Option<DecodeH264ProfileCapabilities>,
418}
419
420#[derive(Debug, Clone, Copy)]
422pub struct DecodeH264ProfileCapabilities {
423 pub min_width: u32,
425 pub max_width: u32,
427 pub min_height: u32,
429 pub max_height: u32,
431 pub max_level_idc: u8,
433}
434
435#[derive(Debug, Clone)]
436pub(crate) struct NativeDecodeCapabilities {
437 pub(crate) baseline: Option<NativeDecodeProfileCapabilities>,
438 pub(crate) main: Option<NativeDecodeProfileCapabilities>,
439 pub(crate) high: Option<NativeDecodeProfileCapabilities>,
440}
441
442impl NativeDecodeCapabilities {
443 pub(crate) fn user_facing(&self) -> DecodeH264Capabilities {
444 DecodeH264Capabilities {
445 baseline_profile: self
446 .baseline
447 .as_ref()
448 .and_then(|profile| profile.user_facing().ok()),
449 main_profile: self
450 .main
451 .as_ref()
452 .and_then(|profile| profile.user_facing().ok()),
453 high_profile: self
454 .high
455 .as_ref()
456 .and_then(|profile| profile.user_facing().ok()),
457 }
458 }
459
460 pub(crate) fn query(instance: &Instance, device: vk::PhysicalDevice) -> Self {
461 let baseline = NativeDecodeProfileCapabilities::query(
462 instance,
463 device,
464 vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_BASELINE,
465 )
466 .ok();
467 let main = NativeDecodeProfileCapabilities::query(
468 instance,
469 device,
470 vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_MAIN,
471 )
472 .ok();
473 let high = NativeDecodeProfileCapabilities::query(
474 instance,
475 device,
476 vk::native::StdVideoH264ProfileIdc_STD_VIDEO_H264_PROFILE_IDC_HIGH,
477 )
478 .ok();
479
480 Self {
481 baseline,
482 main,
483 high,
484 }
485 }
486
487 pub(crate) fn profile(&self, profile: H264Profile) -> Option<&NativeDecodeProfileCapabilities> {
488 match profile {
489 H264Profile::Baseline => self.baseline.as_ref(),
490 H264Profile::Main => self.main.as_ref(),
491 H264Profile::High => self.high.as_ref(),
492 }
493 }
494
495 pub(crate) fn max_profile(&self) -> H264Profile {
496 if self.high.is_some() {
497 H264Profile::High
498 } else if self.main.is_some() {
499 H264Profile::Main
500 } else {
501 H264Profile::Baseline
502 }
503 }
504}
505
506#[derive(Debug, Clone)]
507pub(crate) struct NativeDecodeProfileCapabilities {
508 pub(crate) video_capabilities: vk::VideoCapabilitiesKHR<'static>,
509 #[allow(dead_code)]
510 pub(crate) decode_capabilities: vk::VideoDecodeCapabilitiesKHR<'static>,
511 pub(crate) h264_decode_capabilities: vk::VideoDecodeH264CapabilitiesKHR<'static>,
512 pub(crate) h264_dpb_format_properties: vk::VideoFormatPropertiesKHR<'static>,
513 pub(crate) h264_dst_format_properties: Option<vk::VideoFormatPropertiesKHR<'static>>,
514}
515
516impl NativeDecodeProfileCapabilities {
517 pub(crate) fn user_facing(&self) -> Result<DecodeH264ProfileCapabilities, VulkanDecoderError> {
518 Ok(DecodeH264ProfileCapabilities {
519 min_width: self.video_capabilities.min_coded_extent.width,
520 max_width: self.video_capabilities.max_coded_extent.width,
521 min_height: self.video_capabilities.min_coded_extent.height,
522 max_height: self.video_capabilities.max_coded_extent.height,
523 max_level_idc: vk_to_h264_level_idc(self.h264_decode_capabilities.max_level_idc)?,
524 })
525 }
526
527 pub(crate) fn query(
528 instance: &Instance,
529 device: vk::PhysicalDevice,
530 profile: vk::native::StdVideoH264ProfileIdc,
531 ) -> Result<Self, VulkanInitError> {
532 let mut h264_decode_profile_info = vk::VideoDecodeH264ProfileInfoKHR::default()
533 .picture_layout(vk::VideoDecodeH264PictureLayoutFlagsKHR::PROGRESSIVE)
534 .std_profile_idc(profile);
535
536 let decode_profile_info = vk::VideoProfileInfoKHR::default()
537 .video_codec_operation(vk::VideoCodecOperationFlagsKHR::DECODE_H264)
538 .chroma_subsampling(vk::VideoChromaSubsamplingFlagsKHR::TYPE_420)
539 .luma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8)
540 .chroma_bit_depth(vk::VideoComponentBitDepthFlagsKHR::TYPE_8)
541 .push_next(&mut h264_decode_profile_info);
542
543 let mut h264_decode_caps = vk::VideoDecodeH264CapabilitiesKHR::default();
544 let mut decode_caps = vk::VideoDecodeCapabilitiesKHR {
545 p_next: (&mut h264_decode_caps as *mut _) as *mut c_void, ..Default::default()
547 };
548
549 let mut caps = vk::VideoCapabilitiesKHR::default().push_next(&mut decode_caps);
550
551 unsafe {
552 (instance
553 .video_queue_instance_ext
554 .fp()
555 .get_physical_device_video_capabilities_khr)(
556 device,
557 &decode_profile_info,
558 &mut caps,
559 )
560 .result()?
561 };
562
563 let video_capabilities = vk::VideoCapabilitiesKHR::default()
564 .flags(caps.flags)
565 .min_bitstream_buffer_size_alignment(caps.min_bitstream_buffer_size_alignment)
566 .min_bitstream_buffer_offset_alignment(caps.min_bitstream_buffer_offset_alignment)
567 .picture_access_granularity(caps.picture_access_granularity)
568 .min_coded_extent(caps.min_coded_extent)
569 .max_coded_extent(caps.max_coded_extent)
570 .max_dpb_slots(caps.max_dpb_slots)
571 .max_active_reference_pictures(caps.max_active_reference_pictures)
572 .std_header_version(caps.std_header_version);
573
574 let decode_capabilities =
575 vk::VideoDecodeCapabilitiesKHR::default().flags(decode_caps.flags);
576
577 let h264_decode_capabilities = vk::VideoDecodeH264CapabilitiesKHR::default()
578 .max_level_idc(h264_decode_caps.max_level_idc)
579 .field_offset_granularity(h264_decode_caps.field_offset_granularity);
580
581 let flags = decode_caps.flags;
582
583 let h264_dpb_format_properties =
584 if flags.contains(vk::VideoDecodeCapabilityFlagsKHR::DPB_AND_OUTPUT_COINCIDE) {
585 query_video_format_properties(
586 device,
587 &instance.video_queue_instance_ext,
588 &decode_profile_info,
589 vk::ImageUsageFlags::VIDEO_DECODE_DST_KHR
590 | vk::ImageUsageFlags::VIDEO_DECODE_DPB_KHR
591 | vk::ImageUsageFlags::TRANSFER_SRC,
592 )?
593 } else {
594 query_video_format_properties(
595 device,
596 &instance.video_queue_instance_ext,
597 &decode_profile_info,
598 vk::ImageUsageFlags::VIDEO_DECODE_DPB_KHR,
599 )?
600 };
601
602 let h264_dst_format_properties =
603 if flags.contains(vk::VideoDecodeCapabilityFlagsKHR::DPB_AND_OUTPUT_COINCIDE) {
604 None
605 } else {
606 Some(query_video_format_properties(
607 device,
608 &instance.video_queue_instance_ext,
609 &decode_profile_info,
610 vk::ImageUsageFlags::VIDEO_DECODE_DST_KHR | vk::ImageUsageFlags::TRANSFER_SRC,
611 )?)
612 };
613
614 let h264_dpb_format_properties = match h264_dpb_format_properties
615 .into_iter()
616 .find(|f| f.format == vk::Format::G8_B8R8_2PLANE_420_UNORM)
617 {
618 Some(f) => f,
619 None => return Err(VulkanInitError::NoNV12ProfileSupport),
620 };
621
622 let h264_dst_format_properties = match h264_dst_format_properties {
623 Some(format_properties) => match format_properties
624 .into_iter()
625 .find(|f| f.format == vk::Format::G8_B8R8_2PLANE_420_UNORM)
626 {
627 Some(f) => Some(f),
628 None => return Err(VulkanInitError::NoNV12ProfileSupport),
629 },
630 None => None,
631 };
632
633 Ok(Self {
634 video_capabilities,
635 decode_capabilities,
636 h264_decode_capabilities,
637 h264_dpb_format_properties,
638 h264_dst_format_properties,
639 })
640 }
641}