Skip to main content

anvilkit_render/renderer/
surface.rs

1//! # 窗口表面和交换链管理
2//! 
3//! 提供 wgpu 表面配置、交换链管理和帧缓冲功能。
4
5use std::sync::Arc;
6use wgpu::{
7    Surface, SurfaceConfiguration, TextureFormat, PresentMode, CompositeAlphaMode,
8    SurfaceTexture,
9};
10use winit::window::Window;
11use log::{info, warn, debug};
12
13use crate::renderer::RenderDevice;
14use anvilkit_core::error::{AnvilKitError, Result};
15
16/// 渲染表面
17/// 
18/// 管理窗口表面、交换链配置和帧缓冲,提供渲染目标管理功能。
19/// 
20/// # 设计理念
21/// 
22/// - **自适应配置**: 根据设备能力自动配置表面参数
23/// - **动态调整**: 支持窗口大小变化时的动态重配置
24/// - **格式选择**: 自动选择最佳的纹理格式和呈现模式
25/// - **错误恢复**: 处理表面丢失等异常情况
26/// 
27/// # 示例
28/// 
29/// ```rust,no_run
30/// use anvilkit_render::renderer::{RenderDevice, RenderSurface};
31/// use std::sync::Arc;
32/// use winit::window::Window;
33/// 
34/// # async fn example() -> anvilkit_core::error::Result<()> {
35/// // 创建设备和表面
36/// // let window = Arc::new(window);
37/// // let device = RenderDevice::new(&window).await?;
38/// // let surface = RenderSurface::new(&device, &window)?;
39/// 
40/// // 获取当前帧
41/// // let frame = surface.get_current_frame()?;
42/// # Ok(())
43/// # }
44/// ```
45pub struct RenderSurface {
46    /// wgpu 表面(持有 Arc<Window>,保证生命周期安全)
47    surface: Surface<'static>,
48    /// 表面配置
49    config: SurfaceConfiguration,
50    /// 当前纹理格式
51    format: TextureFormat,
52    /// 持有窗口引用以保证 surface 生命周期
53    _window: Arc<Window>,
54}
55
56impl RenderSurface {
57    /// 创建新的渲染表面
58    /// 
59    /// # 参数
60    /// 
61    /// - `device`: 渲染设备
62    /// - `window`: 窗口实例
63    /// 
64    /// # 返回
65    /// 
66    /// 成功时返回 RenderSurface 实例,失败时返回错误
67    /// 
68    /// # 示例
69    /// 
70    /// ```rust,no_run
71    /// use anvilkit_render::renderer::{RenderDevice, RenderSurface};
72    /// use std::sync::Arc;
73    /// use winit::window::Window;
74    /// 
75    /// # async fn example() -> anvilkit_core::error::Result<()> {
76    /// // let window = Arc::new(window);
77    /// // let device = RenderDevice::new(&window).await?;
78    /// // let surface = RenderSurface::new(&device, &window)?;
79    /// # Ok(())
80    /// # }
81    /// ```
82    pub fn new(device: &RenderDevice, window: &Arc<Window>) -> Result<Self> {
83        Self::new_with_vsync(device, window, false)
84    }
85
86    /// 创建新的渲染表面(指定 vsync 模式)
87    ///
88    /// - `vsync = true`: 使用 `PresentMode::Fifo`(垂直同步)
89    /// - `vsync = false`: 优先使用 `PresentMode::Mailbox`(三重缓冲,低延迟)
90    pub fn new_with_vsync(device: &RenderDevice, window: &Arc<Window>, vsync: bool) -> Result<Self> {
91        info!("创建渲染表面 (vsync={})", vsync);
92
93        // 创建表面
94        let surface = device.instance().create_surface(window.clone())
95            .map_err(|e| AnvilKitError::render(format!("创建表面失败: {}", e)))?;
96
97        // 获取表面能力
98        let capabilities = surface.get_capabilities(device.adapter());
99
100        // 选择纹理格式
101        let format = Self::choose_format(&capabilities.formats);
102
103        // 获取窗口大小
104        let size = window.inner_size();
105
106        // 选择呈现模式
107        let present_mode = if vsync {
108            PresentMode::Fifo
109        } else {
110            Self::choose_present_mode(&capabilities.present_modes)
111        };
112
113        // 创建表面配置
114        let config = SurfaceConfiguration {
115            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
116            format,
117            width: size.width,
118            height: size.height,
119            present_mode,
120            alpha_mode: Self::choose_alpha_mode(&capabilities.alpha_modes),
121            view_formats: vec![],
122            desired_maximum_frame_latency: 2,
123        };
124        
125        // 配置表面
126        surface.configure(device.device(), &config);
127        
128        info!("渲染表面创建成功");
129        info!("表面格式: {:?}", format);
130        info!("表面大小: {}x{}", config.width, config.height);
131        info!("呈现模式: {:?}", config.present_mode);
132        
133        Ok(Self {
134            surface,
135            config,
136            format,
137            _window: window.clone(),
138        })
139    }
140    
141    /// 选择纹理格式
142    /// 
143    /// # 参数
144    /// 
145    /// - `formats`: 支持的格式列表
146    /// 
147    /// # 返回
148    /// 
149    /// 返回选择的纹理格式
150    fn choose_format(formats: &[TextureFormat]) -> TextureFormat {
151        // 优先选择 sRGB 格式
152        for &format in formats {
153            match format {
154                TextureFormat::Bgra8UnormSrgb | TextureFormat::Rgba8UnormSrgb => {
155                    debug!("选择纹理格式: {:?}", format);
156                    return format;
157                }
158                _ => {}
159            }
160        }
161        
162        // 回退到第一个可用格式
163        let format = formats[0];
164        debug!("回退到纹理格式: {:?}", format);
165        format
166    }
167    
168    /// 选择呈现模式
169    /// 
170    /// # 参数
171    /// 
172    /// - `modes`: 支持的呈现模式列表
173    /// 
174    /// # 返回
175    /// 
176    /// 返回选择的呈现模式
177    fn choose_present_mode(modes: &[PresentMode]) -> PresentMode {
178        // 优先选择 Mailbox 模式(三重缓冲)
179        if modes.contains(&PresentMode::Mailbox) {
180            debug!("选择呈现模式: Mailbox");
181            return PresentMode::Mailbox;
182        }
183        
184        // 回退到 Fifo 模式(垂直同步)
185        debug!("选择呈现模式: Fifo");
186        PresentMode::Fifo
187    }
188    
189    /// 选择 Alpha 混合模式
190    /// 
191    /// # 参数
192    /// 
193    /// - `modes`: 支持的 Alpha 模式列表
194    /// 
195    /// # 返回
196    /// 
197    /// 返回选择的 Alpha 模式
198    fn choose_alpha_mode(modes: &[CompositeAlphaMode]) -> CompositeAlphaMode {
199        // 优先选择 Auto 模式
200        if modes.contains(&CompositeAlphaMode::Auto) {
201            debug!("选择 Alpha 模式: Auto");
202            return CompositeAlphaMode::Auto;
203        }
204        
205        // 回退到 Opaque 模式
206        debug!("选择 Alpha 模式: Opaque");
207        CompositeAlphaMode::Opaque
208    }
209    
210    /// 调整表面大小
211    /// 
212    /// # 参数
213    /// 
214    /// - `device`: 渲染设备
215    /// - `width`: 新的宽度
216    /// - `height`: 新的高度
217    /// 
218    /// # 返回
219    /// 
220    /// 成功时返回 Ok(()),失败时返回错误
221    /// 
222    /// # 示例
223    /// 
224    /// ```rust,no_run
225    /// # use anvilkit_render::renderer::{RenderDevice, RenderSurface};
226    /// # async fn example(device: &RenderDevice, surface: &mut RenderSurface) -> anvilkit_core::error::Result<()> {
227    /// surface.resize(device, 1920, 1080)?;
228    /// # Ok(())
229    /// # }
230    /// ```
231    pub fn resize(&mut self, device: &RenderDevice, width: u32, height: u32) -> Result<()> {
232        if width == 0 || height == 0 {
233            warn!("忽略无效的表面大小: {}x{}", width, height);
234            return Ok(());
235        }
236        
237        info!("调整表面大小: {}x{}", width, height);
238        
239        self.config.width = width;
240        self.config.height = height;
241        
242        self.surface.configure(device.device(), &self.config);
243        
244        Ok(())
245    }
246    
247    /// 获取当前帧纹理
248    /// 
249    /// # 返回
250    /// 
251    /// 成功时返回 SurfaceTexture,失败时返回错误
252    /// 
253    /// # 示例
254    /// 
255    /// ```rust,no_run
256    /// # use anvilkit_render::renderer::RenderSurface;
257    /// # async fn example(surface: &RenderSurface) -> anvilkit_core::error::Result<()> {
258    /// let frame = surface.get_current_frame()?;
259    /// let view = frame.texture.create_view(&Default::default());
260    /// // 使用纹理视图进行渲染
261    /// frame.present();
262    /// # Ok(())
263    /// # }
264    /// ```
265    pub fn get_current_frame(&self) -> Result<SurfaceTexture> {
266        self.surface.get_current_texture()
267            .map_err(|e| match e {
268                wgpu::SurfaceError::Lost => {
269                    AnvilKitError::render("表面丢失,需要重新配置".to_string())
270                }
271                wgpu::SurfaceError::OutOfMemory => {
272                    AnvilKitError::render("GPU 内存不足".to_string())
273                }
274                wgpu::SurfaceError::Timeout => {
275                    AnvilKitError::render("获取表面纹理超时".to_string())
276                }
277                wgpu::SurfaceError::Outdated => {
278                    AnvilKitError::render("表面配置过时,需要重新配置".to_string())
279                }
280            })
281    }
282
283    /// 重新配置表面(用于 Lost/Outdated 恢复)
284    pub fn reconfigure(&self, device: &RenderDevice) {
285        info!("重新配置渲染表面: {}x{}", self.config.width, self.config.height);
286        self.surface.configure(device.device(), &self.config);
287    }
288
289    /// 获取当前帧,自动恢复 Lost/Outdated 错误
290    ///
291    /// 如果首次获取失败(Lost 或 Outdated),自动 reconfigure 后重试一次。
292    pub fn get_current_frame_with_recovery(&self, device: &RenderDevice) -> Result<SurfaceTexture> {
293        match self.surface.get_current_texture() {
294            Ok(frame) => Ok(frame),
295            Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
296                warn!("表面需要重新配置,正在恢复...");
297                self.reconfigure(device);
298                // 重试一次
299                self.surface.get_current_texture()
300                    .map_err(|e| AnvilKitError::render(format!("表面恢复后仍失败: {}", e)))
301            }
302            Err(wgpu::SurfaceError::OutOfMemory) => {
303                Err(AnvilKitError::render("GPU 内存不足".to_string()))
304            }
305            Err(wgpu::SurfaceError::Timeout) => {
306                Err(AnvilKitError::render("获取表面纹理超时".to_string()))
307            }
308        }
309    }
310    
311    /// 获取表面配置
312    /// 
313    /// # 返回
314    /// 
315    /// 返回当前的表面配置
316    /// 
317    /// # 示例
318    /// 
319    /// ```rust,no_run
320    /// # use anvilkit_render::renderer::RenderSurface;
321    /// # async fn example(surface: &RenderSurface) {
322    /// let config = surface.config();
323    /// println!("表面大小: {}x{}", config.width, config.height);
324    /// # }
325    /// ```
326    pub fn config(&self) -> &SurfaceConfiguration {
327        &self.config
328    }
329    
330    /// 获取纹理格式
331    /// 
332    /// # 返回
333    /// 
334    /// 返回当前的纹理格式
335    /// 
336    /// # 示例
337    /// 
338    /// ```rust,no_run
339    /// # use anvilkit_render::renderer::RenderSurface;
340    /// # async fn example(surface: &RenderSurface) {
341    /// let format = surface.format();
342    /// println!("纹理格式: {:?}", format);
343    /// # }
344    /// ```
345    pub fn format(&self) -> TextureFormat {
346        self.format
347    }
348    
349    /// 获取表面大小
350    /// 
351    /// # 返回
352    /// 
353    /// 返回 (宽度, 高度) 元组
354    /// 
355    /// # 示例
356    /// 
357    /// ```rust,no_run
358    /// # use anvilkit_render::renderer::RenderSurface;
359    /// # async fn example(surface: &RenderSurface) {
360    /// let (width, height) = surface.size();
361    /// println!("表面大小: {}x{}", width, height);
362    /// # }
363    /// ```
364    pub fn size(&self) -> (u32, u32) {
365        (self.config.width, self.config.height)
366    }
367    
368    /// 获取表面引用
369    /// 
370    /// # 返回
371    /// 
372    /// 返回 wgpu 表面的引用
373    /// 
374    /// # 示例
375    /// 
376    /// ```rust,no_run
377    /// # use anvilkit_render::renderer::RenderSurface;
378    /// # async fn example(surface: &RenderSurface) {
379    /// let wgpu_surface = surface.surface();
380    /// // 使用原始表面进行高级操作
381    /// # }
382    /// ```
383    pub fn surface(&self) -> &Surface<'static> {
384        &self.surface
385    }
386}
387
388#[cfg(test)]
389mod tests {
390    use super::*;
391    use wgpu::{TextureFormat, PresentMode, CompositeAlphaMode};
392    
393    #[test]
394    fn test_format_selection() {
395        let formats = vec![
396            TextureFormat::Rgba8Unorm,
397            TextureFormat::Bgra8UnormSrgb,
398            TextureFormat::Rgba8UnormSrgb,
399        ];
400        
401        let chosen = RenderSurface::choose_format(&formats);
402        assert_eq!(chosen, TextureFormat::Bgra8UnormSrgb);
403    }
404    
405    #[test]
406    fn test_present_mode_selection() {
407        let modes = vec![
408            PresentMode::Fifo,
409            PresentMode::Mailbox,
410            PresentMode::Immediate,
411        ];
412        
413        let chosen = RenderSurface::choose_present_mode(&modes);
414        assert_eq!(chosen, PresentMode::Mailbox);
415    }
416    
417    #[test]
418    fn test_alpha_mode_selection() {
419        let modes = vec![
420            CompositeAlphaMode::Opaque,
421            CompositeAlphaMode::Auto,
422            CompositeAlphaMode::PreMultiplied,
423        ];
424
425        let chosen = RenderSurface::choose_alpha_mode(&modes);
426        assert_eq!(chosen, CompositeAlphaMode::Auto);
427    }
428
429    #[test]
430    fn test_format_srgb_preference() {
431        // sRGB formats should be preferred
432        let formats = vec![
433            TextureFormat::Rgba8Unorm,
434            TextureFormat::Bgra8UnormSrgb,
435            TextureFormat::Rgba8UnormSrgb,
436        ];
437
438        let srgb = formats.iter().find(|f| {
439            matches!(f,
440                TextureFormat::Bgra8UnormSrgb |
441                TextureFormat::Rgba8UnormSrgb
442            )
443        });
444        assert!(srgb.is_some());
445    }
446
447    #[test]
448    fn test_present_mode_vsync() {
449        // Fifo mode is VSync on
450        let mode = PresentMode::Fifo;
451        assert_eq!(mode, PresentMode::Fifo);
452
453        // Immediate mode is VSync off
454        let mode = PresentMode::Immediate;
455        assert_eq!(mode, PresentMode::Immediate);
456    }
457}