1
0
Fork 0
forked from wry/wry

text: use udmabuf for text upload

This commit is contained in:
Julian Orth 2025-10-01 14:05:33 +02:00
parent 5758e16658
commit c008b7ea35
12 changed files with 301 additions and 80 deletions

View file

@ -821,7 +821,7 @@ pub trait GfxContext: Debug {
fn create_dmabuf_buffer( fn create_dmabuf_buffer(
&self, &self,
dmabuf: &Rc<OwnedFd>, dmabuf: &OwnedFd,
offset: usize, offset: usize,
size: usize, size: usize,
) -> Result<Rc<dyn GfxBuffer>, GfxError> { ) -> Result<Rc<dyn GfxBuffer>, GfxError> {

View file

@ -398,7 +398,7 @@ impl GfxContext for Context {
fn create_dmabuf_buffer( fn create_dmabuf_buffer(
&self, &self,
dmabuf: &Rc<OwnedFd>, dmabuf: &OwnedFd,
offset: usize, offset: usize,
size: usize, size: usize,
) -> Result<Rc<dyn GfxBuffer>, GfxError> { ) -> Result<Rc<dyn GfxBuffer>, GfxError> {

View file

@ -27,7 +27,7 @@ pub struct VulkanDmabufBuffer {
impl VulkanDevice { impl VulkanDevice {
pub fn create_dmabuf_buffer( pub fn create_dmabuf_buffer(
self: &Rc<Self>, self: &Rc<Self>,
dmabuf: &Rc<OwnedFd>, dmabuf: &OwnedFd,
offset: u64, offset: u64,
size: u64, size: u64,
) -> Result<Rc<VulkanDmabufBuffer>, VulkanError> { ) -> Result<Rc<VulkanDmabufBuffer>, VulkanError> {

View file

@ -287,7 +287,7 @@ impl WlBuffer {
if *udmabuf_impossible { if *udmabuf_impossible {
return Ok(None); return Ok(None);
} }
let Some(dev) = self.client.state.udmabuf() else { let Some(dev) = self.client.state.udmabuf.get() else {
return Ok(None); return Ok(None);
}; };
let mask = page_size() - 1; let mask = page_size() - 1;

View file

@ -7,7 +7,10 @@ use {
}, },
std::{cell::Cell, ptr, rc::Rc}, std::{cell::Cell, ptr, rc::Rc},
thiserror::Error, thiserror::Error,
uapi::{IntoUstr, c}, uapi::{
IntoUstr,
c::{self, memset},
},
}; };
pub mod consts; pub mod consts;
@ -26,6 +29,13 @@ unsafe extern "C" {
width: c::c_int, width: c::c_int,
height: c::c_int, height: c::c_int,
) -> *mut cairo_surface_t; ) -> *mut cairo_surface_t;
fn cairo_image_surface_create_for_data(
data: *mut u8,
format: cairo_format_t,
width: c::c_int,
height: c::c_int,
stride: c::c_int,
) -> *mut cairo_surface_t;
fn cairo_image_surface_get_height(surface: *mut cairo_surface_t) -> c::c_int; fn cairo_image_surface_get_height(surface: *mut cairo_surface_t) -> c::c_int;
fn cairo_image_surface_get_stride(surface: *mut cairo_surface_t) -> c::c_int; fn cairo_image_surface_get_stride(surface: *mut cairo_surface_t) -> c::c_int;
fn cairo_image_surface_get_data(surface: *mut cairo_surface_t) -> *mut u8; fn cairo_image_surface_get_data(surface: *mut cairo_surface_t) -> *mut u8;
@ -41,6 +51,8 @@ unsafe extern "C" {
fn cairo_set_operator(cr: *mut cairo_t, op: cairo_operator_t); fn cairo_set_operator(cr: *mut cairo_t, op: cairo_operator_t);
fn cairo_set_source_rgba(cr: *mut cairo_t, red: f64, green: f64, blue: f64, alpha: f64); fn cairo_set_source_rgba(cr: *mut cairo_t, red: f64, green: f64, blue: f64, alpha: f64);
fn cairo_move_to(cr: *mut cairo_t, x: f64, y: f64); fn cairo_move_to(cr: *mut cairo_t, x: f64, y: f64);
fn cairo_format_stride_for_width(format: cairo_format_t, width: c::c_int) -> c::c_int;
} }
#[repr(transparent)] #[repr(transparent)]
@ -141,6 +153,30 @@ impl CairoImageSurface {
} }
} }
pub unsafe fn new_image_surface_with_data(
format: CairoFormat,
data: *mut u8,
width: i32,
height: i32,
stride: i32,
) -> Result<Rc<Self>, PangoError> {
unsafe {
memset(data.cast(), 0, (stride * height) as usize);
let s = cairo_image_surface_create_for_data(
data,
format.raw() as _,
width as _,
height as _,
stride as _,
);
let status = cairo_surface_status(s);
if status != 0 {
return Err(PangoError::CreateSurface(status as _));
}
Ok(Rc::new(Self { s }))
}
}
pub fn create_context(self: &Rc<Self>) -> Result<Rc<CairoContext>, PangoError> { pub fn create_context(self: &Rc<Self>) -> Result<Rc<CairoContext>, PangoError> {
unsafe { unsafe {
let c = cairo_create(self.s); let c = cairo_create(self.s);
@ -372,3 +408,13 @@ impl Drop for PangoLayout {
} }
} }
} }
pub fn cairo_size(format: CairoFormat, width: i32, height: i32) -> Option<(i32, usize)> {
let stride = unsafe { cairo_format_stride_for_width(format.raw() as _, width as _) };
if stride < 0 {
return None;
}
let stride = stride as i32;
let size = height.checked_mul(stride)? as usize;
Some((stride, size))
}

View file

@ -99,7 +99,7 @@ use {
TearingMode, ToplevelData, ToplevelNode, ToplevelNodeBase, VrrMode, WorkspaceNode, TearingMode, ToplevelData, ToplevelNode, ToplevelNodeBase, VrrMode, WorkspaceNode,
generic_node_visitor, generic_node_visitor,
}, },
udmabuf::{Udmabuf, UdmabufError}, udmabuf::UdmabufHolder,
utils::{ utils::{
activation_token::ActivationToken, activation_token::ActivationToken,
asyncevent::AsyncEvent, asyncevent::AsyncEvent,
@ -112,7 +112,6 @@ use {
hash_map_ext::HashMapExt, hash_map_ext::HashMapExt,
linkedlist::LinkedList, linkedlist::LinkedList,
numcell::NumCell, numcell::NumCell,
oserror::OsError,
queue::AsyncQueue, queue::AsyncQueue,
refcounted::RefCounted, refcounted::RefCounted,
run_toplevel::RunToplevel, run_toplevel::RunToplevel,
@ -152,7 +151,7 @@ use {
time::Duration, time::Duration,
}, },
thiserror::Error, thiserror::Error,
uapi::{OwnedFd, c}, uapi::OwnedFd,
}; };
pub struct State { pub struct State {
@ -290,7 +289,7 @@ pub struct State {
pub xdg_surface_configure_events: AsyncQueue<XdgSurfaceConfigureEvent>, pub xdg_surface_configure_events: AsyncQueue<XdgSurfaceConfigureEvent>,
pub workspace_display_order: Cell<WorkspaceDisplayOrder>, pub workspace_display_order: Cell<WorkspaceDisplayOrder>,
pub outputs_without_hc: NumCell<usize>, pub outputs_without_hc: NumCell<usize>,
pub udmabuf: CloneCell<Option<Option<Rc<Udmabuf>>>>, pub udmabuf: Rc<UdmabufHolder>,
} }
// impl Drop for State { // impl Drop for State {
@ -1568,25 +1567,6 @@ impl State {
found_tree.clear(); found_tree.clear();
node node
} }
pub fn udmabuf(&self) -> Option<Rc<Udmabuf>> {
if let Some(u) = self.udmabuf.get() {
return u;
}
match Udmabuf::new() {
Ok(u) => {
let u = Rc::new(u);
self.udmabuf.set(Some(Some(u.clone())));
Some(u)
}
Err(UdmabufError::Open(OsError(c::EPERM))) => None,
Err(e) => {
log::error!("Could not create udmabuf device: {}", ErrorFmt(e));
self.udmabuf.set(Some(None));
None
}
}
}
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -4,20 +4,24 @@ use {
cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker, PendingJob}, cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker, PendingJob},
format::ARGB8888, format::ARGB8888,
gfx_api::{ gfx_api::{
AsyncShmGfxTexture, AsyncShmGfxTextureCallback, GfxContext, GfxError, GfxStagingBuffer, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, GfxBuffer, GfxContext, GfxError,
GfxTexture, PendingShmTransfer, STAGING_UPLOAD, GfxStagingBuffer, GfxTexture, PendingShmTransfer, STAGING_UPLOAD,
}, },
pango::{ pango::{
CairoContext, CairoImageSurface, PangoCairoContext, PangoError, PangoFontDescription, CairoContext, CairoImageSurface, PangoCairoContext, PangoError, PangoFontDescription,
PangoLayout, PangoLayout, cairo_size,
consts::{ consts::{
CAIRO_FORMAT_ARGB32, CAIRO_OPERATOR_SOURCE, PANGO_ELLIPSIZE_END, PANGO_SCALE, CAIRO_FORMAT_ARGB32, CAIRO_OPERATOR_SOURCE, CairoFormat, PANGO_ELLIPSIZE_END,
PANGO_SCALE,
}, },
}, },
rect::{Rect, Region}, rect::{Rect, Region},
state::State,
theme::Color, theme::Color,
udmabuf::UdmabufHolder,
utils::{ utils::{
clonecell::CloneCell, double_buffered::DoubleBuffered, on_drop_event::OnDropEvent, clonecell::CloneCell, double_buffered::DoubleBuffered, errorfmt::ErrorFmt,
on_drop_event::OnDropEvent, oserror::OsError, page_size::page_size,
}, },
}, },
std::{ std::{
@ -25,10 +29,20 @@ use {
cell::{Cell, RefCell}, cell::{Cell, RefCell},
mem, mem,
ops::Neg, ops::Neg,
ptr,
rc::{Rc, Weak}, rc::{Rc, Weak},
sync::Arc, slice,
sync::{
Arc,
atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering::Relaxed},
},
}, },
thiserror::Error, thiserror::Error,
uapi::{
OwnedFd,
c::{self, off_t},
ftruncate,
},
}; };
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -41,14 +55,18 @@ pub enum TextError {
PangoContext(#[source] PangoError), PangoContext(#[source] PangoError),
#[error("Could not create a pango layout")] #[error("Could not create a pango layout")]
CreateLayout(#[source] PangoError), CreateLayout(#[source] PangoError),
#[error("Could not access the cairo image data")]
ImageData(#[source] PangoError),
#[error("Texture upload failed")] #[error("Texture upload failed")]
Upload(#[source] GfxError), Upload(#[source] GfxError),
#[error("Could not create a texture")] #[error("Could not create a texture")]
CreateTexture(#[source] GfxError), CreateTexture(#[source] GfxError),
#[error("Rendering is not scheduled or not yet completed")] #[error("Rendering is not scheduled or not yet completed")]
NotScheduled, NotScheduled,
#[error("The size calculation overflowed")]
SizeOverflow,
#[error("Could not resize the memfd")]
ResizeMemfd(#[source] OsError),
#[error("Could not map the memfd")]
MapMemfd(#[source] OsError),
} }
impl<'a> Config<'a> { impl<'a> Config<'a> {
@ -107,8 +125,22 @@ struct Data {
layout: PangoLayout, layout: PangoLayout,
} }
fn create_data(font: &str, width: i32, height: i32, scale: Option<f64>) -> Result<Data, TextError> { const FORMAT: CairoFormat = CAIRO_FORMAT_ARGB32;
let image = match CairoImageSurface::new_image_surface(CAIRO_FORMAT_ARGB32, width, height) {
fn create_data(
memfd: &Memfd,
font: &str,
width: i32,
height: i32,
scale: Option<f64>,
) -> Result<Data, TextError> {
let Some((stride, size)) = cairo_size(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)
} {
Ok(s) => s, Ok(s) => s,
Err(e) => return Err(TextError::CreateImage(e)), Err(e) => return Err(TextError::CreateImage(e)),
}; };
@ -139,12 +171,13 @@ fn create_data(font: &str, width: i32, height: i32, scale: Option<f64>) -> Resul
} }
fn measure( fn measure(
memfd: &Memfd,
font: &str, font: &str,
text: &str, text: &str,
markup: bool, markup: bool,
scale: Option<f64>, scale: Option<f64>,
) -> Result<TextMeasurement, TextError> { ) -> Result<TextMeasurement, TextError> {
let data = create_data(font, 1, 1, scale)?; let data = create_data(memfd, font, 1, 1, scale)?;
if markup { if markup {
data.layout.set_markup(text); data.layout.set_markup(text);
} else { } else {
@ -156,6 +189,7 @@ fn measure(
} }
fn render( fn render(
memfd: &Memfd,
x: i32, x: i32,
y: Option<i32>, y: Option<i32>,
width: i32, width: i32,
@ -173,10 +207,9 @@ fn render(
width, width,
height, height,
stride: width * 4, stride: width * 4,
data: vec![],
}); });
} }
let data = create_data(font, width, height, scale)?; let data = create_data(memfd, font, width, height, scale)?;
if ellipsize { if ellipsize {
data.layout data.layout
.set_width((width - 2 * padding).max(0) * PANGO_SCALE); .set_width((width - 2 * padding).max(0) * PANGO_SCALE);
@ -199,11 +232,11 @@ fn render(
width, width,
height, height,
stride: data.image.stride(), stride: data.image.stride(),
data: data.image.data().map_err(TextError::ImageData)?.to_vec(),
}) })
} }
fn render_fitting( fn render_fitting(
memfd: &Memfd,
height: Option<i32>, height: Option<i32>,
font: &str, font: &str,
text: &str, text: &str,
@ -211,7 +244,7 @@ fn render_fitting(
markup: bool, markup: bool,
scale: Option<f64>, scale: Option<f64>,
) -> Result<RenderedText, TextError> { ) -> Result<RenderedText, TextError> {
let measurement = measure(font, text, markup, scale)?; let measurement = measure(memfd, font, text, markup, scale)?;
let x = measurement.ink_rect.x1().neg(); let x = measurement.ink_rect.x1().neg();
let y = match height { let y = match height {
Some(_) => None, Some(_) => None,
@ -220,7 +253,7 @@ fn render_fitting(
let width = measurement.ink_rect.width(); let width = measurement.ink_rect.width();
let height = height.unwrap_or(measurement.ink_rect.height()); let height = height.unwrap_or(measurement.ink_rect.height());
render( render(
x, y, width, height, 0, font, text, color, false, markup, scale, memfd, x, y, width, height, 0, font, text, color, false, markup, scale,
) )
} }
@ -233,11 +266,10 @@ struct RenderedText {
width: i32, width: i32,
height: i32, height: i32,
stride: i32, stride: i32,
data: Vec<Cell<u8>>,
} }
#[derive(Default)]
struct RenderWork { struct RenderWork {
memfd: Arc<Memfd>,
config: Config<'static>, config: Config<'static>,
result: Option<Result<RenderedText, TextError>>, result: Option<Result<RenderedText, TextError>>,
} }
@ -265,7 +297,7 @@ impl RenderWork {
color, color,
markup, markup,
scale, scale,
} => render_fitting(height, font, text, color, markup, scale), } => render_fitting(&self.memfd, height, font, text, color, markup, scale),
Config::Render { Config::Render {
x, x,
y, y,
@ -279,7 +311,18 @@ impl RenderWork {
markup, markup,
scale, scale,
} => render( } => render(
x, y, width, height, padding, font, text, color, ellipsize, markup, scale, &self.memfd,
x,
y,
width,
height,
padding,
font,
text,
color,
ellipsize,
markup,
scale,
), ),
} }
} }
@ -303,6 +346,7 @@ impl Drop for TextTexture {
struct Shared { struct Shared {
cpu_worker: Rc<CpuWorker>, cpu_worker: Rc<CpuWorker>,
ctx: Rc<dyn GfxContext>, ctx: Rc<dyn GfxContext>,
udmabuf: Rc<UdmabufHolder>,
staging: CloneCell<Option<Rc<dyn GfxStagingBuffer>>>, staging: CloneCell<Option<Rc<dyn GfxStagingBuffer>>>,
textures: DoubleBuffered<TextBuffer>, textures: DoubleBuffered<TextBuffer>,
pending_render: Cell<Option<PendingJob>>, pending_render: Cell<Option<PendingJob>>,
@ -312,6 +356,15 @@ struct Shared {
waiter: Cell<Option<Rc<dyn OnCompleted>>>, waiter: Cell<Option<Rc<dyn OnCompleted>>>,
busy: Cell<bool>, busy: Cell<bool>,
flip_is_noop: Cell<bool>, flip_is_noop: Cell<bool>,
memfd: Arc<Memfd>,
gfx_buffer: CloneCell<Option<Option<Rc<dyn GfxBuffer>>>>,
}
struct Memfd {
fd: OwnedFd,
size: AtomicUsize,
size_changed: AtomicBool,
mapping: AtomicPtr<u8>,
} }
impl Shared { impl Shared {
@ -325,6 +378,36 @@ impl Shared {
waiter.completed(); waiter.completed();
} }
} }
fn get_gfx_buffer(&self) -> Option<Rc<dyn GfxBuffer>> {
if self.memfd.size_changed.load(Relaxed) {
self.gfx_buffer.take();
self.memfd.size_changed.store(false, Relaxed);
}
if let Some(res) = self.gfx_buffer.get() {
return res;
}
let size = self.memfd.size.load(Relaxed);
let udmabuf = self.udmabuf.get()?;
let res = 'res: {
let dmabuf = match udmabuf.create_dmabuf_from_memfd(&self.memfd.fd, 0, size) {
Ok(b) => b,
Err(e) => {
log::error!("Could not create udmabuf: {}", ErrorFmt(e));
break 'res None;
}
};
match self.ctx.create_dmabuf_buffer(&dmabuf, 0, size) {
Ok(b) => Some(b),
Err(e) => {
log::debug!("Could not create GfxBuffer: {}", ErrorFmt(e));
None
}
}
};
self.gfx_buffer.set(Some(res.clone()));
res
}
} }
#[derive(PartialEq, Default)] #[derive(PartialEq, Default)]
@ -365,10 +448,14 @@ pub trait OnCompleted {
} }
impl TextTexture { impl TextTexture {
pub fn new(cpu_worker: &Rc<CpuWorker>, ctx: &Rc<dyn GfxContext>) -> Self { pub fn new(state: &Rc<State>, ctx: &Rc<dyn GfxContext>) -> Self {
let memfd = uapi::memfd_create("text", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING)
.expect("Could not create memfd");
let _ = uapi::fcntl_add_seals(memfd.raw(), c::F_SEAL_SHRINK);
let data = Rc::new(Shared { let data = Rc::new(Shared {
cpu_worker: cpu_worker.clone(), cpu_worker: state.cpu_worker.clone(),
ctx: ctx.clone(), ctx: ctx.clone(),
udmabuf: state.udmabuf.clone(),
staging: Default::default(), staging: Default::default(),
textures: Default::default(), textures: Default::default(),
pending_render: Default::default(), pending_render: Default::default(),
@ -378,6 +465,13 @@ impl TextTexture {
waiter: Default::default(), waiter: Default::default(),
busy: Default::default(), busy: Default::default(),
flip_is_noop: Default::default(), flip_is_noop: Default::default(),
memfd: Arc::new(Memfd {
fd: memfd,
size: Default::default(),
size_changed: Default::default(),
mapping: Default::default(),
}),
gfx_buffer: Default::default(),
}); });
Self { data } Self { data }
} }
@ -403,13 +497,18 @@ impl TextTexture {
} }
let mut job = self.data.render_job.take().unwrap_or_else(|| { let mut job = self.data.render_job.take().unwrap_or_else(|| {
Box::new(RenderJob { Box::new(RenderJob {
work: Default::default(), work: RenderWork {
memfd: self.data.memfd.clone(),
config: Default::default(),
result: Default::default(),
},
data: Rc::downgrade(&self.data), data: Rc::downgrade(&self.data),
}) })
}); });
job.work = RenderWork { job.work = RenderWork {
config: config.to_static(), config: config.to_static(),
result: None, result: None,
..job.work
}; };
let pending = self.data.cpu_worker.submit(job); let pending = self.data.cpu_worker.submit(job);
self.data.pending_render.set(Some(pending)); self.data.pending_render.set(Some(pending));
@ -527,29 +626,36 @@ impl CpuJob for RenderJob {
} }
}; };
let mut staging_opt = data.staging.take(); let mut staging_opt = data.staging.take();
if let Some(staging) = &staging_opt let pending = if let Some(gfx_buffer) = data.get_gfx_buffer() {
&& staging.size() != tex.staging_size() tex.clone()
{ .async_upload_from_buffer(
staging_opt = None; &gfx_buffer,
} data.clone(),
let staging = match staging_opt { Region::new(Rect::new_sized_unchecked(0, 0, rt.width, rt.height)),
Some(s) => s, )
None => data .map_err(TextError::Upload)
.ctx } else {
.create_staging_buffer(tex.staging_size(), STAGING_UPLOAD), if let Some(staging) = &staging_opt
&& staging.size() != tex.staging_size()
{
staging_opt = None;
}
let staging = staging_opt.get_or_insert_with(|| {
data.ctx
.create_staging_buffer(tex.staging_size(), STAGING_UPLOAD)
});
tex.clone()
.async_upload(
&staging,
data.clone(),
Rc::new(data.memfd.data(rt.stride, rt.height)),
Region::new(Rect::new_sized_unchecked(0, 0, rt.width, rt.height)),
)
.map_err(TextError::Upload)
}; };
let pending = tex
.clone()
.async_upload(
&staging,
data.clone(),
Rc::new(rt.data),
Region::new(Rect::new_sized_unchecked(0, 0, rt.width, rt.height)),
)
.map_err(TextError::Upload);
if pending.is_ok() { if pending.is_ok() {
data.textures.back().tex.set(Some(tex)); data.textures.back().tex.set(Some(tex));
data.staging.set(Some(staging)); data.staging.set(staging_opt);
} }
match pending { match pending {
Ok(Some(p)) => data.pending_upload.set(Some(p)), Ok(Some(p)) => data.pending_upload.set(Some(p)),
@ -571,3 +677,66 @@ impl OnCompleted for OnDropEvent {
// nothing // nothing
} }
} }
impl Memfd {
fn get_pointer_for_size(&self, size: usize) -> Result<*mut u8, TextError> {
let old_size = self.size.load(Relaxed);
if old_size >= size {
return Ok(self.mapping.load(Relaxed));
}
let Some(size) = size.checked_next_multiple_of(page_size()) else {
return Err(TextError::SizeOverflow);
};
let Ok(isize) = off_t::try_from(size) else {
return Err(TextError::SizeOverflow);
};
if let Err(e) = ftruncate(self.fd.raw(), isize) {
return Err(TextError::ResizeMemfd(e.into()));
}
let old_ptr = self.mapping.load(Relaxed);
let new_ptr = if old_ptr.is_null() {
unsafe {
c::mmap(
ptr::null_mut(),
size,
c::PROT_READ | c::PROT_WRITE,
c::MAP_SHARED,
self.fd.raw(),
0,
)
}
} else {
unsafe { c::mremap(old_ptr.cast(), old_size, size, c::MREMAP_MAYMOVE) }
};
if new_ptr == c::MAP_FAILED {
return Err(TextError::MapMemfd(OsError::default()));
}
let new_ptr = new_ptr.cast();
self.mapping.store(new_ptr, Relaxed);
self.size.store(size, Relaxed);
self.size_changed.store(true, Relaxed);
Ok(new_ptr)
}
fn data(&self, stride: i32, height: i32) -> Vec<Cell<u8>> {
let size = (stride * height) as usize;
assert!(size <= self.size.load(Relaxed));
if size == 0 {
return vec![];
}
let mapping = self.mapping.load(Relaxed);
unsafe { slice::from_raw_parts(mapping.cast(), size).to_vec() }
}
}
impl Drop for Memfd {
fn drop(&mut self) {
let ptr = self.mapping.load(Relaxed);
if ptr.is_null() {
return;
}
unsafe {
c::munmap(ptr.cast(), self.size.load(Relaxed));
}
}
}

