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