diff --git a/release-notes.md b/release-notes.md index 077b98d1..4daddc9b 100644 --- a/release-notes.md +++ b/release-notes.md @@ -8,6 +8,7 @@ - Add support for pointer-gestures-unstable-v1. - Configs can now handle switch events (laptop lid closed/opened). - 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) diff --git a/src/gfx_apis/vulkan/format.rs b/src/gfx_apis/vulkan/format.rs index f5f425ae..98c1c460 100644 --- a/src/gfx_apis/vulkan/format.rs +++ b/src/gfx_apis/vulkan/format.rs @@ -2,7 +2,7 @@ use { crate::{ format::{Format, FORMATS}, gfx_apis::vulkan::{instance::VulkanInstance, VulkanError}, - video::Modifier, + video::{Modifier, LINEAR_MODIFIER}, }, ahash::AHashMap, ash::{ @@ -17,14 +17,14 @@ use { }, }, isnt::std_1::collections::IsntHashMapExt, + std::cmp::min, }; #[derive(Debug)] pub struct VulkanFormat { pub format: &'static Format, pub modifiers: AHashMap, - pub shm: Option, - pub features: FormatFeatureFlags, + pub shm: Option, } #[derive(Debug)] @@ -34,6 +34,7 @@ pub struct VulkanModifier { pub features: FormatFeatureFlags, pub render_max_extents: Option, pub texture_max_extents: Option, + pub render_needs_bridge: bool, } #[derive(Copy, Clone, Debug)] @@ -43,7 +44,7 @@ pub struct VulkanMaxExtents { } #[derive(Debug)] -pub struct VulkanShmFormat { +pub struct VulkanInternalFormat { pub max_extents: VulkanMaxExtents, } @@ -51,6 +52,7 @@ const FRAMEBUFFER_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw( 0 | FormatFeatureFlags::COLOR_ATTACHMENT.as_raw() | FormatFeatureFlags::COLOR_ATTACHMENT_BLEND.as_raw(), ); +const FRAMEBUFFER_BRIDGED_FEATURES: FormatFeatureFlags = FormatFeatureFlags::TRANSFER_DST; const TEX_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw( 0 | FormatFeatureFlags::SAMPLED_IMAGE.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( 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( 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 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() { dst.insert( format.drm, @@ -112,7 +116,6 @@ impl VulkanInstance { format, modifiers, shm, - features: format_properties.format_properties.optimal_tiling_features, }, ); } @@ -124,14 +127,25 @@ impl VulkanInstance { phy_dev: PhysicalDevice, format: &Format, props: &FormatProperties2, - ) -> Result, VulkanError> { + ) -> Result, VulkanError> { if format.shm_info.is_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, VulkanError> { if !props .format_properties .optimal_tiling_features - .contains(SHM_FEATURES) + .contains(features) { return Ok(None); } @@ -139,7 +153,7 @@ impl VulkanInstance { .ty(ImageType::TYPE_2D) .format(format.vk_format) .tiling(ImageTiling::OPTIMAL) - .usage(SHM_USAGE); + .usage(usage); let mut format_properties = ImageFormatProperties2::builder(); let res = unsafe { self.instance.get_physical_device_image_format_properties2( @@ -154,7 +168,7 @@ impl VulkanInstance { _ => Err(VulkanError::LoadImageProperties(e)), }; } - Ok(Some(VulkanShmFormat { + Ok(Some(VulkanInternalFormat { max_extents: VulkanMaxExtents { width: format_properties.image_format_properties.max_extent.width, height: format_properties.image_format_properties.max_extent.height, @@ -166,6 +180,7 @@ impl VulkanInstance { &self, phy_dev: PhysicalDevice, format: &Format, + internal_format_properties: &FormatProperties2, props: &DrmFormatModifierPropertiesListEXT, ) -> Result, VulkanError> { if props.drm_format_modifier_count == 0 { @@ -190,7 +205,7 @@ impl VulkanInstance { }; let mut mods = AHashMap::new(); for modifier in drm_mods { - let render_max_extents = self.get_max_extents( + let mut render_max_extents = self.get_max_extents( phy_dev, format, FRAMEBUFFER_FEATURES, @@ -199,6 +214,18 @@ impl VulkanInstance { )?; let texture_max_extents = 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( modifier.drm_format_modifier, VulkanModifier { @@ -207,12 +234,52 @@ impl VulkanInstance { features: modifier.drm_format_modifier_tiling_features, render_max_extents, texture_max_extents, + render_needs_bridge, }, ); } Ok(mods) } + fn get_fb_bridged_max_extents( + &self, + phy_dev: PhysicalDevice, + format: &Format, + internal_format_properties: &FormatProperties2, + modifier: &DrmFormatModifierPropertiesEXT, + ) -> Result, 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( &self, phy_dev: PhysicalDevice, diff --git a/src/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index f8f3fa8f..d78fb413 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -39,6 +39,7 @@ pub struct VulkanDmaBufImageTemplate { pub(super) dmabuf: DmaBuf, pub(super) render_max_extents: Option, pub(super) texture_max_extents: Option, + pub(super) render_needs_bridge: bool, } pub struct VulkanImage { @@ -53,6 +54,7 @@ pub struct VulkanImage { pub(super) is_undefined: Cell, pub(super) ty: VulkanImageMemory, pub(super) render_ops: CloneCell>, + pub(super) bridge: Option, } pub enum VulkanImageMemory { @@ -72,6 +74,11 @@ pub struct VulkanShmImage { pub(super) _allocation: VulkanAllocation, } +pub struct VulkanFramebufferBridge { + pub(super) dmabuf_image: Image, + pub(super) _allocation: VulkanAllocation, +} + impl Drop for VulkanDmaBufImage { fn drop(&mut self) { unsafe { @@ -96,6 +103,12 @@ impl Drop for VulkanImage { .destroy_image_view(render_view, 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), ty: VulkanImageMemory::Internal(shm), render_ops: Default::default(), + bridge: None, })) } @@ -264,6 +278,7 @@ impl VulkanRenderer { dmabuf: dmabuf.clone(), render_max_extents: modifier.render_max_extents, texture_max_extents: modifier.texture_max_extents, + render_needs_bridge: modifier.render_needs_bridge, })) } } @@ -302,21 +317,14 @@ impl VulkanDevice { impl VulkanDmaBufImageTemplate { pub fn create_framebuffer(self: &Rc) -> Result, VulkanError> { - self.create_image(true, None) + self.create_image(true) } - pub fn create_texture( - self: &Rc, - shm: Option, - ) -> Result, VulkanError> { - self.create_image(false, shm) + pub fn create_texture(self: &Rc) -> Result, VulkanError> { + self.create_image(false) } - fn create_image( - self: &Rc, - for_rendering: bool, - shm: Option, - ) -> Result, VulkanError> { + fn create_image(self: &Rc, for_rendering: bool) -> Result, VulkanError> { let device = &self.renderer.device; let max_extents = match for_rendering { true => self.render_max_extents, @@ -350,12 +358,13 @@ impl VulkanDmaBufImageTemplate { true => ImageCreateFlags::DISJOINT, false => ImageCreateFlags::empty(), }; - let usage = ImageUsageFlags::TRANSFER_SRC - | match (for_rendering, shm.is_some()) { - (true, _) => ImageUsageFlags::COLOR_ATTACHMENT, - (false, false) => ImageUsageFlags::SAMPLED, - (false, true) => ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER_DST, - }; + let usage = match for_rendering { + true => match self.render_needs_bridge { + true => ImageUsageFlags::TRANSFER_DST, + false => ImageUsageFlags::TRANSFER_SRC | ImageUsageFlags::COLOR_ATTACHMENT, + }, + false => ImageUsageFlags::TRANSFER_SRC | ImageUsageFlags::SAMPLED, + }; let create_info = ImageCreateInfo::builder() .image_type(ImageType::TYPE_2D) .format(self.dmabuf.format.vk_format) @@ -464,15 +473,30 @@ impl VulkanDmaBufImageTemplate { } let res = unsafe { device.device.bind_image_memory2(&bind_image_memory_infos) }; res.map_err(VulkanError::BindImageMemory)?; - let texture_view = device.create_image_view(image, self.dmabuf.format, false)?; - let render_view = device.create_image_view(image, self.dmabuf.format, true)?; + let mut primary_image = image; + 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); mem::forget(destroy_image); + mem::forget(destroy_bridge_image); Ok(Rc::new(VulkanImage { renderer: self.renderer.clone(), texture_view, render_view: Some(render_view), - image, + image: primary_image, width: self.width, height: self.height, stride: 0, @@ -483,8 +507,53 @@ impl VulkanDmaBufImageTemplate { }), format: self.dmabuf.format, 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 { @@ -495,9 +564,7 @@ impl GfxImage for VulkanDmaBufImageTemplate { } fn to_texture(self: Rc) -> Result, GfxError> { - self.create_texture(None) - .map(|v| v as _) - .map_err(|e| e.into()) + self.create_texture().map(|v| v as _).map_err(|e| e.into()) } fn width(&self) -> i32 { diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 2811a57c..b751da4c 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -33,12 +33,13 @@ use { AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferImageCopy, BufferImageCopy2, BufferMemoryBarrier2, ClearColorValue, ClearValue, CommandBuffer, CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags, - CopyBufferToImageInfo2, DependencyInfo, DependencyInfoKHR, DescriptorImageInfo, - DescriptorType, Extent2D, Extent3D, Fence, ImageAspectFlags, ImageLayout, - ImageMemoryBarrier2, ImageMemoryBarrier2Builder, ImageSubresourceLayers, - ImageSubresourceRange, PipelineBindPoint, PipelineStageFlags2, Rect2D, - RenderingAttachmentInfo, RenderingInfo, SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, - ShaderStageFlags, SubmitInfo2, Viewport, WriteDescriptorSet, QUEUE_FAMILY_FOREIGN_EXT, + CopyBufferToImageInfo2, CopyImageInfo2, DependencyInfo, DependencyInfoKHR, + DescriptorImageInfo, DescriptorType, Extent2D, Extent3D, Fence, ImageAspectFlags, + ImageCopy2, ImageLayout, ImageMemoryBarrier2, ImageMemoryBarrier2Builder, + ImageSubresourceLayers, ImageSubresourceRange, PipelineBindPoint, PipelineStageFlags2, + Rect2D, RenderingAttachmentInfo, RenderingInfo, SemaphoreSubmitInfo, + SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport, WriteDescriptorSet, + QUEUE_FAMILY_FOREIGN_EXT, }, Device, }, @@ -266,19 +267,33 @@ impl VulkanRenderer { let memory = &mut *memory; memory.image_barriers.clear(); memory.shm_barriers.clear(); - let fb_image_memory_barrier = image_barrier() - .src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT) - .dst_queue_family_index(self.device.graphics_queue_idx) + let mut fb_image_memory_barrier = image_barrier() .image(fb.image) - .old_layout(if fb.is_undefined.get() { - ImageLayout::UNDEFINED - } else { - ImageLayout::GENERAL - }) .new_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .dst_access_mask(AccessFlags2::COLOR_ATTACHMENT_WRITE) - .dst_stage_mask(PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - .build(); + .dst_access_mask( + AccessFlags2::COLOR_ATTACHMENT_WRITE | AccessFlags2::COLOR_ATTACHMENT_READ, + ) + .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); for img in &memory.sample { let image_memory_barrier = image_barrier() @@ -542,22 +557,95 @@ impl VulkanRenderer { } } - fn final_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) { + 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(); - memory.shm_barriers.clear(); - let fb_image_memory_barrier = image_barrier() - .src_queue_family_index(self.device.graphics_queue_idx) - .dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT) + let bridge_image_memory_barrier = image_barrier() .image(fb.image) .old_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .new_layout(ImageLayout::GENERAL) + .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) { + let mut memory = self.memory.borrow_mut(); + let memory = &mut *memory; + memory.image_barriers.clear(); + memory.shm_barriers.clear(); + let mut fb_image_memory_barrier = image_barrier() + .src_queue_family_index(self.device.graphics_queue_idx) + .dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT) + .new_layout(ImageLayout::GENERAL); + if let Some(bridge) = &fb.bridge { + fb_image_memory_barrier = fb_image_memory_barrier + .image(bridge.dmabuf_image) + .old_layout(ImageLayout::TRANSFER_DST_OPTIMAL) + .src_access_mask(AccessFlags2::TRANSFER_WRITE) + .src_stage_mask(PipelineStageFlags2::TRANSFER); + } 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); for img in &memory.sample { let image_memory_barrier = image_barrier() @@ -828,31 +916,28 @@ impl VulkanRenderer { }) .build(); let staging = self.create_staging_buffer(size, false, true, true)?; - let initial_tex_barrier = image_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_tex_barrier; let initial_buffer_barrier = BufferMemoryBarrier2::builder() .buffer(staging.buffer) .offset(0) .size(staging.size) .dst_access_mask(AccessFlags2::TRANSFER_WRITE) .dst_stage_mask(PipelineStageFlags2::TRANSFER); - let initial_barriers = DependencyInfo::builder() - .buffer_memory_barriers(slice::from_ref(&initial_buffer_barrier)) - .image_memory_barriers(slice::from_ref(&initial_tex_barrier)); - let 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); + let mut initial_barriers = DependencyInfo::builder() + .buffer_memory_barriers(slice::from_ref(&initial_buffer_barrier)); + if tex.bridge.is_none() { + initial_tex_barrier = image_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); + initial_barriers = + initial_barriers.image_memory_barriers(slice::from_ref(&initial_tex_barrier)); + } + let final_tex_barrier; let final_buffer_barrier = BufferMemoryBarrier2::builder() .buffer(staging.buffer) .offset(0) @@ -861,9 +946,20 @@ impl VulkanRenderer { .src_stage_mask(PipelineStageFlags2::TRANSFER) .dst_access_mask(AccessFlags2::HOST_READ) .dst_stage_mask(PipelineStageFlags2::HOST); - let final_barriers = DependencyInfo::builder() - .buffer_memory_barriers(slice::from_ref(&final_buffer_barrier)) - .image_memory_barriers(slice::from_ref(&final_tex_barrier)); + let mut final_barriers = DependencyInfo::builder() + .buffer_memory_barriers(slice::from_ref(&final_buffer_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 mut semaphores = vec![]; let mut semaphore_infos = vec![]; @@ -985,6 +1081,7 @@ impl VulkanRenderer { self.set_viewport(buf.buffer, fb); self.record_draws(buf.buffer, opts)?; self.end_rendering(buf.buffer); + self.copy_bridge_to_dmabuf(buf.buffer, fb); self.final_barriers(buf.buffer, fb); self.end_command_buffer(buf.buffer)?; self.create_wait_semaphores(fb)?;