1#![allow(missing_docs)]
24
25use crate::device::Device as DeviceAPI;
26use crate::{ContextID, Error, SurfaceAccess, SurfaceInfo, SurfaceType};
27use euclid::default::Size2D;
28use fnv::{FnvHashMap, FnvHashSet};
29use glow as gl;
30use glow::Context as Gl;
31use glow::HasContext;
32use log::debug;
33use std::collections::hash_map::Entry;
34use std::fmt::Debug;
35use std::hash::Hash;
36use std::mem;
37use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
38
39struct SwapChainData<Device: DeviceAPI> {
41 size: Size2D<i32>,
43 context_id: ContextID,
45 surface_access: SurfaceAccess,
47 back_buffer: BackBuffer<Device>,
49 pending_surface: Option<Device::Surface>,
51 recycled_surfaces: Vec<Device::Surface>,
53}
54
55pub enum PreserveBuffer<'a> {
56 Yes(&'a Gl),
57 No,
58}
59
60enum BackBuffer<Device: DeviceAPI> {
61 Attached,
62 Detached(Device::Surface),
63 TakenAttached,
64 TakenDetached,
65}
66
67impl<Device: DeviceAPI> BackBuffer<Device> {
68 fn take_surface(
69 &mut self,
70 device: &Device,
71 context: &mut Device::Context,
72 ) -> Result<Device::Surface, Error> {
73 let new_back_buffer = match self {
74 BackBuffer::Attached => BackBuffer::TakenAttached,
75 BackBuffer::Detached(_) => BackBuffer::TakenDetached,
76 _ => return Err(Error::Failed),
77 };
78 let surface = match mem::replace(self, new_back_buffer) {
79 BackBuffer::Attached => device.unbind_surface_from_context(context)?.unwrap(),
80 BackBuffer::Detached(surface) => surface,
81 _ => unreachable!(),
82 };
83 Ok(surface)
84 }
85 fn take_surface_texture(
86 &mut self,
87 device: &Device,
88 context: &mut Device::Context,
89 ) -> Result<Device::SurfaceTexture, Error> {
90 let surface = self.take_surface(device, context)?;
91 device
92 .create_surface_texture(context, surface)
93 .map_err(|(err, surface)| {
94 let _ = self.replace_surface(device, context, surface);
95 err
96 })
97 }
98 fn replace_surface(
99 &mut self,
100 device: &Device,
101 context: &mut Device::Context,
102 surface: Device::Surface,
103 ) -> Result<(), Error> {
104 let new_back_buffer = match self {
105 BackBuffer::TakenAttached => {
106 if let Err((err, mut surface)) = device.bind_surface_to_context(context, surface) {
107 debug!("Oh no, destroying surface");
108 let _ = device.destroy_surface(context, &mut surface);
109 return Err(err);
110 }
111 BackBuffer::Attached
112 }
113 BackBuffer::TakenDetached => BackBuffer::Detached(surface),
114 _ => return Err(Error::Failed),
115 };
116 *self = new_back_buffer;
117 Ok(())
118 }
119 fn replace_surface_texture(
120 &mut self,
121 device: &Device,
122 context: &mut Device::Context,
123 surface_texture: Device::SurfaceTexture,
124 ) -> Result<(), Error> {
125 let surface = device
126 .destroy_surface_texture(context, surface_texture)
127 .map_err(|(err, _)| err)?;
128 self.replace_surface(device, context, surface)
129 }
130}
131
132impl<Device: DeviceAPI> SwapChainData<Device> {
133 fn validate_context(&self, device: &Device, context: &Device::Context) -> Result<(), Error> {
135 if self.context_id == device.context_id(context) {
136 Ok(())
137 } else {
138 Err(Error::IncompatibleContext)
139 }
140 }
141
142 fn swap_buffers(
146 &mut self,
147 device: &mut Device,
148 context: &mut Device::Context,
149 preserve_buffer: PreserveBuffer<'_>,
150 ) -> Result<(), Error> {
151 debug!("Swap buffers on context {:?}", self.context_id);
152 self.validate_context(device, context)?;
153
154 if let Some(old_front_buffer) = self.pending_surface.take() {
156 let SurfaceInfo { id, size, .. } = device.surface_info(&old_front_buffer);
157 debug!(
158 "Recycling surface {:?} ({:?}) for context {:?}",
159 id, size, self.context_id
160 );
161 self.recycle_surface(old_front_buffer);
162 }
163
164 let new_back_buffer = self
166 .recycled_surfaces
167 .iter()
168 .position(|surface| device.surface_info(surface).size == self.size)
169 .map(|index| {
170 debug!("Recycling surface for context {:?}", self.context_id);
171 Ok(self.recycled_surfaces.swap_remove(index))
172 })
173 .unwrap_or_else(|| {
174 debug!(
175 "Creating a new surface ({:?}) for context {:?}",
176 self.size, self.context_id
177 );
178 let surface_type = SurfaceType::Generic { size: self.size };
179 device.create_surface(context, self.surface_access, surface_type)
180 })?;
181
182 let back_info = device.surface_info(&new_back_buffer);
183
184 debug!(
186 "Surface {:?} is the new back buffer for context {:?}",
187 device.surface_info(&new_back_buffer).id,
188 self.context_id
189 );
190 let new_front_buffer = self.back_buffer.take_surface(device, context)?;
191 self.back_buffer
192 .replace_surface(device, context, new_back_buffer)?;
193
194 if let PreserveBuffer::Yes(gl) = preserve_buffer {
195 let front_info = device.surface_info(&new_front_buffer);
196 unsafe {
197 gl.bind_framebuffer(gl::READ_FRAMEBUFFER, front_info.framebuffer_object);
198 debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
199 gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, back_info.framebuffer_object);
200 debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
201 gl.blit_framebuffer(
202 0,
203 0,
204 front_info.size.width,
205 front_info.size.height,
206 0,
207 0,
208 back_info.size.width,
209 back_info.size.height,
210 gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT,
211 gl::NEAREST,
212 );
213 debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
214 }
215 }
216
217 debug!(
219 "Surface {:?} is the new front buffer for context {:?}",
220 device.surface_info(&new_front_buffer).id,
221 self.context_id
222 );
223 self.pending_surface = Some(new_front_buffer);
224 for mut surface in self.recycled_surfaces.drain(..) {
225 debug!("Destroying a surface for context {:?}", self.context_id);
226 device.destroy_surface(context, &mut surface)?;
227 }
228
229 Ok(())
230 }
231
232 fn take_attachment_from(
237 &mut self,
238 device: &mut Device,
239 context: &mut Device::Context,
240 other: &mut SwapChainData<Device>,
241 ) -> Result<(), Error> {
242 self.validate_context(device, context)?;
243 other.validate_context(device, context)?;
244 let our_surface = self.back_buffer.take_surface(device, context)?;
245 let their_surface = other.back_buffer.take_surface(device, context)?;
246 mem::swap(&mut self.back_buffer, &mut other.back_buffer);
247 self.back_buffer
248 .replace_surface(device, context, our_surface)?;
249 other
250 .back_buffer
251 .replace_surface(device, context, their_surface)?;
252 Ok(())
253 }
254
255 fn resize(
262 &mut self,
263 device: &mut Device,
264 context: &mut Device::Context,
265 size: Size2D<i32>,
266 ) -> Result<(), Error> {
267 debug!(
268 "Resizing context {:?} to {:?}",
269 device.context_id(context),
270 size
271 );
272 self.validate_context(device, context)?;
273 if (size.width < 1) || (size.height < 1) {
274 return Err(Error::Failed);
275 }
276 let surface_type = SurfaceType::Generic { size };
277 let new_back_buffer = device.create_surface(context, self.surface_access, surface_type)?;
278 let mut old_back_buffer = self.back_buffer.take_surface(device, context)?;
279 self.back_buffer
280 .replace_surface(device, context, new_back_buffer)?;
281 device.destroy_surface(context, &mut old_back_buffer)?;
282 self.size = size;
283 Ok(())
284 }
285
286 fn size(&self) -> Size2D<i32> {
289 self.size
290 }
291
292 fn take_surface_texture(
295 &mut self,
296 device: &Device,
297 context: &mut Device::Context,
298 ) -> Result<Device::SurfaceTexture, Error> {
299 self.validate_context(device, context)?;
300 self.back_buffer.take_surface_texture(device, context)
301 }
302
303 fn recycle_surface_texture(
306 &mut self,
307 device: &Device,
308 context: &mut Device::Context,
309 surface_texture: Device::SurfaceTexture,
310 ) -> Result<(), Error> {
311 self.validate_context(device, context)?;
312 self.back_buffer
313 .replace_surface_texture(device, context, surface_texture)
314 }
315
316 fn take_surface(&mut self) -> Option<Device::Surface> {
320 self.pending_surface
321 .take()
322 .or_else(|| self.recycled_surfaces.pop())
323 }
324
325 fn take_pending_surface(&mut self) -> Option<Device::Surface> {
329 self.pending_surface.take()
330 }
331
332 fn recycle_surface(&mut self, surface: Device::Surface) {
335 self.recycled_surfaces.push(surface)
336 }
337
338 fn clear_surface(
342 &mut self,
343 device: &mut Device,
344 context: &mut Device::Context,
345 gl: &Gl,
346 color: [f32; 4],
347 ) -> Result<(), Error> {
348 self.validate_context(device, context)?;
349
350 let draw_fbo;
352 let read_fbo;
353 let mut clear_color = [0., 0., 0., 0.];
354 let mut clear_depth = [0.];
355 let mut clear_stencil = [0];
356 let color_mask;
357 let depth_mask;
358 let mut stencil_mask = [0];
359 let scissor_enabled = unsafe { gl.is_enabled(gl::SCISSOR_TEST) };
360 let rasterizer_enabled = unsafe { gl.is_enabled(gl::RASTERIZER_DISCARD) };
361 unsafe {
362 draw_fbo = gl.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING);
363 read_fbo = gl.get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING);
364 gl.get_parameter_f32_slice(gl::COLOR_CLEAR_VALUE, &mut clear_color[..]);
365 gl.get_parameter_f32_slice(gl::DEPTH_CLEAR_VALUE, &mut clear_depth[..]);
366 gl.get_parameter_i32_slice(gl::STENCIL_CLEAR_VALUE, &mut clear_stencil[..]);
367 depth_mask = gl.get_parameter_bool(gl::DEPTH_WRITEMASK);
368 gl.get_parameter_i32_slice(gl::STENCIL_WRITEMASK, &mut stencil_mask[..]);
369 color_mask = gl.get_parameter_bool_array::<4>(gl::COLOR_WRITEMASK);
370 }
371
372 let reattach = if self.is_attached() {
374 None
375 } else {
376 let surface = self.back_buffer.take_surface(device, context)?;
377 let mut reattach = device.unbind_surface_from_context(context)?;
378 if let Err((err, mut surface)) = device.bind_surface_to_context(context, surface) {
379 debug!("Oh no, destroying surfaces");
380 let _ = device.destroy_surface(context, &mut surface);
381 if let Some(ref mut reattach) = reattach {
382 let _ = device.destroy_surface(context, reattach);
383 }
384 return Err(err);
385 }
386 reattach
387 };
388
389 let fbo = device
391 .context_surface_info(context)
392 .unwrap()
393 .unwrap()
394 .framebuffer_object;
395 unsafe {
396 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
397 gl.clear_color(color[0], color[1], color[2], color[3]);
398 gl.clear_depth(1.);
399 gl.clear_stencil(0);
400 gl.disable(gl::SCISSOR_TEST);
401 gl.disable(gl::RASTERIZER_DISCARD);
402 gl.depth_mask(true);
403 gl.stencil_mask(0xFFFFFFFF);
404 gl.color_mask(true, true, true, true);
405 gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
406 }
407 if let Some(surface) = reattach {
409 let mut old_surface = device.unbind_surface_from_context(context)?.unwrap();
410 if let Err((err, mut surface)) = device.bind_surface_to_context(context, surface) {
411 debug!("Oh no, destroying surface");
412 let _ = device.destroy_surface(context, &mut surface);
413 let _ = device.destroy_surface(context, &mut old_surface);
414 return Err(err);
415 }
416 self.back_buffer
417 .replace_surface(device, context, old_surface)?;
418 }
419
420 unsafe {
422 gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, draw_fbo);
423 gl.bind_framebuffer(gl::READ_FRAMEBUFFER, read_fbo);
424 gl.clear_color(
425 clear_color[0],
426 clear_color[1],
427 clear_color[2],
428 clear_color[3],
429 );
430 gl.color_mask(color_mask[0], color_mask[1], color_mask[2], color_mask[3]);
431 gl.clear_depth(clear_depth[0] as f64);
432 gl.clear_stencil(clear_stencil[0]);
433 gl.depth_mask(depth_mask);
434 gl.stencil_mask(stencil_mask[0] as _);
435 if scissor_enabled {
436 gl.enable(gl::SCISSOR_TEST);
437 }
438 if rasterizer_enabled {
439 gl.enable(gl::RASTERIZER_DISCARD);
440 }
441 }
442
443 Ok(())
444 }
445
446 fn is_attached(&self) -> bool {
448 match self.back_buffer {
449 BackBuffer::Attached | BackBuffer::TakenAttached => true,
450 BackBuffer::Detached(_) | BackBuffer::TakenDetached => false,
451 }
452 }
453
454 fn destroy(&mut self, device: &mut Device, context: &mut Device::Context) -> Result<(), Error> {
458 self.validate_context(device, context)?;
459 let surfaces = self
460 .pending_surface
461 .take()
462 .into_iter()
463 .chain(self.back_buffer.take_surface(device, context).into_iter())
464 .chain(self.recycled_surfaces.drain(..));
465 for mut surface in surfaces {
466 device.destroy_surface(context, &mut surface)?;
467 }
468 Ok(())
469 }
470}
471
472pub struct SwapChain<Device: DeviceAPI>(Arc<Mutex<SwapChainData<Device>>>);
474
475impl<Device: DeviceAPI> Clone for SwapChain<Device> {
477 fn clone(&self) -> Self {
478 SwapChain(self.0.clone())
479 }
480}
481
482impl<Device: DeviceAPI> SwapChain<Device> {
483 fn lock(&self) -> MutexGuard<SwapChainData<Device>> {
485 self.0.lock().unwrap_or_else(|err| err.into_inner())
486 }
487
488 pub fn swap_buffers(
492 &self,
493 device: &mut Device,
494 context: &mut Device::Context,
495 preserve_buffer: PreserveBuffer<'_>,
496 ) -> Result<(), Error> {
497 self.lock().swap_buffers(device, context, preserve_buffer)
498 }
499
500 pub fn take_attachment_from(
505 &self,
506 device: &mut Device,
507 context: &mut Device::Context,
508 other: &SwapChain<Device>,
509 ) -> Result<(), Error> {
510 self.lock()
511 .take_attachment_from(device, context, &mut *other.lock())
512 }
513
514 pub fn resize(
520 &self,
521 device: &mut Device,
522 context: &mut Device::Context,
523 size: Size2D<i32>,
524 ) -> Result<(), Error> {
525 self.lock().resize(device, context, size)
526 }
527
528 pub fn size(&self) -> Size2D<i32> {
531 self.lock().size()
532 }
533
534 pub fn take_surface_texture(
537 &self,
538 device: &Device,
539 context: &mut Device::Context,
540 ) -> Result<Device::SurfaceTexture, Error> {
541 self.lock().take_surface_texture(device, context)
542 }
543
544 pub fn recycle_surface_texture(
547 &self,
548 device: &Device,
549 context: &mut Device::Context,
550 surface_texture: Device::SurfaceTexture,
551 ) -> Result<(), Error> {
552 self.lock()
553 .recycle_surface_texture(device, context, surface_texture)
554 }
555
556 pub fn take_pending_surface(&self) -> Option<Device::Surface> {
560 self.lock().take_pending_surface()
561 }
562
563 pub fn clear_surface(
567 &self,
568 device: &mut Device,
569 context: &mut Device::Context,
570 gl: &Gl,
571 color: [f32; 4],
572 ) -> Result<(), Error> {
573 self.lock().clear_surface(device, context, gl, color)
574 }
575
576 pub fn is_attached(&self) -> bool {
578 self.lock().is_attached()
579 }
580
581 pub fn destroy(&self, device: &mut Device, context: &mut Device::Context) -> Result<(), Error> {
585 self.lock().destroy(device, context)
586 }
587
588 pub fn create_attached(
590 device: &mut Device,
591 context: &mut Device::Context,
592 surface_access: SurfaceAccess,
593 ) -> Result<SwapChain<Device>, Error> {
594 let size = device.context_surface_info(context).unwrap().unwrap().size;
595 Ok(SwapChain(Arc::new(Mutex::new(SwapChainData {
596 size,
597 context_id: device.context_id(context),
598 surface_access,
599 back_buffer: BackBuffer::Attached,
600 pending_surface: None,
601 recycled_surfaces: Vec::new(),
602 }))))
603 }
604
605 pub fn create_detached(
607 device: &mut Device,
608 context: &mut Device::Context,
609 surface_access: SurfaceAccess,
610 size: Size2D<i32>,
611 ) -> Result<SwapChain<Device>, Error> {
612 let surface_type = SurfaceType::Generic { size };
613 let surface = device.create_surface(context, surface_access, surface_type)?;
614 Ok(SwapChain(Arc::new(Mutex::new(SwapChainData {
615 size,
616 context_id: device.context_id(context),
617 surface_access,
618 back_buffer: BackBuffer::Detached(surface),
619 pending_surface: None,
620 recycled_surfaces: Vec::new(),
621 }))))
622 }
623}
624
625impl<Device> SwapChainAPI for SwapChain<Device>
626where
627 Device: 'static + DeviceAPI,
628 Device::Surface: Send,
629{
630 type Surface = Device::Surface;
631
632 fn take_surface(&self) -> Option<Device::Surface> {
636 self.lock().take_surface()
637 }
638
639 fn recycle_surface(&self, surface: Device::Surface) {
642 self.lock().recycle_surface(surface)
643 }
644}
645
646#[derive(Default)]
648pub struct SwapChains<SwapChainID: Eq + Hash, Device: DeviceAPI> {
649 ids: Arc<Mutex<FnvHashMap<ContextID, FnvHashSet<SwapChainID>>>>,
651 table: Arc<RwLock<FnvHashMap<SwapChainID, SwapChain<Device>>>>,
653}
654
655impl<SwapChainID: Eq + Hash, Device: DeviceAPI> Clone for SwapChains<SwapChainID, Device> {
657 fn clone(&self) -> Self {
658 SwapChains {
659 ids: self.ids.clone(),
660 table: self.table.clone(),
661 }
662 }
663}
664
665impl<SwapChainID, Device> SwapChains<SwapChainID, Device>
666where
667 SwapChainID: Clone + Eq + Hash + Debug,
668 Device: DeviceAPI,
669{
670 pub fn new() -> SwapChains<SwapChainID, Device> {
672 SwapChains {
673 ids: Arc::new(Mutex::new(FnvHashMap::default())),
674 table: Arc::new(RwLock::new(FnvHashMap::default())),
675 }
676 }
677
678 fn ids(&self) -> MutexGuard<FnvHashMap<ContextID, FnvHashSet<SwapChainID>>> {
680 self.ids.lock().unwrap_or_else(|err| err.into_inner())
681 }
682
683 fn table(&self) -> RwLockReadGuard<FnvHashMap<SwapChainID, SwapChain<Device>>> {
685 self.table.read().unwrap_or_else(|err| err.into_inner())
686 }
687
688 fn table_mut(&self) -> RwLockWriteGuard<FnvHashMap<SwapChainID, SwapChain<Device>>> {
690 self.table.write().unwrap_or_else(|err| err.into_inner())
691 }
692
693 pub fn create_attached_swap_chain(
696 &self,
697 id: SwapChainID,
698 device: &mut Device,
699 context: &mut Device::Context,
700 surface_access: SurfaceAccess,
701 ) -> Result<(), Error> {
702 match self.table_mut().entry(id.clone()) {
703 Entry::Occupied(_) => Err(Error::Failed)?,
704 Entry::Vacant(entry) => {
705 entry.insert(SwapChain::create_attached(device, context, surface_access)?)
706 }
707 };
708 self.ids()
709 .entry(device.context_id(context))
710 .or_insert_with(Default::default)
711 .insert(id);
712 Ok(())
713 }
714
715 pub fn create_detached_swap_chain(
718 &self,
719 id: SwapChainID,
720 size: Size2D<i32>,
721 device: &mut Device,
722 context: &mut Device::Context,
723 surface_access: SurfaceAccess,
724 ) -> Result<(), Error> {
725 match self.table_mut().entry(id.clone()) {
726 Entry::Occupied(_) => Err(Error::Failed)?,
727 Entry::Vacant(entry) => entry.insert(SwapChain::create_detached(
728 device,
729 context,
730 surface_access,
731 size,
732 )?),
733 };
734 self.ids()
735 .entry(device.context_id(context))
736 .or_insert_with(Default::default)
737 .insert(id);
738 Ok(())
739 }
740
741 pub fn destroy(
745 &self,
746 id: SwapChainID,
747 device: &mut Device,
748 context: &mut Device::Context,
749 ) -> Result<(), Error> {
750 if let Some(swap_chain) = self.table_mut().remove(&id) {
751 swap_chain.destroy(device, context)?;
752 }
753 if let Some(ids) = self.ids().get_mut(&device.context_id(context)) {
754 ids.remove(&id);
755 }
756 Ok(())
757 }
758
759 pub fn destroy_all(
762 &self,
763 device: &mut Device,
764 context: &mut Device::Context,
765 ) -> Result<(), Error> {
766 if let Some(mut ids) = self.ids().remove(&device.context_id(context)) {
767 for id in ids.drain() {
768 if let Some(swap_chain) = self.table_mut().remove(&id) {
769 swap_chain.destroy(device, context)?;
770 }
771 }
772 }
773 Ok(())
774 }
775
776 pub fn iter(
779 &self,
780 device: &mut Device,
781 context: &mut Device::Context,
782 ) -> impl Iterator<Item = (SwapChainID, SwapChain<Device>)> {
783 self.ids()
784 .get(&device.context_id(context))
785 .iter()
786 .flat_map(|ids| ids.iter())
787 .filter_map(|id| Some((id.clone(), self.table().get(id)?.clone())))
788 .collect::<Vec<_>>()
789 .into_iter()
790 }
791}
792
793impl<SwapChainID, Device> SwapChainsAPI<SwapChainID> for SwapChains<SwapChainID, Device>
794where
795 SwapChainID: 'static + Clone + Eq + Hash + Debug + Sync + Send,
796 Device: 'static + DeviceAPI,
797 Device::Surface: Send,
798{
799 type Surface = Device::Surface;
800 type SwapChain = SwapChain<Device>;
801
802 fn get(&self, id: SwapChainID) -> Option<SwapChain<Device>> {
804 debug!("Getting swap chain {:?}", id);
805 self.table().get(&id).cloned()
806 }
807}
808
809pub trait SwapChainAPI: 'static + Clone + Send {
811 type Surface;
812
813 fn take_surface(&self) -> Option<Self::Surface>;
815
816 fn recycle_surface(&self, surface: Self::Surface);
818}
819
820pub trait SwapChainsAPI<SwapChainID>: 'static + Clone + Send {
822 type Surface;
823 type SwapChain: SwapChainAPI<Surface = Self::Surface>;
824
825 fn get(&self, id: SwapChainID) -> Option<Self::SwapChain>;
827}