Merge pull request #195 from mahkoh/jorth/vulkan-linear
Add support for hardware cursors on nvidia + vulkan
This commit is contained in:
commit
5ce9d38c59
4 changed files with 314 additions and 82 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
- Add support for pointer-gestures-unstable-v1.
|
- Add support for pointer-gestures-unstable-v1.
|
||||||
- Configs can now handle switch events (laptop lid closed/opened).
|
- Configs can now handle switch events (laptop lid closed/opened).
|
||||||
- Add support for tablet-v2.
|
- Add support for tablet-v2.
|
||||||
|
- Add support for linear framebuffers (hardware cursors/screensharing) on NVIDIA if the Vulkan renderer is used. (The OpenGL renderer does not support this.)
|
||||||
|
|
||||||
# 1.1.0 (2024-04-22)
|
# 1.1.0 (2024-04-22)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
format::{Format, FORMATS},
|
format::{Format, FORMATS},
|
||||||
gfx_apis::vulkan::{instance::VulkanInstance, VulkanError},
|
gfx_apis::vulkan::{instance::VulkanInstance, VulkanError},
|
||||||
video::Modifier,
|
video::{Modifier, LINEAR_MODIFIER},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
ash::{
|
ash::{
|
||||||
|
|
@ -17,14 +17,14 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isnt::std_1::collections::IsntHashMapExt,
|
isnt::std_1::collections::IsntHashMapExt,
|
||||||
|
std::cmp::min,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VulkanFormat {
|
pub struct VulkanFormat {
|
||||||
pub format: &'static Format,
|
pub format: &'static Format,
|
||||||
pub modifiers: AHashMap<Modifier, VulkanModifier>,
|
pub modifiers: AHashMap<Modifier, VulkanModifier>,
|
||||||
pub shm: Option<VulkanShmFormat>,
|
pub shm: Option<VulkanInternalFormat>,
|
||||||
pub features: FormatFeatureFlags,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -34,6 +34,7 @@ pub struct VulkanModifier {
|
||||||
pub features: FormatFeatureFlags,
|
pub features: FormatFeatureFlags,
|
||||||
pub render_max_extents: Option<VulkanMaxExtents>,
|
pub render_max_extents: Option<VulkanMaxExtents>,
|
||||||
pub texture_max_extents: Option<VulkanMaxExtents>,
|
pub texture_max_extents: Option<VulkanMaxExtents>,
|
||||||
|
pub render_needs_bridge: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
|
@ -43,7 +44,7 @@ pub struct VulkanMaxExtents {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VulkanShmFormat {
|
pub struct VulkanInternalFormat {
|
||||||
pub max_extents: VulkanMaxExtents,
|
pub max_extents: VulkanMaxExtents,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,6 +52,7 @@ const FRAMEBUFFER_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
0 | FormatFeatureFlags::COLOR_ATTACHMENT.as_raw()
|
0 | FormatFeatureFlags::COLOR_ATTACHMENT.as_raw()
|
||||||
| FormatFeatureFlags::COLOR_ATTACHMENT_BLEND.as_raw(),
|
| FormatFeatureFlags::COLOR_ATTACHMENT_BLEND.as_raw(),
|
||||||
);
|
);
|
||||||
|
const FRAMEBUFFER_BRIDGED_FEATURES: FormatFeatureFlags = FormatFeatureFlags::TRANSFER_DST;
|
||||||
const TEX_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
const TEX_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
0 | FormatFeatureFlags::SAMPLED_IMAGE.as_raw()
|
0 | FormatFeatureFlags::SAMPLED_IMAGE.as_raw()
|
||||||
| FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
| FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
||||||
|
|
@ -65,6 +67,7 @@ const SHM_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
const FRAMEBUFFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
const FRAMEBUFFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||||
0 | ImageUsageFlags::COLOR_ATTACHMENT.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
0 | ImageUsageFlags::COLOR_ATTACHMENT.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
||||||
);
|
);
|
||||||
|
const FRAMEBUFFER_BRIDGED_USAGE: ImageUsageFlags = ImageUsageFlags::TRANSFER_DST;
|
||||||
const TEX_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
const TEX_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||||
0 | ImageUsageFlags::SAMPLED.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
0 | ImageUsageFlags::SAMPLED.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
||||||
);
|
);
|
||||||
|
|
@ -104,7 +107,8 @@ impl VulkanInstance {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let shm = self.load_shm_format(phy_dev, format, &format_properties)?;
|
let shm = self.load_shm_format(phy_dev, format, &format_properties)?;
|
||||||
let modifiers = self.load_drm_format(phy_dev, format, &modifier_props)?;
|
let modifiers =
|
||||||
|
self.load_drm_format(phy_dev, format, &format_properties, &modifier_props)?;
|
||||||
if shm.is_some() || modifiers.is_not_empty() {
|
if shm.is_some() || modifiers.is_not_empty() {
|
||||||
dst.insert(
|
dst.insert(
|
||||||
format.drm,
|
format.drm,
|
||||||
|
|
@ -112,7 +116,6 @@ impl VulkanInstance {
|
||||||
format,
|
format,
|
||||||
modifiers,
|
modifiers,
|
||||||
shm,
|
shm,
|
||||||
features: format_properties.format_properties.optimal_tiling_features,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -124,14 +127,25 @@ impl VulkanInstance {
|
||||||
phy_dev: PhysicalDevice,
|
phy_dev: PhysicalDevice,
|
||||||
format: &Format,
|
format: &Format,
|
||||||
props: &FormatProperties2,
|
props: &FormatProperties2,
|
||||||
) -> Result<Option<VulkanShmFormat>, VulkanError> {
|
) -> Result<Option<VulkanInternalFormat>, VulkanError> {
|
||||||
if format.shm_info.is_none() {
|
if format.shm_info.is_none() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
self.load_internal_format(phy_dev, format, props, SHM_FEATURES, SHM_USAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_internal_format(
|
||||||
|
&self,
|
||||||
|
phy_dev: PhysicalDevice,
|
||||||
|
format: &Format,
|
||||||
|
props: &FormatProperties2,
|
||||||
|
features: FormatFeatureFlags,
|
||||||
|
usage: ImageUsageFlags,
|
||||||
|
) -> Result<Option<VulkanInternalFormat>, VulkanError> {
|
||||||
if !props
|
if !props
|
||||||
.format_properties
|
.format_properties
|
||||||
.optimal_tiling_features
|
.optimal_tiling_features
|
||||||
.contains(SHM_FEATURES)
|
.contains(features)
|
||||||
{
|
{
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +153,7 @@ impl VulkanInstance {
|
||||||
.ty(ImageType::TYPE_2D)
|
.ty(ImageType::TYPE_2D)
|
||||||
.format(format.vk_format)
|
.format(format.vk_format)
|
||||||
.tiling(ImageTiling::OPTIMAL)
|
.tiling(ImageTiling::OPTIMAL)
|
||||||
.usage(SHM_USAGE);
|
.usage(usage);
|
||||||
let mut format_properties = ImageFormatProperties2::builder();
|
let mut format_properties = ImageFormatProperties2::builder();
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
self.instance.get_physical_device_image_format_properties2(
|
self.instance.get_physical_device_image_format_properties2(
|
||||||
|
|
@ -154,7 +168,7 @@ impl VulkanInstance {
|
||||||
_ => Err(VulkanError::LoadImageProperties(e)),
|
_ => Err(VulkanError::LoadImageProperties(e)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(Some(VulkanShmFormat {
|
Ok(Some(VulkanInternalFormat {
|
||||||
max_extents: VulkanMaxExtents {
|
max_extents: VulkanMaxExtents {
|
||||||
width: format_properties.image_format_properties.max_extent.width,
|
width: format_properties.image_format_properties.max_extent.width,
|
||||||
height: format_properties.image_format_properties.max_extent.height,
|
height: format_properties.image_format_properties.max_extent.height,
|
||||||
|
|
@ -166,6 +180,7 @@ impl VulkanInstance {
|
||||||
&self,
|
&self,
|
||||||
phy_dev: PhysicalDevice,
|
phy_dev: PhysicalDevice,
|
||||||
format: &Format,
|
format: &Format,
|
||||||
|
internal_format_properties: &FormatProperties2,
|
||||||
props: &DrmFormatModifierPropertiesListEXT,
|
props: &DrmFormatModifierPropertiesListEXT,
|
||||||
) -> Result<AHashMap<Modifier, VulkanModifier>, VulkanError> {
|
) -> Result<AHashMap<Modifier, VulkanModifier>, VulkanError> {
|
||||||
if props.drm_format_modifier_count == 0 {
|
if props.drm_format_modifier_count == 0 {
|
||||||
|
|
@ -190,7 +205,7 @@ impl VulkanInstance {
|
||||||
};
|
};
|
||||||
let mut mods = AHashMap::new();
|
let mut mods = AHashMap::new();
|
||||||
for modifier in drm_mods {
|
for modifier in drm_mods {
|
||||||
let render_max_extents = self.get_max_extents(
|
let mut render_max_extents = self.get_max_extents(
|
||||||
phy_dev,
|
phy_dev,
|
||||||
format,
|
format,
|
||||||
FRAMEBUFFER_FEATURES,
|
FRAMEBUFFER_FEATURES,
|
||||||
|
|
@ -199,6 +214,18 @@ impl VulkanInstance {
|
||||||
)?;
|
)?;
|
||||||
let texture_max_extents =
|
let texture_max_extents =
|
||||||
self.get_max_extents(phy_dev, format, TEX_FEATURES, TEX_USAGE, &modifier)?;
|
self.get_max_extents(phy_dev, format, TEX_FEATURES, TEX_USAGE, &modifier)?;
|
||||||
|
let mut render_needs_bridge = false;
|
||||||
|
if render_max_extents.is_none() && modifier.drm_format_modifier == LINEAR_MODIFIER {
|
||||||
|
render_max_extents = self.get_fb_bridged_max_extents(
|
||||||
|
phy_dev,
|
||||||
|
format,
|
||||||
|
internal_format_properties,
|
||||||
|
&modifier,
|
||||||
|
)?;
|
||||||
|
if render_max_extents.is_some() {
|
||||||
|
render_needs_bridge = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
mods.insert(
|
mods.insert(
|
||||||
modifier.drm_format_modifier,
|
modifier.drm_format_modifier,
|
||||||
VulkanModifier {
|
VulkanModifier {
|
||||||
|
|
@ -207,12 +234,52 @@ impl VulkanInstance {
|
||||||
features: modifier.drm_format_modifier_tiling_features,
|
features: modifier.drm_format_modifier_tiling_features,
|
||||||
render_max_extents,
|
render_max_extents,
|
||||||
texture_max_extents,
|
texture_max_extents,
|
||||||
|
render_needs_bridge,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(mods)
|
Ok(mods)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_fb_bridged_max_extents(
|
||||||
|
&self,
|
||||||
|
phy_dev: PhysicalDevice,
|
||||||
|
format: &Format,
|
||||||
|
internal_format_properties: &FormatProperties2,
|
||||||
|
modifier: &DrmFormatModifierPropertiesEXT,
|
||||||
|
) -> Result<Option<VulkanMaxExtents>, VulkanError> {
|
||||||
|
let transfer_dst_max_extents = self.get_max_extents(
|
||||||
|
phy_dev,
|
||||||
|
format,
|
||||||
|
FRAMEBUFFER_BRIDGED_FEATURES,
|
||||||
|
FRAMEBUFFER_BRIDGED_USAGE,
|
||||||
|
&modifier,
|
||||||
|
)?;
|
||||||
|
let Some(transfer_dst_max_extents) = transfer_dst_max_extents else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
let bridge_format = self.load_internal_format(
|
||||||
|
phy_dev,
|
||||||
|
format,
|
||||||
|
internal_format_properties,
|
||||||
|
FRAMEBUFFER_FEATURES,
|
||||||
|
FRAMEBUFFER_USAGE,
|
||||||
|
)?;
|
||||||
|
let Some(bridge_format) = bridge_format else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
Ok(Some(VulkanMaxExtents {
|
||||||
|
width: min(
|
||||||
|
transfer_dst_max_extents.width,
|
||||||
|
bridge_format.max_extents.width,
|
||||||
|
),
|
||||||
|
height: min(
|
||||||
|
transfer_dst_max_extents.height,
|
||||||
|
bridge_format.max_extents.height,
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_max_extents(
|
fn get_max_extents(
|
||||||
&self,
|
&self,
|
||||||
phy_dev: PhysicalDevice,
|
phy_dev: PhysicalDevice,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ pub struct VulkanDmaBufImageTemplate {
|
||||||
pub(super) dmabuf: DmaBuf,
|
pub(super) dmabuf: DmaBuf,
|
||||||
pub(super) render_max_extents: Option<VulkanMaxExtents>,
|
pub(super) render_max_extents: Option<VulkanMaxExtents>,
|
||||||
pub(super) texture_max_extents: Option<VulkanMaxExtents>,
|
pub(super) texture_max_extents: Option<VulkanMaxExtents>,
|
||||||
|
pub(super) render_needs_bridge: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VulkanImage {
|
pub struct VulkanImage {
|
||||||
|
|
@ -53,6 +54,7 @@ pub struct VulkanImage {
|
||||||
pub(super) is_undefined: Cell<bool>,
|
pub(super) is_undefined: Cell<bool>,
|
||||||
pub(super) ty: VulkanImageMemory,
|
pub(super) ty: VulkanImageMemory,
|
||||||
pub(super) render_ops: CloneCell<Vec<GfxApiOpt>>,
|
pub(super) render_ops: CloneCell<Vec<GfxApiOpt>>,
|
||||||
|
pub(super) bridge: Option<VulkanFramebufferBridge>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum VulkanImageMemory {
|
pub enum VulkanImageMemory {
|
||||||
|
|
@ -72,6 +74,11 @@ pub struct VulkanShmImage {
|
||||||
pub(super) _allocation: VulkanAllocation,
|
pub(super) _allocation: VulkanAllocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VulkanFramebufferBridge {
|
||||||
|
pub(super) dmabuf_image: Image,
|
||||||
|
pub(super) _allocation: VulkanAllocation,
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for VulkanDmaBufImage {
|
impl Drop for VulkanDmaBufImage {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -96,6 +103,12 @@ impl Drop for VulkanImage {
|
||||||
.destroy_image_view(render_view, None);
|
.destroy_image_view(render_view, None);
|
||||||
}
|
}
|
||||||
self.renderer.device.device.destroy_image(self.image, None);
|
self.renderer.device.device.destroy_image(self.image, None);
|
||||||
|
if let Some(bridge) = &self.bridge {
|
||||||
|
self.renderer
|
||||||
|
.device
|
||||||
|
.device
|
||||||
|
.destroy_image(bridge.dmabuf_image, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,6 +227,7 @@ impl VulkanRenderer {
|
||||||
is_undefined: Cell::new(true),
|
is_undefined: Cell::new(true),
|
||||||
ty: VulkanImageMemory::Internal(shm),
|
ty: VulkanImageMemory::Internal(shm),
|
||||||
render_ops: Default::default(),
|
render_ops: Default::default(),
|
||||||
|
bridge: None,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,6 +278,7 @@ impl VulkanRenderer {
|
||||||
dmabuf: dmabuf.clone(),
|
dmabuf: dmabuf.clone(),
|
||||||
render_max_extents: modifier.render_max_extents,
|
render_max_extents: modifier.render_max_extents,
|
||||||
texture_max_extents: modifier.texture_max_extents,
|
texture_max_extents: modifier.texture_max_extents,
|
||||||
|
render_needs_bridge: modifier.render_needs_bridge,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -302,21 +317,14 @@ impl VulkanDevice {
|
||||||
|
|
||||||
impl VulkanDmaBufImageTemplate {
|
impl VulkanDmaBufImageTemplate {
|
||||||
pub fn create_framebuffer(self: &Rc<Self>) -> Result<Rc<VulkanImage>, VulkanError> {
|
pub fn create_framebuffer(self: &Rc<Self>) -> Result<Rc<VulkanImage>, VulkanError> {
|
||||||
self.create_image(true, None)
|
self.create_image(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_texture(
|
pub fn create_texture(self: &Rc<Self>) -> Result<Rc<VulkanImage>, VulkanError> {
|
||||||
self: &Rc<Self>,
|
self.create_image(false)
|
||||||
shm: Option<VulkanShmImage>,
|
|
||||||
) -> Result<Rc<VulkanImage>, VulkanError> {
|
|
||||||
self.create_image(false, shm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_image(
|
fn create_image(self: &Rc<Self>, for_rendering: bool) -> Result<Rc<VulkanImage>, VulkanError> {
|
||||||
self: &Rc<Self>,
|
|
||||||
for_rendering: bool,
|
|
||||||
shm: Option<VulkanShmImage>,
|
|
||||||
) -> Result<Rc<VulkanImage>, VulkanError> {
|
|
||||||
let device = &self.renderer.device;
|
let device = &self.renderer.device;
|
||||||
let max_extents = match for_rendering {
|
let max_extents = match for_rendering {
|
||||||
true => self.render_max_extents,
|
true => self.render_max_extents,
|
||||||
|
|
@ -350,12 +358,13 @@ impl VulkanDmaBufImageTemplate {
|
||||||
true => ImageCreateFlags::DISJOINT,
|
true => ImageCreateFlags::DISJOINT,
|
||||||
false => ImageCreateFlags::empty(),
|
false => ImageCreateFlags::empty(),
|
||||||
};
|
};
|
||||||
let usage = ImageUsageFlags::TRANSFER_SRC
|
let usage = match for_rendering {
|
||||||
| match (for_rendering, shm.is_some()) {
|
true => match self.render_needs_bridge {
|
||||||
(true, _) => ImageUsageFlags::COLOR_ATTACHMENT,
|
true => ImageUsageFlags::TRANSFER_DST,
|
||||||
(false, false) => ImageUsageFlags::SAMPLED,
|
false => ImageUsageFlags::TRANSFER_SRC | ImageUsageFlags::COLOR_ATTACHMENT,
|
||||||
(false, true) => ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER_DST,
|
},
|
||||||
};
|
false => ImageUsageFlags::TRANSFER_SRC | ImageUsageFlags::SAMPLED,
|
||||||
|
};
|
||||||
let create_info = ImageCreateInfo::builder()
|
let create_info = ImageCreateInfo::builder()
|
||||||
.image_type(ImageType::TYPE_2D)
|
.image_type(ImageType::TYPE_2D)
|
||||||
.format(self.dmabuf.format.vk_format)
|
.format(self.dmabuf.format.vk_format)
|
||||||
|
|
@ -464,15 +473,30 @@ impl VulkanDmaBufImageTemplate {
|
||||||
}
|
}
|
||||||
let res = unsafe { device.device.bind_image_memory2(&bind_image_memory_infos) };
|
let res = unsafe { device.device.bind_image_memory2(&bind_image_memory_infos) };
|
||||||
res.map_err(VulkanError::BindImageMemory)?;
|
res.map_err(VulkanError::BindImageMemory)?;
|
||||||
let texture_view = device.create_image_view(image, self.dmabuf.format, false)?;
|
let mut primary_image = image;
|
||||||
let render_view = device.create_image_view(image, self.dmabuf.format, true)?;
|
let mut destroy_bridge_image = None;
|
||||||
|
let mut bridge = None;
|
||||||
|
if for_rendering && self.render_needs_bridge {
|
||||||
|
let (bridge_image, allocation) = self.create_bridge()?;
|
||||||
|
primary_image = bridge_image;
|
||||||
|
destroy_bridge_image = Some(OnDrop(|| unsafe {
|
||||||
|
device.device.destroy_image(primary_image, None)
|
||||||
|
}));
|
||||||
|
bridge = Some(VulkanFramebufferBridge {
|
||||||
|
dmabuf_image: image,
|
||||||
|
_allocation: allocation,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let texture_view = device.create_image_view(primary_image, self.dmabuf.format, false)?;
|
||||||
|
let render_view = device.create_image_view(primary_image, self.dmabuf.format, true)?;
|
||||||
free_device_memories.drain(..).for_each(mem::forget);
|
free_device_memories.drain(..).for_each(mem::forget);
|
||||||
mem::forget(destroy_image);
|
mem::forget(destroy_image);
|
||||||
|
mem::forget(destroy_bridge_image);
|
||||||
Ok(Rc::new(VulkanImage {
|
Ok(Rc::new(VulkanImage {
|
||||||
renderer: self.renderer.clone(),
|
renderer: self.renderer.clone(),
|
||||||
texture_view,
|
texture_view,
|
||||||
render_view: Some(render_view),
|
render_view: Some(render_view),
|
||||||
image,
|
image: primary_image,
|
||||||
width: self.width,
|
width: self.width,
|
||||||
height: self.height,
|
height: self.height,
|
||||||
stride: 0,
|
stride: 0,
|
||||||
|
|
@ -483,8 +507,53 @@ impl VulkanDmaBufImageTemplate {
|
||||||
}),
|
}),
|
||||||
format: self.dmabuf.format,
|
format: self.dmabuf.format,
|
||||||
is_undefined: Cell::new(true),
|
is_undefined: Cell::new(true),
|
||||||
|
bridge,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_bridge(&self) -> Result<(Image, VulkanAllocation), VulkanError> {
|
||||||
|
let create_info = ImageCreateInfo::builder()
|
||||||
|
.image_type(ImageType::TYPE_2D)
|
||||||
|
.format(self.dmabuf.format.vk_format)
|
||||||
|
.mip_levels(1)
|
||||||
|
.array_layers(1)
|
||||||
|
.tiling(ImageTiling::OPTIMAL)
|
||||||
|
.samples(SampleCountFlags::TYPE_1)
|
||||||
|
.sharing_mode(SharingMode::EXCLUSIVE)
|
||||||
|
.initial_layout(ImageLayout::UNDEFINED)
|
||||||
|
.extent(Extent3D {
|
||||||
|
width: self.width,
|
||||||
|
height: self.height,
|
||||||
|
depth: 1,
|
||||||
|
})
|
||||||
|
.usage(ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::TRANSFER_SRC)
|
||||||
|
.build();
|
||||||
|
let image = unsafe { self.renderer.device.device.create_image(&create_info, None) };
|
||||||
|
let image = image.map_err(VulkanError::CreateImage)?;
|
||||||
|
let destroy_image =
|
||||||
|
OnDrop(|| unsafe { self.renderer.device.device.destroy_image(image, None) });
|
||||||
|
let memory_requirements = unsafe {
|
||||||
|
self.renderer
|
||||||
|
.device
|
||||||
|
.device
|
||||||
|
.get_image_memory_requirements(image)
|
||||||
|
};
|
||||||
|
let allocation = self.renderer.allocator.alloc(
|
||||||
|
&memory_requirements,
|
||||||
|
UsageFlags::FAST_DEVICE_ACCESS,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
let res = unsafe {
|
||||||
|
self.renderer.device.device.bind_image_memory(
|
||||||
|
image,
|
||||||
|
allocation.memory,
|
||||||
|
allocation.offset,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
res.map_err(VulkanError::BindImageMemory)?;
|
||||||
|
destroy_image.forget();
|
||||||
|
Ok((image, allocation))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GfxImage for VulkanDmaBufImageTemplate {
|
impl GfxImage for VulkanDmaBufImageTemplate {
|
||||||
|
|
@ -495,9 +564,7 @@ impl GfxImage for VulkanDmaBufImageTemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_texture(self: Rc<Self>) -> Result<Rc<dyn GfxTexture>, GfxError> {
|
fn to_texture(self: Rc<Self>) -> Result<Rc<dyn GfxTexture>, GfxError> {
|
||||||
self.create_texture(None)
|
self.create_texture().map(|v| v as _).map_err(|e| e.into())
|
||||||
.map(|v| v as _)
|
|
||||||
.map_err(|e| e.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn width(&self) -> i32 {
|
fn width(&self) -> i32 {
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,13 @@ use {
|
||||||
AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferImageCopy, BufferImageCopy2,
|
AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferImageCopy, BufferImageCopy2,
|
||||||
BufferMemoryBarrier2, ClearColorValue, ClearValue, CommandBuffer,
|
BufferMemoryBarrier2, ClearColorValue, ClearValue, CommandBuffer,
|
||||||
CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags,
|
CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags,
|
||||||
CopyBufferToImageInfo2, DependencyInfo, DependencyInfoKHR, DescriptorImageInfo,
|
CopyBufferToImageInfo2, CopyImageInfo2, DependencyInfo, DependencyInfoKHR,
|
||||||
DescriptorType, Extent2D, Extent3D, Fence, ImageAspectFlags, ImageLayout,
|
DescriptorImageInfo, DescriptorType, Extent2D, Extent3D, Fence, ImageAspectFlags,
|
||||||
ImageMemoryBarrier2, ImageMemoryBarrier2Builder, ImageSubresourceLayers,
|
ImageCopy2, ImageLayout, ImageMemoryBarrier2, ImageMemoryBarrier2Builder,
|
||||||
ImageSubresourceRange, PipelineBindPoint, PipelineStageFlags2, Rect2D,
|
ImageSubresourceLayers, ImageSubresourceRange, PipelineBindPoint, PipelineStageFlags2,
|
||||||
RenderingAttachmentInfo, RenderingInfo, SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR,
|
Rect2D, RenderingAttachmentInfo, RenderingInfo, SemaphoreSubmitInfo,
|
||||||
ShaderStageFlags, SubmitInfo2, Viewport, WriteDescriptorSet, QUEUE_FAMILY_FOREIGN_EXT,
|
SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport, WriteDescriptorSet,
|
||||||
|
QUEUE_FAMILY_FOREIGN_EXT,
|
||||||
},
|
},
|
||||||
Device,
|
Device,
|
||||||
},
|
},
|
||||||
|
|
@ -266,19 +267,33 @@ impl VulkanRenderer {
|
||||||
let memory = &mut *memory;
|
let memory = &mut *memory;
|
||||||
memory.image_barriers.clear();
|
memory.image_barriers.clear();
|
||||||
memory.shm_barriers.clear();
|
memory.shm_barriers.clear();
|
||||||
let fb_image_memory_barrier = image_barrier()
|
let mut fb_image_memory_barrier = image_barrier()
|
||||||
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
|
||||||
.dst_queue_family_index(self.device.graphics_queue_idx)
|
|
||||||
.image(fb.image)
|
.image(fb.image)
|
||||||
.old_layout(if fb.is_undefined.get() {
|
|
||||||
ImageLayout::UNDEFINED
|
|
||||||
} else {
|
|
||||||
ImageLayout::GENERAL
|
|
||||||
})
|
|
||||||
.new_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
.new_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
.dst_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE)
|
.dst_access_mask(
|
||||||
.dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
|
AccessFlags2::COLOR_ATTACHMENT_WRITE | AccessFlags2::COLOR_ATTACHMENT_READ,
|
||||||
.build();
|
)
|
||||||
|
.dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT);
|
||||||
|
if fb.bridge.is_some() {
|
||||||
|
fb_image_memory_barrier = fb_image_memory_barrier
|
||||||
|
.src_access_mask(AccessFlags2::TRANSFER_READ)
|
||||||
|
.src_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||||
|
.old_layout(if fb.is_undefined.get() {
|
||||||
|
ImageLayout::UNDEFINED
|
||||||
|
} else {
|
||||||
|
ImageLayout::TRANSFER_SRC_OPTIMAL
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fb_image_memory_barrier = fb_image_memory_barrier
|
||||||
|
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||||
|
.dst_queue_family_index(self.device.graphics_queue_idx)
|
||||||
|
.old_layout(if fb.is_undefined.get() {
|
||||||
|
ImageLayout::UNDEFINED
|
||||||
|
} else {
|
||||||
|
ImageLayout::GENERAL
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let fb_image_memory_barrier = fb_image_memory_barrier.build();
|
||||||
memory.image_barriers.push(fb_image_memory_barrier);
|
memory.image_barriers.push(fb_image_memory_barrier);
|
||||||
for img in &memory.sample {
|
for img in &memory.sample {
|
||||||
let image_memory_barrier = image_barrier()
|
let image_memory_barrier = image_barrier()
|
||||||
|
|
@ -542,22 +557,95 @@ impl VulkanRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_bridge_to_dmabuf(&self, buf: CommandBuffer, fb: &VulkanImage) {
|
||||||
|
let Some(bridge) = &fb.bridge else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut memory = self.memory.borrow_mut();
|
||||||
|
let memory = &mut *memory;
|
||||||
|
memory.image_barriers.clear();
|
||||||
|
let bridge_image_memory_barrier = image_barrier()
|
||||||
|
.image(fb.image)
|
||||||
|
.old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.new_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||||
|
.src_access_mask(
|
||||||
|
AccessFlags2::COLOR_ATTACHMENT_WRITE | AccessFlags2::COLOR_ATTACHMENT_READ,
|
||||||
|
)
|
||||||
|
.src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
|
||||||
|
.dst_access_mask(AccessFlags2::TRANSFER_READ)
|
||||||
|
.dst_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||||
|
.build();
|
||||||
|
memory.image_barriers.push(bridge_image_memory_barrier);
|
||||||
|
let dmabuf_image_memory_barrier = image_barrier()
|
||||||
|
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||||
|
.dst_queue_family_index(self.device.graphics_queue_idx)
|
||||||
|
.image(bridge.dmabuf_image)
|
||||||
|
.old_layout(if fb.is_undefined.get() {
|
||||||
|
ImageLayout::UNDEFINED
|
||||||
|
} else {
|
||||||
|
ImageLayout::GENERAL
|
||||||
|
})
|
||||||
|
.new_layout(ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||||
|
.dst_access_mask(AccessFlags2::TRANSFER_WRITE)
|
||||||
|
.dst_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||||
|
.build();
|
||||||
|
memory.image_barriers.push(dmabuf_image_memory_barrier);
|
||||||
|
let dep_info = DependencyInfoKHR::builder().image_memory_barriers(&memory.image_barriers);
|
||||||
|
unsafe {
|
||||||
|
self.device.device.cmd_pipeline_barrier2(buf, &dep_info);
|
||||||
|
}
|
||||||
|
let image_subresource_layers = ImageSubresourceLayers::builder()
|
||||||
|
.aspect_mask(ImageAspectFlags::COLOR)
|
||||||
|
.layer_count(1)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.mip_level(0)
|
||||||
|
.build();
|
||||||
|
let image_copy = ImageCopy2::builder()
|
||||||
|
.src_subresource(image_subresource_layers)
|
||||||
|
.dst_subresource(image_subresource_layers)
|
||||||
|
.extent(Extent3D {
|
||||||
|
width: fb.width,
|
||||||
|
height: fb.height,
|
||||||
|
depth: 1,
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
let copy_image_info = CopyImageInfo2::builder()
|
||||||
|
.src_image(fb.image)
|
||||||
|
.src_image_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||||
|
.dst_image(bridge.dmabuf_image)
|
||||||
|
.dst_image_layout(ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||||
|
.regions(slice::from_ref(&image_copy))
|
||||||
|
.build();
|
||||||
|
unsafe {
|
||||||
|
self.device.device.cmd_copy_image2(buf, ©_image_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn final_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) {
|
fn final_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) {
|
||||||
let mut memory = self.memory.borrow_mut();
|
let mut memory = self.memory.borrow_mut();
|
||||||
let memory = &mut *memory;
|
let memory = &mut *memory;
|
||||||
memory.image_barriers.clear();
|
memory.image_barriers.clear();
|
||||||
memory.shm_barriers.clear();
|
memory.shm_barriers.clear();
|
||||||
let fb_image_memory_barrier = image_barrier()
|
let mut fb_image_memory_barrier = image_barrier()
|
||||||
.src_queue_family_index(self.device.graphics_queue_idx)
|
.src_queue_family_index(self.device.graphics_queue_idx)
|
||||||
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||||
.image(fb.image)
|
.new_layout(ImageLayout::GENERAL);
|
||||||
.old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
if let Some(bridge) = &fb.bridge {
|
||||||
.new_layout(ImageLayout::GENERAL)
|
fb_image_memory_barrier = fb_image_memory_barrier
|
||||||
.src_access_mask(
|
.image(bridge.dmabuf_image)
|
||||||
AccessFlags2::COLOR_ATTACHMENT_WRITE | AccessFlags2::COLOR_ATTACHMENT_READ,
|
.old_layout(ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||||
)
|
.src_access_mask(AccessFlags2::TRANSFER_WRITE)
|
||||||
.src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
|
.src_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||||
.build();
|
} else {
|
||||||
|
fb_image_memory_barrier = fb_image_memory_barrier
|
||||||
|
.image(fb.image)
|
||||||
|
.old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.src_access_mask(
|
||||||
|
AccessFlags2::COLOR_ATTACHMENT_WRITE | AccessFlags2::COLOR_ATTACHMENT_READ,
|
||||||
|
)
|
||||||
|
.src_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT);
|
||||||
|
}
|
||||||
|
let fb_image_memory_barrier = fb_image_memory_barrier.build();
|
||||||
memory.image_barriers.push(fb_image_memory_barrier);
|
memory.image_barriers.push(fb_image_memory_barrier);
|
||||||
for img in &memory.sample {
|
for img in &memory.sample {
|
||||||
let image_memory_barrier = image_barrier()
|
let image_memory_barrier = image_barrier()
|
||||||
|
|
@ -828,31 +916,28 @@ impl VulkanRenderer {
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
let staging = self.create_staging_buffer(size, false, true, true)?;
|
let staging = self.create_staging_buffer(size, false, true, true)?;
|
||||||
let initial_tex_barrier = image_barrier()
|
let initial_tex_barrier;
|
||||||
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
|
||||||
.dst_queue_family_index(self.device.graphics_queue_idx)
|
|
||||||
.image(tex.image)
|
|
||||||
.old_layout(ImageLayout::GENERAL)
|
|
||||||
.new_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
|
||||||
.dst_access_mask(AccessFlags2::TRANSFER_READ)
|
|
||||||
.dst_stage_mask(PipelineStageFlags2::TRANSFER);
|
|
||||||
let initial_buffer_barrier = BufferMemoryBarrier2::builder()
|
let initial_buffer_barrier = BufferMemoryBarrier2::builder()
|
||||||
.buffer(staging.buffer)
|
.buffer(staging.buffer)
|
||||||
.offset(0)
|
.offset(0)
|
||||||
.size(staging.size)
|
.size(staging.size)
|
||||||
.dst_access_mask(AccessFlags2::TRANSFER_WRITE)
|
.dst_access_mask(AccessFlags2::TRANSFER_WRITE)
|
||||||
.dst_stage_mask(PipelineStageFlags2::TRANSFER);
|
.dst_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||||
let initial_barriers = DependencyInfo::builder()
|
let mut initial_barriers = DependencyInfo::builder()
|
||||||
.buffer_memory_barriers(slice::from_ref(&initial_buffer_barrier))
|
.buffer_memory_barriers(slice::from_ref(&initial_buffer_barrier));
|
||||||
.image_memory_barriers(slice::from_ref(&initial_tex_barrier));
|
if tex.bridge.is_none() {
|
||||||
let final_tex_barrier = image_barrier()
|
initial_tex_barrier = image_barrier()
|
||||||
.src_queue_family_index(self.device.graphics_queue_idx)
|
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||||
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
.dst_queue_family_index(self.device.graphics_queue_idx)
|
||||||
.image(tex.image)
|
.image(tex.image)
|
||||||
.old_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
.old_layout(ImageLayout::GENERAL)
|
||||||
.new_layout(ImageLayout::GENERAL)
|
.new_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||||
.src_access_mask(AccessFlags2::TRANSFER_READ)
|
.dst_access_mask(AccessFlags2::TRANSFER_READ)
|
||||||
.src_stage_mask(PipelineStageFlags2::TRANSFER);
|
.dst_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||||
|
initial_barriers =
|
||||||
|
initial_barriers.image_memory_barriers(slice::from_ref(&initial_tex_barrier));
|
||||||
|
}
|
||||||
|
let final_tex_barrier;
|
||||||
let final_buffer_barrier = BufferMemoryBarrier2::builder()
|
let final_buffer_barrier = BufferMemoryBarrier2::builder()
|
||||||
.buffer(staging.buffer)
|
.buffer(staging.buffer)
|
||||||
.offset(0)
|
.offset(0)
|
||||||
|
|
@ -861,9 +946,20 @@ impl VulkanRenderer {
|
||||||
.src_stage_mask(PipelineStageFlags2::TRANSFER)
|
.src_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||||
.dst_access_mask(AccessFlags2::HOST_READ)
|
.dst_access_mask(AccessFlags2::HOST_READ)
|
||||||
.dst_stage_mask(PipelineStageFlags2::HOST);
|
.dst_stage_mask(PipelineStageFlags2::HOST);
|
||||||
let final_barriers = DependencyInfo::builder()
|
let mut final_barriers = DependencyInfo::builder()
|
||||||
.buffer_memory_barriers(slice::from_ref(&final_buffer_barrier))
|
.buffer_memory_barriers(slice::from_ref(&final_buffer_barrier));
|
||||||
.image_memory_barriers(slice::from_ref(&final_tex_barrier));
|
if tex.bridge.is_none() {
|
||||||
|
final_tex_barrier = image_barrier()
|
||||||
|
.src_queue_family_index(self.device.graphics_queue_idx)
|
||||||
|
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||||
|
.image(tex.image)
|
||||||
|
.old_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||||
|
.new_layout(ImageLayout::GENERAL)
|
||||||
|
.src_access_mask(AccessFlags2::TRANSFER_READ)
|
||||||
|
.src_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||||
|
final_barriers =
|
||||||
|
final_barriers.image_memory_barriers(slice::from_ref(&final_tex_barrier));
|
||||||
|
}
|
||||||
let buf = self.allocate_command_buffer()?;
|
let buf = self.allocate_command_buffer()?;
|
||||||
let mut semaphores = vec![];
|
let mut semaphores = vec![];
|
||||||
let mut semaphore_infos = vec![];
|
let mut semaphore_infos = vec![];
|
||||||
|
|
@ -985,6 +1081,7 @@ impl VulkanRenderer {
|
||||||
self.set_viewport(buf.buffer, fb);
|
self.set_viewport(buf.buffer, fb);
|
||||||
self.record_draws(buf.buffer, opts)?;
|
self.record_draws(buf.buffer, opts)?;
|
||||||
self.end_rendering(buf.buffer);
|
self.end_rendering(buf.buffer);
|
||||||
|
self.copy_bridge_to_dmabuf(buf.buffer, fb);
|
||||||
self.final_barriers(buf.buffer, fb);
|
self.final_barriers(buf.buffer, fb);
|
||||||
self.end_command_buffer(buf.buffer)?;
|
self.end_command_buffer(buf.buffer)?;
|
||||||
self.create_wait_semaphores(fb)?;
|
self.create_wait_semaphores(fb)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue