Skip to content

Commit

Permalink
Initial YUV and external memory support (#1467)
Browse files Browse the repository at this point in the history
* vulkano: image: improve formatting

Ran cargo fmt --all.  Should we use clippy too ?

* vk_sys: add additional formats

This updates the vk formats enum to the header that's on my
system (vk 1.2-ish).

* vulkano: image: Add NV12 and YV12 support

These formats are commonly used as targets for hardware and
software video decode.  The common case is the swapchain allocator
(gralloc in the Android use case) allocates some memory, the video
stack decodes to it, and then memory can be composited by Vulkan
or sent directly to the display.

* vk_sys: update structure types

This updates the structure types to a VK 1.2-ish state.  Long term,
it makes a ton of sense to autogenerate vk-sys to make adding
additional features and enumerations easier [1].  For now, we can
hand edit.

[1] (#89)

* vk_sys: add VK_KHR_external_memory_fd bindings

This adds some basic external memory features.  Most of these
features are core in VK1.1.

* vulkano: memory: add and use DeviceMemoryBuilder

We'll need to:

(a) Create exportable memory
(b) import from a OS descriptor to create DeviceMemory
(c) Also support dedicated allocations

The device memory API is becoming rather complicated.  Let's use
the common builder pattern to simplify this.

* vulkano: memory: implement some external features

This change is sufficient to create exportable memory and
export it.  It's only been tested on Linux platforms and depends
on Unix file descriptors, so enable it only there for now.

Import support will be added later.  Support for external buffers
and images can also be added later if someone needs it.
  • Loading branch information
gurchetansingh authored Jan 9, 2021
1 parent 3113d1f commit 2d60c08
Show file tree
Hide file tree
Showing 12 changed files with 1,508 additions and 119 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG_VK_SYS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Unreleased

- Added support for VK1.2 formats.
- Added support for additional image aspect bits.
- Updated the structure type enum to match VK1.2.
- Added some `VK_KHR_external_memory` and `VK_KHR_external_memory_fd`
bindings:
+ enum `ExternalMemoryHandleTypeFlagBits`
+ struct `ExportMemoryAllocateInfo`
+ struct `ExternalMemoryBufferCreateInfo`
+ struct `ExternalMemoryImageCreateInfo`
+ struct `MemoryFdPropertiesKHR`
+ struct `MemoryGetFdInfoKHR`
+ struct `ImportMemoryFdInfoKHR`
+ function `GetMemoryFdKHR`
+ function `GetMemoryFdPropertiesKHR`

# Version 0.5.3 (2020-12-26)

- Added support for:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG_VULKANO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Unreleased

- Added support for `ImageAspect` and YV12/NV12 formats, for use with the UnsafeImage API.
- Added basic VK_KHR_external_memory, VK_KHR_external_memory_fd, and VK_EXT_external_memory_dma_buf support.

# Version 0.20.0 (2020-12-26)

- **Breaking** The `ImmutableImage::from_iter` and `ImmutableImage::from_buffer` can build Mipmaps
Expand Down
863 changes: 832 additions & 31 deletions vk-sys/src/lib.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions vulkano/src/device/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ device_extensions! {
ext_debug_utils => b"VK_EXT_debug_utils",
khr_multiview => b"VK_KHR_multiview",
ext_full_screen_exclusive => b"VK_EXT_full_screen_exclusive",
khr_external_memory => b"VK_KHR_external_memory",
khr_external_memory_fd => b"VK_KHR_external_memory_fd",
ext_external_memory_dmabuf => b"VK_EXT_external_memory_dma_buf",
}

/// This helper type can only be instantiated inside this module.
Expand Down
44 changes: 40 additions & 4 deletions vulkano/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ macro_rules! formats {
}
}

/// Returns (width, heigh) of the dimensions for block based formats. For
/// Returns (width, height) of the dimensions for block based formats. For
/// non block formats will return (1,1)
#[inline]
pub fn block_dimensions(&self) -> (u32, u32) {
Expand Down Expand Up @@ -432,13 +432,35 @@ macro_rules! formats {
}
};

(__inner_impl__ $name:ident ycbcr) => {
unsafe impl FormatDesc for $name {
type ClearValue = [f32; 4];

#[inline]
fn format(&self) -> Format {
Format::$name
}

#[inline]
fn decode_clear_value(&self, val: Self::ClearValue) -> ClearValue {
ClearValue::None
}
}

unsafe impl PossibleYcbcrFormatDesc for $name {
#[inline(always)]
fn is_ycbcr(&self) -> bool { true }
}
};

(__inner_ty__ $name:ident float=$num:tt) => { FormatTy::Float };
(__inner_ty__ $name:ident uint=$num:tt) => { FormatTy::Uint };
(__inner_ty__ $name:ident sint=$num:tt) => { FormatTy::Sint };
(__inner_ty__ $name:ident depth) => { FormatTy::Depth };
(__inner_ty__ $name:ident stencil) => { FormatTy::Stencil };
(__inner_ty__ $name:ident depthstencil) => { FormatTy::DepthStencil };
(__inner_ty__ $name:ident compressed=$f:tt) => { FormatTy::Compressed };
(__inner_ty__ $name:ident ycbcr) => { FormatTy::Ycbcr };


(__inner_strongstorage__ $name:ident [$ty:ty; $dim:expr]) => {
Expand Down Expand Up @@ -648,6 +670,8 @@ formats! {
ASTC_12x10SrgbBlock => FORMAT_ASTC_12x10_SRGB_BLOCK [(12, 10)] [Some(16)] [compressed=texture_compression_astc_ldr] {u8},
ASTC_12x12UnormBlock => FORMAT_ASTC_12x12_UNORM_BLOCK [(12, 12)] [Some(16)] [compressed=texture_compression_astc_ldr] {u8},
ASTC_12x12SrgbBlock => FORMAT_ASTC_12x12_SRGB_BLOCK [(12, 12)] [Some(16)] [compressed=texture_compression_astc_ldr] {u8},
G8B8R8_3PLANE420Unorm => FORMAT_G8_B8_R8_3PLANE_420_UNORM [(1, 1)] [None] [ycbcr] {},
G8B8R8_2PLANE420Unorm => FORMAT_G8_B8R8_2PLANE_420_UNORM [(1, 1)] [None] [ycbcr] {},
}

pub unsafe trait FormatDesc {
Expand Down Expand Up @@ -772,6 +796,19 @@ unsafe impl PossibleFloatOrCompressedFormatDesc for Format {
}
}

/// Trait for types that can possibly describe a Ycbcr format.
pub unsafe trait PossibleYcbcrFormatDesc: FormatDesc {
/// Trait for types that can possibly describe a Ycbcr format.
fn is_ycbcr(&self) -> bool;
}

unsafe impl PossibleYcbcrFormatDesc for Format {
#[inline]
fn is_ycbcr(&self) -> bool {
self.ty() == FormatTy::Ycbcr
}
}

macro_rules! impl_pixel {
{$($ty:ty;)+} => {
$(impl_pixel!(inner $ty);)*
Expand Down Expand Up @@ -818,16 +855,15 @@ pub enum FormatTy {
Stencil,
DepthStencil,
Compressed,
Ycbcr,
}

impl FormatTy {
/// Returns true if `Depth`, `Stencil`, `DepthStencil`. False otherwise.
#[inline]
pub fn is_depth_and_or_stencil(&self) -> bool {
match *self {
FormatTy::Depth => true,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil => true,
_ => false,
}
}
Expand Down
132 changes: 132 additions & 0 deletions vulkano/src/image/aspect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) 2020 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::BitOr;
use vk;

/// Describes how an aspect of the image that be used to query Vulkan. This is **not** just a suggestion.
/// Check out VkImageAspectFlagBits in the Vulkan spec.
///
/// If you specify an aspect of the image that doesn't exist (for example, depth for a YUV image), a panic
/// will happen.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImageAspect {
pub color: bool,
pub depth: bool,
pub stencil: bool,
pub metadata: bool,
pub plane0: bool,
pub plane1: bool,
pub plane2: bool,
pub memory_plane0: bool,
pub memory_plane1: bool,
pub memory_plane2: bool,
}

impl ImageAspect {
/// Builds a `ImageAspect` with all values set to false. Useful as a default value.
///
/// # Example
///
/// ```rust
/// use vulkano::image::ImageAspect as ImageAspect;
///
/// let _aspect = ImageAspect {
/// color: true,
/// depth: true,
/// .. ImageAspect::none()
/// };
/// ```
#[inline]
pub fn none() -> ImageAspect {
ImageAspect {
color: false,
depth: false,
stencil: false,
metadata: false,
plane0: false,
plane1: false,
plane2: false,
memory_plane0: false,
memory_plane1: false,
memory_plane2: false,
}
}

#[inline]
pub(crate) fn to_aspect_bits(&self) -> vk::ImageAspectFlagBits {
let mut result = 0;
if self.color {
result |= vk::IMAGE_ASPECT_COLOR_BIT;
}
if self.depth {
result |= vk::IMAGE_ASPECT_DEPTH_BIT;
}
if self.stencil {
result |= vk::IMAGE_ASPECT_STENCIL_BIT;
}
if self.metadata {
result |= vk::IMAGE_ASPECT_METADATA_BIT;
}
if self.plane0 {
result |= vk::IMAGE_ASPECT_PLANE_0_BIT;
}
if self.plane1 {
result |= vk::IMAGE_ASPECT_PLANE_1_BIT;
}
if self.plane2 {
result |= vk::IMAGE_ASPECT_PLANE_2_BIT;
}
if self.memory_plane0 {
result |= vk::IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
}
if self.memory_plane1 {
result |= vk::IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
}
if self.memory_plane2 {
result |= vk::IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT
}
result
}

pub(crate) fn from_bits(val: u32) -> ImageAspect {
ImageAspect {
color: (val & vk::IMAGE_ASPECT_COLOR_BIT) != 0,
depth: (val & vk::IMAGE_ASPECT_DEPTH_BIT) != 0,
stencil: (val & vk::IMAGE_ASPECT_STENCIL_BIT) != 0,
metadata: (val & vk::IMAGE_ASPECT_METADATA_BIT) != 0,
plane0: (val & vk::IMAGE_ASPECT_PLANE_0_BIT) != 0,
plane1: (val & vk::IMAGE_ASPECT_PLANE_1_BIT) != 0,
plane2: (val & vk::IMAGE_ASPECT_PLANE_2_BIT) != 0,
memory_plane0: (val & vk::IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT) != 0,
memory_plane1: (val & vk::IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT) != 0,
memory_plane2: (val & vk::IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT) != 0,
}
}
}

impl BitOr for ImageAspect {
type Output = Self;

#[inline]
fn bitor(self, rhs: Self) -> Self {
ImageAspect {
color: self.color || rhs.color,
depth: self.depth || rhs.depth,
stencil: self.stencil || rhs.stencil,
metadata: self.metadata || rhs.metadata,
plane0: self.plane0 || rhs.plane0,
plane1: self.plane1 || rhs.plane1,
plane2: self.plane2 || rhs.plane2,
memory_plane0: self.memory_plane0 || rhs.memory_plane0,
memory_plane1: self.memory_plane1 || rhs.memory_plane1,
memory_plane2: self.memory_plane2 || rhs.memory_plane2,
}
}
}
11 changes: 4 additions & 7 deletions vulkano/src/image/immutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ pub struct ImmutableImage<F, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc
layout: ImageLayout,
}


/// Image whose purpose is to access only a part of one image, for any kind of access
/// We define a part of one image here by a level of mipmap, or a layer of an array
/// The image attribute must be an implementation of ImageAccess
Expand All @@ -80,8 +79,7 @@ pub struct SubImage {
layout: ImageLayout,
}

impl SubImage
{
impl SubImage {
pub fn new(
image: Arc<dyn ImageAccess + Sync + Send>,
mip_level: u32,
Expand Down Expand Up @@ -120,7 +118,7 @@ fn has_mipmaps(mipmaps: MipmapsCount) -> bool {
match mipmaps {
MipmapsCount::One => false,
MipmapsCount::Log2 => true,
MipmapsCount::Specific(x) => x > 1
MipmapsCount::Specific(x) => x > 1,
}
}

Expand Down Expand Up @@ -422,7 +420,7 @@ impl<F> ImmutableImage<F> {

let future = match cb.execute(queue) {
Ok(f) => f,
Err(e) => unreachable!("{:?}", e)
Err(e) => unreachable!("{:?}", e),
};

image.initialized.store(true, Ordering::Relaxed);
Expand Down Expand Up @@ -583,8 +581,7 @@ where
}
}

unsafe impl ImageAccess for SubImage
{
unsafe impl ImageAccess for SubImage {
#[inline]
fn inner(&self) -> ImageInner {
self.image.inner()
Expand Down
31 changes: 25 additions & 6 deletions vulkano/src/image/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use std::cmp;
use std::convert::TryFrom;

pub use self::aspect::ImageAspect;
pub use self::attachment::AttachmentImage;
pub use self::immutable::ImmutableImage;
pub use self::layout::ImageLayout;
Expand All @@ -60,6 +61,7 @@ pub use self::traits::ImageInner;
pub use self::traits::ImageViewAccess;
pub use self::usage::ImageUsage;

mod aspect;
pub mod attachment; // TODO: make private
pub mod immutable; // TODO: make private
mod layout;
Expand Down Expand Up @@ -684,11 +686,11 @@ impl ImageDimensions {

#[cfg(test)]
mod tests {
use format;
use image::Dimensions;
use image::ImageDimensions;
use image::ImmutableImage;
use image::Dimensions;
use image::MipmapsCount;
use format;

#[test]
fn max_mipmaps() {
Expand Down Expand Up @@ -806,22 +808,39 @@ mod tests {
fn mipmap_working_immutable_image() {
let (device, queue) = gfx_dev_and_queue!();

let dimensions = Dimensions::Dim2d{width: 512, height: 512};
let dimensions = Dimensions::Dim2d {
width: 512,
height: 512,
};
{
let mut vec = Vec::new();

vec.resize(512 * 512, 0u8);

let (image, _) = ImmutableImage::from_iter(vec.into_iter(), dimensions, MipmapsCount::One, format::R8Unorm, queue.clone()).unwrap();
let (image, _) = ImmutableImage::from_iter(
vec.into_iter(),
dimensions,
MipmapsCount::One,
format::R8Unorm,
queue.clone(),
)
.unwrap();
assert_eq!(image.mipmap_levels(), 1);
}
{
let mut vec = Vec::new();

vec.resize(512 * 512, 0u8);

let (image, _) = ImmutableImage::from_iter(vec.into_iter(), dimensions, MipmapsCount::Log2, format::R8Unorm, queue.clone()).unwrap();
let (image, _) = ImmutableImage::from_iter(
vec.into_iter(),
dimensions,
MipmapsCount::Log2,
format::R8Unorm,
queue.clone(),
)
.unwrap();
assert_eq!(image.mipmap_levels(), 10);
}
}
}
}
Loading

0 comments on commit 2d60c08

Please sign in to comment.