View file

@ -725,8 +725,7 @@ impl ContainerNode {
let title = child.title.borrow_mut(); let title = child.title.borrow_mut();
let tt = &mut *child.title_tex.borrow_mut(); let tt = &mut *child.title_tex.borrow_mut();
for (scale, _) in scales.iter() { for (scale, _) in scales.iter() {
let tex = tt let tex = tt.get_or_insert_with(*scale, || TextTexture::new(&self.state, &ctx));
.get_or_insert_with(*scale, || TextTexture::new(&self.state.cpu_worker, &ctx));
let mut th = th; let mut th = th;
let mut scalef = None; let mut scalef = None;
let mut width = rect.width(); let mut width = rect.width();

View file

@ -215,8 +215,7 @@ impl FloatNode {
let tr = self.title_rect.get(); let tr = self.title_rect.get();
let tt = &mut *self.title_textures.borrow_mut(); let tt = &mut *self.title_textures.borrow_mut();
for (scale, _) in scales.iter() { for (scale, _) in scales.iter() {
let tex = let tex = tt.get_or_insert_with(*scale, || TextTexture::new(&self.state, &ctx));
tt.get_or_insert_with(*scale, || TextTexture::new(&self.state.cpu_worker, &ctx));
let mut th = tr.height(); let mut th = tr.height();
let mut scalef = None; let mut scalef = None;
let mut width = tr.width(); let mut width = tr.width();

View file

@ -530,7 +530,7 @@ impl OutputNode {
let active_id = self.workspace.get().map(|w| w.id); let active_id = self.workspace.get().map(|w| w.id);
for ws in self.workspaces.iter() { for ws in self.workspaces.iter() {
let tex = &mut *ws.title_texture.borrow_mut(); let tex = &mut *ws.title_texture.borrow_mut();
let tex = tex.get_or_insert_with(|| TextTexture::new(&self.state.cpu_worker, &ctx)); let tex = tex.get_or_insert_with(|| TextTexture::new(&self.state, &ctx));
let tc = match active_id == Some(ws.id) { let tc = match active_id == Some(ws.id) {
true => theme.colors.focused_title_text.get(), true => theme.colors.focused_title_text.get(),
false => theme.colors.unfocused_title_text.get(), false => theme.colors.unfocused_title_text.get(),
@ -548,7 +548,7 @@ impl OutputNode {
let mut rd = self.render_data.borrow_mut(); let mut rd = self.render_data.borrow_mut();
let tex = rd.status.get_or_insert_with(|| OutputStatus { let tex = rd.status.get_or_insert_with(|| OutputStatus {
tex_x: 0, tex_x: 0,
tex: TextTexture::new(&self.state.cpu_worker, &ctx), tex: TextTexture::new(&self.state, &ctx),
}); });
let status = self.status.get(); let status = self.status.get();
let tc = self.state.theme.colors.bar_text.get(); let tc = self.state.theme.colors.bar_text.get();

View file

@ -111,8 +111,7 @@ impl PlaceholderNode {
let rect = self.toplevel.pos.get(); let rect = self.toplevel.pos.get();
let mut textures = self.textures.borrow_mut(); let mut textures = self.textures.borrow_mut();
for (scale, _) in scales.iter() { for (scale, _) in scales.iter() {
let tex = textures let tex = textures.get_or_insert_with(*scale, || TextTexture::new(&self.state, &ctx));
.get_or_insert_with(*scale, || TextTexture::new(&self.state.cpu_worker, &ctx));
let mut width = rect.width(); let mut width = rect.width();
let mut height = rect.height(); let mut height = rect.height();
if *scale != 1 { if *scale != 1 {

View file

@ -2,7 +2,10 @@ use {
crate::{ crate::{
allocator::{Allocator, AllocatorError, BufferObject, BufferUsage, MappedBuffer}, allocator::{Allocator, AllocatorError, BufferObject, BufferUsage, MappedBuffer},
format::Format, format::Format,
utils::{compat::IoctlNumber, oserror::OsError, page_size::page_size}, utils::{
clonecell::CloneCell, compat::IoctlNumber, errorfmt::ErrorFmt, oserror::OsError,
page_size::page_size,
},
video::{ video::{
LINEAR_MODIFIER, Modifier, LINEAR_MODIFIER, Modifier,
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec}, dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
@ -51,6 +54,32 @@ pub enum UdmabufError {
Map(#[source] OsError), Map(#[source] OsError),
} }
#[derive(Default)]
pub struct UdmabufHolder {
udmabuf: CloneCell<Option<Option<Rc<Udmabuf>>>>,
}
impl UdmabufHolder {
pub fn get(&self) -> Option<Rc<Udmabuf>> {
if let Some(u) = self.udmabuf.get() {
return u;
}
match Udmabuf::new() {
Ok(u) => {
let u = Rc::new(u);
self.udmabuf.set(Some(Some(u.clone())));
Some(u)
}
Err(UdmabufError::Open(OsError(c::EPERM))) => None,
Err(e) => {
log::error!("Could not create udmabuf device: {}", ErrorFmt(e));
self.udmabuf.set(Some(None));
None
}
}
}
}
pub struct Udmabuf { pub struct Udmabuf {
fd: OwnedFd, fd: OwnedFd,
} }