freya_winit/drivers/
software.rs1use std::num::NonZeroU32;
2
3use freya_engine::prelude::{
4 AlphaType,
5 ColorType,
6 ImageInfo,
7 Surface as SkiaSurface,
8 wrap_pixels,
9};
10use raw_window_handle::{
11 DisplayHandle,
12 HandleError,
13 HasDisplayHandle,
14 HasWindowHandle,
15 RawDisplayHandle,
16 RawWindowHandle,
17 WindowHandle,
18};
19use winit::{
20 dpi::PhysicalSize,
21 event_loop::ActiveEventLoop,
22 window::{
23 Window,
24 WindowAttributes,
25 },
26};
27
28struct DisplayHandleWrapper(RawDisplayHandle);
29
30impl HasDisplayHandle for DisplayHandleWrapper {
31 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
32 Ok(unsafe { DisplayHandle::borrow_raw(self.0) })
34 }
35}
36
37struct WindowHandleWrapper(RawWindowHandle);
38
39impl HasWindowHandle for WindowHandleWrapper {
40 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
41 Ok(unsafe { WindowHandle::borrow_raw(self.0) })
43 }
44}
45
46pub struct SoftwareDriver {
48 _context: softbuffer::Context<DisplayHandleWrapper>,
49 surface: softbuffer::Surface<DisplayHandleWrapper, WindowHandleWrapper>,
50}
51
52impl SoftwareDriver {
53 pub fn new(
54 event_loop: &ActiveEventLoop,
55 window_attributes: WindowAttributes,
56 ) -> Result<(Self, Window), Box<dyn std::error::Error>> {
57 let window = event_loop.create_window(window_attributes)?;
58 let driver = Self::from_window(&window)?;
59 Ok((driver, window))
60 }
61
62 pub fn from_window(window: &Window) -> Result<Self, Box<dyn std::error::Error>> {
64 let display_handle = window.display_handle()?.as_raw();
65 let window_handle = window.window_handle()?.as_raw();
66
67 let context = softbuffer::Context::new(DisplayHandleWrapper(display_handle))
68 .map_err(|err| format!("Could not create softbuffer context: {err}"))?;
69 let mut surface = softbuffer::Surface::new(&context, WindowHandleWrapper(window_handle))
70 .map_err(|err| format!("Could not create softbuffer surface: {err}"))?;
71
72 let size = window.inner_size();
73 if let (Some(width), Some(height)) =
74 (NonZeroU32::new(size.width), NonZeroU32::new(size.height))
75 {
76 surface
77 .resize(width, height)
78 .map_err(|err| format!("Could not size softbuffer surface: {err}"))?;
79 }
80
81 Ok(Self {
82 _context: context,
83 surface,
84 })
85 }
86
87 pub fn present(
88 &mut self,
89 size: PhysicalSize<u32>,
90 window: &Window,
91 render: impl FnOnce(&mut SkiaSurface),
92 ) {
93 let (Some(width), Some(height)) =
94 (NonZeroU32::new(size.width), NonZeroU32::new(size.height))
95 else {
96 return;
97 };
98
99 let mut buffer = match self.surface.buffer_mut() {
100 Ok(buffer) => buffer,
101 Err(err) => {
102 tracing::error!("Failed to acquire software buffer: {err:?}");
103 return;
104 }
105 };
106
107 let info = ImageInfo::new(
108 (width.get() as i32, height.get() as i32),
109 ColorType::BGRA8888,
110 AlphaType::Premul,
111 None,
112 );
113 let row_bytes = width.get() as usize * 4;
114 let pixels: &mut [u32] = &mut buffer;
115 let bytes: &mut [u8] = unsafe {
117 std::slice::from_raw_parts_mut(pixels.as_mut_ptr() as *mut u8, pixels.len() * 4)
118 };
119
120 match wrap_pixels(&info, bytes, Some(row_bytes), None) {
121 Some(mut wrapped_surface) => render(&mut wrapped_surface),
122 None => {
123 tracing::error!("Failed to wrap software pixels into a Skia surface");
124 return;
125 }
126 }
127
128 window.pre_present_notify();
129 if let Err(err) = buffer.present() {
130 tracing::error!("Failed to present software buffer: {err:?}");
131 }
132 }
133
134 pub fn resize(&mut self, size: PhysicalSize<u32>) {
135 let (Some(width), Some(height)) =
136 (NonZeroU32::new(size.width), NonZeroU32::new(size.height))
137 else {
138 return;
139 };
140 if let Err(err) = self.surface.resize(width, height) {
141 tracing::error!("Failed to resize software surface: {err:?}");
142 }
143 }
144}