use std::rc::Rc;
use crate::{
buffer::{Buffer, Content},
texture::TextureAny,
Context, ContextExt, GlObject,
};
use crate::{backend::Facade, context::CommandContext, gl};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SemaphoreCreationError {
SemaphoreObjectNotSupported,
SemaphoreObjectFdNotSupported,
NullResult,
}
impl std::fmt::Display for SemaphoreCreationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use self::SemaphoreCreationError::*;
let desc = match *self {
SemaphoreObjectNotSupported => "Driver does not support EXT_semaphore",
SemaphoreObjectFdNotSupported => "Driver does not support EXT_semaphore_fd",
NullResult => "OpenGL returned a null pointer when creating semaphore",
};
f.write_str(desc)
}
}
impl std::error::Error for SemaphoreCreationError {}
#[derive(Debug, Clone, Copy)]
pub enum TextureLayout {
None,
General,
ColorAttachment,
DepthStencilAttachment,
DepthStencilReadOnly,
ShaderReadOnly,
TransferSrc,
TransferDst,
DepthReadOnlyStencilAttachment,
DepthAttachmentStencilReadOnly,
}
impl Into<crate::gl::types::GLenum> for TextureLayout {
fn into(self) -> crate::gl::types::GLenum {
match self {
TextureLayout::None => gl::NONE,
TextureLayout::General => gl::LAYOUT_GENERAL_EXT,
TextureLayout::ColorAttachment => gl::LAYOUT_COLOR_ATTACHMENT_EXT,
TextureLayout::DepthStencilAttachment => gl::LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT,
TextureLayout::DepthStencilReadOnly => gl::LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT,
TextureLayout::ShaderReadOnly => gl::LAYOUT_SHADER_READ_ONLY_EXT,
TextureLayout::TransferSrc => gl::LAYOUT_TRANSFER_SRC_EXT,
TextureLayout::TransferDst => gl::LAYOUT_TRANSFER_DST_EXT,
TextureLayout::DepthReadOnlyStencilAttachment => gl::LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT,
TextureLayout::DepthAttachmentStencilReadOnly => {
gl::LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT
}
}
}
}
pub struct Semaphore {
context: Rc<Context>,
id: gl::types::GLuint,
}
impl Semaphore {
#[cfg(target_os = "linux")]
pub unsafe fn new_from_fd<F: Facade + ?Sized>(
facade: &F,
fd: std::fs::File,
) -> Result<Self, SemaphoreCreationError> {
use std::os::unix::io::AsRawFd;
let ctxt = facade.get_context().make_current();
let sem = Self::new(facade, &ctxt)?;
if ctxt.extensions.gl_ext_semaphore_fd {
ctxt.gl
.ImportSemaphoreFdEXT(sem.id, gl::HANDLE_TYPE_OPAQUE_FD_EXT, fd.as_raw_fd());
if ctxt.gl.IsSemaphoreEXT(sem.id) == gl::FALSE {
Err(SemaphoreCreationError::NullResult)
} else {
Ok(sem)
}
} else {
Err(SemaphoreCreationError::SemaphoreObjectFdNotSupported)
}
}
fn new<F: Facade + ?Sized>(
facade: &F,
ctxt: &CommandContext<'_>,
) -> Result<Self, SemaphoreCreationError> {
if ctxt.extensions.gl_ext_semaphore {
let id = unsafe {
let mut id: gl::types::GLuint = 0;
ctxt.gl.GenSemaphoresEXT(1, &mut id as *mut u32);
id
};
Ok(Self {
context: facade.get_context().clone(),
id,
})
} else {
Err(SemaphoreCreationError::SemaphoreObjectNotSupported)
}
}
pub fn wait_textures(&self, textures: Option<&[(&TextureAny, TextureLayout)]>) {
self.wait::<u32>(textures, None)
}
pub fn wait<T: ?Sized>(
&self,
textures: Option<&[(&TextureAny, TextureLayout)]>,
buffers: Option<&[&Buffer<T>]>,
) where
T: Content,
{
let ctxt = self.context.get_context().make_current();
let (buffer_ids, buffer_num, _) = if let Some(buffs) = buffers {
let ids = buffs.iter().map(|b| b.get_id()).collect::<Vec<_>>();
(ids.as_ptr(), buffs.len(), Some(ids))
} else {
(std::ptr::null(), 0, None)
};
let (texture_ids, texture_layouts, textures_num, _, _) = if let Some(textures) = textures {
let ids = textures.iter().map(|t| t.0.get_id()).collect::<Vec<_>>();
let layouts = textures
.iter()
.map(|t| t.1.into())
.collect::<Vec<gl::types::GLenum>>();
(
ids.as_ptr(),
layouts.as_ptr(),
textures.len(),
Some(ids),
Some(layouts),
)
} else {
(std::ptr::null(), std::ptr::null(), 0, None, None)
};
unsafe {
ctxt.gl.WaitSemaphoreEXT(
self.id,
buffer_num as u32,
buffer_ids,
textures_num as u32,
texture_ids,
texture_layouts,
)
}
}
pub fn signal_textures(&self, textures: Option<&[(&TextureAny, TextureLayout)]>) {
self.signal::<u32>(textures, None)
}
pub fn signal<T: ?Sized>(
&self,
textures: Option<&[(&TextureAny, TextureLayout)]>,
buffers: Option<&[&Buffer<T>]>,
) where
T: Content,
{
let ctxt = self.context.get_context().make_current();
let (buffer_ids, buffer_num, _) = if let Some(buffs) = buffers {
let ids = buffs.iter().map(|b| b.get_id()).collect::<Vec<_>>();
(ids.as_ptr(), buffs.len(), Some(ids))
} else {
(std::ptr::null(), 0, None)
};
let (texture_ids, texture_layouts, textures_num, _, _) = if let Some(textures) = textures {
let ids = textures.iter().map(|t| t.0.get_id()).collect::<Vec<_>>();
let layouts = textures
.iter()
.map(|t| t.1.into())
.collect::<Vec<gl::types::GLenum>>();
(
ids.as_ptr(),
layouts.as_ptr(),
textures.len(),
Some(ids),
Some(layouts),
)
} else {
(std::ptr::null(), std::ptr::null(), 0, None, None)
};
unsafe {
ctxt.gl.SignalSemaphoreEXT(
self.id,
buffer_num as u32,
buffer_ids,
textures_num as u32,
texture_ids,
texture_layouts,
);
ctxt.gl.Flush(); }
}
}
impl GlObject for Semaphore {
type Id = gl::types::GLuint;
#[inline]
fn get_id(&self) -> gl::types::GLuint {
self.id
}
}
impl Drop for Semaphore {
fn drop(&mut self) {
let ctxt = self.context.get_context().make_current();
unsafe { ctxt.gl.DeleteSemaphoresEXT(1, &mut self.id as *mut u32) };
}
}