Skip to content

Commit

Permalink
Add support for video capabilities and formats
Browse files Browse the repository at this point in the history
  • Loading branch information
dwlsalmeida committed Oct 2, 2023
1 parent 18a40c8 commit 238ce58
Show file tree
Hide file tree
Showing 4 changed files with 458 additions and 26 deletions.
41 changes: 40 additions & 1 deletion examples/src/bin/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::sync::Arc;

use vulkano::{
device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, QueueFlags},
image::ImageUsage,
instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions},
video::{H264ProfileInfo, ProfileInfo, VideoDecodeH264PictureLayoutFlags, VideoFormatInfo},
VulkanLibrary,
};

Expand Down Expand Up @@ -99,5 +101,42 @@ fn main() {
video_properties.video_codec_operations
);

// let video_capabilities = //vkGetPhysicalDeviceVideoCapabilitiesKHR
let profile_info = ProfileInfo {
video_codec_operation: vulkano::video::VideoCodecOperation::DecodeH264,
chroma_subsampling: vulkano::video::VideoChromaSubsampling::Type420,
luma_bit_depth: vulkano::video::VideoComponentBitDepth::Type8,
chroma_bit_depth: Some(vulkano::video::VideoComponentBitDepth::Type8),
codec_profile_info: vulkano::video::DecodeProfileInfo::H264(H264ProfileInfo {
std_profile_idc: 0,
picture_layout: VideoDecodeH264PictureLayoutFlags::PROGRESSIVE,
..Default::default()
}),
..Default::default()
};

let video_caps = physical_device.video_capabilities(profile_info).unwrap();
println!("Video capabilities: {:#?}", video_caps);

// let h264_caps = match video_caps.decode_capabilities.codec_capabilities {
// vulkano::video::VideoDecodeCodecCapabilities::H264(ref caps) => caps,
// _ => panic!("unexpected codec capabilities"),
// };

let video_format_info = VideoFormatInfo {
image_usage: if video_caps.decode_capabilities.flags
& vulkano::video::VideoDecodeCapabilityFlags::DPB_AND_OUTPUT_COINCIDE
== 0
{
ImageUsage::VIDEO_DECODE_DPB
} else {
ImageUsage::VIDEO_DECODE_DPB
| ImageUsage::VIDEO_DECODE_DST
| ImageUsage::TRANSFER_SRC
| ImageUsage::SAMPLED
},
};

let formats = physical_device
.video_format_properties(video_format_info)
.unwrap();
}
181 changes: 181 additions & 0 deletions vulkano/src/device/physical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ use crate::{
semaphore::{ExternalSemaphoreInfo, ExternalSemaphoreProperties},
Sharing,
},
video::{
ProfileInfo, VideoCapabilities, VideoCodecOperation, VideoDecodeCapabilities,
VideoDecodeCodecCapabilities, VideoDecodeH264Capabilities, VideoFormatInfo,
VideoFormatProperties,
},
DebugWrapper, ExtensionProperties, Requires, RequiresAllOf, RequiresOneOf, Validated,
ValidationError, Version, VulkanError, VulkanObject,
};
Expand Down Expand Up @@ -2654,6 +2659,182 @@ impl PhysicalDevice {
visual_id,
) != 0
}

pub fn video_format_properties(
&self,
video_format_info: VideoFormatInfo,
) -> Result<Vec<VideoFormatProperties>, Validated<VulkanError>> {
self.validate_video_format_info(&video_format_info)?;

unsafe { Ok(self.video_format_properties_unchecked(video_format_info)?) }
}

fn validate_video_format_info(
&self,
video_format_info: &VideoFormatInfo,
) -> Result<(), Box<ValidationError>> {
if !self.supported_extensions.khr_video_queue || self.api_version() < Version::V1_3 {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("khr_video_queue"),
// Requires::APIVersion(Version::V1_3), // ?
])]),
..Default::default()
}));
} else {
Ok(())
}
}

#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn video_format_properties_unchecked(
&self,
video_format_info: VideoFormatInfo,
) -> Result<Vec<VideoFormatProperties>, VulkanError> {
let mut video_format_properties = vec![];

Ok(video_format_properties)
}

pub fn video_capabilities(
&self,
profile_info: ProfileInfo,
) -> Result<VideoCapabilities, Validated<VulkanError>> {
self.validate_video_capabilities(&profile_info)?;

unsafe { Ok(self.video_capabilities_unchecked(profile_info)?) }
}

fn validate_video_capabilities(
&self,
profile_info: &ProfileInfo,
) -> Result<(), Box<ValidationError>> {
if !self.supported_extensions.khr_video_queue || self.api_version() < Version::V1_3 {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceExtension("khr_video_queue"),
// Requires::APIVersion(Version::V1_3), // ?
])]),
..Default::default()
}));
}

profile_info
.validate()
.map_err(|err| err.add_context("profile_info"))
}

