732 lines
26 KiB
Rust
732 lines
26 KiB
Rust
use {
|
|
crate::{
|
|
cmm::cmm_description::{ColorDescription, LinearColorDescription},
|
|
format::Format,
|
|
gfx_api::{
|
|
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback,
|
|
AsyncShmGfxTextureTransferCancellable, GfxApiOpt, GfxBlendBuffer, GfxBuffer, GfxError,
|
|
GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture,
|
|
PendingShmTransfer, ReleaseSync, ShmGfxTexture, ShmMemory, SyncFile,
|
|
},
|
|
gfx_apis::vulkan::{
|
|
VulkanError, allocator::VulkanAllocation, device::VulkanDevice,
|
|
format::VulkanModifierLimits, renderer::VulkanRenderer, shm_image::VulkanShmImage,
|
|
transfer::TransferType,
|
|
},
|
|
rect::Region,
|
|
theme::Color,
|
|
video::dmabuf::{DmaBuf, PlaneVec},
|
|
},
|
|
ash::vk::{
|
|
BindImageMemoryInfo, BindImagePlaneMemoryInfo, ComponentMapping, ComponentSwizzle,
|
|
DescriptorDataEXT, DescriptorGetInfoEXT, DescriptorImageInfo, DescriptorType, DeviceMemory,
|
|
Extent3D, ExternalMemoryHandleTypeFlags, ExternalMemoryImageCreateInfo, FormatFeatureFlags,
|
|
Image, ImageAspectFlags, ImageCreateFlags, ImageCreateInfo,
|
|
ImageDrmFormatModifierExplicitCreateInfoEXT, ImageLayout, ImageMemoryRequirementsInfo2,
|
|
ImagePlaneMemoryRequirementsInfo, ImageSubresourceRange, ImageTiling, ImageType,
|
|
ImageUsageFlags, ImageView, ImageViewCreateInfo, ImageViewType, ImportMemoryFdInfoKHR,
|
|
MemoryAllocateInfo, MemoryDedicatedAllocateInfo, MemoryFdPropertiesKHR,
|
|
MemoryPropertyFlags, MemoryRequirements2, SampleCountFlags, Sampler, SharingMode,
|
|
SubresourceLayout,
|
|
},
|
|
gpu_alloc::UsageFlags,
|
|
run_on_drop::on_drop,
|
|
std::{
|
|
cell::Cell,
|
|
fmt::{Debug, Formatter},
|
|
mem,
|
|
rc::Rc,
|
|
},
|
|
};
|
|
|
|
pub struct VulkanDmaBufImageTemplate {
|
|
pub(super) renderer: Rc<VulkanRenderer>,
|
|
pub(super) width: u32,
|
|
pub(super) height: u32,
|
|
pub(super) disjoint: bool,
|
|
pub(super) dmabuf: DmaBuf,
|
|
pub(super) render_limits: Option<VulkanModifierLimits>,
|
|
pub(super) texture_limits: Option<VulkanModifierLimits>,
|
|
pub(super) render_needs_bridge: bool,
|
|
}
|
|
|
|
pub struct VulkanImage {
|
|
pub(super) renderer: Rc<VulkanRenderer>,
|
|
pub(super) format: &'static Format,
|
|
pub(super) width: u32,
|
|
pub(super) height: u32,
|
|
pub(super) stride: u32,
|
|
pub(super) texture_view: ImageView,
|
|
pub(super) render_view: Option<ImageView>,
|
|
pub(super) image: Image,
|
|
pub(super) is_undefined: Cell<bool>,
|
|
pub(super) contents_are_undefined: Cell<bool>,
|
|
pub(super) queue_state: Cell<QueueState>,
|
|
pub(super) ty: VulkanImageMemory,
|
|
pub(super) bridge: Option<VulkanFramebufferBridge>,
|
|
pub(super) sampled_image_descriptor: Option<Box<[u8]>>,
|
|
pub(super) execution_version: Cell<u64>,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
pub enum QueueState {
|
|
Acquired { family: QueueFamily },
|
|
Releasing,
|
|
Released { to: QueueFamily },
|
|
}
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
pub enum QueueFamily {
|
|
Gfx,
|
|
Transfer,
|
|
}
|
|
|
|
impl QueueState {
|
|
pub fn acquire(self, new: QueueFamily) -> QueueTransfer {
|
|
match self {
|
|
QueueState::Acquired { family } if family == new => QueueTransfer::Unnecessary,
|
|
QueueState::Released { to } if to == new => QueueTransfer::Possible,
|
|
_ => QueueTransfer::Impossible,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
pub enum QueueTransfer {
|
|
Unnecessary,
|
|
Possible,
|
|
Impossible,
|
|
}
|
|
|
|
pub enum VulkanImageMemory {
|
|
DmaBuf(VulkanDmaBufImage),
|
|
Internal(VulkanShmImage),
|
|
Blend(VulkanAllocation),
|
|
}
|
|
|
|
pub struct VulkanDmaBufImage {
|
|
pub(super) template: Rc<VulkanDmaBufImageTemplate>,
|
|
pub(super) mems: PlaneVec<DeviceMemory>,
|
|
}
|
|
|
|
pub struct VulkanFramebufferBridge {
|
|
pub(super) dmabuf_image: Image,
|
|
pub(super) _allocation: VulkanAllocation,
|
|
}
|
|
|
|
impl Drop for VulkanDmaBufImage {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
for &mem in &self.mems {
|
|
self.template.renderer.device.device.free_memory(mem, None);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for VulkanImage {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
self.renderer
|
|
.device
|
|
.device
|
|
.destroy_image_view(self.texture_view, None);
|
|
if let Some(render_view) = self.render_view {
|
|
self.renderer
|
|
.device
|
|
.device
|
|
.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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl VulkanRenderer {
|
|
pub fn import_dmabuf(
|
|
self: &Rc<Self>,
|
|
dmabuf: &DmaBuf,
|
|
) -> Result<Rc<VulkanDmaBufImageTemplate>, VulkanError> {
|
|
let format = self
|
|
.device
|
|
.formats
|
|
.get(&dmabuf.format.drm)
|
|
.ok_or(VulkanError::FormatNotSupported)?;
|
|
let modifier = format
|
|
.modifiers
|
|
.get(&dmabuf.modifier)
|
|
.ok_or(VulkanError::ModifierNotSupported)?;
|
|
if dmabuf.width <= 0 || dmabuf.height <= 0 {
|
|
return Err(VulkanError::NonPositiveImageSize);
|
|
}
|
|
let width = dmabuf.width as u32;
|
|
let height = dmabuf.height as u32;
|
|
let can_render = match &modifier.render_limits {
|
|
None => false,
|
|
Some(t) => width <= t.max_width && height <= t.max_height,
|
|
};
|
|
let can_texture = match &modifier.texture_limits {
|
|
None => false,
|
|
Some(t) => width <= t.max_width && height <= t.max_height,
|
|
};
|
|
if !can_render && !can_texture {
|
|
if modifier.render_limits.is_none() && modifier.texture_limits.is_none() {
|
|
return Err(VulkanError::ModifierUseNotSupported);
|
|
}
|
|
return Err(VulkanError::ImageTooLarge);
|
|
}
|
|
if modifier.planes != dmabuf.planes.len() {
|
|
return Err(VulkanError::BadPlaneCount);
|
|
}
|
|
let disjoint = dmabuf.is_disjoint();
|
|
if disjoint && !modifier.features.contains(FormatFeatureFlags::DISJOINT) {
|
|
return Err(VulkanError::DisjointNotSupported);
|
|
}
|
|
Ok(Rc::new(VulkanDmaBufImageTemplate {
|
|
renderer: self.clone(),
|
|
width,
|
|
height,
|
|
disjoint,
|
|
dmabuf: dmabuf.clone(),
|
|
render_limits: modifier.render_limits,
|
|
texture_limits: modifier.texture_limits,
|
|
render_needs_bridge: modifier.render_needs_bridge,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl VulkanDevice {
|
|
pub fn create_image_view(
|
|
&self,
|
|
image: Image,
|
|
format: &'static Format,
|
|
for_rendering: bool,
|
|
) -> Result<ImageView, VulkanError> {
|
|
let create_info = ImageViewCreateInfo::default()
|
|
.image(image)
|
|
.view_type(ImageViewType::TYPE_2D)
|
|
.format(format.vk_format)
|
|
.components(ComponentMapping {
|
|
r: ComponentSwizzle::IDENTITY,
|
|
g: ComponentSwizzle::IDENTITY,
|
|
b: ComponentSwizzle::IDENTITY,
|
|
a: match format.has_alpha || for_rendering {
|
|
true => ComponentSwizzle::IDENTITY,
|
|
false => ComponentSwizzle::ONE,
|
|
},
|
|
})
|
|
.subresource_range(ImageSubresourceRange {
|
|
aspect_mask: ImageAspectFlags::COLOR,
|
|
base_mip_level: 0,
|
|
level_count: 1,
|
|
base_array_layer: 0,
|
|
layer_count: 1,
|
|
});
|
|
let view = unsafe { self.device.create_image_view(&create_info, None) };
|
|
view.map_err(VulkanError::CreateImageView)
|
|
}
|
|
}
|
|
|
|
impl VulkanDevice {
|
|
pub(super) fn create_sampler_descriptor(&self, sampler: Sampler) -> Box<[u8]> {
|
|
let Some(db) = &self.descriptor_buffer else {
|
|
return Box::new([]);
|
|
};
|
|
let mut buf = vec![0; self.sampler_descriptor_size].into_boxed_slice();
|
|
let info = DescriptorGetInfoEXT::default()
|
|
.ty(DescriptorType::SAMPLER)
|
|
.data(DescriptorDataEXT {
|
|
p_sampler: &sampler,
|
|
});
|
|
unsafe {
|
|
db.get_descriptor(&info, &mut buf);
|
|
}
|
|
buf
|
|
}
|
|
}
|
|
|
|
impl VulkanRenderer {
|
|
pub(super) fn sampled_image_descriptor(
|
|
&self,
|
|
usage: ImageUsageFlags,
|
|
view: ImageView,
|
|
) -> Option<Box<[u8]>> {
|
|
if !usage.contains(ImageUsageFlags::SAMPLED) {
|
|
return None;
|
|
}
|
|
let Some(db) = &self.device.descriptor_buffer else {
|
|
return None;
|
|
};
|
|
let mut buf = vec![0; self.device.sampled_image_descriptor_size].into_boxed_slice();
|
|
let image_info = DescriptorImageInfo::default()
|
|
.image_view(view)
|
|
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
|
|
let info = DescriptorGetInfoEXT::default()
|
|
.ty(DescriptorType::SAMPLED_IMAGE)
|
|
.data(DescriptorDataEXT {
|
|
p_sampled_image: &image_info,
|
|
});
|
|
unsafe {
|
|
db.get_descriptor(&info, &mut buf);
|
|
}
|
|
Some(buf)
|
|
}
|
|
}
|
|
|
|
impl VulkanDmaBufImageTemplate {
|
|
pub fn create_framebuffer(self: &Rc<Self>) -> Result<Rc<VulkanImage>, VulkanError> {
|
|
self.create_image(true)
|
|
}
|
|
|
|
pub fn create_texture(self: &Rc<Self>) -> Result<Rc<VulkanImage>, VulkanError> {
|
|
self.create_image(false)
|
|
}
|
|
|
|
fn create_image(self: &Rc<Self>, for_rendering: bool) -> Result<Rc<VulkanImage>, VulkanError> {
|
|
let device = &self.renderer.device;
|
|
let limits = match for_rendering {
|
|
true => self.render_limits,
|
|
false => self.texture_limits,
|
|
};
|
|
let limits = limits.ok_or(VulkanError::ModifierUseNotSupported)?;
|
|
if self.width > limits.max_width || self.height > limits.max_height {
|
|
return Err(VulkanError::ImageTooLarge);
|
|
}
|
|
let usage;
|
|
let image = {
|
|
let plane_layouts: PlaneVec<_> = self
|
|
.dmabuf
|
|
.planes
|
|
.iter()
|
|
.map(|p| SubresourceLayout {
|
|
offset: p.offset as _,
|
|
row_pitch: p.stride as _,
|
|
size: 0,
|
|
array_pitch: 0,
|
|
depth_pitch: 0,
|
|
})
|
|
.collect();
|
|
let mut mod_info = ImageDrmFormatModifierExplicitCreateInfoEXT::default()
|
|
.drm_format_modifier(self.dmabuf.modifier)
|
|
.plane_layouts(&plane_layouts);
|
|
let mut memory_image_create_info = ExternalMemoryImageCreateInfo::default()
|
|
.handle_types(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
|
let flags = match self.disjoint {
|
|
true => ImageCreateFlags::DISJOINT,
|
|
false => ImageCreateFlags::empty(),
|
|
};
|
|
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::default()
|
|
.image_type(ImageType::TYPE_2D)
|
|
.format(self.dmabuf.format.vk_format)
|
|
.mip_levels(1)
|
|
.array_layers(1)
|
|
.tiling(ImageTiling::DRM_FORMAT_MODIFIER_EXT)
|
|
.samples(SampleCountFlags::TYPE_1)
|
|
.sharing_mode(SharingMode::EXCLUSIVE)
|
|
.initial_layout(ImageLayout::UNDEFINED)
|
|
.extent(Extent3D {
|
|
width: self.width,
|
|
height: self.height,
|
|
depth: 1,
|
|
})
|
|
.usage(usage)
|
|
.flags(flags)
|
|
.push_next(&mut memory_image_create_info)
|
|
.push_next(&mut mod_info);
|
|
let image = unsafe { device.device.create_image(&create_info, None) };
|
|
image.map_err(VulkanError::CreateImage)?
|
|
};
|
|
let destroy_image = on_drop(|| unsafe { device.device.destroy_image(image, None) });
|
|
let num_device_memories = match self.disjoint {
|
|
true => self.dmabuf.planes.len(),
|
|
false => 1,
|
|
};
|
|
let mut device_memories = PlaneVec::new();
|
|
let mut free_device_memories = PlaneVec::new();
|
|
let mut bind_image_plane_memory_infos = PlaneVec::new();
|
|
for plane_idx in 0..num_device_memories {
|
|
let dma_buf_plane = &self.dmabuf.planes[plane_idx];
|
|
let mut memory_fd_properties = MemoryFdPropertiesKHR::default();
|
|
unsafe {
|
|
device
|
|
.external_memory_fd
|
|
.get_memory_fd_properties(
|
|
ExternalMemoryHandleTypeFlags::DMA_BUF_EXT,
|
|
dma_buf_plane.fd.raw(),
|
|
&mut memory_fd_properties,
|
|
)
|
|
.map_err(VulkanError::MemoryFdProperties)?;
|
|
}
|
|
let mut image_memory_requirements_info =
|
|
ImageMemoryRequirementsInfo2::default().image(image);
|
|
let mut image_plane_memory_requirements_info;
|
|
if self.disjoint {
|
|
let plane_aspect = match plane_idx {
|
|
0 => ImageAspectFlags::MEMORY_PLANE_0_EXT,
|
|
1 => ImageAspectFlags::MEMORY_PLANE_1_EXT,
|
|
2 => ImageAspectFlags::MEMORY_PLANE_2_EXT,
|
|
3 => ImageAspectFlags::MEMORY_PLANE_3_EXT,
|
|
_ => unreachable!(),
|
|
};
|
|
image_plane_memory_requirements_info =
|
|
ImagePlaneMemoryRequirementsInfo::default().plane_aspect(plane_aspect);
|
|
image_memory_requirements_info = image_memory_requirements_info
|
|
.push_next(&mut image_plane_memory_requirements_info);
|
|
bind_image_plane_memory_infos
|
|
.push(BindImagePlaneMemoryInfo::default().plane_aspect(plane_aspect));
|
|
}
|
|
let mut memory_requirements = MemoryRequirements2::default();
|
|
unsafe {
|
|
device.device.get_image_memory_requirements2(
|
|
&image_memory_requirements_info,
|
|
&mut memory_requirements,
|
|
);
|
|
}
|
|
let memory_type_bits = memory_requirements.memory_requirements.memory_type_bits
|
|
& memory_fd_properties.memory_type_bits;
|
|
let memory_type_index = self
|
|
.renderer
|
|
.device
|
|
.find_memory_type(MemoryPropertyFlags::empty(), memory_type_bits)
|
|
.ok_or(VulkanError::MemoryType)?;
|
|
let fd = uapi::fcntl_dupfd_cloexec(dma_buf_plane.fd.raw(), 0)
|
|
.map_err(|e| VulkanError::Dupfd(e.into()))?;
|
|
let mut memory_dedicated_allocate_info =
|
|
MemoryDedicatedAllocateInfo::default().image(image);
|
|
let mut import_memory_fd_info = ImportMemoryFdInfoKHR::default()
|
|
.fd(fd.raw())
|
|
.handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
|
let memory_allocate_info = MemoryAllocateInfo::default()
|
|
.allocation_size(memory_requirements.memory_requirements.size)
|
|
.memory_type_index(memory_type_index)
|
|
.push_next(&mut import_memory_fd_info)
|
|
.push_next(&mut memory_dedicated_allocate_info);
|
|
let device_memory =
|
|
unsafe { device.device.allocate_memory(&memory_allocate_info, None) };
|
|
let device_memory = device_memory.map_err(VulkanError::AllocateMemory)?;
|
|
fd.unwrap();
|
|
device_memories.push(device_memory);
|
|
free_device_memories.push(on_drop(move || unsafe {
|
|
device.device.free_memory(device_memory, None)
|
|
}));
|
|
}
|
|
let mut bind_image_memory_infos = Vec::with_capacity(num_device_memories);
|
|
let mut bind_image_plane_memory_infos = bind_image_plane_memory_infos.iter_mut();
|
|
for mem in device_memories.iter().copied() {
|
|
let mut info = BindImageMemoryInfo::default().image(image).memory(mem);
|
|
if self.disjoint {
|
|
info = info.push_next(bind_image_plane_memory_infos.next().unwrap());
|
|
}
|
|
bind_image_memory_infos.push(info);
|
|
}
|
|
let res = unsafe { device.device.bind_image_memory2(&bind_image_memory_infos) };
|
|
res.map_err(VulkanError::BindImageMemory)?;
|
|
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(on_drop(|| 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: primary_image,
|
|
width: self.width,
|
|
height: self.height,
|
|
stride: 0,
|
|
ty: VulkanImageMemory::DmaBuf(VulkanDmaBufImage {
|
|
template: self.clone(),
|
|
mems: device_memories,
|
|
}),
|
|
format: self.dmabuf.format,
|
|
is_undefined: Cell::new(true),
|
|
contents_are_undefined: Cell::new(false),
|
|
queue_state: Cell::new(QueueState::Acquired {
|
|
family: QueueFamily::Gfx,
|
|
}),
|
|
bridge,
|
|
sampled_image_descriptor: self.renderer.sampled_image_descriptor(usage, texture_view),
|
|
execution_version: Cell::new(0),
|
|
}))
|
|
}
|
|
|
|
fn create_bridge(&self) -> Result<(Image, VulkanAllocation), VulkanError> {
|
|
let create_info = ImageCreateInfo::default()
|
|
.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);
|
|
let image = unsafe { self.renderer.device.device.create_image(&create_info, None) };
|
|
let image = image.map_err(VulkanError::CreateImage)?;
|
|
let destroy_image =
|
|
on_drop(|| 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 {
|
|
fn to_framebuffer(self: Rc<Self>) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
|
self.create_framebuffer()
|
|
.map(|v| v as _)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
fn to_texture(self: Rc<Self>) -> Result<Rc<dyn GfxTexture>, GfxError> {
|
|
self.create_texture().map(|v| v as _).map_err(|e| e.into())
|
|
}
|
|
|
|
fn width(&self) -> i32 {
|
|
self.width as i32
|
|
}
|
|
|
|
fn height(&self) -> i32 {
|
|
self.height as i32
|
|
}
|
|
}
|
|
|
|
impl Debug for VulkanImage {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("VulkanDmaBufImage").finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
impl GfxFramebuffer for VulkanImage {
|
|
fn physical_size(&self) -> (i32, i32) {
|
|
(self.width as _, self.height as _)
|
|
}
|
|
|
|
fn render_with_region(
|
|
self: Rc<Self>,
|
|
acquire_sync: AcquireSync,
|
|
release_sync: ReleaseSync,
|
|
cd: &Rc<ColorDescription>,
|
|
ops: &[GfxApiOpt],
|
|
clear: Option<&Color>,
|
|
clear_cd: &Rc<LinearColorDescription>,
|
|
region: &Region,
|
|
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
|
blend_cd: &Rc<ColorDescription>,
|
|
) -> Result<Option<SyncFile>, GfxError> {
|
|
let mut blend_buffer = blend_buffer
|
|
.map(|b| b.clone().into_vk(&self.renderer.device.device))
|
|
.transpose()?;
|
|
if let Some(bb) = &blend_buffer
|
|
&& bb.size() != self.size()
|
|
{
|
|
log::error!(
|
|
"Blend buffer has invalid size: {:?} != {:?}",
|
|
bb.size(),
|
|
self.size()
|
|
);
|
|
blend_buffer = None;
|
|
}
|
|
self.renderer
|
|
.execute(
|
|
&self,
|
|
acquire_sync,
|
|
release_sync,
|
|
cd,
|
|
ops,
|
|
clear,
|
|
clear_cd,
|
|
region,
|
|
blend_buffer,
|
|
blend_cd,
|
|
)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
fn format(&self) -> &'static Format {
|
|
self.format
|
|
}
|
|
}
|
|
|
|
impl GfxInternalFramebuffer for VulkanImage {
|
|
fn stride(&self) -> i32 {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
shm.stride as _
|
|
}
|
|
|
|
fn staging_size(&self) -> usize {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
shm.size as _
|
|
}
|
|
|
|
fn download(
|
|
self: Rc<Self>,
|
|
staging: &Rc<dyn GfxStagingBuffer>,
|
|
callback: Rc<dyn AsyncShmGfxTextureCallback>,
|
|
mem: Rc<dyn ShmMemory>,
|
|
damage: Region,
|
|
) -> Result<Option<PendingShmTransfer>, GfxError> {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
let staging = staging.clone().into_vk(&self.renderer.device.device);
|
|
let pending = shm.async_transfer(
|
|
&self,
|
|
staging,
|
|
&mem,
|
|
damage,
|
|
callback,
|
|
TransferType::Download,
|
|
)?;
|
|
Ok(pending)
|
|
}
|
|
}
|
|
|
|
impl GfxTexture for VulkanImage {
|
|
fn size(&self) -> (i32, i32) {
|
|
(self.width as _, self.height as _)
|
|
}
|
|
|
|
fn dmabuf(&self) -> Option<&DmaBuf> {
|
|
match &self.ty {
|
|
VulkanImageMemory::DmaBuf(b) => Some(&b.template.dmabuf),
|
|
VulkanImageMemory::Internal(_) => None,
|
|
VulkanImageMemory::Blend(_) => None,
|
|
}
|
|
}
|
|
|
|
fn format(&self) -> &'static Format {
|
|
self.format
|
|
}
|
|
}
|
|
|
|
impl ShmGfxTexture for VulkanImage {}
|
|
|
|
impl AsyncShmGfxTexture for VulkanImage {
|
|
fn staging_size(&self) -> usize {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
shm.size as _
|
|
}
|
|
|
|
fn async_upload(
|
|
self: Rc<Self>,
|
|
staging: &Rc<dyn GfxStagingBuffer>,
|
|
callback: Rc<dyn AsyncShmGfxTextureCallback>,
|
|
mem: Rc<dyn ShmMemory>,
|
|
damage: Region,
|
|
) -> Result<Option<PendingShmTransfer>, GfxError> {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
let staging = staging.clone().into_vk(&self.renderer.device.device);
|
|
let pending =
|
|
shm.async_transfer(&self, staging, &mem, damage, callback, TransferType::Upload)?;
|
|
Ok(pending)
|
|
}
|
|
|
|
fn async_upload_from_buffer(
|
|
self: Rc<Self>,
|
|
buf: &Rc<dyn GfxBuffer>,
|
|
callback: Rc<dyn AsyncShmGfxTextureCallback>,
|
|
damage: Region,
|
|
) -> Result<Option<PendingShmTransfer>, GfxError> {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
let buf = buf.clone().into_vk(&self.renderer.device.device);
|
|
let pending = shm.async_transfer2(&self, buf, damage, callback)?;
|
|
Ok(pending)
|
|
}
|
|
|
|
fn sync_upload(self: Rc<Self>, mem: &[Cell<u8>], damage: Region) -> Result<(), GfxError> {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
if shm.async_data.as_ref().unwrap().busy.get() {
|
|
return Err(VulkanError::AsyncCopyBusy.into());
|
|
}
|
|
shm.upload(&self, mem, Some(damage.rects()))?;
|
|
Ok(())
|
|
}
|
|
|
|
fn compatible_with(
|
|
&self,
|
|
format: &'static Format,
|
|
width: i32,
|
|
height: i32,
|
|
stride: i32,
|
|
) -> bool {
|
|
self.format == format
|
|
&& self.width == width as u32
|
|
&& self.height == height as u32
|
|
&& self.stride == stride as u32
|
|
}
|
|
}
|
|
|
|
impl AsyncShmGfxTextureTransferCancellable for VulkanImage {
|
|
fn cancel(&self, id: u64) {
|
|
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
|
unreachable!();
|
|
};
|
|
let data = shm.async_data.as_ref().unwrap();
|
|
if data.callback_id.get() == id {
|
|
data.callback.take();
|
|
}
|
|
}
|
|
}
|