Skip to content

Commit e759241

Browse files
committed
refactor(wayland): properly import dmabufs
1 parent 049fe41 commit e759241

File tree

7 files changed

+224
-115
lines changed

7 files changed

+224
-115
lines changed

src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ fn stereokit_loop(
302302

303303
camera::update(token);
304304
#[cfg(feature = "wayland")]
305-
wayland.frame_event();
305+
wayland.early_frame(&graphics_info);
306306
destroy_queue::clear();
307307

308308
objects.update(&sk, token, &dbus_connection, &object_registry);
@@ -316,7 +316,7 @@ fn stereokit_loop(
316316

317317
tick_internal_client();
318318
#[cfg(feature = "wayland")]
319-
wayland.update_graphics(&graphics_info);
319+
wayland.update_graphics();
320320
drawable::draw(token);
321321
audio::update();
322322
}

src/wayland/core/buffer.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
use crate::wayland::{
2-
GraphicsInfo, core::shm_buffer_backing::ShmBufferBacking, dmabuf::buffer_backing::DmabufBacking,
1+
use std::sync::Arc;
2+
3+
use crate::{
4+
core::registry::Registry,
5+
wayland::{
6+
GraphicsInfo, core::shm_buffer_backing::ShmBufferBacking,
7+
dmabuf::buffer_backing::DmabufBacking,
8+
},
39
};
410
use mint::Vector2;
511
use stereokit_rust::tex::Tex;
@@ -9,12 +15,13 @@ use waynest::{
915
wire::ObjectId,
1016
};
1117

18+
pub static BUFFER_REGISTRY: Registry<Buffer> = Registry::new();
19+
1220
#[derive(Debug)]
1321
pub enum BufferBacking {
1422
Shm(ShmBufferBacking),
1523
Dmabuf(DmabufBacking),
1624
}
17-
1825
impl BufferBacking {
1926
// Returns true if the buffer can be released immediately after texture update
2027
pub fn can_release_after_update(&self) -> bool {
@@ -25,15 +32,31 @@ impl BufferBacking {
2532
#[derive(Debug, Dispatcher)]
2633
pub struct Buffer {
2734
pub id: ObjectId,
28-
pub backing: BufferBacking,
35+
backing: BufferBacking,
2936
}
3037

3138
impl Buffer {
39+
pub fn new(client: &mut Client, id: ObjectId, backing: BufferBacking) -> Arc<Self> {
40+
let buffer = client.insert(id, Self { id, backing });
41+
BUFFER_REGISTRY.add_raw(&buffer);
42+
buffer
43+
}
44+
45+
pub fn init_tex(self: Arc<Self>, graphics_info: &GraphicsInfo) {
46+
match &self.backing {
47+
BufferBacking::Shm(_) => (),
48+
BufferBacking::Dmabuf(backing) => backing.init_tex(graphics_info, self.clone()),
49+
}
50+
}
3251
/// Returns the tex if it was updated
33-
pub fn update_tex(&self, graphics_info: &GraphicsInfo) -> Option<Tex> {
52+
pub fn update_tex(&self) -> Option<Tex> {
53+
tracing::info!("Updating texture for buffer {:?}", self.id);
3454
match &self.backing {
3555
BufferBacking::Shm(backing) => backing.update_tex(),
36-
BufferBacking::Dmabuf(backing) => backing.update_tex(graphics_info),
56+
BufferBacking::Dmabuf(backing) => backing
57+
.get_tex()
58+
.map(|tex| tex.get_id().to_string())
59+
.and_then(|tex_id| Tex::find(tex_id).ok()),
3760
}
3861
}
3962

@@ -51,6 +74,7 @@ impl Buffer {
5174

5275
impl WlBuffer for Buffer {
5376
async fn destroy(&self, _client: &mut Client, _sender_id: ObjectId) -> Result<()> {
77+
tracing::info!("Destroying buffer {:?}", self.id);
5478
Ok(())
5579
}
5680
}

src/wayland/core/shm_pool.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,7 @@ impl WlShmPool for ShmPool {
5555
format,
5656
);
5757

58-
client.insert(
59-
id,
60-
Buffer {
61-
id,
62-
backing: BufferBacking::Shm(params),
63-
},
64-
);
58+
Buffer::new(client, id, BufferBacking::Shm(params));
6559
Ok(())
6660
}
6761

src/wayland/core/surface.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
items::panel::Geometry,
1010
},
1111
wayland::{
12-
GraphicsInfo, Message, MessageSink,
12+
Message, MessageSink,
1313
util::{ClientExt, DoubleBuffer},
1414
xdg::toplevel::Toplevel,
1515
},
@@ -110,7 +110,7 @@ impl Surface {
110110
handlers.push(Box::new(handler));
111111
}
112112

113-
pub fn update_graphics(&self, graphics_info: &GraphicsInfo) {
113+
pub fn update_graphics(&self) {
114114
let state_lock = self.state.lock();
115115
if state_lock.current().clean_lock.get().is_some() {
116116
// then we don't need to reupload the texture
@@ -137,7 +137,7 @@ impl Surface {
137137
Mutex::new(mat_wrapper)
138138
});
139139

140-
if let Some(new_tex) = buffer.update_tex(graphics_info) {
140+
if let Some(new_tex) = buffer.update_tex() {
141141
material
142142
.lock()
143143
.0

src/wayland/dmabuf/buffer_backing.rs

Lines changed: 114 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::buffer_params::BufferParams;
2-
use crate::wayland::GraphicsInfo;
2+
use crate::wayland::{GraphicsInfo, Message, MessageSink, core::buffer::Buffer};
3+
use drm_fourcc::DrmFourcc;
34
use khronos_egl::{self as egl, ClientBuffer};
45
use mint::Vector2;
56
use std::{
@@ -25,93 +26,140 @@ const EGL_NO_BUFFER: *mut std::ffi::c_void = std::ptr::null_mut();
2526
#[derive(Debug)]
2627
pub struct DmabufBacking {
2728
params: Arc<BufferParams>,
29+
message_sink: Option<MessageSink>,
2830
size: Vector2<usize>,
29-
format: u32,
31+
format: DrmFourcc,
3032
_flags: Flags,
3133
tex: OnceLock<Tex>,
3234
}
3335

3436
impl DmabufBacking {
35-
pub fn new(params: Arc<BufferParams>, size: Vector2<usize>, format: u32, flags: Flags) -> Self {
37+
pub fn new(
38+
params: Arc<BufferParams>,
39+
message_sink: Option<MessageSink>,
40+
size: Vector2<usize>,
41+
format: DrmFourcc,
42+
flags: Flags,
43+
) -> Self {
44+
tracing::info!(
45+
"Creating new DmabufBacking with BufferParams {:?}",
46+
params.id
47+
);
3648
Self {
3749
params,
50+
message_sink,
3851
size,
3952
format,
4053
_flags: flags,
4154
tex: OnceLock::new(),
4255
}
4356
}
4457

45-
pub fn update_tex(&self, graphics_info: &GraphicsInfo) -> Option<Tex> {
46-
let tex_ref = self.tex.get_or_init(|| {
47-
let mut tex = Tex::new(
48-
TexType::ImageNomips | TexType::Dynamic,
49-
TexFormat::RGBA32,
50-
nanoid::nanoid!(),
58+
fn import_dmabuf(&self, graphics_info: &GraphicsInfo) -> Result<Tex, khronos_egl::Error> {
59+
let mut tex = Tex::new(
60+
TexType::ImageNomips | TexType::Dynamic,
61+
TexFormat::RGBA32,
62+
nanoid::nanoid!(),
63+
);
64+
65+
tracing::info!(format=?self.format, "Wayland: Updating DMABuf tex");
66+
67+
// Get plane info from params
68+
let planes = self.params.lock_planes();
69+
let Some(plane) = planes.get(&0) else {
70+
tracing::error!(
71+
"Wayland: Failed to get plane 0 from BufferParams {:?}",
72+
self.params.id
5173
);
74+
return Err(khronos_egl::Error::BadParameter);
75+
};
76+
tracing::info!(
77+
"Using plane 0 with fd {} from BufferParams {:?}",
78+
plane.fd.as_raw_fd(),
79+
self.params.id
80+
);
81+
// Create EGL image
82+
let image = graphics_info.egl_instance.create_image(
83+
graphics_info.display,
84+
graphics_info.context,
85+
EGL_LINUX_DMA_BUF_EXT as u32,
86+
unsafe { ClientBuffer::from_ptr(EGL_NO_BUFFER) },
87+
&[
88+
EGL_WIDTH as usize,
89+
self.size.x as usize,
90+
EGL_HEIGHT as usize,
91+
self.size.y as usize,
92+
EGL_LINUX_DRM_FOURCC_EXT as usize,
93+
self.format as usize,
94+
EGL_DMA_BUF_PLANE0_FD_EXT as usize,
95+
plane.fd.as_raw_fd() as usize, // EGL will dup() this fd internally
96+
EGL_DMA_BUF_PLANE0_OFFSET_EXT as usize,
97+
plane.offset as usize,
98+
EGL_DMA_BUF_PLANE0_PITCH_EXT as usize,
99+
plane.stride as usize,
100+
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT as usize,
101+
0,
102+
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT as usize,
103+
0,
104+
egl::ATTRIB_NONE,
105+
0,
106+
],
107+
)?;
108+
109+
// The cloned fd will be consumed by create_image, so we don't need to explicitly close it
110+
// Create and bind GL texture
111+
let mut gl_tex = 0;
112+
unsafe {
113+
gl::GenTextures(1, &mut gl_tex);
114+
gl::BindTexture(gl::TEXTURE_2D, gl_tex);
115+
}
52116

53-
// Get plane info from params
54-
let planes = self.params.lock_planes();
55-
if let Some(plane) = planes.get(&0) {
56-
// Create EGL image
57-
let image = graphics_info.egl_instance.create_image(
58-
graphics_info.display,
59-
graphics_info.context,
60-
EGL_LINUX_DMA_BUF_EXT as u32,
61-
unsafe { ClientBuffer::from_ptr(EGL_NO_BUFFER) },
62-
&[
63-
EGL_WIDTH as usize,
64-
self.size.x as usize,
65-
EGL_HEIGHT as usize,
66-
self.size.y as usize,
67-
EGL_LINUX_DRM_FOURCC_EXT as usize,
68-
self.format as usize,
69-
EGL_DMA_BUF_PLANE0_FD_EXT as usize,
70-
plane.fd.as_raw_fd() as usize,
71-
EGL_DMA_BUF_PLANE0_OFFSET_EXT as usize,
72-
plane.offset as usize,
73-
EGL_DMA_BUF_PLANE0_PITCH_EXT as usize,
74-
plane.stride as usize,
75-
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT as usize,
76-
0,
77-
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT as usize,
78-
0,
79-
egl::ATTRIB_NONE,
80-
0,
81-
],
82-
);
117+
// Set the native texture handle directly
118+
// Mesa will handle the OES texture implicitly
119+
tex.set_native_surface(
120+
gl_tex as *mut std::os::raw::c_void,
121+
TexType::ImageNomips | TexType::Dynamic,
122+
0x8058, // GL_RGBA8
123+
self.size.x as i32,
124+
self.size.y as i32,
125+
1, // single surface
126+
true, // we own this texture
127+
);
83128

84-
if let Ok(image) = image {
85-
// Create and bind GL texture
86-
let mut gl_tex = 0;
87-
unsafe {
88-
gl::GenTextures(1, &mut gl_tex);
89-
gl::BindTexture(gl::TEXTURE_2D, gl_tex);
90-
}
129+
// Clean up EGL image
130+
graphics_info
131+
.egl_instance
132+
.destroy_image(graphics_info.display, image)
133+
.ok();
91134

92-
// Set the native texture handle directly
93-
// Mesa will handle the OES texture implicitly
94-
tex.set_native_surface(
95-
gl_tex as *mut std::os::raw::c_void,
96-
TexType::ImageNomips | TexType::Dynamic,
97-
0x8058, // GL_RGBA8
98-
self.size.x as i32,
99-
self.size.y as i32,
100-
1, // single surface
101-
true, // we own this texture
102-
);
135+
Ok(tex)
136+
}
103137

104-
// Clean up EGL image
105-
graphics_info
106-
.egl_instance
107-
.destroy_image(graphics_info.display, image)
108-
.ok();
138+
pub fn init_tex(&self, graphics_info: &GraphicsInfo, buffer: Arc<Buffer>) {
139+
if self.tex.get().is_none() {
140+
match self.import_dmabuf(graphics_info) {
141+
Ok(tex) => {
142+
let _ = self.tex.set(tex);
143+
let _ = self
144+
.message_sink
145+
.as_ref()
146+
.unwrap()
147+
.send(Message::DmabufImportSuccess(self.params.clone(), buffer));
148+
}
149+
Err(e) => {
150+
tracing::error!("Wayland: Error initializing DMABuf tex: {:?}", e);
151+
let _ = self
152+
.message_sink
153+
.as_ref()
154+
.unwrap()
155+
.send(Message::DmabufImportFailure(self.params.clone()));
109156
}
110-
}
157+
};
158+
}
159+
}
111160

112-
tex
113-
});
114-
Tex::find(tex_ref.get_id()).ok()
161+
pub fn get_tex(&self) -> Option<&Tex> {
162+
self.tex.get()
115163
}
116164

117165
pub fn size(&self) -> Vector2<usize> {

0 commit comments

Comments
 (0)