1
0
Fork 0
forked from wry/wry

Merge pull request #195 from mahkoh/jorth/vulkan-linear

Add support for hardware cursors on nvidia + vulkan
This commit is contained in:
mahkoh 2024-05-05 12:47:38 +02:00 committed by GitHub
commit 5ce9d38c59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 314 additions and 82 deletions

View file

@ -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)

View file

@ -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,

View file

@ -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 {

View file

@ -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, &copy_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)?;