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: &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 Ok(())
225 }
226
227 fn take_attachment_from(
232 &mut self,
233 device: &Device,
234 context: &mut Device::Context,
235 other: &mut SwapChainData<Device>,
236 ) -> Result<(), Error> {
237 self.validate_context(device, context)?;
238 other.validate_context(device, context)?;
239 let our_surface = self.back_buffer.take_surface(device, context)?;
240 let their_surface = other.back_buffer.take_surface(device, context)?;
241 mem::swap(&mut self.back_buffer, &mut other.back_buffer);
242 self.back_buffer
243 .replace_surface(device, context, our_surface)?;
244 other
245 .back_buffer
246 .replace_surface(device, context, their_surface)?;
247 Ok(())
248 }
249
250 fn resize(
257 &mut self,
258 device: &Device,
259 context: &mut Device::Context,
260 size: Size2D<i32>,
261 ) -> Result<(), Error> {
262 debug!(
263 "Resizing context {:?} to {:?}",
264 device.context_id(context),
265 size
266 );
267 self.validate_context(device, context)?;
268 if (size.width < 1) || (size.height < 1) {
269 return Err(Error::Failed);
270 }
271 let surface_type = SurfaceType::Generic { size };
272 let new_back_buffer = device.create_surface(context, self.surface_access, surface_type)?;
273 let mut old_back_buffer = self.back_buffer.take_surface(device, context)?;
274 self.back_buffer
275 .replace_surface(device, context, new_back_buffer)?;
276 device.destroy_surface(context, &mut old_back_buffer)?;
277 for mut surface in self.recycled_surfaces.drain(..) {
278 device.destroy_surface(context, &mut surface)?;
279 }
280 self.size = size;
281 Ok(())
282 }
283
284 fn size(&self) -> Size2D<i32> {
287 self.size
288 }
289
290 fn take_surface_texture(
293 &mut self,
294 device: &Device,
295 context: &mut Device::Context,
296 ) -> Result<Device::SurfaceTexture, Error> {
297 self.validate_context(device, context)?;
298 self.back_buffer.take_surface_texture(device, context)
299 }
300
301 fn recycle_surface_texture(
304 &mut self,
305 device: &Device,
306 context: &mut Device::Context,
307 surface_texture: Device::SurfaceTexture,
308 ) -> Result<(), Error> {
309 self.validate_context(device, context)?;
310 self.back_buffer
311 .replace_surface_texture(device, context, surface_texture)
312 }
313
314 fn take_surface(&mut self) -> Option<Device::Surface> {
318 self.pending_surface
319 .take()
320 .or_else(|| self.recycled_surfaces.pop())
321 }
322
323 fn take_pending_surface(&mut self) -> Option<Device::Surface> {
327 self.pending_surface.take()
328 }
329
330 fn recycle_surface(&mut self, surface: Device::Surface) {
333 self.recycled_surfaces.push(surface)
334 }
335
336 fn clear_surface(
340 &mut self,
341 device: &Device,
342 context: &mut Device::Context,
343 gl: &Gl,
344 color: [f32; 4],
345 ) -> Result<(), Error> {
346 self.validate_context(device, context)?;
347
348 let draw_fbo;
350 let read_fbo;
351 let mut clear_color = [0., 0., 0., 0.];
352 let mut clear_depth = [0.];
353 let mut clear_stencil = [0];
354 let color_mask;
355 let depth_mask;
356 let mut stencil_mask = [0];
357 let scissor_enabled = unsafe { gl.is_enabled(gl::SCISSOR_TEST) };
358 let rasterizer_enabled = unsafe { gl.is_enabled(gl::RASTERIZER_DISCARD) };
359 unsafe {
360 draw_fbo = gl.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING);
361 read_fbo = gl.get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING);
362 gl.get_parameter_f32_slice(gl::COLOR_CLEAR_VALUE, &mut clear_color[..]);
363 gl.get_parameter_f32_slice(gl::DEPTH_CLEAR_VALUE, &mut clear_depth[..]);
364 gl.get_parameter_i32_slice(gl::STENCIL_CLEAR_VALUE, &mut clear_stencil[..]);
365 depth_mask = gl.get_parameter_bool(gl::DEPTH_WRITEMASK);
366 gl.get_parameter_i32_slice(gl::STENCIL_WRITEMASK, &mut stencil_mask[..]);
367 color_mask = gl.get_parameter_bool_array::<4>(gl::COLOR_WRITEMASK);
368 }
369
370 let reattach = if self.is_attached() {
372 None
373 } else {
374 let surface = self.back_buffer.take_surface(device, context)?;
375 let mut reattach = device.unbind_surface_from_context(context)?;
376 if let Err((err, mut surface)) = device.bind_surface_to_context(context, surface) {
377 debug!("Oh no, destroying surfaces");
378 let _ = device.destroy_surface(context, &mut surface);
379 if let Some(ref mut reattach) = reattach {
380 let _ = device.destroy_surface(context, reattach);
381 }
382 return Err(err);
383 }
384 reattach
385 };
386
387 let fbo = device
389 .context_surface_info(context)
390 .unwrap()
391 .unwrap()
392 .framebuffer_object;
393 unsafe {
394 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
395 gl.clear_color(color[0], color[1], color[2], color[3]);
396 gl.clear_depth(1.);
397 gl.clear_stencil(0);
398 gl.disable(gl::SCISSOR_TEST);
399 gl.disable(gl::RASTERIZER_DISCARD);
400 gl.depth_mask(true);
401 gl.stencil_mask(0xFFFFFFFF);
402 gl.color_mask(true, true, true, true);
403 gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
404 }
405 if let Some(surface) = reattach {
407 let mut old_surface = device.unbind_surface_from_context(context)?.unwrap();
408 if let Err((err, mut surface)) = device.bind_surface_to_context(context, surface) {
409 debug!("Oh no, destroying surface");
410 let _ = device.destroy_surface(context, &mut surface);
411 let _ = device.destroy_surface(context, &mut old_surface);
412 return Err(err);
413 }
414 self.back_buffer
415 .replace_surface(device, context, old_surface)?;
416 }
417
418 unsafe {
420 gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, draw_fbo);
421 gl.bind_framebuffer(gl::READ_FRAMEBUFFER, read_fbo);
422 gl.clear_color(
423 clear_color[0],
424 clear_color[1],
425 clear_color[2],
426 clear_color[3],
427 );
428 gl.color_mask(color_mask[0], color_mask[1], color_mask[2], color_mask[3]);
429 gl.clear_depth(clear_depth[0] as f64);
430 gl.clear_stencil(clear_stencil[0]);
431 gl.depth_mask(depth_mask);
432 gl.stencil_mask(stencil_mask[0] as _);
433 if scissor_enabled {
434 gl.enable(gl::SCISSOR_TEST);
435 }
436 if rasterizer_enabled {
437 gl.enable(gl::RASTERIZER_DISCARD);
438 }
439 }
440
441 Ok(())
442 }
443
444 fn is_attached(&self) -> bool {
446 match self.back_buffer {
447 BackBuffer::Attached | BackBuffer::TakenAttached => true,
448 BackBuffer::Detached(_) | BackBuffer::TakenDetached => false,
449 }
450 }
451
452 fn destroy(&mut self, device: &Device, context: &mut Device::Context) -> Result<(), Error> {
456 self.validate_context(device, context)?;
457 let surfaces = self
458 .pending_surface
459 .take()
460 .into_iter()
461 .chain(self.back_buffer.take_surface(device, context).into_iter())
462 .chain(self.recycled_surfaces.drain(..));
463 for mut surface in surfaces {
464 device.destroy_surface(context, &mut surface)?;
465 }
466 Ok(())
467 }
468}
469
470pub struct SwapChain<Device: DeviceAPI>(Arc<Mutex<SwapChainData<Device>>>);
472
473impl<Device: DeviceAPI> Clone for SwapChain<Device> {
475 fn clone(&self) -> Self {
476 SwapChain(self.0.clone())
477 }
478}
479
480impl<Device: DeviceAPI> SwapChain<Device> {
481 fn lock(&self) -> MutexGuard<SwapChainData<Device>> {
483 self.0.lock().unwrap_or_else(|err| err.into_inner())
484 }
485
486 pub fn swap_buffers(
490 &self,
491 device: &Device,
492 context: &mut Device::Context,
493 preserve_buffer: PreserveBuffer<'_>,
494 ) -> Result<(), Error> {
495 self.lock().swap_buffers(device, context, preserve_buffer)
496 }
497
498 pub fn take_attachment_from(
503 &self,
504 device: &Device,
505 context: &mut Device::Context,
506 other: &SwapChain<Device>,
507 ) -> Result<(), Error> {
508 self.lock()
509 .take_attachment_from(device, context, &mut *other.lock())
510 }
511
512 pub fn resize(
518 &self,
519 device: &Device,
520 context: &mut Device::Context,
521 size: Size2D<i32>,
522 ) -> Result<(), Error> {
523 self.lock().resize(device, context, size)
524 }
525
526 pub fn size(&self) -> Size2D<i32> {
529 self.lock().size()
530 }
531
532 pub fn take_surface_texture(
535 &self,
536 device: &Device,
537 context: &mut Device::Context,
538 ) -> Result<Device::SurfaceTexture, Error> {
539 self.lock().take_surface_texture(device, context)
540 }
541
542 pub fn recycle_surface_texture(
545 &self,
546 device: &Device,
547 context: &mut Device::Context,
548 surface_texture: Device::SurfaceTexture,
549 ) -> Result<(), Error> {
550 self.lock()
551 .recycle_surface_texture(device, context, surface_texture)
552 }
553
554 pub fn take_pending_surface(&self) -> Option<Device::Surface> {
558 self.lock().take_pending_surface()
559 }
560
561 pub fn clear_surface(
565 &self,
566 device: &Device,
567 context: &mut Device::Context,
568 gl: &Gl,
569 color: [f32; 4],
570 ) -> Result<(), Error> {
571 self.lock().clear_surface(device, context, gl, color)
572 }
573
574 pub fn is_attached(&self) -> bool {
576 self.lock().is_attached()
577 }
578
579 pub fn destroy(&self, device: &Device, context: &mut Device::Context) -> Result<(), Error> {
583 self.lock().destroy(device, context)
584 }
585
586 pub fn create_attached(
588 device: &Device,
589 context: &mut Device::Context,
590 surface_access: SurfaceAccess,
591 ) -> Result<SwapChain<Device>, Error> {
592 let size = device.context_surface_info(context).unwrap().unwrap().size;
593 Ok(SwapChain(Arc::new(Mutex::new(SwapChainData {
594 size,
595 context_id: device.context_id(context),
596 surface_access,
597 back_buffer: BackBuffer::Attached,
598 pending_surface: None,
599 recycled_surfaces: Vec::new(),
600 }))))
601 }
602
603 pub fn create_detached(
605 device: &Device,
606 context: &mut Device::Context,
607 surface_access: SurfaceAccess,
608 size: Size2D<i32>,
609 ) -> Result<SwapChain<Device>, Error> {
610 let surface_type = SurfaceType::Generic { size };
611 let surface = device.create_surface(context, surface_access, surface_type)?;
612 Ok(SwapChain(Arc::new(Mutex::new(SwapChainData {
613 size,
614 context_id: device.context_id(context),
615 surface_access,
616 back_buffer: BackBuffer::Detached(surface),
617 pending_surface: None,
618 recycled_surfaces: Vec::new(),
619 }))))
620 }
621}
622
623impl<Device> SwapChainAPI for SwapChain<Device>
624where
625 Device: 'static + DeviceAPI,
626 Device::Surface: Send,
627{
628 type Surface = Device::Surface;
629
630 fn take_surface(&self) -> Option<Device::Surface> {
634 self.lock().take_surface()
635 }
636
637 fn recycle_surface(&self, surface: Device::Surface) {
640 self.lock().recycle_surface(surface)
641 }
642}
643
644#[derive(Default)]
646pub struct SwapChains<SwapChainID: Eq + Hash, Device: DeviceAPI> {
647 ids: Arc<Mutex<FnvHashMap<ContextID, FnvHashSet<SwapChainID>>>>,
649 table: Arc<RwLock<FnvHashMap<SwapChainID, SwapChain<Device>>>>,
651}
652
653impl<SwapChainID: Eq + Hash, Device: DeviceAPI> Clone for SwapChains<SwapChainID, Device> {
655 fn clone(&self) -> Self {
656 SwapChains {
657 ids: self.ids.clone(),
658 table: self.table.clone(),
659 }
660 }
661}
662
663impl<SwapChainID, Device> SwapChains<SwapChainID, Device>
664where
665 SwapChainID: Clone + Eq + Hash + Debug,
666 Device: DeviceAPI,
667{
668 pub fn new() -> SwapChains<SwapChainID, Device> {
670 SwapChains {
671 ids: Arc::new(Mutex::new(FnvHashMap::default())),
672 table: Arc::new(RwLock::new(FnvHashMap::default())),
673 }
674 }
675
676 fn ids(&self) -> MutexGuard<FnvHashMap<ContextID, FnvHashSet<SwapChainID>>> {
678 self.ids.lock().unwrap_or_else(|err| err.into_inner())
679 }
680
681 fn table(&self) -> RwLockReadGuard<FnvHashMap<SwapChainID, SwapChain<Device>>> {
683 self.table.read().unwrap_or_else(|err| err.into_inner())
684 }
685
686 fn table_mut(&self) -> RwLockWriteGuard<FnvHashMap<SwapChainID, SwapChain<Device>>> {
688 self.table.write().unwrap_or_else(|err| err.into_inner())
689 }
690
691 pub fn create_attached_swap_chain(
694 &self,
695 id: SwapChainID,
696 device: &Device,
697 context: &mut Device::Context,
698 surface_access: SurfaceAccess,
699 ) -> Result<(), Error> {
700 match self.table_mut().entry(id.clone()) {
701 Entry::Occupied(_) => Err(Error::Failed)?,
702 Entry::Vacant(entry) => {
703 entry.insert(SwapChain::create_attached(device, context, surface_access)?)
704 }
705 };
706 self.ids()
707 .entry(device.context_id(context))
708 .or_insert_with(Default::default)
709 .insert(id);
710 Ok(())
711 }
712
713 pub fn create_detached_swap_chain(
716 &self,
717 id: SwapChainID,
718 size: Size2D<i32>,
719 device: &Device,
720 context: &mut Device::Context,
721 surface_access: SurfaceAccess,
722 ) -> Result<(), Error> {
723 match self.table_mut().entry(id.clone()) {
724 Entry::Occupied(_) => Err(Error::Failed)?,
725 Entry::Vacant(entry) => entry.insert(SwapChain::create_detached(
726 device,
727 context,
728 surface_access,
729 size,
730 )?),
731 };
732 self.ids()
733 .entry(device.context_id(context))
734 .or_insert_with(Default::default)
735 .insert(id);
736 Ok(())
737 }
738
739 pub fn destroy(
743 &self,
744 id: SwapChainID,
745 device: &Device,
746 context: &mut Device::Context,
747 ) -> Result<(), Error> {
748 if let Some(swap_chain) = self.table_mut().remove(&id) {
749 swap_chain.destroy(device, context)?;
750 }
751 if let Some(ids) = self.ids().get_mut(&device.context_id(context)) {
752 ids.remove(&id);
753 }
754 Ok(())
755 }
756
757 pub fn iter(
760 &self,
761 device: &Device,
762 context: &mut Device::Context,
763 ) -> impl Iterator<Item = (SwapChainID, SwapChain<Device>)> {
764 self.ids()
765 .get(&device.context_id(context))
766 .iter()
767 .flat_map(|ids| ids.iter())
768 .filter_map(|id| Some((id.clone(), self.table().get(id)?.clone())))
769 .collect::<Vec<_>>()
770 .into_iter()
771 }
772}
773
774impl<SwapChainID, Device> SwapChainsAPI<SwapChainID> for SwapChains<SwapChainID, Device>
775where
776 SwapChainID: 'static + Clone + Eq + Hash + Debug + Sync + Send,
777 Device: 'static + DeviceAPI,
778 Device::Surface: Send,
779{
780 type Surface = Device::Surface;
781 type SwapChain = SwapChain<Device>;
782
783 fn get(&self, id: SwapChainID) -> Option<SwapChain<Device>> {
785 debug!("Getting swap chain {:?}", id);
786 self.table().get(&id).cloned()
787 }
788}
789
790pub trait SwapChainAPI: 'static + Clone + Send {
792 type Surface;
793
794 fn take_surface(&self) -> Option<Self::Surface>;
796
797 fn recycle_surface(&self, surface: Self::Surface);
799}
800
801pub trait SwapChainsAPI<SwapChainID>: 'static + Clone + Send {
803 type Surface;
804 type SwapChain: SwapChainAPI<Surface = Self::Surface>;
805
806 fn get(&self, id: SwapChainID) -> Option<Self::SwapChain>;
808}