#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn video_capabilities_unchecked(
&self,
profile_info: ProfileInfo,
) -> Result<VideoCapabilities, VulkanError> {
let mut video_capabilities = ash::vk::VideoCapabilitiesKHR::default();
let mut decode_capabilities = ash::vk::VideoDecodeCapabilitiesKHR::default();
let mut h264_decode_capabilities = None;
let mut h264_profile_info = None;

let ProfileInfo {
video_codec_operation,
chroma_subsampling,
luma_bit_depth,
chroma_bit_depth,
codec_profile_info,
_ne: _,
} = profile_info;

let mut profile_info = ash::vk::VideoProfileInfoKHR {
video_codec_operation: video_codec_operation.into(),
chroma_subsampling: chroma_subsampling.into(),
luma_bit_depth: luma_bit_depth.into(),
chroma_bit_depth: if let Some(chroma_bit_depth) = chroma_bit_depth {
chroma_bit_depth.into()
} else {
ash::vk::VideoComponentBitDepthFlagsKHR::INVALID
},
..Default::default()
};

match video_codec_operation {
VideoCodecOperation::EncodeH264 => todo!(),
VideoCodecOperation::EncodeH265 => todo!(),
VideoCodecOperation::DecodeH264 => {
let h264_decode_capabilities = h264_decode_capabilities
.insert(ash::vk::VideoDecodeH264CapabilitiesKHR::default());

let codec_profile_info = match codec_profile_info {
crate::video::DecodeProfileInfo::H264(p) => p,
_ => panic!("invalid profile info for H264"),
};

decode_capabilities.p_next = h264_decode_capabilities as *mut _ as *mut _;
video_capabilities.p_next = &mut decode_capabilities as *mut _ as *mut _;

let codec_profile_info =
h264_profile_info.insert(ash::vk::VideoDecodeH264ProfileInfoKHR {
std_profile_idc: codec_profile_info.std_profile_idc,
picture_layout: codec_profile_info.picture_layout.into(),
..Default::default()
});

// VUID-VkVideoProfileInfoKHR-videoCodecOperation-07179
profile_info.p_next = codec_profile_info as *const _ as *const _;
}
VideoCodecOperation::DecodeH265 => todo!(),
}

let fns = self.instance().fns();
(fns.khr_video_queue
.get_physical_device_video_capabilities_khr)(
self.handle(),
&mut profile_info,
&mut video_capabilities,
)
.result()
.map_err(VulkanError::from)?;

Ok(VideoCapabilities {
flags: video_capabilities.flags.into(),
min_bitstream_buffer_offset_alignment: video_capabilities
.min_bitstream_buffer_offset_alignment,
min_bitstream_buffer_size_alignment: video_capabilities
.min_bitstream_buffer_size_alignment,
picture_access_granularity: [
video_capabilities.picture_access_granularity.width,
video_capabilities.picture_access_granularity.height,
],
min_coded_extent: [
video_capabilities.min_coded_extent.width,
video_capabilities.min_coded_extent.height,
],
max_coded_extent: [
video_capabilities.max_coded_extent.width,
video_capabilities.max_coded_extent.height,
],
max_dpb_slots: video_capabilities.max_dpb_slots,
max_active_reference_pictures: video_capabilities.max_active_reference_pictures,
std_header_version: video_capabilities.std_header_version.into(),
decode_capabilities: VideoDecodeCapabilities {
flags: decode_capabilities.flags.into(),
codec_capabilities: match video_codec_operation {
VideoCodecOperation::DecodeH264 => {
let h264_decode_capabilities = h264_decode_capabilities.unwrap();
VideoDecodeCodecCapabilities::H264(VideoDecodeH264Capabilities {
max_level_idc: h264_decode_capabilities.max_level_idc,
field_offset_granularity: [
h264_decode_capabilities.field_offset_granularity.x,
h264_decode_capabilities.field_offset_granularity.y,
],
_ne: crate::NonExhaustive(()),
})
}
_ => unimplemented!(),
},
_ne: crate::NonExhaustive(()),
},
_ne: crate::NonExhaustive(()),
})
}
}

impl Debug for PhysicalDevice {
Expand Down
9 changes: 3 additions & 6 deletions vulkano/src/image/usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,23 @@ vulkan_bitflags! {
/// The image can be used as an input attachment in a render pass/framebuffer.
INPUT_ATTACHMENT = INPUT_ATTACHMENT,

/* TODO: enable
// TODO: document
VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_video_decode_queue)]),
]),*/
]),

/* TODO: enable
// TODO: document
VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_video_decode_queue)]),
]),*/
]),

/* TODO: enable
// TODO: document
VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR
RequiresOneOf([
RequiresAllOf([DeviceExtension(khr_video_decode_queue)]),
]),*/
]),

/* TODO: enable
// TODO: document
Expand Down
Loading

0 comments on commit 238ce58

Please sign in to comment.