anvilkit-render 0.1.0

Cross-platform rendering system built on wgpu and winit for AnvilKit game engine
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
//! # 窗口表面和交换链管理
//! 
//! 提供 wgpu 表面配置、交换链管理和帧缓冲功能。

use std::sync::Arc;
use wgpu::{
    Surface, SurfaceConfiguration, TextureFormat, PresentMode, CompositeAlphaMode,
    SurfaceTexture,
};
use winit::window::Window;
use log::{info, warn, debug};

use crate::renderer::RenderDevice;
use anvilkit_core::error::{AnvilKitError, Result};

/// 渲染表面
/// 
/// 管理窗口表面、交换链配置和帧缓冲,提供渲染目标管理功能。
/// 
/// # 设计理念
/// 
/// - **自适应配置**: 根据设备能力自动配置表面参数
/// - **动态调整**: 支持窗口大小变化时的动态重配置
/// - **格式选择**: 自动选择最佳的纹理格式和呈现模式
/// - **错误恢复**: 处理表面丢失等异常情况
/// 
/// # 示例
/// 
/// ```rust,no_run
/// use anvilkit_render::renderer::{RenderDevice, RenderSurface};
/// use std::sync::Arc;
/// use winit::window::Window;
/// 
/// # async fn example() -> anvilkit_core::error::Result<()> {
/// // 创建设备和表面
/// // let window = Arc::new(window);
/// // let device = RenderDevice::new(&window).await?;
/// // let surface = RenderSurface::new(&device, &window)?;
/// 
/// // 获取当前帧
/// // let frame = surface.get_current_frame()?;
/// # Ok(())
/// # }
/// ```
pub struct RenderSurface {
    /// wgpu 表面(持有 Arc<Window>,保证生命周期安全)
    surface: Surface<'static>,
    /// 表面配置
    config: SurfaceConfiguration,
    /// 当前纹理格式
    format: TextureFormat,
    /// 持有窗口引用以保证 surface 生命周期
    _window: Arc<Window>,
}

impl RenderSurface {
    /// 创建新的渲染表面
    /// 
    /// # 参数
    /// 
    /// - `device`: 渲染设备
    /// - `window`: 窗口实例
    /// 
    /// # 返回
    /// 
    /// 成功时返回 RenderSurface 实例,失败时返回错误
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// use anvilkit_render::renderer::{RenderDevice, RenderSurface};
    /// use std::sync::Arc;
    /// use winit::window::Window;
    /// 
    /// # async fn example() -> anvilkit_core::error::Result<()> {
    /// // let window = Arc::new(window);
    /// // let device = RenderDevice::new(&window).await?;
    /// // let surface = RenderSurface::new(&device, &window)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn new(device: &RenderDevice, window: &Arc<Window>) -> Result<Self> {
        Self::new_with_vsync(device, window, false)
    }

    /// 创建新的渲染表面(指定 vsync 模式)
    ///
    /// - `vsync = true`: 使用 `PresentMode::Fifo`(垂直同步)
    /// - `vsync = false`: 优先使用 `PresentMode::Mailbox`(三重缓冲,低延迟)
    pub fn new_with_vsync(device: &RenderDevice, window: &Arc<Window>, vsync: bool) -> Result<Self> {
        info!("创建渲染表面 (vsync={})", vsync);

        // 创建表面
        let surface = device.instance().create_surface(window.clone())
            .map_err(|e| AnvilKitError::render(format!("创建表面失败: {}", e)))?;

        // 获取表面能力
        let capabilities = surface.get_capabilities(device.adapter());

        // 选择纹理格式
        let format = Self::choose_format(&capabilities.formats);

        // 获取窗口大小
        let size = window.inner_size();

        // 选择呈现模式
        let present_mode = if vsync {
            PresentMode::Fifo
        } else {
            Self::choose_present_mode(&capabilities.present_modes)
        };

        // 创建表面配置
        let config = SurfaceConfiguration {
            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
            format,
            width: size.width,
            height: size.height,
            present_mode,
            alpha_mode: Self::choose_alpha_mode(&capabilities.alpha_modes),
            view_formats: vec![],
            desired_maximum_frame_latency: 2,
        };
        
        // 配置表面
        surface.configure(device.device(), &config);
        
        info!("渲染表面创建成功");
        info!("表面格式: {:?}", format);
        info!("表面大小: {}x{}", config.width, config.height);
        info!("呈现模式: {:?}", config.present_mode);
        
        Ok(Self {
            surface,
            config,
            format,
            _window: window.clone(),
        })
    }
    
    /// 选择纹理格式
    /// 
    /// # 参数
    /// 
    /// - `formats`: 支持的格式列表
    /// 
    /// # 返回
    /// 
    /// 返回选择的纹理格式
    fn choose_format(formats: &[TextureFormat]) -> TextureFormat {
        // 优先选择 sRGB 格式
        for &format in formats {
            match format {
                TextureFormat::Bgra8UnormSrgb | TextureFormat::Rgba8UnormSrgb => {
                    debug!("选择纹理格式: {:?}", format);
                    return format;
                }
                _ => {}
            }
        }
        
        // 回退到第一个可用格式
        let format = formats[0];
        debug!("回退到纹理格式: {:?}", format);
        format
    }
    
    /// 选择呈现模式
    /// 
    /// # 参数
    /// 
    /// - `modes`: 支持的呈现模式列表
    /// 
    /// # 返回
    /// 
    /// 返回选择的呈现模式
    fn choose_present_mode(modes: &[PresentMode]) -> PresentMode {
        // 优先选择 Mailbox 模式(三重缓冲)
        if modes.contains(&PresentMode::Mailbox) {
            debug!("选择呈现模式: Mailbox");
            return PresentMode::Mailbox;
        }
        
        // 回退到 Fifo 模式(垂直同步)
        debug!("选择呈现模式: Fifo");
        PresentMode::Fifo
    }
    
    /// 选择 Alpha 混合模式
    /// 
    /// # 参数
    /// 
    /// - `modes`: 支持的 Alpha 模式列表
    /// 
    /// # 返回
    /// 
    /// 返回选择的 Alpha 模式
    fn choose_alpha_mode(modes: &[CompositeAlphaMode]) -> CompositeAlphaMode {
        // 优先选择 Auto 模式
        if modes.contains(&CompositeAlphaMode::Auto) {
            debug!("选择 Alpha 模式: Auto");
            return CompositeAlphaMode::Auto;
        }
        
        // 回退到 Opaque 模式
        debug!("选择 Alpha 模式: Opaque");
        CompositeAlphaMode::Opaque
    }
    
    /// 调整表面大小
    /// 
    /// # 参数
    /// 
    /// - `device`: 渲染设备
    /// - `width`: 新的宽度
    /// - `height`: 新的高度
    /// 
    /// # 返回
    /// 
    /// 成功时返回 Ok(()),失败时返回错误
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// # use anvilkit_render::renderer::{RenderDevice, RenderSurface};
    /// # async fn example(device: &RenderDevice, surface: &mut RenderSurface) -> anvilkit_core::error::Result<()> {
    /// surface.resize(device, 1920, 1080)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn resize(&mut self, device: &RenderDevice, width: u32, height: u32) -> Result<()> {
        if width == 0 || height == 0 {
            warn!("忽略无效的表面大小: {}x{}", width, height);
            return Ok(());
        }
        
        info!("调整表面大小: {}x{}", width, height);
        
        self.config.width = width;
        self.config.height = height;
        
        self.surface.configure(device.device(), &self.config);
        
        Ok(())
    }
    
    /// 获取当前帧纹理
    /// 
    /// # 返回
    /// 
    /// 成功时返回 SurfaceTexture,失败时返回错误
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// # use anvilkit_render::renderer::RenderSurface;
    /// # async fn example(surface: &RenderSurface) -> anvilkit_core::error::Result<()> {
    /// let frame = surface.get_current_frame()?;
    /// let view = frame.texture.create_view(&Default::default());
    /// // 使用纹理视图进行渲染
    /// frame.present();
    /// # Ok(())
    /// # }
    /// ```
    pub fn get_current_frame(&self) -> Result<SurfaceTexture> {
        self.surface.get_current_texture()
            .map_err(|e| match e {
                wgpu::SurfaceError::Lost => {
                    AnvilKitError::render("表面丢失,需要重新配置".to_string())
                }
                wgpu::SurfaceError::OutOfMemory => {
                    AnvilKitError::render("GPU 内存不足".to_string())
                }
                wgpu::SurfaceError::Timeout => {
                    AnvilKitError::render("获取表面纹理超时".to_string())
                }
                wgpu::SurfaceError::Outdated => {
                    AnvilKitError::render("表面配置过时,需要重新配置".to_string())
                }
            })
    }

    /// 重新配置表面(用于 Lost/Outdated 恢复)
    pub fn reconfigure(&self, device: &RenderDevice) {
        info!("重新配置渲染表面: {}x{}", self.config.width, self.config.height);
        self.surface.configure(device.device(), &self.config);
    }

    /// 获取当前帧,自动恢复 Lost/Outdated 错误
    ///
    /// 如果首次获取失败(Lost 或 Outdated),自动 reconfigure 后重试一次。
    pub fn get_current_frame_with_recovery(&self, device: &RenderDevice) -> Result<SurfaceTexture> {
        match self.surface.get_current_texture() {
            Ok(frame) => Ok(frame),
            Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
                warn!("表面需要重新配置,正在恢复...");
                self.reconfigure(device);
                // 重试一次
                self.surface.get_current_texture()
                    .map_err(|e| AnvilKitError::render(format!("表面恢复后仍失败: {}", e)))
            }
            Err(wgpu::SurfaceError::OutOfMemory) => {
                Err(AnvilKitError::render("GPU 内存不足".to_string()))
            }
            Err(wgpu::SurfaceError::Timeout) => {
                Err(AnvilKitError::render("获取表面纹理超时".to_string()))
            }
        }
    }
    
    /// 获取表面配置
    /// 
    /// # 返回
    /// 
    /// 返回当前的表面配置
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// # use anvilkit_render::renderer::RenderSurface;
    /// # async fn example(surface: &RenderSurface) {
    /// let config = surface.config();
    /// println!("表面大小: {}x{}", config.width, config.height);
    /// # }
    /// ```
    pub fn config(&self) -> &SurfaceConfiguration {
        &self.config
    }
    
    /// 获取纹理格式
    /// 
    /// # 返回
    /// 
    /// 返回当前的纹理格式
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// # use anvilkit_render::renderer::RenderSurface;
    /// # async fn example(surface: &RenderSurface) {
    /// let format = surface.format();
    /// println!("纹理格式: {:?}", format);
    /// # }
    /// ```
    pub fn format(&self) -> TextureFormat {
        self.format
    }
    
    /// 获取表面大小
    /// 
    /// # 返回
    /// 
    /// 返回 (宽度, 高度) 元组
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// # use anvilkit_render::renderer::RenderSurface;
    /// # async fn example(surface: &RenderSurface) {
    /// let (width, height) = surface.size();
    /// println!("表面大小: {}x{}", width, height);
    /// # }
    /// ```
    pub fn size(&self) -> (u32, u32) {
        (self.config.width, self.config.height)
    }
    
    /// 获取表面引用
    /// 
    /// # 返回
    /// 
    /// 返回 wgpu 表面的引用
    /// 
    /// # 示例
    /// 
    /// ```rust,no_run
    /// # use anvilkit_render::renderer::RenderSurface;
    /// # async fn example(surface: &RenderSurface) {
    /// let wgpu_surface = surface.surface();
    /// // 使用原始表面进行高级操作
    /// # }
    /// ```
    pub fn surface(&self) -> &Surface<'static> {
        &self.surface
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use wgpu::{TextureFormat, PresentMode, CompositeAlphaMode};
    
    #[test]
    fn test_format_selection() {
        let formats = vec![
            TextureFormat::Rgba8Unorm,
            TextureFormat::Bgra8UnormSrgb,
            TextureFormat::Rgba8UnormSrgb,
        ];
        
        let chosen = RenderSurface::choose_format(&formats);
        assert_eq!(chosen, TextureFormat::Bgra8UnormSrgb);
    }
    
    #[test]
    fn test_present_mode_selection() {
        let modes = vec![
            PresentMode::Fifo,
            PresentMode::Mailbox,
            PresentMode::Immediate,
        ];
        
        let chosen = RenderSurface::choose_present_mode(&modes);
        assert_eq!(chosen, PresentMode::Mailbox);
    }
    
    #[test]
    fn test_alpha_mode_selection() {
        let modes = vec![
            CompositeAlphaMode::Opaque,
            CompositeAlphaMode::Auto,
            CompositeAlphaMode::PreMultiplied,
        ];

        let chosen = RenderSurface::choose_alpha_mode(&modes);
        assert_eq!(chosen, CompositeAlphaMode::Auto);
    }

    #[test]
    fn test_format_srgb_preference() {
        // sRGB formats should be preferred
        let formats = vec![
            TextureFormat::Rgba8Unorm,
            TextureFormat::Bgra8UnormSrgb,
            TextureFormat::Rgba8UnormSrgb,
        ];

        let srgb = formats.iter().find(|f| {
            matches!(f,
                TextureFormat::Bgra8UnormSrgb |
                TextureFormat::Rgba8UnormSrgb
            )
        });
        assert!(srgb.is_some());
    }

    #[test]
    fn test_present_mode_vsync() {
        // Fifo mode is VSync on
        let mode = PresentMode::Fifo;
        assert_eq!(mode, PresentMode::Fifo);

        // Immediate mode is VSync off
        let mode = PresentMode::Immediate;
        assert_eq!(mode, PresentMode::Immediate);
    }
}