1
0
Fork 0
forked from wry/wry

render: add support for explicit sync

This commit is contained in:
Julian Orth 2024-03-21 23:26:34 +01:00
parent 1b4492c670
commit 816315170f
22 changed files with 531 additions and 94 deletions

View file

@ -80,6 +80,34 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
&[("target", "GLenum"), ("image", "GLeglImageOES")][..], &[("target", "GLenum"), ("image", "GLeglImageOES")][..],
), ),
("glGetGraphicsResetStatusKHR", "GLenum", &[][..]), ("glGetGraphicsResetStatusKHR", "GLenum", &[][..]),
(
"eglCreateSyncKHR",
"EGLSyncKHR",
&[
("dpy", "EGLDisplay"),
("ty", "EGLenum"),
("attrib_list", "*const EGLint"),
][..],
),
(
"eglDestroySyncKHR",
"EGLBoolean",
&[("dpy", "EGLDisplay"), ("sync", "EGLSyncKHR")][..],
),
(
"eglDupNativeFenceFDANDROID",
"EGLint",
&[("dpy", "EGLDisplay"), ("sync", "EGLSyncKHR")][..],
),
(
"eglWaitSyncKHR",
"EGLint",
&[
("dpy", "EGLDisplay"),
("sync", "EGLSyncKHR"),
("flags", "EGLint"),
][..],
),
]; ];
writeln!(f, "use std::ptr;")?; writeln!(f, "use std::ptr;")?;

View file

@ -3,7 +3,7 @@ use {
async_engine::SpawnedFuture, async_engine::SpawnedFuture,
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
fixed::Fixed, fixed::Fixed,
gfx_api::GfxFramebuffer, gfx_api::{GfxFramebuffer, SyncFile},
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL}, ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
libinput::consts::DeviceCapability, libinput::consts::DeviceCapability,
video::drm::{ConnectorType, DrmError, DrmVersion}, video::drm::{ConnectorType, DrmError, DrmVersion},
@ -106,6 +106,7 @@ pub trait HardwareCursor: Debug {
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer>; fn get_buffer(&self) -> Rc<dyn GfxFramebuffer>;
fn set_position(&self, x: i32, y: i32); fn set_position(&self, x: i32, y: i32);
fn swap_buffer(&self); fn swap_buffer(&self);
fn set_sync_file(&self, sync_file: Option<SyncFile>);
fn commit(&self); fn commit(&self);
fn size(&self) -> (i32, i32); fn size(&self) -> (i32, i32);
} }

View file

