1use std::rc::Rc;
7
8use crate::{
9 buffer::{Buffer, Content},
10 texture::TextureAny,
11 Context, ContextExt, GlObject,
12};
13
14use crate::{backend::Facade, context::CommandContext, gl};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum SemaphoreCreationError {
19 SemaphoreObjectNotSupported,
21 SemaphoreObjectFdNotSupported,
23 NullResult,
25}
26
27impl std::fmt::Display for SemaphoreCreationError {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 use self::SemaphoreCreationError::*;
30
31 let desc = match *self {
32 SemaphoreObjectNotSupported => "Driver does not support EXT_semaphore",
33 SemaphoreObjectFdNotSupported => "Driver does not support EXT_semaphore_fd",
34 NullResult => "OpenGL returned a null pointer when creating semaphore",
35 };
36 f.write_str(desc)
37 }
38}
39
40impl std::error::Error for SemaphoreCreationError {}
41
42#[derive(Debug, Clone, Copy)]
44pub enum TextureLayout {
45 None,
47 General,
49 ColorAttachment,
51 DepthStencilAttachment,
53 DepthStencilReadOnly,
55 ShaderReadOnly,
57 TransferSrc,
59 TransferDst,
61 DepthReadOnlyStencilAttachment,
63 DepthAttachmentStencilReadOnly,
65}
66
67impl Into<crate::gl::types::GLenum> for TextureLayout {
68 fn into(self) -> crate::gl::types::GLenum {
69 match self {
70 TextureLayout::None => gl::NONE,
71 TextureLayout::General => gl::LAYOUT_GENERAL_EXT,
72 TextureLayout::ColorAttachment => gl::LAYOUT_COLOR_ATTACHMENT_EXT,
73 TextureLayout::DepthStencilAttachment => gl::LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT,
74 TextureLayout::DepthStencilReadOnly => gl::LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT,
75 TextureLayout::ShaderReadOnly => gl::LAYOUT_SHADER_READ_ONLY_EXT,
76 TextureLayout::TransferSrc => gl::LAYOUT_TRANSFER_SRC_EXT,
77 TextureLayout::TransferDst => gl::LAYOUT_TRANSFER_DST_EXT,
78 TextureLayout::DepthReadOnlyStencilAttachment => gl::LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT,
79 TextureLayout::DepthAttachmentStencilReadOnly => {
80 gl::LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT
81 }
82 }
83 }
84}
85
86pub struct Semaphore {
88 context: Rc<Context>,
89 id: gl::types::GLuint,
90}
91
92impl Semaphore {
93 #[cfg(target_os = "linux")]
95 pub unsafe fn new_from_fd<F: Facade + ?Sized>(
96 facade: &F,
97 fd: std::fs::File,
98 ) -> Result<Self, SemaphoreCreationError> {
99 use std::os::unix::io::AsRawFd;
100
101 let ctxt = facade.get_context().make_current();
102 let sem = Self::new(facade, &ctxt)?;
103
104 if ctxt.extensions.gl_ext_semaphore_fd {
105 ctxt.gl
106 .ImportSemaphoreFdEXT(sem.id, gl::HANDLE_TYPE_OPAQUE_FD_EXT, fd.as_raw_fd());
107
108 if ctxt.gl.IsSemaphoreEXT(sem.id) == gl::FALSE {
109 Err(SemaphoreCreationError::NullResult)
110 } else {
111 std::mem::forget(fd);
112
113 Ok(sem)
114 }
115 } else {
116 Err(SemaphoreCreationError::SemaphoreObjectFdNotSupported)
117 }
118 }
119
120 fn new<F: Facade + ?Sized>(
121 facade: &F,
122 ctxt: &CommandContext<'_>,
123 ) -> Result<Self, SemaphoreCreationError> {
124 if ctxt.extensions.gl_ext_semaphore {
125 let id = unsafe {
126 let mut id: gl::types::GLuint = 0;
127 ctxt.gl.GenSemaphoresEXT(1, &mut id as *mut u32);
128 id
129 };
130
131 Ok(Self {
132 context: facade.get_context().clone(),
133 id,
134 })
135 } else {
136 Err(SemaphoreCreationError::SemaphoreObjectNotSupported)
137 }
138 }
139 pub fn wait_textures(&self, textures: Option<&[(&TextureAny, TextureLayout)]>) {
141 self.wait::<u32>(textures, None)
143 }
144
145 pub fn wait<T: ?Sized>(
155 &self,
156 textures: Option<&[(&TextureAny, TextureLayout)]>,
157 buffers: Option<&[&Buffer<T>]>,
158 ) where
159 T: Content,
160 {
161 let ctxt = self.context.get_context().make_current();
162
163 let (buffer_ids, buffer_num, _) = if let Some(buffs) = buffers {
164 let ids = buffs.iter().map(|b| b.get_id()).collect::<Vec<_>>();
165 (ids.as_ptr(), buffs.len(), Some(ids))
166 } else {
167 (std::ptr::null(), 0, None)
168 };
169
170 let (texture_ids, texture_layouts, textures_num, _, _) = if let Some(textures) = textures {
171 let ids = textures.iter().map(|t| t.0.get_id()).collect::<Vec<_>>();
172 let layouts = textures
173 .iter()
174 .map(|t| t.1.into())
175 .collect::<Vec<gl::types::GLenum>>();
176 (
177 ids.as_ptr(),
178 layouts.as_ptr(),
179 textures.len(),
180 Some(ids),
181 Some(layouts),
182 )
183 } else {
184 (std::ptr::null(), std::ptr::null(), 0, None, None)
185 };
186
187 unsafe {
188 ctxt.gl.WaitSemaphoreEXT(
189 self.id,
190 buffer_num as u32,
191 buffer_ids,
192 textures_num as u32,
193 texture_ids,
194 texture_layouts,
195 )
196 }
197 }
198
199 pub fn signal_textures(&self, textures: Option<&[(&TextureAny, TextureLayout)]>) {
201 self.signal::<u32>(textures, None)
203 }
204
205 pub fn signal<T: ?Sized>(
209 &self,
210 textures: Option<&[(&TextureAny, TextureLayout)]>,
211 buffers: Option<&[&Buffer<T>]>,
212 ) where
213 T: Content,
214 {
215 let ctxt = self.context.get_context().make_current();
216
217 let (buffer_ids, buffer_num, _) = if let Some(buffs) = buffers {
218 let ids = buffs.iter().map(|b| b.get_id()).collect::<Vec<_>>();
219 (ids.as_ptr(), buffs.len(), Some(ids))
220 } else {
221 (std::ptr::null(), 0, None)
222 };
223
224 let (texture_ids, texture_layouts, textures_num, _, _) = if let Some(textures) = textures {
225 let ids = textures.iter().map(|t| t.0.get_id()).collect::<Vec<_>>();
226 let layouts = textures
227 .iter()
228 .map(|t| t.1.into())
229 .collect::<Vec<gl::types::GLenum>>();
230 (
231 ids.as_ptr(),
232 layouts.as_ptr(),
233 textures.len(),
234 Some(ids),
235 Some(layouts),
236 )
237 } else {
238 (std::ptr::null(), std::ptr::null(), 0, None, None)
239 };
240
241 unsafe {
242 ctxt.gl.SignalSemaphoreEXT(
243 self.id,
244 buffer_num as u32,
245 buffer_ids,
246 textures_num as u32,
247 texture_ids,
248 texture_layouts,
249 );
250 ctxt.gl.Flush(); }
252 }
253}
254
255impl GlObject for Semaphore {
256 type Id = gl::types::GLuint;
257
258 #[inline]
259 fn get_id(&self) -> gl::types::GLuint {
260 self.id
261 }
262}
263
264impl Drop for Semaphore {
265 fn drop(&mut self) {
266 let ctxt = self.context.get_context().make_current();
267 unsafe { ctxt.gl.DeleteSemaphoresEXT(1, &mut self.id as *mut u32) };
268 }
269}