use {
crate::{
gfx_apis::gl::{
RenderError,
egl::context::EglContext,
sys::{
EGL_NONE, EGL_SYNC_NATIVE_FENCE_ANDROID, EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
EGL_TRUE, EGLBoolean, EGLSyncKHR,
},
},
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));
}
}
}