Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-renderer/src/buffer.rs
1//! Advanced buffer management system for GPU resources
2//!
3//! This module provides a comprehensive buffer management system including:
4//! - Dynamic buffer allocation with intelligent pooling
5//! - Multi-tier memory management (device, host-visible, staging)
6//! - Automatic buffer resizing and defragmentation
7//! - Usage pattern analysis and optimization
8//! - Memory pressure detection and mitigation
9//! - Cross-platform buffer optimization
10//! - Performance profiling and analytics
11//! - Lock-free buffer operations where possible
12 
13use anyhow::{Context, Result};
14use parking_lot::{Mutex, RwLock};
15use serde::{Deserialize, Serialize};
16use std::collections::{HashMap, VecDeque};
17use std::ops::Range;
18use std::sync::{
19 atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
20 Arc,
21};
22use std::time::{Duration, Instant};
23use tracing::{debug, info, instrument, warn};
24use wgpu::{Buffer, BufferDescriptor, BufferUsages};
25 
26use crate::device::ManagedDevice;
27use crate::memory::{MemoryManager, MemoryTier};
28use crate::resources::ResourceHandle;
29 
30/// Buffer usage patterns for optimization
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
32pub enum BufferUsagePattern {
33 /// Static data that rarely changes
34 Static,
35 /// Dynamic data that changes frequently
36 Dynamic,
37 /// Streaming data that changes every frame
38 Streaming,
39 /// Temporary data for single-use operations
40 Transient,
41 /// Persistent data that lives for the entire application
42 Persistent,
43}
44 
45/// Buffer allocation strategy
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
47pub enum AllocationStrategy {
48 /// Best fit allocation
49 BestFit,
50 /// First fit allocation
51 FirstFit,
52 /// Buddy allocation
53 Buddy,
54 /// Pool allocation
55 Pool,
56 /// Linear allocation
57 Linear,
58}
59 
60/// Buffer configuration
61#[derive(Debug, Clone, PartialEq, Eq, Hash)]
62pub struct BufferConfig {
63 pub name: String,
64 pub size: u64,
65 pub usage: BufferUsages,
66 pub usage_pattern: BufferUsagePattern,
67 pub allocation_strategy: AllocationStrategy,
68 pub alignment: u64,
69 pub mapped_at_creation: bool,
70 pub persistent_mapping: bool,
71}
72 
73/// Buffer allocation information
74#[derive(Debug)]
75pub struct BufferAllocation {
76 pub buffer: Arc<Buffer>,
77 pub offset: u64,
78 pub size: u64,
79 pub usage_pattern: BufferUsagePattern,
80 pub allocation_time: Instant,
81 pub last_access: Instant,
82 pub access_count: AtomicU64,
83 pub memory_tier: MemoryTier,
84}
85 
86/// Buffer pool for efficient reuse
87pub struct BufferPool {
88 device: Arc<ManagedDevice>,
89 _memory_manager: Arc<Mutex<MemoryManager>>,
90 
91 // Pool storage by size and usage
92 pools: RwLock<HashMap<(u64, BufferUsages), VecDeque<Arc<Buffer>>>>,
93 
94 // Active allocations
95 active_allocations: RwLock<HashMap<ResourceHandle, BufferAllocation>>,
96 
97 // Configuration
98 max_pool_size: AtomicUsize,
99 _min_buffer_size: AtomicU64,
100 _max_buffer_size: AtomicU64,
101 alignment_requirement: AtomicU64,
102 
103 // Statistics
104 allocation_count: AtomicU64,
105 deallocation_count: AtomicU64,
106 pool_hits: AtomicU64,
107 pool_misses: AtomicU64,
108 total_allocated_bytes: AtomicU64,
109 peak_allocated_bytes: AtomicU64,
110 
111 // Performance tracking
112 allocation_times: RwLock<VecDeque<Duration>>,
113 usage_patterns: RwLock<HashMap<BufferUsagePattern, BufferUsageStats>>,
114}
115 
116/// Buffer usage statistics
117#[derive(Debug, Clone, Default)]
118pub struct BufferUsageStats {
119 pub allocation_count: u64,
120 pub total_size: u64,
121 pub average_lifetime: Duration,
122 pub access_frequency: f64,
123 pub fragmentation_ratio: f32,
124}
125 
126/// Dynamic buffer that can grow and shrink
127pub struct DynamicBuffer {
128 _device: Arc<ManagedDevice>,
129 buffer_pool: Arc<BufferPool>,
130 
131 // Current buffer
132 current_buffer: RwLock<Option<Arc<Buffer>>>,
133 current_size: AtomicU64,
134 used_size: AtomicU64,
135 
136 // Configuration
137 config: BufferConfig,
138 growth_factor: f32,
139 shrink_threshold: f32,
140 
141 // Statistics
142 resize_count: AtomicU64,
143 last_resize: RwLock<Option<Instant>>,
144}
145 
146/// Staging buffer for efficient data transfers
147#[allow(dead_code)]
148pub struct StagingBuffer {
149 device: Arc<ManagedDevice>,
150 buffer: Arc<Buffer>,
151 mapped_range: Option<Range<u64>>,
152 size: u64,
153 usage_pattern: BufferUsagePattern,
154 
155 // Transfer tracking
156 pending_transfers: RwLock<Vec<PendingTransfer>>,
157 completed_transfers: AtomicU64,
158}
159 
160/// Pending transfer operation
161#[derive(Debug, Clone)]
162pub struct PendingTransfer {
163 pub source_offset: u64,
164 pub dest_buffer: Arc<Buffer>,
165 pub dest_offset: u64,
166 pub size: u64,
167 pub timestamp: Instant,
168}
169 
170/// Ring buffer for streaming data
171pub struct RingBuffer {
172 _device: Arc<ManagedDevice>,
173 buffer: Arc<Buffer>,
174 size: u64,
175 head: AtomicU64,
176 tail: AtomicU64,
177 wrapped: AtomicBool,
178 
179 // Configuration
180 alignment: u64,
181 _usage_pattern: BufferUsagePattern,
182 
183 // Statistics
184 write_count: AtomicU64,
185 bytes_written: AtomicU64,
186 overruns: AtomicU64,
187}
188 
189/// Buffer manager coordinating all buffer operations
190pub struct BufferManager {
191 device: Arc<ManagedDevice>,
192 _memory_manager: Arc<Mutex<MemoryManager>>,
193 
194 // Buffer pools
195 vertex_pool: Arc<BufferPool>,
196 index_pool: Arc<BufferPool>,
197 uniform_pool: Arc<BufferPool>,
198 storage_pool: Arc<BufferPool>,
199 staging_pool: Arc<BufferPool>,
200 
201 // Dynamic buffers
202 dynamic_buffers: RwLock<HashMap<ResourceHandle, Arc<DynamicBuffer>>>,
203 
204 // Ring buffers
205 ring_buffers: RwLock<HashMap<ResourceHandle, Arc<RingBuffer>>>,
206 
207 // Staging buffers
208 _staging_buffers: RwLock<HashMap<ResourceHandle, Arc<StagingBuffer>>>,
209 
210 // Global statistics
211 total_buffers: AtomicU64,
212 total_memory_usage: AtomicU64,
213 _fragmentation_ratio: RwLock<f32>,
214 
215 // Configuration
216 auto_defragmentation: AtomicBool,
217 memory_pressure_threshold: AtomicU64,
218 _profiling_enabled: AtomicBool,
219}
220 
221impl Default for BufferConfig {
222 fn default() -> Self {
223 Self {
224 name: "unnamed".to_string(),
225 size: 1024,
226 usage: BufferUsages::VERTEX,
227 usage_pattern: BufferUsagePattern::Dynamic,
228 allocation_strategy: AllocationStrategy::Pool,
229 alignment: 256,
230 mapped_at_creation: false,
231 persistent_mapping: false,
232 }
233 }
234}
235 
236impl BufferPool {
237 /// Create a new buffer pool
238 pub fn new(device: Arc<ManagedDevice>, memory_manager: Arc<Mutex<MemoryManager>>) -> Self {
239 Self {
240 device,
241 _memory_manager: memory_manager,
242 pools: RwLock::new(HashMap::new()),
243 active_allocations: RwLock::new(HashMap::new()),
244 max_pool_size: AtomicUsize::new(100),
245 _min_buffer_size: AtomicU64::new(256),
246 _max_buffer_size: AtomicU64::new(256 * 1024 * 1024), // 256MB
247 alignment_requirement: AtomicU64::new(256),
248 allocation_count: AtomicU64::new(0),
249 deallocation_count: AtomicU64::new(0),
250 pool_hits: AtomicU64::new(0),
251 pool_misses: AtomicU64::new(0),
252 total_allocated_bytes: AtomicU64::new(0),
253 peak_allocated_bytes: AtomicU64::new(0),
254 allocation_times: RwLock::new(VecDeque::new()),
255 usage_patterns: RwLock::new(HashMap::new()),
256 }
257 }
258 
259 /// Allocate a buffer from the pool
260 #[instrument(skip(self))]
261 pub fn allocate(&self, config: &BufferConfig) -> Result<ResourceHandle> {
262 let start_time = Instant::now();
263 
264 // Align size to requirements
265 let aligned_size = self.align_size(config.size);
266 let pool_key = (aligned_size, config.usage);
267 
268 // Try to get from pool first
269 if let Some(buffer) = self.try_get_from_pool(&pool_key) {
270 self.pool_hits.fetch_add(1, Ordering::Relaxed);
271 return self.create_allocation(buffer, config, start_time);
272 }
273 
274 self.pool_misses.fetch_add(1, Ordering::Relaxed);
275 
276 // Create new buffer
277 let buffer = self.create_buffer(config, aligned_size)?;
278 self.create_allocation(Arc::new(buffer), config, start_time)
279 }
280 
281 /// Try to get buffer from pool
282 fn try_get_from_pool(&self, pool_key: &(u64, BufferUsages)) -> Option<Arc<Buffer>> {
283 let mut pools = self.pools.write();
284 if let Some(pool) = pools.get_mut(pool_key) {
285 pool.pop_front()
286 } else {
287 None
288 }
289 }
290 
291 /// Create a new buffer
292 fn create_buffer(&self, config: &BufferConfig, size: u64) -> Result<Buffer> {
293 let buffer = self.device.device.create_buffer(&BufferDescriptor {
294 label: Some(&config.name),
295 size,
296 usage: config.usage,
297 mapped_at_creation: config.mapped_at_creation,
298 });
299 
300 Ok(buffer)
301 }
302 
303 /// Create allocation record
304 fn create_allocation(
305 &self,
306 buffer: Arc<Buffer>,
307 config: &BufferConfig,
308 start_time: Instant,
309 ) -> Result<ResourceHandle> {
310 let handle = ResourceHandle::new();
311 let allocation_time = start_time.elapsed();
312 
313 let allocation = BufferAllocation {
314 buffer,
315 offset: 0,
316 size: config.size,
317 usage_pattern: config.usage_pattern,
318 allocation_time: start_time,
319 last_access: start_time,
320 access_count: AtomicU64::new(0),
321 memory_tier: MemoryTier::HighSpeed, // Default tier
322 };
323 
324 self.active_allocations.write().insert(handle, allocation);
325 
326 // Update statistics
327 self.allocation_count.fetch_add(1, Ordering::Relaxed);
328 self.total_allocated_bytes
329 .fetch_add(config.size, Ordering::Relaxed);
330 
331 let current_total = self.total_allocated_bytes.load(Ordering::Relaxed);
332 let peak = self.peak_allocated_bytes.load(Ordering::Relaxed);
333 if current_total > peak {
334 self.peak_allocated_bytes
335 .store(current_total, Ordering::Relaxed);
336 }
337 
338 // Record allocation time
339 let mut times = self.allocation_times.write();
340 times.push_back(allocation_time);
341 if times.len() > 1000 {
342 times.pop_front();
343 }
344 
345 // Update usage pattern statistics
346 self.update_usage_stats(config.usage_pattern, config.size);
347 
348 debug!(
349 "Allocated buffer '{}' ({} bytes) in {:?}",
350 config.name, config.size, allocation_time
351 );
352 
353 Ok(handle)
354 }
355 
356 /// Deallocate a buffer
357 #[instrument(skip(self))]
358 pub fn deallocate(&self, handle: ResourceHandle) -> Result<()> {
359 let allocation = self
360 .active_allocations
361 .write()
362 .remove(&handle)
363 .context("Buffer allocation not found")?;
364 
365 let pool_key = (allocation.size, allocation.buffer.usage());
366 
367 // Return to pool if there's space
368 let mut pools = self.pools.write();
369 let pool = pools.entry(pool_key).or_insert_with(VecDeque::new);
370 
371 if pool.len() < self.max_pool_size.load(Ordering::Relaxed) {
372 pool.push_back(allocation.buffer);
373 }
374 // Otherwise, buffer will be dropped and freed
375 
376 // Update statistics
377 self.deallocation_count.fetch_add(1, Ordering::Relaxed);
378 self.total_allocated_bytes
379 .fetch_sub(allocation.size, Ordering::Relaxed);
380 
381 debug!("Deallocated buffer (handle: {:?})", handle);
382 
383 Ok(())
384 }
385 
386 /// Get buffer allocation (returns reference to avoid clone issues)
387 pub fn get_allocation(&self, handle: ResourceHandle) -> Option<Arc<Buffer>> {
388 self.active_allocations
389 .read()
390 .get(&handle)
391 .map(|alloc| alloc.buffer.clone())
392 }
393 
394 /// Update access time for buffer
395 pub fn update_access(&self, handle: ResourceHandle) {
396 if let Some(allocation) = self.active_allocations.write().get_mut(&handle) {
397 allocation.last_access = Instant::now();
398 allocation.access_count.fetch_add(1, Ordering::Relaxed);
399 }
400 }
401 
402 /// Align size to requirements
403 fn align_size(&self, size: u64) -> u64 {
404 let alignment = self.alignment_requirement.load(Ordering::Relaxed);
405 (size + alignment - 1) & !(alignment - 1)
406 }
407 
408 /// Update usage pattern statistics
409 fn update_usage_stats(&self, pattern: BufferUsagePattern, size: u64) {
410 let mut stats = self.usage_patterns.write();
411 let pattern_stats = stats.entry(pattern).or_default();
412 pattern_stats.allocation_count += 1;
413 pattern_stats.total_size += size;
414 }
415 
416 /// Get pool statistics
417 pub fn get_stats(&self) -> HashMap<String, u64> {
418 let mut stats = HashMap::new();
419 stats.insert(
420 "allocations".to_string(),
421 self.allocation_count.load(Ordering::Relaxed),
422 );
423 stats.insert(
424 "deallocations".to_string(),
425 self.deallocation_count.load(Ordering::Relaxed),
426 );
427 stats.insert(
428 "pool_hits".to_string(),
429 self.pool_hits.load(Ordering::Relaxed),
430 );
431 stats.insert(
432 "pool_misses".to_string(),
433 self.pool_misses.load(Ordering::Relaxed),
434 );
435 stats.insert(
436 "total_bytes".to_string(),
437 self.total_allocated_bytes.load(Ordering::Relaxed),
438 );
439 stats.insert(
440 "peak_bytes".to_string(),
441 self.peak_allocated_bytes.load(Ordering::Relaxed),
442 );
443 stats
444 }
445 
446 /// Clear unused buffers from pools
447 pub fn cleanup(&self) {
448 let mut pools = self.pools.write();
449 for pool in pools.values_mut() {
450 pool.clear();
451 }
452 info!("Cleared buffer pools");
453 }
454 
455 /// Set maximum pool size
456 pub fn set_max_pool_size(&self, size: usize) {
457 self.max_pool_size.store(size, Ordering::Relaxed);
458 }
459}
460 
461impl DynamicBuffer {
462 /// Create a new dynamic buffer
463 pub fn new(
464 device: Arc<ManagedDevice>,
465 buffer_pool: Arc<BufferPool>,
466 config: BufferConfig,
467 ) -> Self {
468 Self {
469 _device: device,
470 buffer_pool,
471 current_buffer: RwLock::new(None),
472 current_size: AtomicU64::new(0),
473 used_size: AtomicU64::new(0),
474 config,
475 growth_factor: 1.5,
476 shrink_threshold: 0.25,
477 resize_count: AtomicU64::new(0),
478 last_resize: RwLock::new(None),
479 }
480 }
481 
482 /// Ensure buffer has at least the specified capacity
483 pub fn ensure_capacity(&self, required_size: u64) -> Result<()> {
484 let current_size = self.current_size.load(Ordering::Relaxed);
485 
486 if required_size <= current_size {
487 return Ok(());
488 }
489 
490 let new_size = (required_size as f32 * self.growth_factor) as u64;
491 self.resize(new_size)?;
492 
493 Ok(())
494 }
495 
496 /// Resize the buffer
497 fn resize(&self, new_size: u64) -> Result<()> {
498 let mut config = self.config.clone();
499 config.size = new_size;
500 
501 let handle = self.buffer_pool.allocate(&config)?;
502 let allocation = self
503 .buffer_pool
504 .get_allocation(handle)
505 .context("Failed to get buffer allocation")?;
506 
507 // Copy existing data if needed
508 if let Some(_old_buffer) = self.current_buffer.read().as_ref() {}
509 
510 *self.current_buffer.write() = Some(allocation);
511 self.current_size.store(new_size, Ordering::Relaxed);
512 self.resize_count.fetch_add(1, Ordering::Relaxed);
513 *self.last_resize.write() = Some(Instant::now());
514 
515 debug!("Resized dynamic buffer to {} bytes", new_size);
516 
517 Ok(())
518 }
519 
520 /// Get current buffer
521 pub fn get_buffer(&self) -> Option<Arc<Buffer>> {
522 self.current_buffer.read().clone()
523 }
524 
525 /// Update used size
526 pub fn set_used_size(&self, size: u64) {
527 self.used_size.store(size, Ordering::Relaxed);
528 
529 // Check if we should shrink
530 let current_size = self.current_size.load(Ordering::Relaxed);
531 let usage_ratio = size as f32 / current_size as f32;
532 
533 if usage_ratio < self.shrink_threshold && current_size > self.config.size {
534 let new_size =
535 std::cmp::max((size as f32 * self.growth_factor) as u64, self.config.size);
536 
537 if let Err(e) = self.resize(new_size) {
538 warn!("Failed to shrink buffer: {}", e);
539 }
540 }
541 }
542}
543 
544impl RingBuffer {
545 /// Create a new ring buffer
546 pub fn new(
547 device: Arc<ManagedDevice>,
548 size: u64,
549 usage: BufferUsages,
550 usage_pattern: BufferUsagePattern,
551 ) -> Result<Self> {
552 let buffer = Arc::new(device.device.create_buffer(&BufferDescriptor {
553 label: Some("RingBuffer"),
554 size,
555 usage,
556 mapped_at_creation: false,
557 }));
558 
559 Ok(Self {
560 _device: device,
561 buffer,
562 size,
563 head: AtomicU64::new(0),
564 tail: AtomicU64::new(0),
565 wrapped: AtomicBool::new(false),
566 alignment: 256,
567 _usage_pattern: usage_pattern,
568 write_count: AtomicU64::new(0),
569 bytes_written: AtomicU64::new(0),
570 overruns: AtomicU64::new(0),
571 })
572 }
573 
574 /// Allocate space in the ring buffer
575 pub fn allocate(&self, size: u64) -> Option<u64> {
576 let aligned_size = (size + self.alignment - 1) & !(self.alignment - 1);
577 let head = self.head.load(Ordering::Relaxed);
578 let tail = self.tail.load(Ordering::Relaxed);
579 
580 let available = if self.wrapped.load(Ordering::Relaxed) {
581 if head >= tail {
582 tail - head
583 } else {
584 self.size - head + tail
585 }
586 } else {
587 self.size - head
588 };
589 
590 if aligned_size > available {
591 self.overruns.fetch_add(1, Ordering::Relaxed);
592 return None;
593 }
594 
595 let offset = head;
596 let new_head = (head + aligned_size) % self.size;
597 
598 if new_head < head {
599 self.wrapped.store(true, Ordering::Relaxed);
600 }
601 
602 self.head.store(new_head, Ordering::Relaxed);
603 self.write_count.fetch_add(1, Ordering::Relaxed);
604 self.bytes_written
605 .fetch_add(aligned_size, Ordering::Relaxed);
606 
607 Some(offset)
608 }
609 
610 /// Get buffer reference
611 pub fn get_buffer(&self) -> &Arc<Buffer> {
612 &self.buffer
613 }
614 
615 /// Get statistics
616 pub fn get_stats(&self) -> HashMap<String, u64> {
617 let mut stats = HashMap::new();
618 stats.insert(
619 "writes".to_string(),
620 self.write_count.load(Ordering::Relaxed),
621 );
622 stats.insert(
623 "bytes_written".to_string(),
624 self.bytes_written.load(Ordering::Relaxed),
625 );
626 stats.insert(
627 "overruns".to_string(),
628 self.overruns.load(Ordering::Relaxed),
629 );
630 stats.insert("head".to_string(), self.head.load(Ordering::Relaxed));
631 stats.insert("tail".to_string(), self.tail.load(Ordering::Relaxed));
632 stats
633 }
634}
635 
636impl BufferManager {
637 /// Create a new buffer manager
638 pub fn new(device: Arc<ManagedDevice>, memory_manager: Arc<Mutex<MemoryManager>>) -> Self {
639 let vertex_pool = Arc::new(BufferPool::new(device.clone(), memory_manager.clone()));
640 let index_pool = Arc::new(BufferPool::new(device.clone(), memory_manager.clone()));
641 let uniform_pool = Arc::new(BufferPool::new(device.clone(), memory_manager.clone()));
642 let storage_pool = Arc::new(BufferPool::new(device.clone(), memory_manager.clone()));
643 let staging_pool = Arc::new(BufferPool::new(device.clone(), memory_manager.clone()));
644 
645 Self {
646 device,
647 _memory_manager: memory_manager,
648 vertex_pool,
649 index_pool,
650 uniform_pool,
651 storage_pool,
652 staging_pool,
653 dynamic_buffers: RwLock::new(HashMap::new()),
654 ring_buffers: RwLock::new(HashMap::new()),
655 _staging_buffers: RwLock::new(HashMap::new()),
656 total_buffers: AtomicU64::new(0),
657 total_memory_usage: AtomicU64::new(0),
658 _fragmentation_ratio: RwLock::new(0.0),
659 auto_defragmentation: AtomicBool::new(true),
660 memory_pressure_threshold: AtomicU64::new(1024 * 1024 * 1024), // 1GB
661 _profiling_enabled: AtomicBool::new(true),
662 }
663 }
664 
665 /// Allocate a buffer with the specified configuration
666 pub fn allocate_buffer(&self, config: &BufferConfig) -> Result<ResourceHandle> {
667 let pool = self.get_pool_for_usage(config.usage);
668 let handle = pool.allocate(config)?;
669 
670 self.total_buffers.fetch_add(1, Ordering::Relaxed);
671 self.total_memory_usage
672 .fetch_add(config.size, Ordering::Relaxed);
673 
674 Ok(handle)
675 }
676 
677 /// Deallocate a buffer
678 pub fn deallocate_buffer(&self, handle: ResourceHandle, usage: BufferUsages) -> Result<()> {
679 let pool = self.get_pool_for_usage(usage);
680 
681 if let Some(_buffer) = pool.get_allocation(handle) {
682 // Size tracking would need to be handled differently
683 // For now, just proceed with deallocation
684 }
685 
686 pool.deallocate(handle)?;
687 self.total_buffers.fetch_sub(1, Ordering::Relaxed);
688 
689 Ok(())
690 }
691 
692 /// Create a dynamic buffer
693 pub fn create_dynamic_buffer(&self, config: BufferConfig) -> Result<ResourceHandle> {
694 let handle = ResourceHandle::new();
695 let pool = self.get_pool_for_usage(config.usage);
696 
697 let dynamic_buffer = Arc::new(DynamicBuffer::new(self.device.clone(), pool, config));
698 
699 self.dynamic_buffers.write().insert(handle, dynamic_buffer);
700 
701 Ok(handle)
702 }
703 
704 /// Create a ring buffer
705 pub fn create_ring_buffer(
706 &self,
707 size: u64,
708 usage: BufferUsages,
709 usage_pattern: BufferUsagePattern,
710 ) -> Result<ResourceHandle> {
711 let handle = ResourceHandle::new();
712 
713 let ring_buffer = Arc::new(RingBuffer::new(
714 self.device.clone(),
715 size,
716 usage,
717 usage_pattern,
718 )?);
719 
720 self.ring_buffers.write().insert(handle, ring_buffer);
721 self.total_buffers.fetch_add(1, Ordering::Relaxed);
722 self.total_memory_usage.fetch_add(size, Ordering::Relaxed);
723 
724 Ok(handle)
725 }
726 
727 /// Get pool for buffer usage
728 fn get_pool_for_usage(&self, usage: BufferUsages) -> Arc<BufferPool> {
729 if usage.contains(BufferUsages::VERTEX) {
730 self.vertex_pool.clone()
731 } else if usage.contains(BufferUsages::INDEX) {
732 self.index_pool.clone()
733 } else if usage.contains(BufferUsages::UNIFORM) {
734 self.uniform_pool.clone()
735 } else if usage.contains(BufferUsages::STORAGE) {
736 self.storage_pool.clone()
737 } else {
738 self.staging_pool.clone()
739 }
740 }
741 
742 /// Get buffer manager statistics
743 pub fn get_stats(&self) -> HashMap<String, u64> {
744 let mut stats = HashMap::new();
745 stats.insert(
746 "total_buffers".to_string(),
747 self.total_buffers.load(Ordering::Relaxed),
748 );
749 stats.insert(
750 "total_memory".to_string(),
751 self.total_memory_usage.load(Ordering::Relaxed),
752 );
753 
754 // Add pool-specific stats
755 let vertex_stats = self.vertex_pool.get_stats();
756 for (key, value) in vertex_stats {
757 stats.insert(format!("vertex_{}", key), value);
758 }
759 
760 let uniform_stats = self.uniform_pool.get_stats();
761 for (key, value) in uniform_stats {
762 stats.insert(format!("uniform_{}", key), value);
763 }
764 
765 stats
766 }
767 
768 /// Get buffer by handle
769 pub fn get_buffer(&self, handle: ResourceHandle) -> Option<Arc<Buffer>> {
770 // Check all pools
771 if let Some(buffer) = self.vertex_pool.get_allocation(handle) {
772 return Some(buffer);
773 }
774 if let Some(buffer) = self.index_pool.get_allocation(handle) {
775 return Some(buffer);
776 }
777 if let Some(buffer) = self.uniform_pool.get_allocation(handle) {
778 return Some(buffer);
779 }
780 if let Some(buffer) = self.storage_pool.get_allocation(handle) {
781 return Some(buffer);
782 }
783 if let Some(buffer) = self.staging_pool.get_allocation(handle) {
784 return Some(buffer);
785 }
786 
787 // Check dynamic buffers
788 if let Some(dynamic) = self.dynamic_buffers.read().get(&handle) {
789 return dynamic.get_buffer();
790 }
791 
792 // Check ring buffers
793 if let Some(ring) = self.ring_buffers.read().get(&handle) {
794 return Some(ring.get_buffer().clone());
795 }
796 
797 None
798 }
799 
800 /// Perform defragmentation if needed
801 pub fn defragment(&self) -> Result<()> {
802 if !self.auto_defragmentation.load(Ordering::Relaxed) {
803 return Ok(());
804 }
805 
806 let memory_usage = self.total_memory_usage.load(Ordering::Relaxed);
807 let threshold = self.memory_pressure_threshold.load(Ordering::Relaxed);
808 
809 if memory_usage > threshold {
810 info!("Starting buffer defragmentation");
811 
812 // Clear unused buffers from pools
813 self.vertex_pool.cleanup();
814 self.index_pool.cleanup();
815 self.uniform_pool.cleanup();
816 self.storage_pool.cleanup();
817 self.staging_pool.cleanup();
818 
819 info!("Buffer defragmentation completed");
820 }
821 
822 Ok(())
823 }
824 
825 /// Set auto defragmentation
826 pub fn set_auto_defragmentation(&self, enabled: bool) {
827 self.auto_defragmentation.store(enabled, Ordering::Relaxed);
828 }
829 
830 /// Set memory pressure threshold
831 pub fn set_memory_pressure_threshold(&self, threshold: u64) {
832 self.memory_pressure_threshold
833 .store(threshold, Ordering::Relaxed);
834 }
835 
836 /// Initialize the buffer manager (integration method)
837 pub fn initialize(&self) -> Result<()> {
838 info!("Buffer manager initialized");
839 Ok(())
840 }
841 
842 /// Create buffer (integration method)
843 pub fn create_buffer(&self, config: &BufferConfig) -> Result<ResourceHandle> {
844 self.allocate_buffer(config)
845 }
846 
847 /// Collect garbage (integration method)
848 pub fn collect_garbage(&self) {
849 let _ = self.defragment();
850 }
851}
852