pub struct FrameContext { /* private fields */ }Expand description
Context for a single frame of rendering.
When a GpuFrameProfiler is attached (via [RenderableWindow::set_gpu_profiler]),
GPU profiling scopes are automatically created around render passes in
with_pass and clear_and_render.
Queries are resolved and the profiler frame is ended in the Drop implementation.
Implementations§
Source§impl FrameContext
impl FrameContext
Sourcepub fn compute_pass<'a>(&'a mut self, label: &'a str) -> ComputePass<'a>
pub fn compute_pass<'a>(&'a mut self, label: &'a str) -> ComputePass<'a>
Create a compute pass with a label.
Sourcepub fn compute_pass_unlabeled(&mut self) -> ComputePass<'_>
pub fn compute_pass_unlabeled(&mut self) -> ComputePass<'_>
Create a compute pass without a label.
Source§impl FrameContext
impl FrameContext
Sourcepub fn surface(&self) -> &Surface
pub fn surface(&self) -> &Surface
Get the surface for this frame.
§Panics
Panics if the surface has already been consumed. Use try_surface() for fallible access.
Sourcepub fn try_surface(&self) -> Option<&Surface>
pub fn try_surface(&self) -> Option<&Surface>
Try to get the surface for this frame.
Returns None if the surface has already been consumed.
Sourcepub fn has_surface(&self) -> bool
pub fn has_surface(&self) -> bool
Check if the surface is available.
pub fn surface_format(&self) -> TextureFormat
pub fn increment_passes(&mut self)
pub fn increment_draw_calls(&mut self)
pub fn stats(&self) -> &FrameStats
pub fn graphics_context(&self) -> &GraphicsContext
Sourcepub fn graphics_context_arc(&self) -> &Arc<GraphicsContext>
pub fn graphics_context_arc(&self) -> &Arc<GraphicsContext>
Get a cloneable Arc reference to the graphics context.
Sourcepub fn encoder(&mut self) -> &mut CommandEncoder
pub fn encoder(&mut self) -> &mut CommandEncoder
Get the command encoder for this frame.
§Panics
Panics if the encoder has already been taken. Use try_encoder() for fallible access.
Sourcepub fn try_encoder(&mut self) -> Option<&mut CommandEncoder>
pub fn try_encoder(&mut self) -> Option<&mut CommandEncoder>
Try to get the command encoder for this frame.
Returns None if the encoder has already been taken.
Sourcepub fn has_encoder(&self) -> bool
pub fn has_encoder(&self) -> bool
Check if the encoder is available.
Sourcepub fn encoder_and_surface(&mut self) -> (&mut CommandEncoder, &Surface)
pub fn encoder_and_surface(&mut self) -> (&mut CommandEncoder, &Surface)
Get the encoder and surface together.
§Panics
Panics if either the encoder or surface has been consumed.
Use try_encoder_and_surface() for fallible access.
Sourcepub fn try_encoder_and_surface(
&mut self,
) -> Option<(&mut CommandEncoder, &Surface)>
pub fn try_encoder_and_surface( &mut self, ) -> Option<(&mut CommandEncoder, &Surface)>
Try to get the encoder and surface together.
Returns None if either has been consumed.
Sourcepub fn encoder_ref(&self) -> Option<&CommandEncoder>
pub fn encoder_ref(&self) -> Option<&CommandEncoder>
Get direct access to the command encoder (immutable).
Sourcepub fn encoder_mut(&mut self) -> Option<&mut CommandEncoder>
pub fn encoder_mut(&mut self) -> Option<&mut CommandEncoder>
Get mutable access to the command encoder.
Sourcepub fn surface_view(&self) -> &TextureView
pub fn surface_view(&self) -> &TextureView
Get the surface texture view for this frame.
§Panics
Panics if the surface has been consumed. Use try_surface_view() for fallible access.
Sourcepub fn try_surface_view(&self) -> Option<&TextureView>
pub fn try_surface_view(&self) -> Option<&TextureView>
Try to get the surface texture view for this frame.
Sourcepub fn surface_texture(&self) -> &Texture
pub fn surface_texture(&self) -> &Texture
Get the surface texture for this frame.
§Panics
Panics if the surface has been consumed. Use try_surface_texture() for fallible access.
Sourcepub fn try_surface_texture(&self) -> Option<&Texture>
pub fn try_surface_texture(&self) -> Option<&Texture>
Try to get the surface texture for this frame.
Sourcepub fn finish(self)
pub fn finish(self)
Examples found in repository?
91 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
92 if window_id != self.window_id {
93 return;
94 }
95
96 events.dispatch(|event| {
97 if let astrelis_winit::event::Event::WindowResized(size) = event {
98 self.window.resized(*size);
99 astrelis_winit::event::HandleStatus::consumed()
100 } else {
101 astrelis_winit::event::HandleStatus::ignored()
102 }
103 });
104
105 let mut frame = self.window.begin_drawing();
106 frame.clear_and_render(
107 RenderTarget::Surface,
108 Color::from_rgb_u8(20, 30, 40),
109 |_pass| {},
110 );
111 frame.finish();
112 }More examples
93 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
94 if window_id != self.window_id {
95 return;
96 }
97
98 events.dispatch(|event| {
99 if let astrelis_winit::event::Event::WindowResized(size) = event {
100 self.window.resized(*size);
101 astrelis_winit::event::HandleStatus::consumed()
102 } else {
103 astrelis_winit::event::HandleStatus::ignored()
104 }
105 });
106
107 let mut frame = self.window.begin_drawing();
108 frame.clear_and_render(
109 RenderTarget::Surface,
110 Color::from_rgb_u8(20, 30, 40),
111 |_pass| {},
112 );
113 frame.finish();
114 }91 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
92 if window_id != self.window_id {
93 return;
94 }
95
96 events.dispatch(|event| {
97 if let astrelis_winit::event::Event::WindowResized(size) = event {
98 self.window.resized(*size);
99 astrelis_winit::event::HandleStatus::consumed()
100 } else {
101 astrelis_winit::event::HandleStatus::ignored()
102 }
103 });
104
105 let mut frame = self.window.begin_drawing();
106 frame.clear_and_render(
107 RenderTarget::Surface,
108 Color::from_rgb_u8(20, 30, 40),
109 |_pass| {},
110 );
111 frame.finish();
112 }86 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
87 // Get the color for this window
88 let Some(&color) = self.window_colors.get(&window_id) else {
89 return;
90 };
91
92 // WindowManager automatically handles:
93 // 1. Window lookup (no manual HashMap.get_mut)
94 // 2. Resize events (automatic)
95 // 3. Event dispatching
96 self.window_manager
97 .render_window(window_id, events, |window, _events| {
98 // No need to manually handle resize events!
99 // WindowManager already did that for us
100
101 // Just render!
102 let mut frame = window.begin_drawing();
103
104 frame.clear_and_render(RenderTarget::Surface, color, |_pass| {
105 // Additional rendering would go here
106 });
107
108 frame.finish();
109 });
110 }107 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
108 if window_id != self.window_id {
109 return;
110 }
111
112 // Handle resize
113 events.dispatch(|event| {
114 if let astrelis_winit::event::Event::WindowResized(size) = event {
115 self.window.resized(*size);
116 astrelis_winit::event::HandleStatus::consumed()
117 } else {
118 astrelis_winit::event::HandleStatus::ignored()
119 }
120 });
121
122 // In a real application, materials would be bound during rendering:
123 // material.bind(&mut render_pass);
124 // draw_mesh(&mesh);
125
126 // Begin frame
127 let mut frame = self.window.begin_drawing();
128
129 frame.clear_and_render(
130 RenderTarget::Surface,
131 Color::from_rgb_u8(20, 30, 40),
132 |_pass| {
133 // Materials would be applied here in actual rendering
134 // This is a conceptual demonstration
135 },
136 );
137
138 frame.finish();
139 }390 fn render(
391 &mut self,
392 _ctx: &mut astrelis_winit::app::AppCtx,
393 window_id: WindowId,
394 events: &mut astrelis_winit::event::EventBatch,
395 ) {
396 let Some(window) = self.windows.get_mut(&window_id) else {
397 return;
398 };
399
400 // Handle resize
401 events.dispatch(|event| {
402 if let astrelis_winit::event::Event::WindowResized(size) = event {
403 window.resized(*size);
404 astrelis_winit::event::HandleStatus::consumed()
405 } else {
406 astrelis_winit::event::HandleStatus::ignored()
407 }
408 });
409
410 let mut frame = window.begin_drawing();
411
412 // Render with automatic scoping (no manual {} block needed)
413 frame.clear_and_render(
414 RenderTarget::Surface,
415 Color::rgb(0.1, 0.1, 0.15),
416 |pass| {
417 let pass = pass.wgpu_pass();
418 pass.set_pipeline(&self.pipeline);
419 pass.set_bind_group(0, &self.bind_group, &[]);
420 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
421 pass.draw(0..6, 0..1);
422 },
423 );
424
425 frame.finish();
426 }Sourcepub fn gpu_profiler(&self) -> Option<&GpuFrameProfiler>
pub fn gpu_profiler(&self) -> Option<&GpuFrameProfiler>
Get the GPU profiler attached to this frame, if any.
Sourcepub fn has_gpu_profiler(&self) -> bool
pub fn has_gpu_profiler(&self) -> bool
Check if GPU profiling is active for this frame.
Sourcepub fn with_pass<'a, F>(&'a mut self, builder: RenderPassBuilder<'a>, f: F)where
F: FnOnce(&mut RenderPass<'a>),
pub fn with_pass<'a, F>(&'a mut self, builder: RenderPassBuilder<'a>, f: F)where
F: FnOnce(&mut RenderPass<'a>),
Execute a closure with a render pass, automatically handling scoping.
This is the ergonomic RAII pattern that eliminates the need for manual { } blocks.
The render pass is automatically dropped after the closure completes.
When a GPU profiler is attached to this frame (via [RenderableWindow::set_gpu_profiler]),
a GPU profiling scope is automatically created around the render pass, using the
pass label (or "render_pass" as default) as the scope name.
§Example
frame.with_pass(
RenderPassBuilder::new()
.target(RenderTarget::Surface)
.clear_color(Color::BLACK),
|pass| {
// Render commands here
// pass automatically drops when closure ends
}
);
frame.finish();Examples found in repository?
372 fn render(
373 &mut self,
374 _ctx: &mut astrelis_winit::app::AppCtx,
375 window_id: WindowId,
376 events: &mut astrelis_winit::event::EventBatch,
377 ) {
378 // Handle resize and get dimensions (scoped to release window borrow)
379 let (phys_width, phys_height) = {
380 let Some(window) = self.windows.get_mut(&window_id) else {
381 return;
382 };
383
384 events.dispatch(|event| {
385 if let astrelis_winit::event::Event::WindowResized(size) = event {
386 window.resized(*size);
387 astrelis_winit::event::HandleStatus::consumed()
388 } else {
389 astrelis_winit::event::HandleStatus::ignored()
390 }
391 });
392
393 let phys = window.physical_size();
394 (phys.width, phys.height)
395 };
396
397 let width = phys_width as f32;
398 let height = phys_height as f32;
399
400 if width < 1.0 || height < 1.0 {
401 return;
402 }
403
404 // Ensure depth buffer matches viewport
405 self.ensure_depth_buffer(phys_width, phys_height);
406
407 // Build instances and prepare GPU data
408 let instances = self.build_instances(width, height);
409 let batch = DrawBatch2D {
410 instances,
411 textures: vec![],
412 projection: Self::ortho_projection(width, height),
413 };
414 self.renderer.prepare(&batch);
415
416 let stats = self.renderer.stats();
417 if self.frame_count % 120 == 0 {
418 tracing::info!(
419 "Frame {}: {} instances ({} opaque, {} transparent), {} draw calls",
420 self.frame_count,
421 stats.instance_count,
422 stats.opaque_count,
423 stats.transparent_count,
424 stats.draw_calls,
425 );
426 }
427
428 // Re-borrow window for rendering
429 let window = self.windows.get_mut(&window_id).unwrap();
430 let mut frame = window.begin_drawing();
431
432 // Use RenderPassBuilder with depth stencil attachment
433 frame.with_pass(
434 astrelis_render::RenderPassBuilder::new()
435 .label("batched_example_pass")
436 .target(astrelis_render::RenderTarget::Surface)
437 .clear_color(astrelis_render::Color::rgba(0.08, 0.08, 0.1, 1.0))
438 .clear_depth(0.0) // 0.0 = far with GreaterEqual
439 .depth_stencil_attachment(
440 &self.depth_view,
441 Some(wgpu::Operations {
442 load: wgpu::LoadOp::Clear(0.0),
443 store: wgpu::StoreOp::Store,
444 }),
445 None,
446 ),
447 |pass| {
448 self.renderer.render(pass.wgpu_pass());
449 },
450 );
451
452 frame.finish();
453 }Sourcepub fn clear_and_render<'a, F>(
&'a mut self,
target: RenderTarget<'a>,
clear_color: impl Into<Color>,
f: F,
)where
F: FnOnce(&mut RenderPass<'a>),
pub fn clear_and_render<'a, F>(
&'a mut self,
target: RenderTarget<'a>,
clear_color: impl Into<Color>,
f: F,
)where
F: FnOnce(&mut RenderPass<'a>),
Convenience method to clear to a color and execute rendering commands.
This is the most common pattern - clear the surface and render.
When a GPU profiler is attached, a scope named "main_pass" is automatically
created around the render pass.
§Example
frame.clear_and_render(
RenderTarget::Surface,
Color::BLACK,
|pass| {
// Render your content here
// Example: ui.render(pass.wgpu_pass());
}
);
frame.finish();Examples found in repository?
91 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
92 if window_id != self.window_id {
93 return;
94 }
95
96 events.dispatch(|event| {
97 if let astrelis_winit::event::Event::WindowResized(size) = event {
98 self.window.resized(*size);
99 astrelis_winit::event::HandleStatus::consumed()
100 } else {
101 astrelis_winit::event::HandleStatus::ignored()
102 }
103 });
104
105 let mut frame = self.window.begin_drawing();
106 frame.clear_and_render(
107 RenderTarget::Surface,
108 Color::from_rgb_u8(20, 30, 40),
109 |_pass| {},
110 );
111 frame.finish();
112 }More examples
93 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
94 if window_id != self.window_id {
95 return;
96 }
97
98 events.dispatch(|event| {
99 if let astrelis_winit::event::Event::WindowResized(size) = event {
100 self.window.resized(*size);
101 astrelis_winit::event::HandleStatus::consumed()
102 } else {
103 astrelis_winit::event::HandleStatus::ignored()
104 }
105 });
106
107 let mut frame = self.window.begin_drawing();
108 frame.clear_and_render(
109 RenderTarget::Surface,
110 Color::from_rgb_u8(20, 30, 40),
111 |_pass| {},
112 );
113 frame.finish();
114 }91 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
92 if window_id != self.window_id {
93 return;
94 }
95
96 events.dispatch(|event| {
97 if let astrelis_winit::event::Event::WindowResized(size) = event {
98 self.window.resized(*size);
99 astrelis_winit::event::HandleStatus::consumed()
100 } else {
101 astrelis_winit::event::HandleStatus::ignored()
102 }
103 });
104
105 let mut frame = self.window.begin_drawing();
106 frame.clear_and_render(
107 RenderTarget::Surface,
108 Color::from_rgb_u8(20, 30, 40),
109 |_pass| {},
110 );
111 frame.finish();
112 }86 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
87 // Get the color for this window
88 let Some(&color) = self.window_colors.get(&window_id) else {
89 return;
90 };
91
92 // WindowManager automatically handles:
93 // 1. Window lookup (no manual HashMap.get_mut)
94 // 2. Resize events (automatic)
95 // 3. Event dispatching
96 self.window_manager
97 .render_window(window_id, events, |window, _events| {
98 // No need to manually handle resize events!
99 // WindowManager already did that for us
100
101 // Just render!
102 let mut frame = window.begin_drawing();
103
104 frame.clear_and_render(RenderTarget::Surface, color, |_pass| {
105 // Additional rendering would go here
106 });
107
108 frame.finish();
109 });
110 }107 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
108 if window_id != self.window_id {
109 return;
110 }
111
112 // Handle resize
113 events.dispatch(|event| {
114 if let astrelis_winit::event::Event::WindowResized(size) = event {
115 self.window.resized(*size);
116 astrelis_winit::event::HandleStatus::consumed()
117 } else {
118 astrelis_winit::event::HandleStatus::ignored()
119 }
120 });
121
122 // In a real application, materials would be bound during rendering:
123 // material.bind(&mut render_pass);
124 // draw_mesh(&mesh);
125
126 // Begin frame
127 let mut frame = self.window.begin_drawing();
128
129 frame.clear_and_render(
130 RenderTarget::Surface,
131 Color::from_rgb_u8(20, 30, 40),
132 |_pass| {
133 // Materials would be applied here in actual rendering
134 // This is a conceptual demonstration
135 },
136 );
137
138 frame.finish();
139 }390 fn render(
391 &mut self,
392 _ctx: &mut astrelis_winit::app::AppCtx,
393 window_id: WindowId,
394 events: &mut astrelis_winit::event::EventBatch,
395 ) {
396 let Some(window) = self.windows.get_mut(&window_id) else {
397 return;
398 };
399
400 // Handle resize
401 events.dispatch(|event| {
402 if let astrelis_winit::event::Event::WindowResized(size) = event {
403 window.resized(*size);
404 astrelis_winit::event::HandleStatus::consumed()
405 } else {
406 astrelis_winit::event::HandleStatus::ignored()
407 }
408 });
409
410 let mut frame = window.begin_drawing();
411
412 // Render with automatic scoping (no manual {} block needed)
413 frame.clear_and_render(
414 RenderTarget::Surface,
415 Color::rgb(0.1, 0.1, 0.15),
416 |pass| {
417 let pass = pass.wgpu_pass();
418 pass.set_pipeline(&self.pipeline);
419 pass.set_bind_group(0, &self.bind_group, &[]);
420 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
421 pass.draw(0..6, 0..1);
422 },
423 );
424
425 frame.finish();
426 }Sourcepub fn clear_pass<'a>(
&'a mut self,
target: RenderTarget<'a>,
clear_color: Color,
) -> RenderPass<'a>
pub fn clear_pass<'a>( &'a mut self, target: RenderTarget<'a>, clear_color: Color, ) -> RenderPass<'a>
Create a render pass that clears to the given color.
Sourcepub fn load_pass<'a>(&'a mut self, target: RenderTarget<'a>) -> RenderPass<'a>
pub fn load_pass<'a>(&'a mut self, target: RenderTarget<'a>) -> RenderPass<'a>
Create a render pass that loads existing content.
Sourcepub fn with_gpu_scope<F>(&mut self, _label: &str, f: F)where
F: FnOnce(&mut CommandEncoder),
pub fn with_gpu_scope<F>(&mut self, _label: &str, f: F)where
F: FnOnce(&mut CommandEncoder),
Execute a closure with a GPU profiling scope on the command encoder.
When gpu-profiling feature is disabled, this simply calls the closure with the encoder.
Trait Implementations§
Source§impl AsWgpu for FrameContext
impl AsWgpu for FrameContext
Source§impl AsWgpuMut for FrameContext
impl AsWgpuMut for FrameContext
Source§fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType
fn as_wgpu_mut(&mut self) -> &mut Self::WgpuType
Auto Trait Implementations§
impl Freeze for FrameContext
impl !RefUnwindSafe for FrameContext
impl Send for FrameContext
impl Sync for FrameContext
impl Unpin for FrameContext
impl !UnwindSafe for FrameContext
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more