@ -9,7 +9,10 @@ use {
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
edid::Descriptor, edid::Descriptor,
format::{Format, ARGB8888, XRGB8888}, format::{Format, ARGB8888, XRGB8888},
gfx_api::{BufferResv, GfxApiOpt, GfxContext, GfxFramebuffer, GfxRenderPass, GfxTexture}, gfx_api::{
AcquireSync, BufferResv, GfxApiOpt, GfxContext, GfxFramebuffer, GfxRenderPass,
GfxTexture, ReleaseSync, SyncFile,
},
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC}, ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
renderer::RenderResult, renderer::RenderResult,
state::State, state::State,
@ -227,6 +230,7 @@ pub struct MetalConnector {
pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 3]>>>, pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 3]>>>,
pub cursor_front_buffer: NumCell<usize>, pub cursor_front_buffer: NumCell<usize>,
pub cursor_swap_buffer: Cell<bool>, pub cursor_swap_buffer: Cell<bool>,
pub cursor_sync_file: CloneCell<Option<SyncFile>>,
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>, pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
pub scanout_buffers: RefCell<AHashMap<DmaBufId, DirectScanoutCache>>, pub scanout_buffers: RefCell<AHashMap<DmaBufId, DirectScanoutCache>>,
@ -244,6 +248,7 @@ pub struct MetalHardwareCursor {
pub cursor_x_pending: Cell<i32>, pub cursor_x_pending: Cell<i32>,
pub cursor_y_pending: Cell<i32>, pub cursor_y_pending: Cell<i32>,
pub cursor_buffers: Rc<[RenderBuffer; 3]>, pub cursor_buffers: Rc<[RenderBuffer; 3]>,
pub sync_file: CloneCell<Option<SyncFile>>,
pub have_changes: Cell<bool>, pub have_changes: Cell<bool>,
} }
@ -270,6 +275,11 @@ impl HardwareCursor for MetalHardwareCursor {
self.have_changes.set(true); self.have_changes.set(true);
} }
fn set_sync_file(&self, sync_file: Option<SyncFile>) {
self.sync_file.set(sync_file);
self.have_changes.set(true);
}
fn commit(&self) { fn commit(&self) {
if self.generation != self.connector.cursor_generation.get() { if self.generation != self.connector.cursor_generation.get() {
return; return;
@ -285,6 +295,7 @@ impl HardwareCursor for MetalHardwareCursor {
if self.cursor_swap_buffer.take() { if self.cursor_swap_buffer.take() {
self.connector.cursor_swap_buffer.set(true); self.connector.cursor_swap_buffer.set(true);
} }
self.connector.cursor_sync_file.set(self.sync_file.take());
self.connector.cursor_changed.set(true); self.connector.cursor_changed.set(true);
if self.connector.can_present.get() { if self.connector.can_present.get() {
self.connector.schedule_present(); self.connector.schedule_present();
@ -350,6 +361,7 @@ pub struct DirectScanoutCache {
#[derive(Debug)] #[derive(Debug)]
pub struct DirectScanoutData { pub struct DirectScanoutData {
tex: Rc<dyn GfxTexture>, tex: Rc<dyn GfxTexture>,
acquire_sync: AcquireSync,
_resv: Option<Rc<dyn BufferResv>>, _resv: Option<Rc<dyn BufferResv>>,
fb: Rc<DrmFramebuffer>, fb: Rc<DrmFramebuffer>,
dma_buf_id: DmaBufId, dma_buf_id: DmaBufId,
@ -370,6 +382,7 @@ pub struct DirectScanoutPosition {
pub struct PresentFb { pub struct PresentFb {
fb: Rc<DrmFramebuffer>, fb: Rc<DrmFramebuffer>,
direct_scanout_data: Option<DirectScanoutData>, direct_scanout_data: Option<DirectScanoutData>,
sync_file: Option<SyncFile>,
} }
impl MetalConnector { impl MetalConnector {
@ -396,6 +409,7 @@ impl MetalConnector {
cursor_x_pending: Cell::new(self.cursor_x.get()), cursor_x_pending: Cell::new(self.cursor_x.get()),
cursor_y_pending: Cell::new(self.cursor_y.get()), cursor_y_pending: Cell::new(self.cursor_y.get()),
cursor_buffers: cp.clone(), cursor_buffers: cp.clone(),
sync_file: Default::default(),
have_changes: Cell::new(false), have_changes: Cell::new(false),
}) as _), }) as _),
_ => None, _ => None,
@ -474,6 +488,10 @@ impl MetalConnector {
} }
ct ct
}; };
if let AcquireSync::None = ct.acquire_sync {
// Cannot perform scanout without sync.
return None;
}
if ct.source.buffer_transform != ct.target.output_transform { if ct.source.buffer_transform != ct.target.output_transform {
// Rotations and mirroring are not supported. // Rotations and mirroring are not supported.
return None; return None;
@ -526,6 +544,7 @@ impl MetalConnector {
if let Some(buffer) = cache.get(&dmabuf.id) { if let Some(buffer) = cache.get(&dmabuf.id) {
return buffer.fb.as_ref().map(|fb| DirectScanoutData { return buffer.fb.as_ref().map(|fb| DirectScanoutData {
tex: buffer.tex.upgrade().unwrap(), tex: buffer.tex.upgrade().unwrap(),
acquire_sync: ct.acquire_sync.clone(),
_resv: ct.buffer_resv.clone(), _resv: ct.buffer_resv.clone(),
fb: fb.clone(), fb: fb.clone(),
dma_buf_id: dmabuf.id, dma_buf_id: dmabuf.id,
@ -550,6 +569,7 @@ impl MetalConnector {
let data = match self.dev.master.add_fb(dmabuf, Some(format.format)) { let data = match self.dev.master.add_fb(dmabuf, Some(format.format)) {
Ok(fb) => Some(DirectScanoutData { Ok(fb) => Some(DirectScanoutData {
tex: ct.tex.clone(), tex: ct.tex.clone(),
acquire_sync: ct.acquire_sync.clone(),
_resv: ct.buffer_resv.clone(), _resv: ct.buffer_resv.clone(),
fb: Rc::new(fb), fb: Rc::new(fb),
dma_buf_id: dmabuf.id, dma_buf_id: dmabuf.id,
@ -630,21 +650,31 @@ impl MetalConnector {
}; };
log::debug!("{} direct scanout on {}", change, self.kernel_id()); log::debug!("{} direct scanout on {}", change, self.kernel_id());
} }
let fb = match &direct_scanout_data { let sync_file;
let fb;
match &direct_scanout_data {
None => { None => {
buffer_fb let sf = buffer_fb
.perform_render_pass(pass) .perform_render_pass(pass)
.map_err(MetalError::RenderFrame)?; .map_err(MetalError::RenderFrame)?;
buffer.copy_to_dev()?; sync_file = buffer.copy_to_dev(sf)?;
self.next_buffer.fetch_add(1); self.next_buffer.fetch_add(1);
output.perform_screencopies(&buffer.render_tex, !render_hw_cursor, 0, 0, None); output.perform_screencopies(&buffer.render_tex, !render_hw_cursor, 0, 0, None);
buffer.drm.clone() fb = buffer.drm.clone();
}
Some(dsd) => {
sync_file = match &dsd.acquire_sync {
AcquireSync::None => None,
AcquireSync::Implicit => None,
AcquireSync::SyncFile { sync_file } => Some(sync_file.clone()),
};
fb = dsd.fb.clone();
} }
Some(dsd) => dsd.fb.clone(),
}; };
Ok(PresentFb { Ok(PresentFb {
fb, fb,
direct_scanout_data, direct_scanout_data,
sync_file,
}) })
} }
@ -699,6 +729,7 @@ impl MetalConnector {
) )
} }
}; };
let in_fence = fb.sync_file.as_ref().map(|s| s.raw()).unwrap_or(-1);
changes.change_object(plane.id, |c| { changes.change_object(plane.id, |c| {
c.change(plane.fb_id, fb.fb.id().0 as _); c.change(plane.fb_id, fb.fb.id().0 as _);
c.change(plane.src_w.id, (src_width as u64) << 16); c.change(plane.src_w.id, (src_width as u64) << 16);
@ -707,11 +738,13 @@ impl MetalConnector {
c.change(plane.crtc_y.id, crtc_y as u64); c.change(plane.crtc_y.id, crtc_y as u64);
c.change(plane.crtc_w.id, crtc_w as u64); c.change(plane.crtc_w.id, crtc_w as u64);
c.change(plane.crtc_h.id, crtc_h as u64); c.change(plane.crtc_h.id, crtc_h as u64);
c.change(plane.in_fence_fd, in_fence as u64);
}); });
new_fb = Some(fb); new_fb = Some(fb);
} }
} }
let mut cursor_swap_buffer = false; let mut cursor_swap_buffer = false;
let mut cursor_sync_file = None;
if self.cursor_changed.get() && cursor.is_some() { if self.cursor_changed.get() && cursor.is_some() {
let plane = cursor.unwrap(); let plane = cursor.unwrap();
if self.cursor_enabled.get() { if self.cursor_enabled.get() {
@ -719,12 +752,14 @@ impl MetalConnector {
let mut front_buffer = self.cursor_front_buffer.get(); let mut front_buffer = self.cursor_front_buffer.get();
if cursor_swap_buffer { if cursor_swap_buffer {
front_buffer = front_buffer.wrapping_add(1); front_buffer = front_buffer.wrapping_add(1);
cursor_sync_file = self.cursor_sync_file.get();
} }
let buffers = self.cursor_buffers.get().unwrap(); let buffers = self.cursor_buffers.get().unwrap();
let buffer = &buffers[front_buffer % buffers.len()]; let buffer = &buffers[front_buffer % buffers.len()];
if cursor_swap_buffer { if cursor_swap_buffer {
buffer.copy_to_dev()?; cursor_sync_file = buffer.copy_to_dev(cursor_sync_file)?;
} }
let in_fence = cursor_sync_file.as_ref().map(|s| s.raw()).unwrap_or(-1);
let (width, height) = buffer.dev_fb.physical_size(); let (width, height) = buffer.dev_fb.physical_size();
changes.change_object(plane.id, |c| { changes.change_object(plane.id, |c| {
c.change(plane.fb_id, buffer.drm.id().0 as _); c.change(plane.fb_id, buffer.drm.id().0 as _);
@ -737,6 +772,7 @@ impl MetalConnector {
c.change(plane.src_y.id, 0); c.change(plane.src_y.id, 0);
c.change(plane.src_w.id, (width as u64) << 16); c.change(plane.src_w.id, (width as u64) << 16);
c.change(plane.src_h.id, (height as u64) << 16); c.change(plane.src_h.id, (height as u64) << 16);
c.change(plane.in_fence_fd, in_fence as u64);
}); });
} else { } else {
changes.change_object(plane.id, |c| { changes.change_object(plane.id, |c| {
@ -775,6 +811,7 @@ impl MetalConnector {
if cursor_swap_buffer { if cursor_swap_buffer {
self.cursor_swap_buffer.set(false); self.cursor_swap_buffer.set(false);
self.cursor_front_buffer.fetch_add(1); self.cursor_front_buffer.fetch_add(1);
self.cursor_sync_file.take();
} }
self.can_present.set(false); self.can_present.set(false);
self.has_damage.set(false); self.has_damage.set(false);
@ -1026,6 +1063,7 @@ fn create_connector(
cursor_changed: Cell::new(false), cursor_changed: Cell::new(false),
cursor_front_buffer: Default::default(), cursor_front_buffer: Default::default(),
cursor_swap_buffer: Cell::new(false), cursor_swap_buffer: Cell::new(false),
cursor_sync_file: Default::default(),
drm_feedback: Default::default(), drm_feedback: Default::default(),
scanout_buffers: Default::default(), scanout_buffers: Default::default(),
active_framebuffer: Default::default(), active_framebuffer: Default::default(),
@ -2426,12 +2464,13 @@ impl RenderBuffer {
.unwrap_or_else(|| self.dev_fb.clone()) .unwrap_or_else(|| self.dev_fb.clone())
} }
fn copy_to_dev(&self) -> Result<(), MetalError> { fn copy_to_dev(&self, sync_file: Option<SyncFile>) -> Result<Option<SyncFile>, MetalError> {
let Some(tex) = &self.dev_tex else { let Some(tex) = &self.dev_tex else {
return Ok(()); return Ok(sync_file);
}; };
let acquire_point = AcquireSync::from_sync_file(sync_file);
self.dev_fb self.dev_fb
.copy_texture(tex, 0, 0) .copy_texture(tex, acquire_point, ReleaseSync::Implicit, 0, 0)
.map_err(MetalError::CopyToOutput) .map_err(MetalError::CopyToOutput)
} }
} }

View file

@ -2,7 +2,7 @@ use {
crate::{ crate::{
fixed::Fixed, fixed::Fixed,
format::ARGB8888, format::ARGB8888,
gfx_api::{GfxContext, GfxError, GfxTexture}, gfx_api::{AcquireSync, GfxContext, GfxError, GfxTexture, ReleaseSync},
rect::Rect, rect::Rect,
renderer::Renderer, renderer::Renderer,
scale::Scale, scale::Scale,
@ -379,6 +379,8 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
scale, scale,
None, None,
None, None,
AcquireSync::None,
ReleaseSync::None,
); );
} }
} }
@ -390,9 +392,18 @@ impl Cursor for StaticCursor {
fn render_hardware_cursor(&self, renderer: &mut Renderer) { fn render_hardware_cursor(&self, renderer: &mut Renderer) {
if let Some(img) = self.image.scales.get(&renderer.scale()) { if let Some(img) = self.image.scales.get(&renderer.scale()) {
renderer renderer.base.render_texture(
.base &img.tex,
.render_texture(&img.tex, 0, 0, None, None, renderer.scale(), None, None); 0,
0,
None,
None,
renderer.scale(),
None,
None,
AcquireSync::None,
ReleaseSync::None,
);
} }
} }
@ -420,9 +431,18 @@ impl Cursor for AnimatedCursor {
fn render_hardware_cursor(&self, renderer: &mut Renderer) { fn render_hardware_cursor(&self, renderer: &mut Renderer) {
let img = &self.images[self.idx.get()]; let img = &self.images[self.idx.get()];
if let Some(img) = img.scales.get(&renderer.scale()) { if let Some(img) = img.scales.get(&renderer.scale()) {
renderer renderer.base.render_texture(
.base &img.tex,
.render_texture(&img.tex, 0, 0, None, None, renderer.scale(), None, None); 0,
0,
None,
None,
renderer.scale(),
None,
None,
AcquireSync::None,
ReleaseSync::None,
);
} }
} }

View file

@ -145,6 +145,8 @@ pub struct CopyTexture {
pub source: SampleRect, pub source: SampleRect,
pub target: FramebufferRect, pub target: FramebufferRect,
pub buffer_resv: Option<Rc<dyn BufferResv>>, pub buffer_resv: Option<Rc<dyn BufferResv>>,
pub acquire_sync: AcquireSync,
pub release_sync: ReleaseSync,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -160,6 +162,40 @@ impl Deref for SyncFile {
unsafe impl UnsafeCellCloneSafe for SyncFile {} unsafe impl UnsafeCellCloneSafe for SyncFile {}
#[derive(Clone)]
pub enum AcquireSync {
None,
Implicit,
SyncFile { sync_file: SyncFile },
}
impl AcquireSync {
pub fn from_sync_file(sync_file: Option<SyncFile>) -> Self {
match sync_file {
None => Self::Implicit,
Some(sync_file) => Self::SyncFile { sync_file },
}
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum ReleaseSync {
None,
Implicit,
Explicit,
}
impl Debug for AcquireSync {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let name = match self {
AcquireSync::None => "None",
AcquireSync::Implicit => "Implicit",
AcquireSync::SyncFile { .. } => "SyncFile",
};
f.debug_struct(name).finish_non_exhaustive()
}
}
pub trait BufferResv: Debug { pub trait BufferResv: Debug {
fn set_sync_file(&self, user: BufferResvUser, sync_file: &SyncFile); fn set_sync_file(&self, user: BufferResvUser, sync_file: &SyncFile);
} }
@ -189,7 +225,11 @@ pub trait GfxFramebuffer: Debug {
fn physical_size(&self) -> (i32, i32); fn physical_size(&self) -> (i32, i32);
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), GfxError>; fn render(
&self,
ops: Vec<GfxApiOpt>,
clear: Option<&Color>,
) -> Result<Option<SyncFile>, GfxError>;
fn copy_to_shm( fn copy_to_shm(
self: Rc<Self>, self: Rc<Self>,
@ -206,11 +246,11 @@ pub trait GfxFramebuffer: Debug {
} }
impl dyn GfxFramebuffer { impl dyn GfxFramebuffer {
pub fn clear(&self) -> Result<(), GfxError> { pub fn clear(&self) -> Result<Option<SyncFile>, GfxError> {
self.clear_with(0.0, 0.0, 0.0, 0.0) self.clear_with(0.0, 0.0, 0.0, 0.0)
} }
pub fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) -> Result<(), GfxError> { pub fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) -> Result<Option<SyncFile>, GfxError> {
let ops = self.take_render_ops(); let ops = self.take_render_ops();
self.render(ops, Some(&Color { r, g, b, a })) self.render(ops, Some(&Color { r, g, b, a }))
} }
@ -240,13 +280,26 @@ impl dyn GfxFramebuffer {
pub fn copy_texture( pub fn copy_texture(
&self, &self,
texture: &Rc<dyn GfxTexture>, texture: &Rc<dyn GfxTexture>,
acquire_sync: AcquireSync,
release_sync: ReleaseSync,
x: i32, x: i32,
y: i32, y: i32,
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
let mut ops = self.take_render_ops(); let mut ops = self.take_render_ops();
let scale = Scale::from_int(1); let scale = Scale::from_int(1);
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
renderer.render_texture(texture, x, y, None, None, scale, None, None); renderer.render_texture(
texture,
x,
y,
None,
None,
scale,
None,
None,
acquire_sync,
release_sync,
);
let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT); let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT);
self.render(ops, clear) self.render(ops, clear)
} }
@ -256,7 +309,7 @@ impl dyn GfxFramebuffer {
scale: Scale, scale: Scale,
clear: Option<&Color>, clear: Option<&Color>,
f: &mut dyn FnMut(&mut RendererBase), f: &mut dyn FnMut(&mut RendererBase),
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
let mut ops = self.take_render_ops(); let mut ops = self.take_render_ops();
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
f(&mut renderer); f(&mut renderer);
@ -331,7 +384,7 @@ impl dyn GfxFramebuffer {
} }
} }
pub fn perform_render_pass(&self, pass: GfxRenderPass) -> Result<(), GfxError> { pub fn perform_render_pass(&self, pass: GfxRenderPass) -> Result<Option<SyncFile>, GfxError> {
self.render(pass.ops, pass.clear.as_ref()) self.render(pass.ops, pass.clear.as_ref())
} }
@ -343,7 +396,7 @@ impl dyn GfxFramebuffer {
result: Option<&mut RenderResult>, result: Option<&mut RenderResult>,
scale: Scale, scale: Scale,
render_hardware_cursor: bool, render_hardware_cursor: bool,
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
self.render_node( self.render_node(
node, node,
state, state,
@ -366,7 +419,7 @@ impl dyn GfxFramebuffer {
render_hardware_cursor: bool, render_hardware_cursor: bool,
black_background: bool, black_background: bool,
transform: Transform, transform: Transform,
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
let pass = self.create_render_pass( let pass = self.create_render_pass(
node, node,
state, state,
@ -386,7 +439,7 @@ impl dyn GfxFramebuffer {
state: &State, state: &State,
scale: Scale, scale: Scale,
transform: Transform, transform: Transform,
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
let mut ops = self.take_render_ops(); let mut ops = self.take_render_ops();
let mut renderer = Renderer { let mut renderer = Renderer {
base: self.renderer_base(&mut ops, scale, transform), base: self.renderer_base(&mut ops, scale, transform),

View file

@ -68,8 +68,8 @@ macro_rules! dynload {
use { use {
crate::{ crate::{
gfx_api::{ gfx_api::{
CopyTexture, FillRect, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, AcquireSync, CopyTexture, FillRect, GfxApiOpt, GfxContext, GfxError, GfxTexture,
SampleRect, ReleaseSync, SyncFile,
}, },
gfx_apis::gl::{ gfx_apis::gl::{
gl::texture::image_target, gl::texture::image_target,
@ -80,8 +80,9 @@ use {
}, },
}, },
theme::Color, theme::Color,
utils::{rc_eq::rc_eq, vecstorage::VecStorage}, utils::{errorfmt::ErrorFmt, rc_eq::rc_eq, vecstorage::VecStorage},
video::{ video::{
dmabuf::DMA_BUF_SYNC_READ,
drm::{Drm, DrmError}, drm::{Drm, DrmError},
gbm::GbmError, gbm::GbmError,
}, },
@ -181,6 +182,14 @@ enum RenderError {
NoSupportedFormats, NoSupportedFormats,
#[error("Cannot convert a shm texture into a framebuffer")] #[error("Cannot convert a shm texture into a framebuffer")]
ShmTextureToFb, ShmTextureToFb,
#[error("Could not create EGLSyncKHR")]
CreateEglSync,
#[error("Could not destroy EGLSyncKHR")]
DestroyEglSync,
#[error("Could not export sync file")]
ExportSyncFile,
#[error("Could not insert wait for EGLSyncKHR")]
WaitSync,
} }
#[derive(Default)] #[derive(Default)]
@ -190,7 +199,7 @@ struct GfxGlState {
copy_tex: VecStorage<&'static CopyTexture>, copy_tex: VecStorage<&'static CopyTexture>,
} }
fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) { fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> {
let mut state = fb.ctx.gl_state.borrow_mut(); let mut state = fb.ctx.gl_state.borrow_mut();
let state = &mut *state; let state = &mut *state;
let mut fill_rect = state.fill_rect.take(); let mut fill_rect = state.fill_rect.take();
@ -256,9 +265,30 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) {
} }
} }
for tex in &*copy_tex { for tex in &*copy_tex {
render_texture(&fb.ctx, &tex.tex.as_gl(), &tex.target, &tex.source) render_texture(&fb.ctx, tex);
} }
} }
if fb.ctx.ctx.dpy.explicit_sync {
let file = match fb.ctx.ctx.export_sync_file() {
Ok(f) => SyncFile(Rc::new(f)),
Err(e) => {
log::error!("Could not create sync file: {}", ErrorFmt(e));
return None;
}
};
let user = fb.ctx.buffer_resv_user;
for op in ops {
if let GfxApiOpt::CopyTexture(ct) = op {
if ct.release_sync == ReleaseSync::Explicit {
if let Some(resv) = &ct.buffer_resv {
resv.set_sync_file(user, &file);
}
}
}
}
return Some(file);
}
None
} }
fn fill_boxes3(ctx: &GlRenderContext, boxes: &[[f32; 2]], color: &Color) { fn fill_boxes3(ctx: &GlRenderContext, boxes: &[[f32; 2]], color: &Color) {
@ -280,15 +310,13 @@ fn fill_boxes3(ctx: &GlRenderContext, boxes: &[[f32; 2]], color: &Color) {
} }
} }
fn render_texture( fn render_texture(ctx: &GlRenderContext, tex: &CopyTexture) {
ctx: &GlRenderContext, let texture = tex.tex.as_gl();
texture: &Texture,
target_rect: &FramebufferRect,
src: &SampleRect,
) {
assert!(rc_eq(&ctx.ctx, &texture.ctx.ctx)); assert!(rc_eq(&ctx.ctx, &texture.ctx.ctx));
let gles = ctx.ctx.dpy.gles; let gles = ctx.ctx.dpy.gles;
unsafe { unsafe {
handle_explicit_sync(ctx, texture, &tex.acquire_sync);
(gles.glActiveTexture)(GL_TEXTURE0); (gles.glActiveTexture)(GL_TEXTURE0);
let target = image_target(texture.gl.external_only); let target = image_target(texture.gl.external_only);
@ -321,8 +349,8 @@ fn render_texture(
(gles.glUniform1i)(prog.tex, 0); (gles.glUniform1i)(prog.tex, 0);
let texcoord = src.to_points(); let texcoord = tex.source.to_points();
let pos = target_rect.to_points(); let pos = tex.target.to_points();
(gles.glVertexAttribPointer)( (gles.glVertexAttribPointer)(
prog.texcoord as _, prog.texcoord as _,
@ -346,6 +374,36 @@ fn render_texture(
} }
} }
fn handle_explicit_sync(ctx: &GlRenderContext, texture: &Texture, sync: &AcquireSync) {
let sync_file = match sync {
AcquireSync::None | AcquireSync::Implicit => return,
AcquireSync::SyncFile { sync_file } => sync_file,
};
let sync_file = match uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) {
Ok(s) => s,
Err(e) => {
log::error!("Could not dup sync file: {}", ErrorFmt(e));
return;
}
};
if ctx.ctx.dpy.explicit_sync {
let sync = match ctx.ctx.create_sync(Some(sync_file)) {
Ok(s) => s,
Err(e) => {
log::error!("Could import sync file: {}", ErrorFmt(e));
return;
}
};
sync.wait();
} else {
if let Some(img) = &texture.gl.img {
if let Err(e) = img.dmabuf.import_sync_file(DMA_BUF_SYNC_READ, &sync_file) {
log::error!("Could not import sync file into dmabuf: {}", ErrorFmt(e));
}
}
}
}
impl dyn GfxTexture { impl dyn GfxTexture {
fn as_gl(&self) -> &Texture { fn as_gl(&self) -> &Texture {
self.as_any() self.as_any()

View file

@ -24,9 +24,10 @@ use {
PROCS, PROCS,
}, },
ext::{ ext::{
get_display_ext, get_gl_ext, DisplayExt, GlExt, EXT_CREATE_CONTEXT_ROBUSTNESS, get_display_ext, get_gl_ext, DisplayExt, GlExt, ANDROID_NATIVE_FENCE_SYNC,
EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS, GL_OES_EGL_IMAGE, GL_OES_EGL_IMAGE_EXTERNAL, EXT_CREATE_CONTEXT_ROBUSTNESS, EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS,
KHR_IMAGE_BASE, KHR_NO_CONFIG_CONTEXT, KHR_SURFACELESS_CONTEXT, GL_OES_EGL_IMAGE, GL_OES_EGL_IMAGE_EXTERNAL, KHR_FENCE_SYNC, KHR_IMAGE_BASE,
KHR_NO_CONFIG_CONTEXT, KHR_SURFACELESS_CONTEXT, KHR_WAIT_SYNC,
MESA_CONFIGLESS_CONTEXT, MESA_CONFIGLESS_CONTEXT,
}, },
proc::ExtProc, proc::ExtProc,
@ -65,6 +66,7 @@ pub struct EglDisplay {
pub formats: AHashMap<u32, EglFormat>, pub formats: AHashMap<u32, EglFormat>,
pub gbm: Rc<GbmDevice>, pub gbm: Rc<GbmDevice>,
pub dpy: EGLDisplay, pub dpy: EGLDisplay,
pub explicit_sync: bool,
} }
impl EglDisplay { impl EglDisplay {
@ -99,6 +101,7 @@ impl EglDisplay {
formats: AHashMap::new(), formats: AHashMap::new(),
gbm: Rc::new(gbm), gbm: Rc::new(gbm),
dpy, dpy,
explicit_sync: false,
}; };
let mut major = 0; let mut major = 0;
let mut minor = 0; let mut minor = 0;
@ -122,6 +125,9 @@ impl EglDisplay {
return Err(RenderError::SurfacelessContext); return Err(RenderError::SurfacelessContext);
} }
dpy.formats = query_formats(procs, dpy.dpy)?; dpy.formats = query_formats(procs, dpy.dpy)?;
dpy.explicit_sync = dpy
.exts
.contains(KHR_FENCE_SYNC | KHR_WAIT_SYNC | ANDROID_NATIVE_FENCE_SYNC);
Ok(Rc::new(dpy)) Ok(Rc::new(dpy))
} }

View file

@ -6,6 +6,7 @@ pub type EGLBoolean = c::c_uint;
#[allow(dead_code)] #[allow(dead_code)]
pub type EGLuint64KHR = u64; pub type EGLuint64KHR = u64;
pub type EGLAttrib = isize; pub type EGLAttrib = isize;
pub type EGLSyncKHR = *mut u8;
egl_transparent!(EGLDisplay); egl_transparent!(EGLDisplay);
egl_transparent!(EGLSurface); egl_transparent!(EGLSurface);
@ -83,6 +84,8 @@ pub const EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT: EGLint = 0x3449;
pub const EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT: EGLint = 0x344A; pub const EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT: EGLint = 0x344A;
pub const EGL_IMAGE_PRESERVED_KHR: EGLint = 0x30D2; pub const EGL_IMAGE_PRESERVED_KHR: EGLint = 0x30D2;
pub const EGL_LINUX_DMA_BUF_EXT: EGLint = 0x3270; pub const EGL_LINUX_DMA_BUF_EXT: EGLint = 0x3270;
pub const EGL_SYNC_NATIVE_FENCE_ANDROID: EGLenum = 0x3144;
pub const EGL_SYNC_NATIVE_FENCE_FD_ANDROID: EGLint = 0x3145;
dynload! { dynload! {
EGL: Egl from "libEGL.so" { EGL: Egl from "libEGL.so" {

View file

@ -78,6 +78,9 @@ bitflags! {
KHR_SURFACELESS_CONTEXT = 1 << 5, KHR_SURFACELESS_CONTEXT = 1 << 5,
IMG_CONTEXT_PRIORITY = 1 << 6, IMG_CONTEXT_PRIORITY = 1 << 6,
EXT_CREATE_CONTEXT_ROBUSTNESS = 1 << 7, EXT_CREATE_CONTEXT_ROBUSTNESS = 1 << 7,
KHR_FENCE_SYNC = 1 << 8,
KHR_WAIT_SYNC = 1 << 9,
ANDROID_NATIVE_FENCE_SYNC = 1 << 10,
} }
pub(crate) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt { pub(crate) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
@ -96,6 +99,9 @@ pub(crate) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
"EGL_EXT_create_context_robustness", "EGL_EXT_create_context_robustness",
EXT_CREATE_CONTEXT_ROBUSTNESS, EXT_CREATE_CONTEXT_ROBUSTNESS,
), ),
("EGL_KHR_fence_sync", KHR_FENCE_SYNC),
("EGL_KHR_wait_sync", KHR_WAIT_SYNC),
("EGL_ANDROID_native_fence_sync", ANDROID_NATIVE_FENCE_SYNC),
]; ];
match get_dpy_extensions(dpy) { match get_dpy_extensions(dpy) {
Some(exts) => get_typed_ext(&exts, DisplayExt::none(), &map), Some(exts) => get_typed_ext(&exts, DisplayExt::none(), &map),

View file

@ -1,4 +1,5 @@
pub(super) mod context; pub(super) mod context;
pub(super) mod framebuffer; pub(super) mod framebuffer;
pub(super) mod image; pub(super) mod image;
pub(super) mod sync;
pub(super) mod texture; pub(super) mod texture;

View file

@ -2,8 +2,8 @@ use {
crate::{ crate::{
format::{Format, XRGB8888}, format::{Format, XRGB8888},
gfx_api::{ gfx_api::{
GfxApiOpt, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage, GfxTexture, BufferResvUser, GfxApiOpt, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage,
ResetStatus, GfxTexture, ResetStatus,
}, },
gfx_apis::gl::{ gfx_apis::gl::{
egl::{context::EglContext, display::EglDisplay, image::EglImage}, egl::{context::EglContext, display::EglDisplay, image::EglImage},
@ -65,6 +65,8 @@ pub(in crate::gfx_apis::gl) struct GlRenderContext {
pub(crate) gfx_ops: RefCell<Vec<GfxApiOpt>>, pub(crate) gfx_ops: RefCell<Vec<GfxApiOpt>>,
pub(in crate::gfx_apis::gl) gl_state: RefCell<GfxGlState>, pub(in crate::gfx_apis::gl) gl_state: RefCell<GfxGlState>,
pub(in crate::gfx_apis::gl) buffer_resv_user: BufferResvUser,
} }
impl Debug for GlRenderContext { impl Debug for GlRenderContext {
@ -141,6 +143,8 @@ impl GlRenderContext {
gfx_ops: Default::default(), gfx_ops: Default::default(),
gl_state: Default::default(), gl_state: Default::default(),
buffer_resv_user: Default::default(),
}) })
} }

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
format::Format, format::Format,
gfx_api::{GfxApiOpt, GfxError, GfxFramebuffer}, gfx_api::{GfxApiOpt, GfxError, GfxFramebuffer, SyncFile},
gfx_apis::gl::{ gfx_apis::gl::{
gl::{ gl::{
frame_buffer::GlFrameBuffer, frame_buffer::GlFrameBuffer,
@ -65,7 +65,11 @@ impl Framebuffer {
}); });
} }
pub fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), RenderError> { pub fn render(
&self,
ops: Vec<GfxApiOpt>,
clear: Option<&Color>,
) -> Result<Option<SyncFile>, RenderError> {
let gles = self.ctx.ctx.dpy.gles; let gles = self.ctx.ctx.dpy.gles;
let res = self.ctx.ctx.with_current(|| { let res = self.ctx.ctx.with_current(|| {
unsafe { unsafe {
@ -77,11 +81,13 @@ impl Framebuffer {
} }
(gles.glBlendFunc)(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); (gles.glBlendFunc)(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} }
run_ops(self, &ops); let fd = run_ops(self, &ops);
if fd.is_none() {
unsafe { unsafe {
(gles.glFlush)(); (gles.glFlush)();
} }
Ok(()) }
Ok(fd)
}); });
*self.ctx.gfx_ops.borrow_mut() = ops; *self.ctx.gfx_ops.borrow_mut() = ops;
res res
@ -103,7 +109,11 @@ impl GfxFramebuffer for Framebuffer {
(self.gl.width, self.gl.height) (self.gl.width, self.gl.height)
} }
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), GfxError> { fn render(
&self,
ops: Vec<GfxApiOpt>,
clear: Option<&Color>,
) -> Result<Option<SyncFile>, GfxError> {
self.render(ops, clear).map_err(|e| e.into()) self.render(ops, clear).map_err(|e| e.into())
} }

View file

@ -0,0 +1,107 @@
use {
crate::{
gfx_apis::gl::{
egl::context::EglContext,
sys::{
EGLBoolean, EGLSyncKHR, EGL_NONE, EGL_SYNC_NATIVE_FENCE_ANDROID,
EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_TRUE,
},
RenderError,
},
utils::errorfmt::ErrorFmt,
},
std::rc::Rc,
uapi::OwnedFd,
};
pub struct EglSync {
ctx: Rc<EglContext>,
sync: EGLSyncKHR,
}
impl EglContext {
pub fn export_sync_file(self: &Rc<Self>) -> Result<OwnedFd, RenderError> {
self.create_sync(None)?.export_sync_file()
}
pub fn create_sync(self: &Rc<Self>, file: Option<OwnedFd>) -> Result<EglSync, RenderError> {
let mut attribs = [EGL_NONE; 3];
if let Some(file) = &file {
attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID;
attribs[1] = file.raw();
}
self.with_current(|| unsafe {
let sync = self.dpy.procs.eglCreateSyncKHR(
self.dpy.dpy,
EGL_SYNC_NATIVE_FENCE_ANDROID,
attribs.as_ptr(),
);
if sync.is_null() {
Err(RenderError::CreateEglSync)
} else {
if let Some(file) = file {
file.unwrap();
}
Ok(EglSync {
ctx: self.clone(),
sync,
})
}
})
}
}
impl EglSync {
pub fn wait(&self) {
let res = self.ctx.with_current(|| unsafe {
let res = self
.ctx
.dpy
.procs
.eglWaitSyncKHR(self.ctx.dpy.dpy, self.sync, 0);
if res as EGLBoolean == EGL_TRUE {
Ok(())
} else {
Err(RenderError::WaitSync)
}
});
if let Err(e) = res {
log::warn!("Could not insert wait point: {}", ErrorFmt(e));
}
}
pub fn export_sync_file(&self) -> Result<OwnedFd, RenderError> {
self.ctx.with_current(|| unsafe {
let fd = self
.ctx
.dpy
.procs
.eglDupNativeFenceFDANDROID(self.ctx.dpy.dpy, self.sync);
if fd == -1 {
Err(RenderError::ExportSyncFile)
} else {
Ok(OwnedFd::new(fd))
}
})
}
}
impl Drop for EglSync {
fn drop(&mut self) {
let res = self.ctx.with_current(|| unsafe {
let res = self
.ctx
.dpy
.procs
.eglDestroySyncKHR(self.ctx.dpy.dpy, self.sync);
if res == EGL_TRUE {
Ok(())
} else {
Err(RenderError::DestroyEglSync)
}
});
if let Err(e) = res {
log::error!("{}", ErrorFmt(e));
}
}
}

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
format::Format, format::Format,
gfx_api::{GfxApiOpt, GfxError, GfxFramebuffer, GfxImage, GfxTexture}, gfx_api::{GfxApiOpt, GfxError, GfxFramebuffer, GfxImage, GfxTexture, SyncFile},
gfx_apis::vulkan::{ gfx_apis::vulkan::{
allocator::VulkanAllocation, device::VulkanDevice, format::VulkanMaxExtents, allocator::VulkanAllocation, device::VulkanDevice, format::VulkanMaxExtents,
renderer::VulkanRenderer, util::OnDrop, VulkanError, renderer::VulkanRenderer, util::OnDrop, VulkanError,
@ -525,7 +525,11 @@ impl GfxFramebuffer for VulkanImage {
(self.width as _, self.height as _) (self.width as _, self.height as _)
} }
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), GfxError> { fn render(
&self,
ops: Vec<GfxApiOpt>,
clear: Option<&Color>,
) -> Result<Option<SyncFile>, GfxError> {
self.renderer self.renderer
.execute(self, &ops, clear) .execute(self, &ops, clear)
.map_err(|e| e.into()) .map_err(|e| e.into())

View file

@ -3,7 +3,8 @@ use {
async_engine::SpawnedFuture, async_engine::SpawnedFuture,
format::Format, format::Format,
gfx_api::{ gfx_api::{
BufferResv, BufferResvUser, GfxApiOpt, GfxFormat, GfxFramebuffer, GfxTexture, SyncFile, AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxFormat, GfxFramebuffer,
GfxTexture, ReleaseSync, SyncFile,
}, },
gfx_apis::vulkan::{ gfx_apis::vulkan::{
allocator::VulkanAllocator, allocator::VulkanAllocator,
@ -48,6 +49,7 @@ use {
rc::Rc, rc::Rc,
slice, slice,
}, },
uapi::OwnedFd,
}; };
pub struct VulkanRenderer { pub struct VulkanRenderer {
@ -70,6 +72,8 @@ pub struct VulkanRenderer {
pub(super) struct UsedTexture { pub(super) struct UsedTexture {
tex: Rc<VulkanImage>, tex: Rc<VulkanImage>,
resv: Option<Rc<dyn BufferResv>>, resv: Option<Rc<dyn BufferResv>>,
acquire_sync: AcquireSync,
release_sync: ReleaseSync,
} }
#[derive(Default)] #[derive(Default)]
@ -185,6 +189,8 @@ impl VulkanRenderer {
memory.textures.push(UsedTexture { memory.textures.push(UsedTexture {
tex, tex,
resv: c.buffer_resv.clone(), resv: c.buffer_resv.clone(),
acquire_sync: c.acquire_sync.clone(),
release_sync: c.release_sync,
}); });
} }
} }
@ -538,12 +544,11 @@ impl VulkanRenderer {
let import = |infos: &mut Vec<SemaphoreSubmitInfoKHR>, let import = |infos: &mut Vec<SemaphoreSubmitInfoKHR>,
semaphores: &mut Vec<Rc<VulkanSemaphore>>, semaphores: &mut Vec<Rc<VulkanSemaphore>>,
img: &VulkanImage, img: &VulkanImage,
sync: &AcquireSync,
flag: u32| flag: u32|
-> Result<(), VulkanError> { -> Result<(), VulkanError> {
if let VulkanImageMemory::DmaBuf(buf) = &img.ty { if let VulkanImageMemory::DmaBuf(buf) = &img.ty {
for plane in &buf.template.dmabuf.planes { let mut import_sync_file = |fd: OwnedFd| -> Result<(), VulkanError> {
let fd = dma_buf_export_sync_file(&plane.fd, flag)
.map_err(VulkanError::IoctlExportSyncFile)?;
let semaphore = self.allocate_semaphore()?; let semaphore = self.allocate_semaphore()?;
semaphore.import_sync_file(fd)?; semaphore.import_sync_file(fd)?;
infos.push( infos.push(
@ -553,6 +558,22 @@ impl VulkanRenderer {
.build(), .build(),
); );
semaphores.push(semaphore); semaphores.push(semaphore);
Ok(())
};
match sync {
AcquireSync::None => {}
AcquireSync::Implicit { .. } => {
for plane in &buf.template.dmabuf.planes {
let fd = dma_buf_export_sync_file(&plane.fd, flag)
.map_err(VulkanError::IoctlExportSyncFile)?;
import_sync_file(fd)?;
}
}
AcquireSync::SyncFile { sync_file } => {
let fd = uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0)
.map_err(|e| VulkanError::Dupfd(e.into()))?;
import_sync_file(fd)?;
}
} }
} }
Ok(()) Ok(())
@ -562,6 +583,7 @@ impl VulkanRenderer {
&mut memory.wait_semaphore_infos, &mut memory.wait_semaphore_infos,
&mut memory.wait_semaphores, &mut memory.wait_semaphores,
&texture.tex, &texture.tex,
&texture.acquire_sync,
DMA_BUF_SYNC_READ, DMA_BUF_SYNC_READ,
)?; )?;
} }
@ -569,6 +591,7 @@ impl VulkanRenderer {
&mut memory.wait_semaphore_infos, &mut memory.wait_semaphore_infos,
&mut memory.wait_semaphores, &mut memory.wait_semaphores,
fb, fb,
&AcquireSync::Implicit,
DMA_BUF_SYNC_WRITE, DMA_BUF_SYNC_WRITE,
)?; )?;
Ok(()) Ok(())
@ -580,20 +603,31 @@ impl VulkanRenderer {
Some(sync_file) => sync_file, Some(sync_file) => sync_file,
_ => return, _ => return,
}; };
let import = |img: &VulkanImage, resv: Option<Rc<dyn BufferResv>>, flag: u32| { let import =
|img: &VulkanImage, sync: ReleaseSync, resv: Option<Rc<dyn BufferResv>>, flag: u32| {
if sync == ReleaseSync::None {
return;
}
if let Some(resv) = resv { if let Some(resv) = resv {
resv.set_sync_file(self.buffer_resv_user, sync_file); resv.set_sync_file(self.buffer_resv_user, sync_file);
} else if let VulkanImageMemory::DmaBuf(buf) = &img.ty { } else if sync == ReleaseSync::Implicit {
if let VulkanImageMemory::DmaBuf(buf) = &img.ty {
if let Err(e) = buf.template.dmabuf.import_sync_file(flag, sync_file) { if let Err(e) = buf.template.dmabuf.import_sync_file(flag, sync_file) {
log::error!("Could not import sync file into dmabuf: {}", ErrorFmt(e)); log::error!("Could not import sync file into dmabuf: {}", ErrorFmt(e));
log::warn!("Relying on implicit sync"); log::warn!("Relying on implicit sync");
} }
} }
}
}; };
for texture in &mut memory.textures { for texture in &mut memory.textures {
import(&texture.tex, texture.resv.take(), DMA_BUF_SYNC_READ); import(
&texture.tex,
texture.release_sync,
texture.resv.take(),
DMA_BUF_SYNC_READ,
);
} }
import(fb, None, DMA_BUF_SYNC_WRITE); import(fb, ReleaseSync::Implicit, None, DMA_BUF_SYNC_WRITE);
} }
fn submit(&self, buf: CommandBuffer) -> Result<(), VulkanError> { fn submit(&self, buf: CommandBuffer) -> Result<(), VulkanError> {
@ -656,7 +690,7 @@ impl VulkanRenderer {
}); });
self.pending_frames.set(frame.point, frame.clone()); self.pending_frames.set(frame.point, frame.clone());
let future = self.device.instance.eng.spawn(await_release( let future = self.device.instance.eng.spawn(await_release(
memory.release_sync_file.take(), memory.release_sync_file.clone(),
self.device.instance.ring.clone(), self.device.instance.ring.clone(),
frame.clone(), frame.clone(),
self.clone(), self.clone(),
@ -699,7 +733,13 @@ impl VulkanRenderer {
true, true,
)?; )?;
(&*tmp_tex as &dyn GfxFramebuffer) (&*tmp_tex as &dyn GfxFramebuffer)
.copy_texture(&(tex.clone() as _), x, y) .copy_texture(
&(tex.clone() as _),
AcquireSync::None,
ReleaseSync::None,
x,
y,
)
.map_err(VulkanError::GfxError)?; .map_err(VulkanError::GfxError)?;
self.read_all_pixels(&tmp_tex, stride, dst) self.read_all_pixels(&tmp_tex, stride, dst)
} }
@ -839,9 +879,9 @@ impl VulkanRenderer {
fb: &VulkanImage, fb: &VulkanImage,
opts: &[GfxApiOpt], opts: &[GfxApiOpt],
clear: Option<&Color>, clear: Option<&Color>,
) -> Result<(), VulkanError> { ) -> Result<Option<SyncFile>, VulkanError> {
let res = self.try_execute(fb, opts, clear); let res = self.try_execute(fb, opts, clear);
{ let sync_file = {
let mut memory = self.memory.borrow_mut(); let mut memory = self.memory.borrow_mut();
memory.flush.clear(); memory.flush.clear();
memory.textures.clear(); memory.textures.clear();
@ -849,9 +889,9 @@ impl VulkanRenderer {
memory.sample.clear(); memory.sample.clear();
memory.wait_semaphores.clear(); memory.wait_semaphores.clear();
memory.release_fence.take(); memory.release_fence.take();
memory.release_sync_file.take(); memory.release_sync_file.take()
} };
res res.map(|_| sync_file)
} }
fn allocate_command_buffer(&self) -> Result<Rc<VulkanCommandBuffer>, VulkanError> { fn allocate_command_buffer(&self) -> Result<Rc<VulkanCommandBuffer>, VulkanError> {

View file

@ -47,8 +47,8 @@ impl VulkanSemaphore {
.external_semaphore_fd .external_semaphore_fd
.import_semaphore_fd(&fd_info) .import_semaphore_fd(&fd_info)
}; };
mem::forget(sync_file);
res.map_err(VulkanError::ImportSyncFile)?; res.map_err(VulkanError::ImportSyncFile)?;
mem::forget(sync_file);
Ok(()) Ok(())
} }
} }

View file

@ -306,7 +306,8 @@ impl WlSeatGlobal {
transform, transform,
); );
match res { match res {
Ok(_) => { Ok(sync_file) => {
hc.set_sync_file(sync_file);
hc.swap_buffer(); hc.swap_buffer();
} }
Err(e) => { Err(e) => {

View file

@ -16,7 +16,7 @@ use {
client::{Client, ClientError, RequestParser}, client::{Client, ClientError, RequestParser},
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
fixed::Fixed, fixed::Fixed,
gfx_api::{BufferResv, BufferResvUser, SampleRect, SyncFile}, gfx_api::{AcquireSync, BufferResv, BufferResvUser, SampleRect, SyncFile},
ifs::{ ifs::{
wl_buffer::WlBuffer, wl_buffer::WlBuffer,
wl_callback::WlCallback, wl_callback::WlCallback,
@ -136,6 +136,7 @@ impl NodeVisitorBase for SurfaceSendPreferredTransformVisitor {
pub struct SurfaceBuffer { pub struct SurfaceBuffer {
pub buffer: Rc<WlBuffer>, pub buffer: Rc<WlBuffer>,
sync_files: SmallMap<BufferResvUser, SyncFile, 1>, sync_files: SmallMap<BufferResvUser, SyncFile, 1>,
pub sync: AcquireSync,
} }
impl Drop for SurfaceBuffer { impl Drop for SurfaceBuffer {
@ -837,6 +838,7 @@ impl WlSurface {
let surface_buffer = SurfaceBuffer { let surface_buffer = SurfaceBuffer {
buffer, buffer,
sync_files: Default::default(), sync_files: Default::default(),
sync: AcquireSync::Implicit,
}; };
self.buffer.set(Some(Rc::new(surface_buffer))); self.buffer.set(Some(Rc::new(surface_buffer)));
self.buf_x.fetch_add(dx); self.buf_x.fetch_add(dx);

View file

@ -4,7 +4,7 @@ use {
cursor::KnownCursor, cursor::KnownCursor,
fixed::Fixed, fixed::Fixed,
format::ARGB8888, format::ARGB8888,
gfx_api::{GfxContext, GfxFramebuffer}, gfx_api::{AcquireSync, GfxContext, GfxFramebuffer, ReleaseSync},
ifs::zwlr_layer_shell_v1::OVERLAY, ifs::zwlr_layer_shell_v1::OVERLAY,
portal::ptl_display::{PortalDisplay, PortalOutput, PortalSeat}, portal::ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
renderer::renderer_base::RendererBase, renderer::renderer_base::RendererBase,
@ -223,6 +223,8 @@ impl GuiElement for Button {
r.scale(), r.scale(),
None, None,
None, None,
AcquireSync::None,
ReleaseSync::None,
); );
} }
} }
@ -325,6 +327,8 @@ impl GuiElement for Label {
r.scale(), r.scale(),
None, None,
None, None,
AcquireSync::None,
ReleaseSync::None,
); );
} }
} }

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
gfx_api::{GfxApiOpt, SampleRect}, gfx_api::{AcquireSync, GfxApiOpt, ReleaseSync, SampleRect},
ifs::{ ifs::{
wl_callback::WlCallback, wl_callback::WlCallback,
wl_surface::{ wl_surface::{
@ -151,13 +151,33 @@ impl Renderer<'_> {
let scale = output.global.persistent.scale.get(); let scale = output.global.persistent.scale.get();
for title in &rd.titles { for title in &rd.titles {
let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y); let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y);
self.base self.base.render_texture(
.render_texture(&title.tex, x, y, None, None, scale, None, None); &title.tex,
x,
y,
None,
None,
scale,
None,
None,
AcquireSync::None,
ReleaseSync::None,
);
} }
if let Some(status) = &rd.status { if let Some(status) = &rd.status {
let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y); let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y);
self.base self.base.render_texture(
.render_texture(&status.tex.texture, x, y, None, None, scale, None, None); &status.tex.texture,
x,
y,
None,
None,
scale,
None,
None,
AcquireSync::None,
ReleaseSync::None,
);
} }
} }
if let Some(ws) = output.workspace.get() { if let Some(ws) = output.workspace.get() {
@ -193,8 +213,18 @@ impl Renderer<'_> {
let (tex_width, tex_height) = tex.texture.size(); let (tex_width, tex_height) = tex.texture.size();
let x = x + (pos.width() - tex_width) / 2; let x = x + (pos.width() - tex_width) / 2;
let y = y + (pos.height() - tex_height) / 2; let y = y + (pos.height() - tex_height) / 2;
self.base self.base.render_texture(
.render_texture(&tex.texture, x, y, None, None, self.base.scale, None, None); &tex.texture,
x,
y,
None,
None,
self.base.scale,
None,
None,
AcquireSync::None,
ReleaseSync::None,
);
} }
} }
@ -232,6 +262,8 @@ impl Renderer<'_> {
self.base.scale, self.base.scale,
None, None,
None, None,
AcquireSync::None,
ReleaseSync::None,
); );
} }
} }
@ -354,6 +386,10 @@ impl Renderer<'_> {
bounds: Option<&Rect>, bounds: Option<&Rect>,
) { ) {
if let Some(tex) = buffer.buffer.texture.get() { if let Some(tex) = buffer.buffer.texture.get() {
let release_sync = match buffer.sync {
AcquireSync::Implicit => ReleaseSync::Implicit,
AcquireSync::None | AcquireSync::SyncFile { .. } => ReleaseSync::Explicit,
};
self.base.render_texture( self.base.render_texture(
&tex, &tex,
x, x,
@ -363,6 +399,8 @@ impl Renderer<'_> {
self.base.scale, self.base.scale,
bounds, bounds,
Some(buffer.clone()), Some(buffer.clone()),
buffer.sync.clone(),
release_sync,
); );
} else if let Some(color) = &buffer.buffer.color { } else if let Some(color) = &buffer.buffer.color {
if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) {
@ -420,6 +458,8 @@ impl Renderer<'_> {
self.base.scale, self.base.scale,
None, None,
None, None,
AcquireSync::None,
ReleaseSync::None,
); );
} }
let body = Rect::new_sized( let body = Rect::new_sized(

View file

@ -1,7 +1,8 @@
use { use {
crate::{ crate::{
gfx_api::{ gfx_api::{
BufferResv, CopyTexture, FillRect, FramebufferRect, GfxApiOpt, GfxTexture, SampleRect, AcquireSync, BufferResv, CopyTexture, FillRect, FramebufferRect, GfxApiOpt, GfxTexture,
ReleaseSync, SampleRect,
}, },
rect::Rect, rect::Rect,
scale::Scale, scale::Scale,
@ -133,6 +134,8 @@ impl RendererBase<'_> {
tscale: Scale, tscale: Scale,
bounds: Option<&Rect>, bounds: Option<&Rect>,
buffer_resv: Option<Rc<dyn BufferResv>>, buffer_resv: Option<Rc<dyn BufferResv>>,
acquire_sync: AcquireSync,
release_sync: ReleaseSync,
) { ) {
let mut texcoord = tpoints.unwrap_or_else(SampleRect::identity); let mut texcoord = tpoints.unwrap_or_else(SampleRect::identity);
@ -172,6 +175,8 @@ impl RendererBase<'_> {
source: texcoord, source: texcoord,
target, target,
buffer_resv, buffer_resv,
acquire_sync,
release_sync,
})); }));
} }
} }

View file

@ -17,7 +17,10 @@ use {
fixed::Fixed, fixed::Fixed,
forker::ForkerProxy, forker::ForkerProxy,
format::Format, format::Format,
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture, SampleRect}, gfx_api::{
AcquireSync, GfxContext, GfxError, GfxFramebuffer, GfxTexture, ReleaseSync, SampleRect,
SyncFile,
},
gfx_apis::create_gfx_context, gfx_apis::create_gfx_context,
globals::{Globals, GlobalsError, WaylandGlobal}, globals::{Globals, GlobalsError, WaylandGlobal},
ifs::{ ifs::{
@ -770,8 +773,8 @@ impl State {
tex: &Rc<dyn GfxTexture>, tex: &Rc<dyn GfxTexture>,
rr: &mut RenderResult, rr: &mut RenderResult,
render_hw_cursor: bool, render_hw_cursor: bool,
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
fb.render_output( let sync_file = fb.render_output(
output, output,
self, self,
Some(output.global.pos.get()), Some(output.global.pos.get()),
@ -781,7 +784,7 @@ impl State {
)?; )?;
output.perform_screencopies(tex, !render_hw_cursor, 0, 0, None); output.perform_screencopies(tex, !render_hw_cursor, 0, 0, None);
rr.dispatch_frame_requests(); rr.dispatch_frame_requests();
Ok(()) Ok(sync_file)
} }
pub fn perform_screencopy( pub fn perform_screencopy(
@ -794,7 +797,7 @@ impl State {
y_off: i32, y_off: i32,
size: Option<(i32, i32)>, size: Option<(i32, i32)>,
transform: Transform, transform: Transform,
) -> Result<(), GfxError> { ) -> Result<Option<SyncFile>, GfxError> {
let mut ops = target.take_render_ops(); let mut ops = target.take_render_ops();
let mut renderer = Renderer { let mut renderer = Renderer {
base: target.renderer_base(&mut ops, Scale::from_int(1), Transform::None), base: target.renderer_base(&mut ops, Scale::from_int(1), Transform::None),
@ -817,6 +820,8 @@ impl State {
Scale::from_int(1), Scale::from_int(1),
None, None,
None, None,
AcquireSync::None,
ReleaseSync::Implicit,
); );
if render_hardware_cursors { if render_hardware_cursors {
for seat in self.globals.lock_seats().values() { for seat in self.globals.lock_seats().values() {