astrelis_render/
extension.rs

1//! Extension traits for low-level wgpu access.
2//!
3//! This module provides traits that allow accessing the underlying wgpu types
4//! from the Astrelis wrapper types. Use these when you need raw wgpu access
5//! for advanced use cases not covered by the high-level API.
6//!
7//! # Example
8//!
9//! ```ignore
10//! use astrelis_render::{GraphicsContext, GraphicsContextExt, AsWgpu};
11//!
12//! let ctx = GraphicsContext::new_owned_sync_or_panic();
13//!
14//! // Access raw wgpu device
15//! let device: &wgpu::Device = ctx.device();
16//! let queue: &wgpu::Queue = ctx.queue();
17//!
18//! // Create custom wgpu resources
19//! let buffer = device.create_buffer(&wgpu::BufferDescriptor {
20//!     label: Some("Custom Buffer"),
21//!     size: 1024,
22//!     usage: wgpu::BufferUsages::UNIFORM,
23//!     mapped_at_creation: false,
24//! });
25//! ```
26
27use std::sync::Arc;
28
29use crate::{
30    ComputePass, FrameContext, Framebuffer, GraphicsContext, RenderPass, WindowContext,
31};
32
33// =============================================================================
34// Core Extension Traits
35// =============================================================================
36
37/// Access the underlying wgpu type (immutable).
38///
39/// Implement this trait to expose the underlying wgpu type for advanced access.
40pub trait AsWgpu {
41    /// The underlying wgpu type.
42    type WgpuType;
43
44    /// Get a reference to the underlying wgpu type.
45    fn as_wgpu(&self) -> &Self::WgpuType;
46}
47
48/// Access the underlying wgpu type (mutable).
49///
50/// Implement this trait to expose mutable access to the underlying wgpu type.
51pub trait AsWgpuMut: AsWgpu {
52    /// Get a mutable reference to the underlying wgpu type.
53    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType;
54}
55
56/// Consume and return the underlying wgpu type.
57///
58/// Implement this trait when ownership of the wgpu type can be transferred.
59pub trait IntoWgpu {
60    /// The underlying wgpu type.
61    type WgpuType;
62
63    /// Consume self and return the underlying wgpu type.
64    fn into_wgpu(self) -> Self::WgpuType;
65}
66
67// =============================================================================
68// GraphicsContextExt
69// =============================================================================
70
71/// Extended access to GraphicsContext internals.
72///
73/// This trait provides direct access to the underlying wgpu components
74/// for advanced use cases that require raw wgpu operations.
75pub trait GraphicsContextExt {
76    /// Get a reference to the wgpu device.
77    fn device(&self) -> &wgpu::Device;
78
79    /// Get a reference to the wgpu queue.
80    fn queue(&self) -> &wgpu::Queue;
81
82    /// Get a reference to the wgpu adapter.
83    fn adapter(&self) -> &wgpu::Adapter;
84
85    /// Get a reference to the wgpu instance.
86    fn instance(&self) -> &wgpu::Instance;
87}
88
89impl GraphicsContextExt for GraphicsContext {
90    fn device(&self) -> &wgpu::Device {
91        &self.device
92    }
93
94    fn queue(&self) -> &wgpu::Queue {
95        &self.queue
96    }
97
98    fn adapter(&self) -> &wgpu::Adapter {
99        &self.adapter
100    }
101
102    fn instance(&self) -> &wgpu::Instance {
103        &self.instance
104    }
105}
106
107impl GraphicsContextExt for Arc<GraphicsContext> {
108    fn device(&self) -> &wgpu::Device {
109        &self.device
110    }
111
112    fn queue(&self) -> &wgpu::Queue {
113        &self.queue
114    }
115
116    fn adapter(&self) -> &wgpu::Adapter {
117        &self.adapter
118    }
119
120    fn instance(&self) -> &wgpu::Instance {
121        &self.instance
122    }
123}
124
125// =============================================================================
126// AsWgpu Implementations
127// =============================================================================
128
129impl AsWgpu for GraphicsContext {
130    type WgpuType = wgpu::Device;
131
132    fn as_wgpu(&self) -> &Self::WgpuType {
133        &self.device
134    }
135}
136
137impl AsWgpu for Arc<GraphicsContext> {
138    type WgpuType = wgpu::Device;
139
140    fn as_wgpu(&self) -> &Self::WgpuType {
141        &self.device
142    }
143}
144
145impl<'a> AsWgpu for FrameContext {
146    type WgpuType = wgpu::CommandEncoder;
147
148    fn as_wgpu(&self) -> &Self::WgpuType {
149        self.encoder.as_ref().expect("Encoder already taken")
150    }
151}
152
153impl<'a> AsWgpuMut for FrameContext {
154    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType {
155        self.encoder.as_mut().expect("Encoder already taken")
156    }
157}
158
159impl<'a> AsWgpu for RenderPass<'a> {
160    type WgpuType = wgpu::RenderPass<'static>;
161
162    fn as_wgpu(&self) -> &Self::WgpuType {
163        self.descriptor.as_ref().unwrap()
164    }
165}
166
167impl<'a> AsWgpuMut for RenderPass<'a> {
168    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType {
169        self.descriptor.as_mut().unwrap()
170    }
171}
172
173impl<'a> AsWgpu for ComputePass<'a> {
174    type WgpuType = wgpu::ComputePass<'static>;
175
176    fn as_wgpu(&self) -> &Self::WgpuType {
177        self.pass.as_ref().unwrap()
178    }
179}
180
181impl<'a> AsWgpuMut for ComputePass<'a> {
182    fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType {
183        self.pass.as_mut().unwrap()
184    }
185}
186
187impl AsWgpu for Framebuffer {
188    type WgpuType = wgpu::Texture;
189
190    fn as_wgpu(&self) -> &Self::WgpuType {
191        self.color_texture()
192    }
193}
194
195impl AsWgpu for WindowContext {
196    type WgpuType = wgpu::Surface<'static>;
197
198    fn as_wgpu(&self) -> &Self::WgpuType {
199        &self.surface
200    }
201}
202
203// =============================================================================
204// FrameContextExt
205// =============================================================================
206
207/// Extended access to FrameContext internals.
208pub trait FrameContextExt {
209    /// Get direct access to the command encoder.
210    fn encoder_ref(&self) -> Option<&wgpu::CommandEncoder>;
211
212    /// Get mutable access to the command encoder.
213    fn encoder_mut(&mut self) -> Option<&mut wgpu::CommandEncoder>;
214
215    /// Get the surface texture view for this frame.
216    fn surface_view(&self) -> &wgpu::TextureView;
217
218    /// Get the surface texture for this frame.
219    fn surface_texture(&self) -> &wgpu::Texture;
220}
221
222impl FrameContextExt for FrameContext {
223    fn encoder_ref(&self) -> Option<&wgpu::CommandEncoder> {
224        self.encoder.as_ref()
225    }
226
227    fn encoder_mut(&mut self) -> Option<&mut wgpu::CommandEncoder> {
228        self.encoder.as_mut()
229    }
230
231    fn surface_view(&self) -> &wgpu::TextureView {
232        self.surface().view()
233    }
234
235    fn surface_texture(&self) -> &wgpu::Texture {
236        self.surface().texture()
237    }
238}
239
240// =============================================================================
241// RenderPassExt (for raw access)
242// =============================================================================
243
244/// Extended access to RenderPass internals.
245pub trait RenderPassRawExt<'a> {
246    /// Get raw access to the underlying wgpu render pass.
247    fn raw_pass(&mut self) -> &mut wgpu::RenderPass<'static>;
248
249    /// Get the graphics context.
250    fn graphics_context(&self) -> &GraphicsContext;
251}
252
253impl<'a> RenderPassRawExt<'a> for RenderPass<'a> {
254    fn raw_pass(&mut self) -> &mut wgpu::RenderPass<'static> {
255        self.descriptor.as_mut().unwrap()
256    }
257
258    fn graphics_context(&self) -> &GraphicsContext {
259        &self.context.context
260    }
261}
262
263// =============================================================================
264// ComputePassExt (for raw access)
265// =============================================================================
266
267/// Extended access to ComputePass internals.
268pub trait ComputePassRawExt<'a> {
269    /// Get raw access to the underlying wgpu compute pass.
270    fn raw_pass(&mut self) -> &mut wgpu::ComputePass<'static>;
271
272    /// Get the graphics context.
273    fn graphics_context(&self) -> &GraphicsContext;
274}
275
276impl<'a> ComputePassRawExt<'a> for ComputePass<'a> {
277    fn raw_pass(&mut self) -> &mut wgpu::ComputePass<'static> {
278        self.pass.as_mut().unwrap()
279    }
280
281    fn graphics_context(&self) -> &GraphicsContext {
282        &self.context.context
283    }
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289
290    // Note: These tests require a GPU context, so they're integration tests.
291    // Here we just test that the traits compile correctly.
292
293    #[test]
294    fn test_trait_object_safety() {
295        // Ensure the core traits can be used as trait objects where applicable
296        fn _takes_as_wgpu<T: AsWgpu>(_: &T) {}
297        fn _takes_as_wgpu_mut<T: AsWgpuMut>(_: &mut T) {}
298        fn _takes_into_wgpu<T: IntoWgpu>(_: T) {}
299        fn _takes_graphics_context_ext<T: GraphicsContextExt>(_: &T) {}
300    }
301}