Merge pull request #623 from mahkoh/jorth/udmabuf-to-shm
linux-dmabuf: intercept udmabuf buffers
This commit is contained in:
commit
f00202f149
23 changed files with 311 additions and 154 deletions
|
|
@ -54,8 +54,9 @@ impl ClientMem {
|
|||
read_only: bool,
|
||||
client: Option<&Client>,
|
||||
cpu: Option<&Rc<CpuWorker>>,
|
||||
is_udmabuf: bool,
|
||||
) -> Result<Self, ClientMemError> {
|
||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_SHARED)
|
||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_SHARED, is_udmabuf)
|
||||
}
|
||||
|
||||
pub fn new_private(
|
||||
|
|
@ -65,7 +66,7 @@ impl ClientMem {
|
|||
client: Option<&Client>,
|
||||
cpu: Option<&Rc<CpuWorker>>,
|
||||
) -> Result<Self, ClientMemError> {
|
||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_PRIVATE)
|
||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_PRIVATE, false)
|
||||
}
|
||||
|
||||
fn new2(
|
||||
|
|
@ -75,10 +76,12 @@ impl ClientMem {
|
|||
client: Option<&Client>,
|
||||
cpu: Option<&Rc<CpuWorker>>,
|
||||
flags: c::c_int,
|
||||
is_udmabuf: bool,
|
||||
) -> Result<Self, ClientMemError> {
|
||||
let mut sigbus_impossible = false;
|
||||
let mut sigbus_impossible = is_udmabuf;
|
||||
let mut real_size = None;
|
||||
if let Ok(seals) = uapi::fcntl_get_seals(fd.raw())
|
||||
if !sigbus_impossible
|
||||
&& let Ok(seals) = uapi::fcntl_get_seals(fd.raw())
|
||||
&& seals & c::F_SEAL_SHRINK != 0
|
||||
&& let Ok(stat) = uapi::fstat(fd.raw())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use {
|
|||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FormatShmInfo {
|
||||
pub bpp: u32,
|
||||
pub gl_format: GLint,
|
||||
pub gl_internal_format: GLenum,
|
||||
pub gl_type: GLint,
|
||||
|
|
@ -38,6 +37,7 @@ pub struct Format {
|
|||
pub opaque: Option<&'static Format>,
|
||||
pub shm_info: Option<FormatShmInfo>,
|
||||
pub config: ConfigFormat,
|
||||
pub bpp: u32,
|
||||
}
|
||||
|
||||
const fn default(config: ConfigFormat) -> Format {
|
||||
|
|
@ -52,6 +52,7 @@ const fn default(config: ConfigFormat) -> Format {
|
|||
opaque: None,
|
||||
shm_info: None,
|
||||
config,
|
||||
bpp: 4,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,12 +160,12 @@ pub fn map_wayland_format_id(id: u32) -> u32 {
|
|||
pub static ARGB8888: &Format = &Format {
|
||||
name: "argb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
bpp: 4,
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: ARGB8888_DRM,
|
||||
wl_id: Some(ARGB8888_ID),
|
||||
external_only_guess: false,
|
||||
|
|
@ -177,12 +178,12 @@ pub static ARGB8888: &Format = &Format {
|
|||
pub static XRGB8888: &Format = &Format {
|
||||
name: "xrgb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
bpp: 4,
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: XRGB8888_DRM,
|
||||
wl_id: Some(XRGB8888_ID),
|
||||
external_only_guess: false,
|
||||
|
|
@ -195,12 +196,12 @@ pub static XRGB8888: &Format = &Format {
|
|||
static ABGR8888: &Format = &Format {
|
||||
name: "abgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
bpp: 4,
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
|
|
@ -213,12 +214,12 @@ static ABGR8888: &Format = &Format {
|
|||
static XBGR8888: &Format = &Format {
|
||||
name: "xbgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
bpp: 4,
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
|
|
@ -231,6 +232,7 @@ static XBGR8888: &Format = &Format {
|
|||
static R8: &Format = &Format {
|
||||
name: "r8",
|
||||
vk_format: vk::Format::R8_UNORM,
|
||||
bpp: 1,
|
||||
drm: fourcc_code('R', '8', ' ', ' '),
|
||||
pipewire: SPA_VIDEO_FORMAT_GRAY8,
|
||||
..default(ConfigFormat::R8)
|
||||
|
|
@ -239,6 +241,7 @@ static R8: &Format = &Format {
|
|||
static GR88: &Format = &Format {
|
||||
name: "gr88",
|
||||
vk_format: vk::Format::R8G8_UNORM,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('G', 'R', '8', '8'),
|
||||
..default(ConfigFormat::GR88)
|
||||
};
|
||||
|
|
@ -246,6 +249,7 @@ static GR88: &Format = &Format {
|
|||
static RGB888: &Format = &Format {
|
||||
name: "rgb888",
|
||||
vk_format: vk::Format::B8G8R8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('R', 'G', '2', '4'),
|
||||
pipewire: SPA_VIDEO_FORMAT_BGR,
|
||||
..default(ConfigFormat::RGB888)
|
||||
|
|
@ -254,6 +258,7 @@ static RGB888: &Format = &Format {
|
|||
static BGR888: &Format = &Format {
|
||||
name: "bgr888",
|
||||
vk_format: vk::Format::R8G8B8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('B', 'G', '2', '4'),
|
||||
pipewire: SPA_VIDEO_FORMAT_RGB,
|
||||
..default(ConfigFormat::BGR888)
|
||||
|
|
@ -262,6 +267,7 @@ static BGR888: &Format = &Format {
|
|||
static RGBA4444: &Format = &Format {
|
||||
name: "rgba4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX4444),
|
||||
|
|
@ -271,6 +277,7 @@ static RGBA4444: &Format = &Format {
|
|||
static RGBX4444: &Format = &Format {
|
||||
name: "rgbx4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '2'),
|
||||
..default(ConfigFormat::RGBX4444)
|
||||
};
|
||||
|
|
@ -278,6 +285,7 @@ static RGBX4444: &Format = &Format {
|
|||
static BGRA4444: &Format = &Format {
|
||||
name: "bgra4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX4444),
|
||||
|
|
@ -287,6 +295,7 @@ static BGRA4444: &Format = &Format {
|
|||
static BGRX4444: &Format = &Format {
|
||||
name: "bgrx4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '2'),
|
||||
..default(ConfigFormat::BGRX4444)
|
||||
};
|
||||
|
|
@ -294,6 +303,7 @@ static BGRX4444: &Format = &Format {
|
|||
static RGB565: &Format = &Format {
|
||||
name: "rgb565",
|
||||
vk_format: vk::Format::R5G6B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'G', '1', '6'),
|
||||
pipewire: SPA_VIDEO_FORMAT_BGR16,
|
||||
..default(ConfigFormat::RGB565)
|
||||
|
|
@ -302,6 +312,7 @@ static RGB565: &Format = &Format {
|
|||
static BGR565: &Format = &Format {
|
||||
name: "bgr565",
|
||||
vk_format: vk::Format::B5G6R5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'G', '1', '6'),
|
||||
pipewire: SPA_VIDEO_FORMAT_RGB16,
|
||||
..default(ConfigFormat::BGR565)
|
||||
|
|
@ -310,6 +321,7 @@ static BGR565: &Format = &Format {
|
|||
static RGBA5551: &Format = &Format {
|
||||
name: "rgba5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX5551),
|
||||
|
|
@ -319,6 +331,7 @@ static RGBA5551: &Format = &Format {
|
|||
static RGBX5551: &Format = &Format {
|
||||
name: "rgbx5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '5'),
|
||||
..default(ConfigFormat::RGBX5551)
|
||||
};
|
||||
|
|
@ -326,6 +339,7 @@ static RGBX5551: &Format = &Format {
|
|||
static BGRA5551: &Format = &Format {
|
||||
name: "bgra5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX5551),
|
||||
|
|
@ -335,6 +349,7 @@ static BGRA5551: &Format = &Format {
|
|||
static BGRX5551: &Format = &Format {
|
||||
name: "bgrx5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '5'),
|
||||
..default(ConfigFormat::BGRX5551)
|
||||
};
|
||||
|
|
@ -342,6 +357,7 @@ static BGRX5551: &Format = &Format {
|
|||
static ARGB1555: &Format = &Format {
|
||||
name: "argb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('A', 'R', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB1555),
|
||||
|
|
@ -351,6 +367,7 @@ static ARGB1555: &Format = &Format {
|
|||
static XRGB1555: &Format = &Format {
|
||||
name: "xrgb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('X', 'R', '1', '5'),
|
||||
pipewire: SPA_VIDEO_FORMAT_BGR15,
|
||||
..default(ConfigFormat::XRGB1555)
|
||||
|
|
@ -359,6 +376,7 @@ static XRGB1555: &Format = &Format {
|
|||
static ARGB2101010: &Format = &Format {
|
||||
name: "argb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'R', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB2101010),
|
||||
|
|
@ -369,6 +387,7 @@ static ARGB2101010: &Format = &Format {
|
|||
static XRGB2101010: &Format = &Format {
|
||||
name: "xrgb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'R', '3', '0'),
|
||||
pipewire: SPA_VIDEO_FORMAT_xRGB_210LE,
|
||||
..default(ConfigFormat::XRGB2101010)
|
||||
|
|
@ -377,6 +396,7 @@ static XRGB2101010: &Format = &Format {
|
|||
static ABGR2101010: &Format = &Format {
|
||||
name: "abgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR2101010),
|
||||
|
|
@ -387,6 +407,7 @@ static ABGR2101010: &Format = &Format {
|
|||
static XBGR2101010: &Format = &Format {
|
||||
name: "xbgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '3', '0'),
|
||||
pipewire: SPA_VIDEO_FORMAT_xBGR_210LE,
|
||||
..default(ConfigFormat::XBGR2101010)
|
||||
|
|
@ -395,6 +416,7 @@ static XBGR2101010: &Format = &Format {
|
|||
static ABGR16161616: &Format = &Format {
|
||||
name: "abgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', '8'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616),
|
||||
|
|
@ -404,6 +426,7 @@ static ABGR16161616: &Format = &Format {
|
|||
static XBGR16161616: &Format = &Format {
|
||||
name: "xbgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', '8'),
|
||||
..default(ConfigFormat::XBGR16161616)
|
||||
};
|
||||
|
|
@ -411,6 +434,7 @@ static XBGR16161616: &Format = &Format {
|
|||
pub static ABGR16161616F: &Format = &Format {
|
||||
name: "abgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', 'H'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616F),
|
||||
|
|
@ -420,6 +444,7 @@ pub static ABGR16161616F: &Format = &Format {
|
|||
static XBGR16161616F: &Format = &Format {
|
||||
name: "xbgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', 'H'),
|
||||
..default(ConfigFormat::XBGR16161616F)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -824,10 +824,12 @@ pub trait GfxContext: Debug {
|
|||
dmabuf: &OwnedFd,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
format: &'static Format,
|
||||
) -> Result<Rc<dyn GfxBuffer>, GfxError> {
|
||||
let _ = dmabuf;
|
||||
let _ = offset;
|
||||
let _ = size;
|
||||
let _ = format;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Host buffers are not supported")]
|
||||
|
|
@ -850,6 +852,7 @@ pub struct GfxFormat {
|
|||
pub format: &'static Format,
|
||||
pub read_modifiers: IndexSet<Modifier>,
|
||||
pub write_modifiers: IndexMap<Modifier, GfxWriteModifier>,
|
||||
pub supports_shm: bool,
|
||||
}
|
||||
|
||||
#[derive(Error)]
|
||||
|
|
@ -879,6 +882,7 @@ impl GfxFormat {
|
|||
.map(|(m, v)| (*m, v.clone()))
|
||||
.filter(|(m, _)| other.read_modifiers.contains(m))
|
||||
.collect(),
|
||||
supports_shm: self.supports_shm && other.supports_shm,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,13 +201,17 @@ impl EglDisplay {
|
|||
}
|
||||
read_modifiers.insert(modifier.modifier);
|
||||
}
|
||||
if !read_modifiers.is_empty() || !write_modifiers.is_empty() {
|
||||
if !read_modifiers.is_empty()
|
||||
|| !write_modifiers.is_empty()
|
||||
|| format.format.shm_info.is_some()
|
||||
{
|
||||
formats.insert(
|
||||
drm,
|
||||
GfxFormat {
|
||||
format: format.format,
|
||||
read_modifiers,
|
||||
write_modifiers,
|
||||
supports_shm: format.format.shm_info.is_some(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ impl GlTexture {
|
|||
(gles.glBindTexture)(GL_TEXTURE_2D, tex);
|
||||
(gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
(gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
(gles.glPixelStorei)(GL_UNPACK_ROW_LENGTH_EXT, stride / shm_info.bpp as GLint);
|
||||
(gles.glPixelStorei)(GL_UNPACK_ROW_LENGTH_EXT, stride / format.bpp as GLint);
|
||||
(gles.glTexImage2D)(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ impl AsyncShmGfxTexture for Texture {
|
|||
(gles.glTexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
(gles.glPixelStorei)(
|
||||
GL_UNPACK_ROW_LENGTH_EXT,
|
||||
self.gl.stride / shm_info.bpp as GLint,
|
||||
self.gl.stride / self.format.bpp as GLint,
|
||||
);
|
||||
(gles.glTexImage2D)(
|
||||
GL_TEXTURE_2D,
|
||||
|
|
|
|||
|
|
@ -179,8 +179,6 @@ pub enum VulkanError {
|
|||
InvalidStride,
|
||||
#[error("Shm stride and height do not match buffer size")]
|
||||
InvalidBufferSize,
|
||||
#[error("Buffer format {0} is not supported for shm buffers in Vulkan context")]
|
||||
UnsupportedShmFormat(&'static str),
|
||||
#[error("Only BO_USE_RENDERING and BO_USE_WRITE are supported")]
|
||||
UnsupportedBufferUsage,
|
||||
#[error("None of the supplied modifiers are supported")]
|
||||
|
|
@ -223,6 +221,8 @@ pub enum VulkanError {
|
|||
GetFl(#[source] OsError),
|
||||
#[error("GBM implementation cannot be used with software renderer")]
|
||||
SoftwareRendererNotUsable,
|
||||
#[error("DMABUF buffer offsets must be aligned to 4 bytes and the pixel size")]
|
||||
DmaBufBufferOffsetAlignment,
|
||||
}
|
||||
|
||||
impl From<VulkanError> for GfxError {
|
||||
|
|
@ -401,12 +401,13 @@ impl GfxContext for Context {
|
|||
dmabuf: &OwnedFd,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
format: &'static Format,
|
||||
) -> Result<Rc<dyn GfxBuffer>, GfxError> {
|
||||
self.0.check_defunct()?;
|
||||
let buffer = self
|
||||
.0
|
||||
.device
|
||||
.create_dmabuf_buffer(dmabuf, offset as u64, size as u64)?;
|
||||
let buffer =
|
||||
self.0
|
||||
.device
|
||||
.create_dmabuf_buffer(dmabuf, offset as u64, size as u64, format)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -457,10 +457,7 @@ impl Allocator for VulkanBoAllocator {
|
|||
impl VulkanBo {
|
||||
fn map(self: &Rc<Self>, write: bool) -> Result<VulkanBoMapping, VulkanError> {
|
||||
let format = self.buf.format;
|
||||
let Some(shm_info) = &format.shm_info else {
|
||||
return Err(VulkanError::ShmNotSupported);
|
||||
};
|
||||
let stride = self.buf.width as u32 * shm_info.bpp;
|
||||
let stride = self.buf.width as u32 * format.bpp;
|
||||
let size = self.buf.height as u32 * stride;
|
||||
let data = &self.allocator;
|
||||
let staging =
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
format::Format,
|
||||
gfx_api::GfxBuffer,
|
||||
gfx_apis::vulkan::{VulkanError, device::VulkanDevice},
|
||||
utils::on_drop::OnDrop,
|
||||
|
|
@ -9,13 +10,15 @@ use {
|
|||
vk::{
|
||||
self, BufferCreateInfo, BufferUsageFlags, ExternalMemoryBufferCreateInfo,
|
||||
ExternalMemoryHandleTypeFlags, ImportMemoryFdInfoKHR, MemoryAllocateInfo,
|
||||
MemoryFdPropertiesKHR, MemoryPropertyFlags,
|
||||
MemoryDedicatedAllocateInfo, MemoryFdPropertiesKHR, MemoryPropertyFlags,
|
||||
},
|
||||
},
|
||||
std::{any::Any, rc::Rc},
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
pub(super) const TRANSFER_QUEUE_BUFFER_ALIGNMENT: u64 = 4;
|
||||
|
||||
pub struct VulkanDmabufBuffer {
|
||||
pub(super) device: Rc<VulkanDevice>,
|
||||
pub(super) size: u64,
|
||||
|
|
@ -30,7 +33,11 @@ impl VulkanDevice {
|
|||
dmabuf: &OwnedFd,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
format: &'static Format,
|
||||
) -> Result<Rc<VulkanDmabufBuffer>, VulkanError> {
|
||||
if offset % TRANSFER_QUEUE_BUFFER_ALIGNMENT != 0 || offset % format.bpp as u64 != 0 {
|
||||
return Err(VulkanError::DmaBufBufferOffsetAlignment);
|
||||
}
|
||||
let mut memory_fd_properties = MemoryFdPropertiesKHR::default();
|
||||
unsafe {
|
||||
self.external_memory_fd
|
||||
|
|
@ -66,13 +73,15 @@ impl VulkanDevice {
|
|||
let fd =
|
||||
uapi::fcntl_dupfd_cloexec(dmabuf.raw(), 0).map_err(|e| VulkanError::Dupfd(e.into()))?;
|
||||
let memory = {
|
||||
let mut dedicated = MemoryDedicatedAllocateInfo::default().buffer(buffer);
|
||||
let mut import_info = ImportMemoryFdInfoKHR::default()
|
||||
.fd(fd.raw())
|
||||
.handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
||||
let allocate_info = MemoryAllocateInfo::default()
|
||||
.allocation_size(requirements.size)
|
||||
.memory_type_index(memory_type)
|
||||
.push_next(&mut import_info);
|
||||
.push_next(&mut import_info)
|
||||
.push_next(&mut dedicated);
|
||||
unsafe {
|
||||
self.device
|
||||
.allocate_memory(&allocate_info, None)
|
||||
|
|
|
|||
|
|
@ -171,9 +171,6 @@ impl VulkanInstance {
|
|||
format: &Format,
|
||||
props: &FormatProperties,
|
||||
) -> Result<Option<VulkanInternalFormat>, VulkanError> {
|
||||
if format.shm_info.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
self.load_internal_format(phy_dev, format, props, SHM_FEATURES, SHM_USAGE)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ impl VulkanDevice {
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
supports_shm: vk.shm.is_some(),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
cpu_worker::CpuWorker,
|
||||
format::{Format, FormatShmInfo},
|
||||
format::Format,
|
||||
gfx_api::SyncFile,
|
||||
gfx_apis::vulkan::{
|
||||
VulkanError,
|
||||
|
|
@ -22,18 +22,17 @@ use {
|
|||
CopyImageToBufferInfo2, DependencyInfoKHR, DeviceSize, Extent3D, ImageAspectFlags,
|
||||
ImageCreateInfo, ImageLayout, ImageSubresourceLayers, ImageSubresourceRange, ImageTiling,
|
||||
ImageType, ImageUsageFlags, ImageViewCreateInfo, ImageViewType, Offset3D,
|
||||
PipelineStageFlags2, SampleCountFlags, SharingMode, SubmitInfo2,
|
||||
PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT, SampleCountFlags, SharingMode, SubmitInfo2,
|
||||
},
|
||||
gpu_alloc::UsageFlags,
|
||||
isnt::std_1::primitive::IsntSliceExt,
|
||||
std::{cell::Cell, ptr, rc::Rc, slice},
|
||||
std::{cell::Cell, mem, ptr, rc::Rc, slice},
|
||||
};
|
||||
|
||||
pub struct VulkanShmImage {
|
||||
pub(super) size: DeviceSize,
|
||||
pub(super) stride: u32,
|
||||
pub(super) _allocation: VulkanAllocation,
|
||||
pub(super) shm_info: &'static FormatShmInfo,
|
||||
pub(super) async_data: Option<VulkanShmImageAsyncData>,
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +67,7 @@ impl VulkanShmImage {
|
|||
if full {
|
||||
builder = builder
|
||||
.buffer_image_height(img.height)
|
||||
.buffer_row_length(img.stride / self.shm_info.bpp);
|
||||
.buffer_row_length(img.stride / img.format.bpp);
|
||||
}
|
||||
builder
|
||||
};
|
||||
|
|
@ -99,7 +98,7 @@ impl VulkanShmImage {
|
|||
damage.width() as u32,
|
||||
damage.height() as u32,
|
||||
));
|
||||
total_size += damage.width() as u32 * damage.height() as u32 * self.shm_info.bpp;
|
||||
total_size += damage.width() as u32 * damage.height() as u32 * img.format.bpp;
|
||||
}
|
||||
cpy = &cpy_many[..];
|
||||
} else {
|
||||
|
|
@ -124,7 +123,7 @@ impl VulkanShmImage {
|
|||
let width = cpy.image_extent.width as usize;
|
||||
let height = cpy.image_extent.height as usize;
|
||||
let stride = self.stride as usize;
|
||||
let bpp = self.shm_info.bpp as usize;
|
||||
let bpp = img.format.bpp as usize;
|
||||
for dy in 0..height {
|
||||
let lo = (y + dy) * stride + x * bpp;
|
||||
let len = width * bpp;
|
||||
|
|
@ -143,6 +142,7 @@ impl VulkanShmImage {
|
|||
cpy,
|
||||
false,
|
||||
TransferType::Upload,
|
||||
false,
|
||||
)?;
|
||||
let future = img.renderer.eng.spawn(
|
||||
"await upload",
|
||||
|
|
@ -160,6 +160,7 @@ impl VulkanShmImage {
|
|||
regions: &[BufferImageCopy2],
|
||||
use_transfer_queue: bool,
|
||||
tt: TransferType,
|
||||
foreign_buffer: bool,
|
||||
) -> Result<
|
||||
(
|
||||
Rc<VulkanCommandBuffer>,
|
||||
|
|
@ -169,22 +170,50 @@ impl VulkanShmImage {
|
|||
),
|
||||
VulkanError,
|
||||
> {
|
||||
let memory_barrier = |sam, ssm, dam, dsm| {
|
||||
BufferMemoryBarrier2::default()
|
||||
.buffer(buffer)
|
||||
.offset(0)
|
||||
.size(size)
|
||||
.src_access_mask(sam)
|
||||
.src_stage_mask(ssm)
|
||||
.dst_access_mask(dam)
|
||||
.dst_stage_mask(dsm)
|
||||
};
|
||||
let mut transfer_queue_family_idx = img.renderer.device.graphics_queue_idx;
|
||||
if use_transfer_queue
|
||||
&& let Some(idx) = img.renderer.device.distinct_transfer_queue_family_idx
|
||||
{
|
||||
transfer_queue_family_idx = idx;
|
||||
}
|
||||
let memory_barrier = |release| {
|
||||
let mut sq;
|
||||
let mut sam;
|
||||
let mut ssm;
|
||||
if foreign_buffer {
|
||||
sq = QUEUE_FAMILY_FOREIGN_EXT;
|
||||
sam = AccessFlags2::NONE;
|
||||
ssm = PipelineStageFlags2::NONE;
|
||||
} else {
|
||||
sq = transfer_queue_family_idx;
|
||||
sam = match tt {
|
||||
TransferType::Upload => AccessFlags2::HOST_WRITE,
|
||||
TransferType::Download => AccessFlags2::HOST_READ,
|
||||
};
|
||||
ssm = PipelineStageFlags2::HOST;
|
||||
}
|
||||
let mut dq = transfer_queue_family_idx;
|
||||
let mut dam = match tt {
|
||||
TransferType::Upload => AccessFlags2::TRANSFER_READ,
|
||||
TransferType::Download => AccessFlags2::TRANSFER_WRITE,
|
||||
};
|
||||
let mut dsm = PipelineStageFlags2::TRANSFER;
|
||||
if release {
|
||||
mem::swap(&mut sq, &mut dq);
|
||||
mem::swap(&mut sam, &mut dam);
|
||||
mem::swap(&mut ssm, &mut dsm);
|
||||
}
|
||||
BufferMemoryBarrier2::default()
|
||||
.buffer(buffer)
|
||||
.offset(0)
|
||||
.size(size)
|
||||
.src_queue_family_index(sq)
|
||||
.src_access_mask(sam)
|
||||
.src_stage_mask(ssm)
|
||||
.dst_queue_family_index(dq)
|
||||
.dst_access_mask(dam)
|
||||
.dst_stage_mask(dsm)
|
||||
};
|
||||
let mut initial_image_barrier = image_barrier()
|
||||
.image(img.image)
|
||||
.src_queue_family_index(img.renderer.device.graphics_queue_idx)
|
||||
|
|
@ -208,18 +237,7 @@ impl VulkanShmImage {
|
|||
.src_access_mask(AccessFlags2::SHADER_SAMPLED_READ)
|
||||
.src_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER)
|
||||
}
|
||||
let initial_buffer_barrier = memory_barrier(
|
||||
match tt {
|
||||
TransferType::Upload => AccessFlags2::HOST_WRITE,
|
||||
TransferType::Download => AccessFlags2::HOST_READ,
|
||||
},
|
||||
PipelineStageFlags2::HOST,
|
||||
match tt {
|
||||
TransferType::Upload => AccessFlags2::TRANSFER_READ,
|
||||
TransferType::Download => AccessFlags2::TRANSFER_WRITE,
|
||||
},
|
||||
PipelineStageFlags2::TRANSFER,
|
||||
);
|
||||
let initial_buffer_barrier = memory_barrier(false);
|
||||
let initial_dep_info = DependencyInfoKHR::default()
|
||||
.buffer_memory_barriers(slice::from_ref(&initial_buffer_barrier))
|
||||
.image_memory_barriers(slice::from_ref(&initial_image_barrier));
|
||||
|
|
@ -248,18 +266,7 @@ impl VulkanShmImage {
|
|||
})
|
||||
.dst_stage_mask(PipelineStageFlags2::FRAGMENT_SHADER);
|
||||
}
|
||||
let final_buffer_barrier = memory_barrier(
|
||||
match tt {
|
||||
TransferType::Upload => AccessFlags2::TRANSFER_READ,
|
||||
TransferType::Download => AccessFlags2::TRANSFER_WRITE,
|
||||
},
|
||||
PipelineStageFlags2::TRANSFER,
|
||||
match tt {
|
||||
TransferType::Upload => AccessFlags2::HOST_WRITE,
|
||||
TransferType::Download => AccessFlags2::HOST_READ,
|
||||
},
|
||||
PipelineStageFlags2::HOST,
|
||||
);
|
||||
let final_buffer_barrier = memory_barrier(true);
|
||||
let final_dep_info = DependencyInfoKHR::default()
|
||||
.buffer_memory_barriers(slice::from_ref(&final_buffer_barrier))
|
||||
.image_memory_barriers(slice::from_ref(&final_image_barrier));
|
||||
|
|
@ -359,16 +366,13 @@ impl VulkanRenderer {
|
|||
for_download: bool,
|
||||
cpu_worker: Option<&Rc<CpuWorker>>,
|
||||
) -> Result<Rc<VulkanImage>, VulkanError> {
|
||||
let Some(shm_info) = &format.shm_info else {
|
||||
return Err(VulkanError::UnsupportedShmFormat(format.name));
|
||||
};
|
||||
if width <= 0 || height <= 0 || stride <= 0 {
|
||||
return Err(VulkanError::NonPositiveImageSize);
|
||||
}
|
||||
let width = width as u32;
|
||||
let height = height as u32;
|
||||
let stride = stride as u32;
|
||||
if stride % shm_info.bpp != 0 || stride / shm_info.bpp < width {
|
||||
if stride % format.bpp != 0 || stride / format.bpp < width {
|
||||
return Err(VulkanError::InvalidStride);
|
||||
}
|
||||
let vk_format = self
|
||||
|
|
@ -453,7 +457,6 @@ impl VulkanRenderer {
|
|||
size,
|
||||
stride,
|
||||
_allocation: allocation,
|
||||
shm_info,
|
||||
async_data,
|
||||
};
|
||||
destroy_image.forget();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use {
|
|||
gfx_apis::vulkan::{
|
||||
VulkanError,
|
||||
command::VulkanCommandBuffer,
|
||||
dmabuf_buffer::VulkanDmabufBuffer,
|
||||
dmabuf_buffer::{TRANSFER_QUEUE_BUFFER_ALIGNMENT, VulkanDmabufBuffer},
|
||||
fence::VulkanFence,
|
||||
image::{QueueFamily, QueueState, QueueTransfer, VulkanImage, VulkanImageMemory},
|
||||
renderer::image_barrier,
|
||||
|
|
@ -227,8 +227,25 @@ impl VulkanShmImage {
|
|||
let mut copies_ref = data.regions.borrow_mut();
|
||||
let copies = &mut *copies_ref;
|
||||
copies.clear();
|
||||
let mut copy = |x, y, width, height| {
|
||||
let buffer_offset = (y as u32 * img.stride + x as u32 * self.shm_info.bpp) as u64;
|
||||
let mut copy = |mut x, mut y, mut width, mut height| {
|
||||
let x_orig = x;
|
||||
let width_orig = width;
|
||||
let mut buffer_offset;
|
||||
loop {
|
||||
buffer_offset = (y as u32 * img.stride + x as u32 * img.format.bpp) as u64;
|
||||
if buffer_offset.is_multiple_of(TRANSFER_QUEUE_BUFFER_ALIGNMENT) {
|
||||
break;
|
||||
}
|
||||
if x > 0 {
|
||||
x -= 1;
|
||||
width += 1;
|
||||
} else {
|
||||
y -= 1;
|
||||
height += 1;
|
||||
x = x_orig;
|
||||
width = width_orig;
|
||||
}
|
||||
}
|
||||
let copy = BufferImageCopy2::default()
|
||||
.buffer_offset(buffer_offset + extra_offset)
|
||||
.image_offset(Offset3D { x, y, z: 0 })
|
||||
|
|
@ -244,7 +261,7 @@ impl VulkanShmImage {
|
|||
layer_count: 1,
|
||||
})
|
||||
.buffer_image_height(img.height)
|
||||
.buffer_row_length(img.stride / self.shm_info.bpp);
|
||||
.buffer_row_length(img.stride / img.format.bpp);
|
||||
copies.push(copy);
|
||||
};
|
||||
let (width_mask, height_mask) = img.renderer.device.transfer_granularity_mask;
|
||||
|
|
@ -451,7 +468,7 @@ impl VulkanShmImage {
|
|||
}
|
||||
job.work.width = img.width as _;
|
||||
job.work.stride = img.stride as _;
|
||||
job.work.bpp = self.shm_info.bpp as _;
|
||||
job.work.bpp = img.format.bpp as _;
|
||||
job.work.rects.clear();
|
||||
for copy in copies {
|
||||
job.work.rects.push(
|
||||
|
|
@ -472,7 +489,7 @@ impl VulkanShmImage {
|
|||
for copy in copies {
|
||||
min_offset = min_offset.min(copy.buffer_offset);
|
||||
let len = img.stride * (copy.image_extent.height - 1)
|
||||
+ copy.image_extent.width * self.shm_info.bpp;
|
||||
+ copy.image_extent.width * img.format.bpp;
|
||||
max_offset = max_offset.max(copy.buffer_offset + len as u64);
|
||||
}
|
||||
let mut job = data.io_job.take().unwrap_or_else(|| {
|
||||
|
|
@ -520,19 +537,26 @@ impl VulkanShmImage {
|
|||
}
|
||||
img.renderer.check_defunct()?;
|
||||
let regions = &*data.regions.borrow();
|
||||
let (buffer, size) = match data.staging.get() {
|
||||
let (buffer, size, foreign_buffer) = match data.staging.get() {
|
||||
Some(s) => {
|
||||
let staging = s.staging.get().unwrap();
|
||||
staging.upload(|_, _| ())?;
|
||||
(staging.buffer, staging.size)
|
||||
(staging.buffer, staging.size, false)
|
||||
}
|
||||
_ => {
|
||||
let host_buffer = data.buffer.get().unwrap();
|
||||
(host_buffer.buffer, host_buffer.size)
|
||||
(host_buffer.buffer, host_buffer.size, true)
|
||||
}
|
||||
};
|
||||
let (cmd, fence, sync_file, point) =
|
||||
self.submit_buffer_image_copy(img, buffer, size, regions, true, TransferType::Upload)?;
|
||||
let (cmd, fence, sync_file, point) = self.submit_buffer_image_copy(
|
||||
img,
|
||||
buffer,
|
||||
size,
|
||||
regions,
|
||||
true,
|
||||
TransferType::Upload,
|
||||
foreign_buffer,
|
||||
)?;
|
||||
img.queue_state.set(QueueState::Releasing);
|
||||
let future = img.renderer.eng.spawn(
|
||||
"await async upload",
|
||||
|
|
@ -566,6 +590,7 @@ impl VulkanShmImage {
|
|||
copies,
|
||||
true,
|
||||
TransferType::Download,
|
||||
false,
|
||||
)?;
|
||||
img.queue_state.set(QueueState::Releasing);
|
||||
let future = img.renderer.eng.spawn(
|
||||
|
|
|
|||
|
|
@ -108,20 +108,38 @@ impl WlBuffer {
|
|||
stride: i32,
|
||||
format: &'static Format,
|
||||
mem: &Rc<ClientMem>,
|
||||
udmabuf: Option<(&Rc<OwnedFd>, usize)>,
|
||||
) -> Result<Self, WlBufferError> {
|
||||
let Some(shm_info) = &format.shm_info else {
|
||||
return Err(WlBufferError::UnsupportedShmFormat(format.name));
|
||||
};
|
||||
let bytes = stride as u64 * height as u64;
|
||||
let required = bytes + offset as u64;
|
||||
if required > mem.len() as u64 {
|
||||
return Err(WlBufferError::OutOfBounds);
|
||||
}
|
||||
let mem = Rc::new(mem.offset(offset));
|
||||
let min_row_size = width as u64 * shm_info.bpp as u64;
|
||||
let min_row_size = width as u64 * format.bpp as u64;
|
||||
if (stride as u64) < min_row_size {
|
||||
return Err(WlBufferError::StrideTooSmall);
|
||||
}
|
||||
let dmabuf_buffer_params = match udmabuf {
|
||||
None => DmabufBufferParams {
|
||||
size: bytes as usize,
|
||||
udmabuf: None,
|
||||
udmabuf_offset: 0,
|
||||
udmabuf_size: 0,
|
||||
udmabuf_impossible: !mem.pool().is_sealed_memfd(),
|
||||
host_buffer: None,
|
||||
host_buffer_impossible: !mem.pool().is_sealed_memfd(),
|
||||
},
|
||||
Some((udmabuf, size)) => DmabufBufferParams {
|
||||
size,
|
||||
udmabuf: Some(udmabuf.clone()),
|
||||
udmabuf_offset: offset,
|
||||
udmabuf_size: size,
|
||||
udmabuf_impossible: false,
|
||||
host_buffer: None,
|
||||
host_buffer_impossible: false,
|
||||
},
|
||||
};
|
||||
Ok(Self {
|
||||
id,
|
||||
destroyed: Cell::new(false),
|
||||
|
|
@ -131,15 +149,7 @@ impl WlBuffer {
|
|||
dmabuf: None,
|
||||
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
|
||||
storage: RefCell::new(Some(WlBufferStorage::Shm {
|
||||
dmabuf_buffer_params: DmabufBufferParams {
|
||||
size: bytes as usize,
|
||||
udmabuf: None,
|
||||
udmabuf_offset: 0,
|
||||
udmabuf_size: 0,
|
||||
udmabuf_impossible: !mem.pool().is_sealed_memfd(),
|
||||
host_buffer: None,
|
||||
host_buffer_impossible: !mem.pool().is_sealed_memfd(),
|
||||
},
|
||||
dmabuf_buffer_params,
|
||||
mem,
|
||||
stride,
|
||||
})),
|
||||
|
|
@ -194,9 +204,9 @@ impl WlBuffer {
|
|||
};
|
||||
let had_texture = match s {
|
||||
WlBufferStorage::Shm {
|
||||
mem,
|
||||
dmabuf_buffer_params:
|
||||
DmabufBufferParams {
|
||||
udmabuf_impossible,
|
||||
host_buffer,
|
||||
host_buffer_impossible,
|
||||
..
|
||||
|
|
@ -204,7 +214,7 @@ impl WlBuffer {
|
|||
..
|
||||
} => {
|
||||
host_buffer.take();
|
||||
*host_buffer_impossible = !mem.pool().is_sealed_memfd();
|
||||
*host_buffer_impossible = *udmabuf_impossible;
|
||||
return match surface {
|
||||
Some(s) => {
|
||||
s.shm_staging.take();
|
||||
|
|
@ -310,14 +320,15 @@ impl WlBuffer {
|
|||
}
|
||||
}
|
||||
};
|
||||
let hb = match ctx.create_dmabuf_buffer(&udmabuf, *udmabuf_offset, *udmabuf_size) {
|
||||
Ok(hb) => hb,
|
||||
Err(e) => {
|
||||
*host_buffer_impossible = true;
|
||||
log::debug!("Could not create gfx host buffer: {}", ErrorFmt(e));
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let hb =
|
||||
match ctx.create_dmabuf_buffer(&udmabuf, *udmabuf_offset, *udmabuf_size, self.format) {
|
||||
Ok(hb) => hb,
|
||||
Err(e) => {
|
||||
*host_buffer_impossible = true;
|
||||
log::debug!("Could not create gfx host buffer: {}", ErrorFmt(e));
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
*host_buffer = Some(hb.clone());
|
||||
Ok(Some(hb))
|
||||
}
|
||||
|
|
@ -407,8 +418,6 @@ pub enum WlBufferError {
|
|||
GfxError(#[from] GfxError),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("Buffer format {0} is not supported for shm buffers")]
|
||||
UnsupportedShmFormat(&'static str),
|
||||
}
|
||||
efrom!(WlBufferError, ClientMemError);
|
||||
efrom!(WlBufferError, ClientError);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
format::FORMATS,
|
||||
globals::{Global, GlobalName},
|
||||
ifs::wl_shm_pool::{WlShmPool, WlShmPoolError},
|
||||
leaks::Tracker,
|
||||
|
|
@ -44,12 +43,14 @@ impl WlShmGlobal {
|
|||
});
|
||||
track!(client, obj);
|
||||
client.add_client_obj(&obj)?;
|
||||
for format in FORMATS {
|
||||
if format.shm_info.is_some() {
|
||||
client.event(Format {
|
||||
self_id: id,
|
||||
format: format.wl_id.unwrap_or(format.drm),
|
||||
});
|
||||
if let Some(ctx) = client.state.render_ctx.get() {
|
||||
for format in ctx.formats().values() {
|
||||
if format.supports_shm {
|
||||
client.event(Format {
|
||||
self_id: id,
|
||||
format: format.format.wl_id.unwrap_or(format.format.drm),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ impl WlShmPool {
|
|||
false,
|
||||
Some(client),
|
||||
Some(&client.state.cpu_worker),
|
||||
false,
|
||||
)?)),
|
||||
fd,
|
||||
tracker: Default::default(),
|
||||
|
|
@ -53,10 +54,9 @@ impl WlShmPoolRequestHandler for WlShmPool {
|
|||
|
||||
fn create_buffer(&self, req: CreateBuffer, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let drm_format = map_wayland_format_id(req.format);
|
||||
let format = match formats().get(&drm_format) {
|
||||
Some(f) if f.shm_info.is_some() => *f,
|
||||
_ => return Err(WlShmPoolError::InvalidFormat(req.format)),
|
||||
};
|
||||
let format = formats()
|
||||
.get(&drm_format)
|
||||
.ok_or(WlShmPoolError::InvalidFormat(req.format))?;
|
||||
if req.height < 0 || req.width < 0 || req.stride < 0 || req.offset < 0 {
|
||||
return Err(WlShmPoolError::NegativeParameters);
|
||||
}
|
||||
|
|
@ -69,6 +69,7 @@ impl WlShmPoolRequestHandler for WlShmPool {
|
|||
req.stride,
|
||||
format,
|
||||
&self.mem.get(),
|
||||
None,
|
||||
)?);
|
||||
track!(self.client, buffer);
|
||||
self.client.add_client_obj(&buffer)?;
|
||||
|
|
@ -93,6 +94,7 @@ impl WlShmPoolRequestHandler for WlShmPool {
|
|||
false,
|
||||
Some(&self.client),
|
||||
Some(&self.client.state.cpu_worker),
|
||||
false,
|
||||
)?));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
use {
|
||||
crate::{
|
||||
client::ClientError,
|
||||
clientmem::{ClientMem, ClientMemError},
|
||||
gfx_api::GfxError,
|
||||
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
||||
ifs::{
|
||||
wl_buffer::{WlBuffer, WlBufferError},
|
||||
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
||||
|
|
@ -102,25 +106,52 @@ impl ZwpLinuxBufferParamsV1 {
|
|||
fd: p.fd,
|
||||
});
|
||||
}
|
||||
let img = ctx.dmabuf_img(&dmabuf)?;
|
||||
let (is_client_id, buffer_id) = match buffer_id {
|
||||
Some(i) => (true, i),
|
||||
None => (false, self.parent.client.new_id()?),
|
||||
let get_id = || match buffer_id {
|
||||
None => self.parent.client.new_id(),
|
||||
Some(i) => Ok(i),
|
||||
};
|
||||
let buffer = if format.supports_shm
|
||||
&& let Some(size) = dmabuf.udmabuf_size()
|
||||
{
|
||||
let p = &dmabuf.planes[0];
|
||||
let client_mem = ClientMem::new(
|
||||
&p.fd,
|
||||
size,
|
||||
true,
|
||||
Some(&self.parent.client),
|
||||
Some(&self.parent.client.state.cpu_worker),
|
||||
true,
|
||||
)
|
||||
.map(Rc::new)
|
||||
.map_err(ZwpLinuxBufferParamsV1Error::CreateClientMem)?;
|
||||
Rc::new(WlBuffer::new_shm(
|
||||
get_id()?,
|
||||
&self.parent.client,
|
||||
p.offset as usize,
|
||||
dmabuf.width,
|
||||
dmabuf.height,
|
||||
p.stride as _,
|
||||
format.format,
|
||||
&client_mem,
|
||||
Some((&p.fd, size)),
|
||||
)?)
|
||||
} else {
|
||||
let img = ctx.dmabuf_img(&dmabuf)?;
|
||||
Rc::new(WlBuffer::new_dmabuf(
|
||||
get_id()?,
|
||||
&self.parent.client,
|
||||
format.format,
|
||||
dmabuf,
|
||||
&img,
|
||||
))
|
||||
};
|
||||
let buffer = Rc::new(WlBuffer::new_dmabuf(
|
||||
buffer_id,
|
||||
&self.parent.client,
|
||||
format.format,
|
||||
dmabuf,
|
||||
&img,
|
||||
));
|
||||
track!(self.parent.client, buffer);
|
||||
if is_client_id {
|
||||
if buffer_id.is_some() {
|
||||
self.parent.client.add_client_obj(&buffer)?;
|
||||
} else {
|
||||
self.parent.client.add_server_obj(&buffer);
|
||||
}
|
||||
Ok(buffer_id)
|
||||
Ok(buffer.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,5 +249,10 @@ pub enum ZwpLinuxBufferParamsV1Error {
|
|||
MissingPlane(usize),
|
||||
#[error("Could not import the buffer")]
|
||||
ImportError(#[from] GfxError),
|
||||
#[error("Could not create ClientMem")]
|
||||
CreateClientMem(#[source] ClientMemError),
|
||||
#[error(transparent)]
|
||||
WlBufferError(Box<WlBufferError>),
|
||||
}
|
||||
efrom!(ZwpLinuxBufferParamsV1Error, ClientError);
|
||||
efrom!(ZwpLinuxBufferParamsV1Error, WlBufferError);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ impl TestGfxCtx {
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
supports_shm: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ testcase!();
|
|||
|
||||
/// Test that wl_shm supports the required formats
|
||||
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||
run.backend.install_render_context(false)?;
|
||||
let client = run.create_client().await?;
|
||||
let formats = client.shm.formats().await;
|
||||
tassert!(formats.contains(&XRGB8888.wl_id.unwrap()));
|
||||
|
|
|
|||
15
src/text.rs
15
src/text.rs
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
cmm::cmm_eotf::Eotf,
|
||||
cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker, PendingJob},
|
||||
format::ARGB8888,
|
||||
format::{ARGB8888, Format},
|
||||
gfx_api::{
|
||||
AsyncShmGfxTexture, AsyncShmGfxTextureCallback, GfxBuffer, GfxContext, GfxError,
|
||||
GfxStagingBuffer, GfxTexture, PendingShmTransfer, STAGING_UPLOAD,
|
||||
|
|
@ -125,7 +125,8 @@ struct Data {
|
|||
layout: PangoLayout,
|
||||
}
|
||||
|
||||
const FORMAT: CairoFormat = CAIRO_FORMAT_ARGB32;
|
||||
const CAIRO_FORMAT: CairoFormat = CAIRO_FORMAT_ARGB32;
|
||||
const FORMAT: &Format = ARGB8888;
|
||||
|
||||
fn create_data(
|
||||
memfd: &Memfd,
|
||||
|
|
@ -134,12 +135,12 @@ fn create_data(
|
|||
height: i32,
|
||||
scale: Option<f64>,
|
||||
) -> Result<Data, TextError> {
|
||||
let Some((stride, size)) = cairo_size(FORMAT, width, height) else {
|
||||
let Some((stride, size)) = cairo_size(CAIRO_FORMAT, width, height) else {
|
||||
return Err(TextError::SizeOverflow);
|
||||
};
|
||||
let data = memfd.get_pointer_for_size(size)?;
|
||||
let image = match unsafe {
|
||||
CairoImageSurface::new_image_surface_with_data(FORMAT, data, width, height, stride)
|
||||
CairoImageSurface::new_image_surface_with_data(CAIRO_FORMAT, data, width, height, stride)
|
||||
} {
|
||||
Ok(s) => s,
|
||||
Err(e) => return Err(TextError::CreateImage(e)),
|
||||
|
|
@ -397,7 +398,7 @@ impl Shared {
|
|||
break 'res None;
|
||||
}
|
||||
};
|
||||
match self.ctx.create_dmabuf_buffer(&dmabuf, 0, size) {
|
||||
match self.ctx.create_dmabuf_buffer(&dmabuf, 0, size, FORMAT) {
|
||||
Ok(b) => Some(b),
|
||||
Err(e) => {
|
||||
log::debug!("Could not create GfxBuffer: {}", ErrorFmt(e));
|
||||
|
|
@ -604,7 +605,7 @@ impl CpuJob for RenderJob {
|
|||
return;
|
||||
}
|
||||
if let Some(t) = &tex
|
||||
&& !t.compatible_with(ARGB8888, rt.width, rt.height, rt.stride)
|
||||
&& !t.compatible_with(FORMAT, rt.width, rt.height, rt.stride)
|
||||
{
|
||||
tex = None;
|
||||
}
|
||||
|
|
@ -614,7 +615,7 @@ impl CpuJob for RenderJob {
|
|||
let tex = data
|
||||
.ctx
|
||||
.clone()
|
||||
.async_shmem_texture(ARGB8888, rt.width, rt.height, rt.stride, &data.cpu_worker)
|
||||
.async_shmem_texture(FORMAT, rt.width, rt.height, rt.stride, &data.cpu_worker)
|
||||
.map_err(TextError::CreateTexture);
|
||||
match tex {
|
||||
Ok(t) => t,
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ pub enum UdmabufError {
|
|||
Open(#[source] OsError),
|
||||
#[error("Only the linear modifier can be allocated")]
|
||||
Modifier,
|
||||
#[error("Format {0} is not supported")]
|
||||
Format(&'static str),
|
||||
#[error("Could not create a memfd")]
|
||||
Memfd(#[source] OsError),
|
||||
#[error("Size calculation overflowed")]
|
||||
|
|
@ -131,16 +129,13 @@ impl Allocator for Udmabuf {
|
|||
if !modifiers.contains(&LINEAR_MODIFIER) {
|
||||
return Err(UdmabufError::Modifier.into());
|
||||
}
|
||||
let Some(shm_info) = &format.shm_info else {
|
||||
return Err(UdmabufError::Format(format.name).into());
|
||||
};
|
||||
let height = height as u64;
|
||||
let width = width as u64;
|
||||
if height > 1 << 16 || width > 1 << 16 {
|
||||
return Err(UdmabufError::Overflow.into());
|
||||
}
|
||||
let stride_mask = 255;
|
||||
let stride = (width * shm_info.bpp as u64 + stride_mask) & !stride_mask;
|
||||
let stride = (width * format.bpp as u64 + stride_mask) & !stride_mask;
|
||||
let size_mask = page_size() as u64 - 1;
|
||||
let size = (height * stride + size_mask) & !size_mask;
|
||||
let memfd = match uapi::memfd_create("udmabuf", MFD_ALLOW_SEALING) {
|
||||
|
|
@ -186,9 +181,6 @@ impl Allocator for Udmabuf {
|
|||
return Err(UdmabufError::Modifier.into());
|
||||
}
|
||||
let plane = &dmabuf.planes[0];
|
||||
let Some(shm_info) = &dmabuf.format.shm_info else {
|
||||
return Err(UdmabufError::Format(dmabuf.format.name).into());
|
||||
};
|
||||
let height = dmabuf.height as u64;
|
||||
let width = dmabuf.width as u64;
|
||||
let stride = plane.stride as u64;
|
||||
|
|
@ -196,7 +188,7 @@ impl Allocator for Udmabuf {
|
|||
if height > 1 << 16 || width > 1 << 16 {
|
||||
return Err(UdmabufError::Overflow.into());
|
||||
}
|
||||
if stride < width * shm_info.bpp as u64 {
|
||||
if stride < width * dmabuf.format.bpp as u64 {
|
||||
return Err(UdmabufError::Stride.into());
|
||||
}
|
||||
let size = offset + stride * height;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@ use {
|
|||
crate::{
|
||||
format::Format,
|
||||
utils::{compat::IoctlNumber, oserror::OsError},
|
||||
video::Modifier,
|
||||
video::{LINEAR_MODIFIER, Modifier},
|
||||
},
|
||||
arrayvec::ArrayVec,
|
||||
std::rc::Rc,
|
||||
uapi::{_IOW, _IOWR, OwnedFd, c::ioctl},
|
||||
std::{rc::Rc, sync::OnceLock},
|
||||
uapi::{
|
||||
_IOW, _IOWR, OwnedFd,
|
||||
c::{self, dev_t, ioctl},
|
||||
format_ustr,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -53,6 +57,46 @@ impl DmaBuf {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn udmabuf_size(&self) -> Option<usize> {
|
||||
if self.planes.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
if self.modifier != LINEAR_MODIFIER {
|
||||
return None;
|
||||
}
|
||||
let stat = match uapi::fstat(self.planes[0].fd.raw()) {
|
||||
Ok(s) => s,
|
||||
_ => return None,
|
||||
};
|
||||
static DMABUF_DEV: OnceLock<dev_t> = OnceLock::new();
|
||||
match DMABUF_DEV.get() {
|
||||
Some(d) => {
|
||||
if stat.st_dev != *d {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if dma_buf_export_sync_file(&self.planes[0].fd, DMA_BUF_SYNC_READ).is_err() {
|
||||
return None;
|
||||
}
|
||||
let _ = DMABUF_DEV.set(stat.st_dev);
|
||||
}
|
||||
}
|
||||
let path = format_ustr!("/sys/kernel/dmabuf/buffers/{}/exporter_name", stat.st_ino);
|
||||
let Ok(file) = uapi::open(path, c::O_RDONLY, 0) else {
|
||||
return None;
|
||||
};
|
||||
const MARKER: &[u8] = b"udmabuf\n";
|
||||
let mut buf = [0u8; MARKER.len()];
|
||||
if uapi::read(file.raw(), &mut buf).is_err() {
|
||||
return None;
|
||||
}
|
||||
if buf != MARKER {
|
||||
return None;
|
||||
}
|
||||
Some(stat.st_size as usize)
|
||||
}
|
||||
|
||||
pub fn import_sync_file(&self, flags: u32, sync_file: &OwnedFd) -> Result<(), OsError> {
|
||||
for plane in &self.planes {
|
||||
dma_buf_import_sync_file(&plane.fd, flags, sync_file)?;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ impl JayRenderCtxEventHandler for UsrJayRenderCtx {
|
|||
format,
|
||||
read_modifiers: Default::default(),
|
||||
write_modifiers: Default::default(),
|
||||
supports_shm: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue