Skip to main content

anvilkit_render/renderer/
buffer_pool.rs

1//! # GPU Buffer Pool
2//!
3//! 可复用的 GPU 缓冲区池,避免子系统渲染器(sprite、particle、UI、line、text)每帧分配新缓冲区。
4//!
5//! ## 使用方式
6//!
7//! ```rust,ignore
8//! let buffer = pool.acquire(device, min_size, usage, label);
9//! // ... 使用 buffer 进行渲染 ...
10//! pool.release(buffer);
11//! ```
12
13use wgpu::{Buffer, BufferUsages, Device};
14
15/// GPU 缓冲区池
16///
17/// 维护一组可复用的 GPU 缓冲区,按大小排序。
18/// `acquire()` 返回一个足够大的闲置缓冲区或创建新缓冲区。
19/// `release()` 将缓冲区归还池中以供下一帧复用。
20pub struct BufferPool {
21    /// 可用缓冲区池 (buffer, capacity_bytes)
22    available: Vec<(Buffer, u64)>,
23    /// 本帧使用中的缓冲区数量(用于统计)
24    in_use_count: usize,
25    /// 池上限
26    max_pool_size: usize,
27}
28
29impl BufferPool {
30    /// 创建新的缓冲区池
31    ///
32    /// `max_pool_size`: 池中最大缓冲区数量(默认推荐 64)
33    pub fn new(max_pool_size: usize) -> Self {
34        Self {
35            available: Vec::new(),
36            in_use_count: 0,
37            max_pool_size,
38        }
39    }
40
41    /// 获取一个至少 `min_size` 字节的缓冲区
42    ///
43    /// 优先复用池中现有的足够大的缓冲区,否则创建新缓冲区。
44    pub fn acquire(
45        &mut self,
46        device: &Device,
47        min_size: u64,
48        usage: BufferUsages,
49        label: &str,
50    ) -> Buffer {
51        // 查找足够大的缓冲区(从小到大排序后二分查找)
52        if let Some(idx) = self.available.iter().position(|(_, cap)| *cap >= min_size) {
53            self.in_use_count += 1;
54            return self.available.remove(idx).0;
55        }
56
57        // 没有合适的缓冲区,创建新的
58        self.in_use_count += 1;
59        device.create_buffer(&wgpu::BufferDescriptor {
60            label: Some(label),
61            size: min_size,
62            usage,
63            mapped_at_creation: false,
64        })
65    }
66
67    /// 归还缓冲区到池中以供复用
68    pub fn release(&mut self, buffer: Buffer, capacity: u64) {
69        self.in_use_count = self.in_use_count.saturating_sub(1);
70
71        // 如果池已满,丢弃最小的缓冲区
72        if self.available.len() >= self.max_pool_size {
73            // 找到最小的缓冲区
74            if let Some(min_idx) = self.available.iter()
75                .enumerate()
76                .min_by_key(|(_, (_, cap))| *cap)
77                .map(|(i, _)| i)
78            {
79                if self.available[min_idx].1 < capacity {
80                    // 新缓冲区更大,替换最小的
81                    self.available.remove(min_idx);
82                } else {
83                    // 新缓冲区是最小的,直接丢弃
84                    return;
85                }
86            }
87        }
88
89        self.available.push((buffer, capacity));
90    }
91
92    /// 当前池中可用缓冲区数量
93    pub fn available_count(&self) -> usize {
94        self.available.len()
95    }
96
97    /// 当前使用中的缓冲区数量
98    pub fn in_use_count(&self) -> usize {
99        self.in_use_count
100    }
101
102    /// 清空池(释放所有缓冲区)
103    pub fn clear(&mut self) {
104        self.available.clear();
105        self.in_use_count = 0;
106    }
107}
108
109impl Default for BufferPool {
110    fn default() -> Self {
111        Self::new(64)
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_buffer_pool_default() {
121        let pool = BufferPool::default();
122        assert_eq!(pool.available_count(), 0);
123        assert_eq!(pool.in_use_count(), 0);
124        assert_eq!(pool.max_pool_size, 64);
125    }
126
127    #[test]
128    fn test_buffer_pool_custom_size() {
129        let pool = BufferPool::new(16);
130        assert_eq!(pool.max_pool_size, 16);
131    }
132}