Skip to main content

astrelis_test_utils/
render_context.rs

1//! Trait abstracting GPU operations for testing.
2//!
3//! The `RenderContext` trait provides an abstraction over GPU operations,
4//! allowing for both real GPU usage and mock implementations for testing.
5
6use crate::gpu_types::*;
7use wgpu::{
8    BindGroupDescriptor, BindGroupLayoutDescriptor, BufferDescriptor, ComputePipelineDescriptor,
9    RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleDescriptor, TextureDescriptor,
10};
11
12/// Trait abstracting GPU resource creation and operations.
13///
14/// # Lifetime Considerations
15///
16/// This trait does NOT use lifetimes because:
17/// 1. All returned types are owned (not borrowed from Device)
18/// 2. GPU resources use reference counting internally
19/// 3. Resources live until dropped
20///
21/// This makes the trait object-safe and easy to mock.
22///
23/// # Borrow Checking Pattern
24///
25/// Methods take `&self` (shared reference) and return owned wrapper types.
26/// This allows:
27/// - Multiple components to share the same context (via Arc)
28/// - Mock implementations to use interior mutability (Mutex)
29/// - No lifetime parameters propagating through the codebase
30///
31/// # Example
32///
33/// ```rust,no_run
34/// use astrelis_test_utils::RenderContext;
35/// use wgpu::{BufferDescriptor, BufferUsages};
36///
37/// fn render_scene(ctx: &dyn RenderContext) {
38///     let desc = BufferDescriptor {
39///         label: None,
40///         size: 16,
41///         usage: BufferUsages::VERTEX,
42///         mapped_at_creation: false,
43///     };
44///     let data = vec![0u8; 16];
45///     let buffer = ctx.create_buffer(&desc);
46///     ctx.write_buffer(&buffer, 0, &data);
47///     // buffer is owned, no lifetime issues
48/// }
49/// ```
50pub trait RenderContext: Send + Sync {
51    // Buffer operations
52
53    /// Create a GPU buffer.
54    ///
55    /// Returns an owned `GpuBuffer` which can be either real or mock.
56    fn create_buffer(&self, desc: &BufferDescriptor) -> GpuBuffer;
57
58    /// Write data to a buffer.
59    ///
60    /// For real buffers, this maps to `queue.write_buffer()`.
61    /// For mock buffers, this records the operation for test verification.
62    fn write_buffer(&self, buffer: &GpuBuffer, offset: u64, data: &[u8]);
63
64    // Texture operations
65
66    /// Create a GPU texture.
67    fn create_texture(&self, desc: &TextureDescriptor) -> GpuTexture;
68
69    // Note: write_texture method will be added when needed during migration
70    // It requires wgpu types that aren't in the public API surface we're using
71
72    // Shader operations
73
74    /// Create a shader module from source code.
75    fn create_shader_module(&self, desc: &ShaderModuleDescriptor) -> GpuShaderModule;
76
77    // Pipeline operations
78
79    /// Create a render pipeline.
80    fn create_render_pipeline(&self, desc: &RenderPipelineDescriptor) -> GpuRenderPipeline;
81
82    /// Create a compute pipeline.
83    fn create_compute_pipeline(&self, desc: &ComputePipelineDescriptor) -> GpuComputePipeline;
84
85    // Bind group operations
86
87    /// Create a bind group layout.
88    fn create_bind_group_layout(&self, desc: &BindGroupLayoutDescriptor) -> GpuBindGroupLayout;
89
90    /// Create a bind group.
91    fn create_bind_group(&self, desc: &BindGroupDescriptor) -> GpuBindGroup;
92
93    // Sampler operations
94
95    /// Create a texture sampler.
96    fn create_sampler(&self, desc: &SamplerDescriptor) -> GpuSampler;
97}
98
99/// Helper trait for converting WGPU descriptors that reference GPU resources.
100///
101/// This is needed because WGPU descriptors contain references to concrete types
102/// like `&wgpu::Buffer`, but our wrappers contain `GpuBuffer`.
103///
104/// We'll implement conversion helpers as needed.
105pub trait DescriptorHelper {
106    /// Convert a descriptor that references wrapped GPU types to one that
107    /// references WGPU types (for real GPU operations).
108    type WgpuDescriptor<'a>
109    where
110        Self: 'a;
111
112    fn to_wgpu(&self) -> Self::WgpuDescriptor<'_>;
113}
114
115// Note: We'll implement DescriptorHelper for specific descriptors as needed
116// during the migration. For now, most descriptors don't reference GPU resources
117// directly and can be used as-is.