metal: add support for copy-device based prime methods
This commit is contained in:
parent
fa897f0f76
commit
a77929741a
7 changed files with 223 additions and 50 deletions
|
|
@ -6,20 +6,22 @@ use {
|
||||||
video::{MetalDrmDevice, MetalRenderContext},
|
video::{MetalDrmDevice, MetalRenderContext},
|
||||||
},
|
},
|
||||||
cmm::cmm_description::ColorDescription,
|
cmm::cmm_description::ColorDescription,
|
||||||
|
copy_device::{CopyDevice, CopyDeviceError, CopyDeviceSupport},
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, GfxBlendBuffer, GfxError, GfxFormat, GfxFramebuffer, GfxTexture,
|
AcquireSync, GfxBlendBuffer, GfxError, GfxFormat, GfxFramebuffer, GfxTexture,
|
||||||
GfxWriteModifier, ReleaseSync, SyncFile, needs_render_usage,
|
GfxWriteModifier, ReleaseSync, SyncFile, needs_render_usage,
|
||||||
},
|
},
|
||||||
rect::{DamageQueue, Rect},
|
rect::{DamageQueue, Rect, Region},
|
||||||
utils::{errorfmt::ErrorFmt, rc_eq::rc_eq},
|
utils::{errorfmt::ErrorFmt, rc_eq::rc_eq},
|
||||||
video::{
|
video::{
|
||||||
Modifier,
|
LINEAR_MODIFIER, Modifier,
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
drm::{DrmError, DrmFramebuffer},
|
drm::{DrmError, DrmFramebuffer},
|
||||||
gbm::{GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT, GbmBo, GbmError},
|
gbm::{GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT, GbmBo, GbmError},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ahash::HashSet,
|
||||||
arrayvec::ArrayVec,
|
arrayvec::ArrayVec,
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
indexmap::{IndexMap, IndexSet},
|
indexmap::{IndexMap, IndexSet},
|
||||||
|
|
@ -78,6 +80,10 @@ pub enum RenderBufferError {
|
||||||
GfxError(#[from] GfxError),
|
GfxError(#[from] GfxError),
|
||||||
#[error("Could not copy frame to output device")]
|
#[error("Could not copy frame to output device")]
|
||||||
CopyToOutput(#[source] GfxError),
|
CopyToOutput(#[source] GfxError),
|
||||||
|
#[error("Could not create a copy device copy")]
|
||||||
|
CreateCopyDeviceCopy(#[source] CopyDeviceError),
|
||||||
|
#[error("Could not execute a copy device copy")]
|
||||||
|
ExecuteCopyDeviceCopy(#[source] CopyDeviceError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -99,6 +105,7 @@ impl RenderBuffer {
|
||||||
pub fn copy_to_dev(
|
pub fn copy_to_dev(
|
||||||
&self,
|
&self,
|
||||||
cd: &Rc<ColorDescription>,
|
cd: &Rc<ColorDescription>,
|
||||||
|
_region: Option<&Region>,
|
||||||
sync_file: Option<SyncFile>,
|
sync_file: Option<SyncFile>,
|
||||||
) -> Result<RenderBufferCopy, RenderBufferError> {
|
) -> Result<RenderBufferCopy, RenderBufferError> {
|
||||||
match &self.prime {
|
match &self.prime {
|
||||||
|
|
@ -158,6 +165,14 @@ impl RenderBuffer {
|
||||||
return Err(RenderBufferError::NotSameSize);
|
return Err(RenderBufferError::NotSameSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(dev) = new.dev_copy_device().or(old.dev_copy_device()) {
|
||||||
|
return dev
|
||||||
|
.create_copy(old.dev_bo().dmabuf(), new.dev_bo().dmabuf())
|
||||||
|
.map_err(RenderBufferError::CreateCopyDeviceCopy)?
|
||||||
|
.execute(None, None)
|
||||||
|
.map_err(RenderBufferError::ExecuteCopyDeviceCopy);
|
||||||
|
}
|
||||||
|
|
||||||
let copy_texture_impl = |fb: &Rc<dyn GfxFramebuffer>, tex: &Rc<dyn GfxTexture>| {
|
let copy_texture_impl = |fb: &Rc<dyn GfxFramebuffer>, tex: &Rc<dyn GfxTexture>| {
|
||||||
fb.copy_texture(
|
fb.copy_texture(
|
||||||
AcquireSync::Unnecessary,
|
AcquireSync::Unnecessary,
|
||||||
|
|
@ -235,6 +250,13 @@ impl RenderBuffer {
|
||||||
RenderBufferPrime::Sampling { dev_bo, .. } => dev_bo,
|
RenderBufferPrime::Sampling { dev_bo, .. } => dev_bo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dev_copy_device(&self) -> Option<&Rc<CopyDevice>> {
|
||||||
|
match &self.prime {
|
||||||
|
RenderBufferPrime::None => None,
|
||||||
|
RenderBufferPrime::Sampling { .. } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Builder<'a> {
|
struct Builder<'a> {
|
||||||
|
|
@ -459,11 +481,15 @@ impl RenderBufferPrime {
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct RenderBufferAllocationDebug {
|
struct RenderBufferAllocationDebug {
|
||||||
|
dev_copy_src_modifiers: Option<Vec<Modifier>>,
|
||||||
|
dev_copy_dst_modifiers: Option<Vec<Modifier>>,
|
||||||
dev_gfx_write_modifiers: Option<Vec<Modifier>>,
|
dev_gfx_write_modifiers: Option<Vec<Modifier>>,
|
||||||
dev_gfx_read_modifiers: Option<Vec<Modifier>>,
|
dev_gfx_read_modifiers: Option<Vec<Modifier>>,
|
||||||
dev_modifiers_possible: Option<Vec<Modifier>>,
|
dev_modifiers_possible: Option<Vec<Modifier>>,
|
||||||
dev_usage: Option<u32>,
|
dev_usage: Option<u32>,
|
||||||
dev_modifier: Option<Modifier>,
|
dev_modifier: Option<Modifier>,
|
||||||
|
render_copy_src_modifiers: Option<Vec<Modifier>>,
|
||||||
|
render_copy_dst_modifiers: Option<Vec<Modifier>>,
|
||||||
render_gfx_write_modifiers: Option<Vec<Modifier>>,
|
render_gfx_write_modifiers: Option<Vec<Modifier>>,
|
||||||
render_gfx_read_modifiers: Option<Vec<Modifier>>,
|
render_gfx_read_modifiers: Option<Vec<Modifier>>,
|
||||||
render_modifiers_possible: Option<Vec<Modifier>>,
|
render_modifiers_possible: Option<Vec<Modifier>>,
|
||||||
|
|
@ -496,6 +522,12 @@ impl Display for ScanoutBufferError {
|
||||||
writeln!(f, "plane modifiers: {:x?}", self.plane_modifiers)?;
|
writeln!(f, "plane modifiers: {:x?}", self.plane_modifiers)?;
|
||||||
writeln!(f, "size: {}x{}", self.width, self.height)?;
|
writeln!(f, "size: {}x{}", self.width, self.height)?;
|
||||||
writeln!(f, "cursor: {}", self.cursor)?;
|
writeln!(f, "cursor: {}", self.cursor)?;
|
||||||
|
if let Some(v) = &self.dbg.dev_copy_src_modifiers {
|
||||||
|
writeln!(f, "scanout copy src modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.dbg.dev_copy_dst_modifiers {
|
||||||
|
writeln!(f, "scanout copy dst modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
if let Some(v) = &self.dbg.dev_gfx_write_modifiers {
|
if let Some(v) = &self.dbg.dev_gfx_write_modifiers {
|
||||||
writeln!(f, "scanout gfx writable modifiers: {:x?}", v)?;
|
writeln!(f, "scanout gfx writable modifiers: {:x?}", v)?;
|
||||||
}
|
}
|
||||||
|
|
@ -511,6 +543,12 @@ impl Display for ScanoutBufferError {
|
||||||
if let Some(v) = &self.render_name {
|
if let Some(v) = &self.render_name {
|
||||||
writeln!(f, "render device: {}", v)?;
|
writeln!(f, "render device: {}", v)?;
|
||||||
}
|
}
|
||||||
|
if let Some(v) = &self.dbg.render_copy_src_modifiers {
|
||||||
|
writeln!(f, "render copy src modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.dbg.render_copy_dst_modifiers {
|
||||||
|
writeln!(f, "render copy dst modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
if let Some(v) = &self.dbg.render_gfx_write_modifiers {
|
if let Some(v) = &self.dbg.render_gfx_write_modifiers {
|
||||||
writeln!(f, "render gfx writable modifiers: {:x?}", v)?;
|
writeln!(f, "render gfx writable modifiers: {:x?}", v)?;
|
||||||
}
|
}
|
||||||
|
|
@ -729,6 +767,43 @@ impl Builder<'_> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_modifiers_iter(&self, support: &[CopyDeviceSupport]) -> impl Iterator<Item = Modifier> {
|
||||||
|
let Builder { width, height, .. } = *self;
|
||||||
|
support
|
||||||
|
.iter()
|
||||||
|
.filter(move |s| s.max_width >= width as _ && s.max_height >= height as _)
|
||||||
|
.map(move |s| s.modifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_modifiers(&self, support: &[CopyDeviceSupport]) -> Vec<Modifier> {
|
||||||
|
self.copy_modifiers_iter(support).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn copy_src_modifiers(&self, dev: &CopyDevice) -> Vec<Modifier> {
|
||||||
|
self.copy_modifiers(dev.src_support(self.format))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn copy_dst_modifiers(&self, dev: &CopyDevice) -> Vec<Modifier> {
|
||||||
|
self.copy_modifiers(dev.dst_support(self.format))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_supports_linear(&self, support: &[CopyDeviceSupport]) -> bool {
|
||||||
|
self.copy_modifiers_iter(support)
|
||||||
|
.any(|m| m == LINEAR_MODIFIER)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn copy_src_supports_linear(&self, dev: &CopyDevice) -> bool {
|
||||||
|
self.copy_supports_linear(dev.src_support(self.format))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn copy_dst_supports_linear(&self, dev: &CopyDevice) -> bool {
|
||||||
|
self.copy_supports_linear(dev.dst_support(self.format))
|
||||||
|
}
|
||||||
|
|
||||||
fn prepare_prime_none(
|
fn prepare_prime_none(
|
||||||
&self,
|
&self,
|
||||||
dbg: &RefCell<RenderBufferAllocationDebug>,
|
dbg: &RefCell<RenderBufferAllocationDebug>,
|
||||||
|
|
@ -936,3 +1011,34 @@ fn sample_modifiers(fmt: &GfxFormat) -> Vec<Modifier> {
|
||||||
fn render_modifiers(fmt: &GfxFormat) -> Vec<Modifier> {
|
fn render_modifiers(fmt: &GfxFormat) -> Vec<Modifier> {
|
||||||
fmt.write_modifiers.keys().copied().collect()
|
fmt.write_modifiers.keys().copied().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn intersect_modifiers<'a>(
|
||||||
|
left: impl IntoIterator<Item = &'a Modifier>,
|
||||||
|
right: impl IntoIterator<Item = &'a Modifier>,
|
||||||
|
) -> Vec<Modifier> {
|
||||||
|
let right: HashSet<_> = right.into_iter().copied().collect();
|
||||||
|
left.into_iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|m| right.contains(m))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn intersect_render_modifiers<'a>(
|
||||||
|
left: &'a GfxFormat,
|
||||||
|
right: impl IntoIterator<Item = &'a Modifier>,
|
||||||
|
) -> Vec<Modifier> {
|
||||||
|
intersect_modifiers(
|
||||||
|
left.write_modifiers
|
||||||
|
.keys()
|
||||||
|
.filter(|m| left.read_modifiers.contains(*m)),
|
||||||
|
right,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn make_linear_only(modifiers: &mut Vec<Modifier>) {
|
||||||
|
if modifiers.contains(&LINEAR_MODIFIER) {
|
||||||
|
*modifiers = vec![LINEAR_MODIFIER];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ impl MetalBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_drm_device_removed(self: &Rc<Self>, dev: &Rc<MetalDrmDeviceData>) {
|
fn handle_drm_device_removed(self: &Rc<Self>, dev: &Rc<MetalDrmDeviceData>) {
|
||||||
|
self.state.copy_device_registry.remove(dev.dev.devnum);
|
||||||
log::info!("Device removed: {}", dev.dev.devnode.to_bytes().as_bstr());
|
log::info!("Device removed: {}", dev.dev.devnode.to_bytes().as_bstr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -557,7 +557,7 @@ impl MetalConnector {
|
||||||
if let Some(sf) = c.cursor_swap_buffer.take() {
|
if let Some(sf) = c.cursor_swap_buffer.take() {
|
||||||
let sf = c
|
let sf = c
|
||||||
.cursor_buffer
|
.cursor_buffer
|
||||||
.copy_to_dev(cd, sf)
|
.copy_to_dev(cd, None, sf)
|
||||||
.map_err(MetalError::CopyToDev)?
|
.map_err(MetalError::CopyToDev)?
|
||||||
.present_block;
|
.present_block;
|
||||||
self.cursor_sync_file.set(sf);
|
self.cursor_sync_file.set(sf);
|
||||||
|
|
@ -875,7 +875,9 @@ impl MetalConnector {
|
||||||
blend_cd,
|
blend_cd,
|
||||||
)
|
)
|
||||||
.map_err(MetalError::RenderFrame)?;
|
.map_err(MetalError::RenderFrame)?;
|
||||||
copy = buffer.copy_to_dev(cd, sf).map_err(MetalError::CopyToDev)?;
|
copy = buffer
|
||||||
|
.copy_to_dev(cd, Some(&latched.damage), sf)
|
||||||
|
.map_err(MetalError::CopyToDev)?;
|
||||||
fb = buffer.drm.clone();
|
fb = buffer.drm.clone();
|
||||||
tex = buffer.render.tex.clone();
|
tex = buffer.render.tex.clone();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use {
|
||||||
transaction::{DrmConnectorState, DrmCrtcState, DrmPlaneState, MetalDeviceTransaction},
|
transaction::{DrmConnectorState, DrmCrtcState, DrmPlaneState, MetalDeviceTransaction},
|
||||||
},
|
},
|
||||||
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
||||||
|
copy_device::{CopyDevice, CopyDeviceRegistry},
|
||||||
drm_feedback::DrmFeedback,
|
drm_feedback::DrmFeedback,
|
||||||
edid::{CtaDataBlock, Descriptor, EdidExtension},
|
edid::{CtaDataBlock, Descriptor, EdidExtension},
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
|
|
@ -58,7 +59,7 @@ use {
|
||||||
isnt::std_1::collections::IsntHashMapExt,
|
isnt::std_1::collections::IsntHashMapExt,
|
||||||
jay_config::video::GfxApi,
|
jay_config::video::GfxApi,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, OnceCell, RefCell},
|
||||||
collections::hash_map::Entry,
|
collections::hash_map::Entry,
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
|
@ -84,6 +85,19 @@ pub struct MetalRenderContext {
|
||||||
pub gfx: Rc<dyn GfxContext>,
|
pub gfx: Rc<dyn GfxContext>,
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
pub devnode: CString,
|
pub devnode: CString,
|
||||||
|
pub copy_device: Rc<CopyDeviceHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyDeviceHolder {
|
||||||
|
pub registry: Rc<CopyDeviceRegistry>,
|
||||||
|
pub devnum: dev_t,
|
||||||
|
pub dev: OnceCell<Option<Rc<CopyDevice>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for CopyDeviceHolder {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("CopyDeviceHolder").finish_non_exhaustive()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetalDrmDevice {
|
pub struct MetalDrmDevice {
|
||||||
|
|
@ -105,6 +119,8 @@ pub struct MetalDrmDevice {
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
pub handle_events: HandleEvents,
|
pub handle_events: HandleEvents,
|
||||||
pub ctx: CloneCell<Rc<MetalRenderContext>>,
|
pub ctx: CloneCell<Rc<MetalRenderContext>>,
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub copy_device: Rc<CopyDeviceHolder>,
|
||||||
pub on_change: OnChange<crate::backend::DrmEvent>,
|
pub on_change: OnChange<crate::backend::DrmEvent>,
|
||||||
pub direct_scanout_enabled: Cell<Option<bool>>,
|
pub direct_scanout_enabled: Cell<Option<bool>>,
|
||||||
pub is_nvidia: bool,
|
pub is_nvidia: bool,
|
||||||
|
|
@ -1987,6 +2003,12 @@ impl MetalBackend {
|
||||||
Err(e) => return Err(MetalError::GbmDevice(e)),
|
Err(e) => return Err(MetalError::GbmDevice(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let copy_device = Rc::new(CopyDeviceHolder {
|
||||||
|
registry: self.state.copy_device_registry.clone(),
|
||||||
|
devnum: pending.devnum,
|
||||||
|
dev: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let gfx = match self.state.create_gfx_context(master, None) {
|
let gfx = match self.state.create_gfx_context(master, None) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
||||||
|
|
@ -1996,6 +2018,7 @@ impl MetalBackend {
|
||||||
gfx,
|
gfx,
|
||||||
gbm: gbm.clone(),
|
gbm: gbm.clone(),
|
||||||
devnode: pending.devnode.clone(),
|
devnode: pending.devnode.clone(),
|
||||||
|
copy_device: copy_device.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut is_nvidia = false;
|
let mut is_nvidia = false;
|
||||||
|
|
@ -2037,6 +2060,7 @@ impl MetalBackend {
|
||||||
handle_events: Cell::new(None),
|
handle_events: Cell::new(None),
|
||||||
},
|
},
|
||||||
ctx: CloneCell::new(ctx),
|
ctx: CloneCell::new(ctx),
|
||||||
|
copy_device,
|
||||||
on_change: Default::default(),
|
on_change: Default::default(),
|
||||||
direct_scanout_enabled: Default::default(),
|
direct_scanout_enabled: Default::default(),
|
||||||
is_nvidia,
|
is_nvidia,
|
||||||
|
|
@ -2462,6 +2486,7 @@ impl MetalBackend {
|
||||||
gfx,
|
gfx,
|
||||||
gbm: old_ctx.gbm.clone(),
|
gbm: old_ctx.gbm.clone(),
|
||||||
devnode: old_ctx.devnode.clone(),
|
devnode: old_ctx.devnode.clone(),
|
||||||
|
copy_device: old_ctx.copy_device.clone(),
|
||||||
}));
|
}));
|
||||||
if dev.is_render_device() {
|
if dev.is_render_device() {
|
||||||
self.make_render_device(dev, true);
|
self.make_render_device(dev, true);
|
||||||
|
|
@ -2622,3 +2647,24 @@ impl MetalBackend {
|
||||||
connector.schedule_present();
|
connector.schedule_present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CopyDeviceHolder {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn get(&self) -> Option<Rc<CopyDevice>> {
|
||||||
|
self.dev
|
||||||
|
.get_or_init(
|
||||||
|
|| match self.registry.get(self.devnum)?.create_device().map(Some) {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Could not get copy device for {}: {}",
|
||||||
|
self.devnum,
|
||||||
|
ErrorFmt(e),
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -629,12 +629,10 @@ impl PhysicalCopyDevice {
|
||||||
Ok(dev)
|
Ok(dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn src_support(&self, format: &Format) -> &[CopyDeviceSupport] {
|
pub fn src_support(&self, format: &Format) -> &[CopyDeviceSupport] {
|
||||||
self.support(format, Dir::Src)
|
self.support(format, Dir::Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn dst_support(&self, format: &Format) -> &[CopyDeviceSupport] {
|
pub fn dst_support(&self, format: &Format) -> &[CopyDeviceSupport] {
|
||||||
self.support(format, Dir::Dst)
|
self.support(format, Dir::Dst)
|
||||||
}
|
}
|
||||||
|
|
@ -646,7 +644,6 @@ impl PhysicalCopyDevice {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn create_device(self: &Rc<Self>) -> Result<Rc<CopyDevice>, CopyDeviceError> {
|
pub fn create_device(self: &Rc<Self>) -> Result<Rc<CopyDevice>, CopyDeviceError> {
|
||||||
let instance = &self.instance.instance;
|
let instance = &self.instance.instance;
|
||||||
let device = {
|
let device = {
|
||||||
|
|
@ -1053,7 +1050,6 @@ impl CopyDevice {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn create_copy(
|
pub fn create_copy(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
src: &DmaBuf,
|
src: &DmaBuf,
|
||||||
|
|
@ -1299,7 +1295,6 @@ impl CopyDeviceCopy {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn execute(
|
pub fn execute(
|
||||||
&self,
|
&self,
|
||||||
sync_file: Option<&SyncFile>,
|
sync_file: Option<&SyncFile>,
|
||||||
|
|
@ -1763,12 +1758,10 @@ impl CopyDeviceRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn remove(&self, dev: c::dev_t) {
|
pub fn remove(&self, dev: c::dev_t) {
|
||||||
self.devs.remove(&dev);
|
self.devs.remove(&dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn get(&self, dev: c::dev_t) -> Option<Rc<PhysicalCopyDevice>> {
|
pub fn get(&self, dev: c::dev_t) -> Option<Rc<PhysicalCopyDevice>> {
|
||||||
if let Some(dev) = self.devs.get(&dev) {
|
if let Some(dev) = self.devs.get(&dev) {
|
||||||
return dev;
|
return dev;
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,6 @@ pub struct State {
|
||||||
pub outputs_without_hc: NumCell<usize>,
|
pub outputs_without_hc: NumCell<usize>,
|
||||||
pub udmabuf: Rc<UdmabufHolder>,
|
pub udmabuf: Rc<UdmabufHolder>,
|
||||||
pub gfx_ctx_changed: EventSource<WlBuffer>,
|
pub gfx_ctx_changed: EventSource<WlBuffer>,
|
||||||
#[expect(dead_code)]
|
|
||||||
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
100
src/udmabuf.rs
100
src/udmabuf.rs
|
|
@ -115,6 +115,64 @@ impl Udmabuf {
|
||||||
};
|
};
|
||||||
Ok(dmabuf)
|
Ok(dmabuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn create_dmabuf(
|
||||||
|
&self,
|
||||||
|
dma_buf_ids: &DmaBufIds,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<DmaBuf, UdmabufError> {
|
||||||
|
Ok(self.create_bo(dma_buf_ids, width, height, format)?.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_bo(
|
||||||
|
&self,
|
||||||
|
dma_buf_ids: &DmaBufIds,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<UdmabufBo, UdmabufError> {
|
||||||
|
let height = height as u64;
|
||||||
|
let width = width as u64;
|
||||||
|
if height > 1 << 16 || width > 1 << 16 {
|
||||||
|
return Err(UdmabufError::Overflow);
|
||||||
|
}
|
||||||
|
let stride = (width * format.bpp as u64).next_multiple_of(LINEAR_STRIDE_ALIGN);
|
||||||
|
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) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(e) => return Err(UdmabufError::Memfd(e.into())),
|
||||||
|
};
|
||||||
|
if let Err(e) = uapi::ftruncate(memfd.raw(), size as _) {
|
||||||
|
return Err(UdmabufError::Truncate(e.into()));
|
||||||
|
}
|
||||||
|
if let Err(e) = uapi::fcntl_add_seals(memfd.raw(), F_SEAL_SHRINK) {
|
||||||
|
return Err(UdmabufError::Seal(e.into()));
|
||||||
|
}
|
||||||
|
let dmabuf = self.create_dmabuf_from_memfd(&memfd, 0, size as _)?;
|
||||||
|
let mut planes = PlaneVec::new();
|
||||||
|
planes.push(DmaBufPlane {
|
||||||
|
offset: 0,
|
||||||
|
stride: stride as _,
|
||||||
|
fd: Rc::new(dmabuf),
|
||||||
|
});
|
||||||
|
let dmabuf = DmaBuf {
|
||||||
|
id: dma_buf_ids.next(),
|
||||||
|
width: width as _,
|
||||||
|
height: height as _,
|
||||||
|
format,
|
||||||
|
modifier: LINEAR_MODIFIER,
|
||||||
|
planes,
|
||||||
|
is_disjoint: Default::default(),
|
||||||
|
};
|
||||||
|
Ok(UdmabufBo {
|
||||||
|
buf: dmabuf,
|
||||||
|
size: size as _,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator for Udmabuf {
|
impl Allocator for Udmabuf {
|
||||||
|
|
@ -134,44 +192,12 @@ impl Allocator for Udmabuf {
|
||||||
if !modifiers.contains(&LINEAR_MODIFIER) {
|
if !modifiers.contains(&LINEAR_MODIFIER) {
|
||||||
return Err(UdmabufError::Modifier.into());
|
return Err(UdmabufError::Modifier.into());
|
||||||
}
|
}
|
||||||
let height = height as u64;
|
Ok(Rc::new(self.create_bo(
|
||||||
let width = width as u64;
|
dma_buf_ids,
|
||||||
if height > 1 << 16 || width > 1 << 16 {
|
width,
|
||||||
return Err(UdmabufError::Overflow.into());
|
height,
|
||||||
}
|
|
||||||
let stride = (width * format.bpp as u64).next_multiple_of(LINEAR_STRIDE_ALIGN);
|
|
||||||
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) {
|
|
||||||
Ok(f) => f,
|
|
||||||
Err(e) => return Err(UdmabufError::Memfd(e.into()).into()),
|
|
||||||
};
|
|
||||||
if let Err(e) = uapi::ftruncate(memfd.raw(), size as _) {
|
|
||||||
return Err(UdmabufError::Truncate(e.into()).into());
|
|
||||||
}
|
|
||||||
if let Err(e) = uapi::fcntl_add_seals(memfd.raw(), F_SEAL_SHRINK) {
|
|
||||||
return Err(UdmabufError::Seal(e.into()).into());
|
|
||||||
}
|
|
||||||
let dmabuf = self.create_dmabuf_from_memfd(&memfd, 0, size as _)?;
|
|
||||||
let mut planes = PlaneVec::new();
|
|
||||||
planes.push(DmaBufPlane {
|
|
||||||
offset: 0,
|
|
||||||
stride: stride as _,
|
|
||||||
fd: Rc::new(dmabuf),
|
|
||||||
});
|
|
||||||
let dmabuf = DmaBuf {
|
|
||||||
id: dma_buf_ids.next(),
|
|
||||||
width: width as _,
|
|
||||||
height: height as _,
|
|
||||||
format,
|
format,
|
||||||
modifier: LINEAR_MODIFIER,
|
)?))
|
||||||
planes,
|
|
||||||
is_disjoint: Default::default(),
|
|
||||||
};
|
|
||||||
Ok(Rc::new(UdmabufBo {
|
|
||||||
buf: dmabuf,
|
|
||||||
size: size as _,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_dmabuf(
|
fn import_dmabuf(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue