pub struct RenderableWindow { /* private fields */ }Expand description
A renderable window that combines a winit Window with a WindowContext.
This is the primary type for rendering to a window. It implements
Deref<Target = WindowContext>, so all WindowContext methods are
available directly.
§GPU Profiling
Attach a GpuFrameProfiler via set_gpu_profiler
to automatically profile render passes. Once attached, all frames created via
begin_drawing will include GPU profiling:
- Render passes in
with_pass()/clear_and_render()get automatic GPU scopes - Queries are resolved and the profiler frame is ended in
FrameContext::Drop
Implementations§
Source§impl RenderableWindow
impl RenderableWindow
pub fn new( window: Window, context: Arc<GraphicsContext>, ) -> Result<Self, GraphicsError>
Sourcepub fn new_with_descriptor(
window: Window,
context: Arc<GraphicsContext>,
descriptor: WindowContextDescriptor,
) -> Result<Self, GraphicsError>
pub fn new_with_descriptor( window: Window, context: Arc<GraphicsContext>, descriptor: WindowContextDescriptor, ) -> Result<Self, GraphicsError>
Examples found in repository?
27fn main() {
28 logging::init();
29
30 run_app(|ctx| {
31 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
32
33 let mut windows = HashMap::new();
34
35 // Create 3 windows with different colors
36 let colors = [
37 wgpu::Color {
38 r: 0.8,
39 g: 0.2,
40 b: 0.2,
41 a: 1.0,
42 },
43 wgpu::Color {
44 r: 0.2,
45 g: 0.8,
46 b: 0.2,
47 a: 1.0,
48 },
49 wgpu::Color {
50 r: 0.2,
51 g: 0.2,
52 b: 0.8,
53 a: 1.0,
54 },
55 ];
56
57 for (i, color) in colors.iter().enumerate() {
58 let window = ctx
59 .create_window(WindowDescriptor {
60 title: format!("Window {} - Multi-Window Example", i + 1),
61 size: Some(WinitPhysicalSize::new(400.0, 300.0)),
62 ..Default::default()
63 })
64 .expect("Failed to create window");
65
66 let renderable_window = RenderableWindow::new_with_descriptor(
67 window,
68 graphics_ctx.clone(),
69 WindowContextDescriptor {
70 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
71 ..Default::default()
72 },
73 ).expect("Failed to create renderable window");
74
75 let window_id = renderable_window.id();
76 windows.insert(window_id, (renderable_window, *color));
77 }
78
79 Box::new(App {
80 windows,
81 })
82 });
83}More examples
36fn main() {
37 logging::init();
38
39 run_app(|ctx| {
40 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
41
42 let window = ctx
43 .create_window(WindowDescriptor {
44 title: "Performance Benchmark - Render Stress Test".to_string(),
45 size: Some(WinitPhysicalSize::new(1280.0, 720.0)),
46 ..Default::default()
47 })
48 .expect("Failed to create window");
49
50 let window = RenderableWindow::new_with_descriptor(
51 window,
52 graphics_ctx.clone(),
53 WindowContextDescriptor {
54 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
55 ..Default::default()
56 },
57 ).expect("Failed to create renderable window");
58
59 let window_id = window.id();
60
61 println!("\n═══════════════════════════════════════════════════════");
62 println!(" ⚡ PERFORMANCE BENCHMARK - Render Stress Test");
63 println!("═══════════════════════════════════════════════════════");
64 println!(" CONTROLS:");
65 println!(" [Space] Toggle rendering on/off");
66 println!(" [+/-] Increase/decrease object count");
67 println!(" Starting with 1000 objects");
68 println!("═══════════════════════════════════════════════════════\n");
69
70 Box::new(PerformanceBenchmark {
71 _context: graphics_ctx,
72 window,
73 window_id,
74 object_count: 1000,
75 rendering: true,
76 frame_count: 0,
77 last_fps_time: Instant::now(),
78 fps: 0.0,
79 last_frame_time: 0.0,
80 })
81 });
82}30fn main() {
31 logging::init();
32
33 run_app(|ctx| {
34 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
35
36 let window = ctx
37 .create_window(WindowDescriptor {
38 title: "Camera Demo - View & Projection".to_string(),
39 size: Some(WinitPhysicalSize::new(1024.0, 768.0)),
40 ..Default::default()
41 })
42 .expect("Failed to create window");
43
44 let window = RenderableWindow::new_with_descriptor(
45 window,
46 graphics_ctx.clone(),
47 WindowContextDescriptor {
48 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
49 ..Default::default()
50 },
51 ).expect("Failed to create renderable window");
52
53 let window_id = window.id();
54
55 println!("\n═══════════════════════════════════════════════════════");
56 println!(" 📹 CAMERA DEMO - View & Projection");
57 println!("═══════════════════════════════════════════════════════");
58 println!("\n CAMERA API FEATURES:");
59 println!(" • Orthographic cameras (2D, UI, isometric)");
60 println!(" • Perspective cameras (3D scenes)");
61 println!(" • View matrix (position, rotation, look-at)");
62 println!(" • Projection matrix (FOV, aspect, near/far planes)");
63 println!(" • Screen-to-world coordinate conversion");
64 println!(" • Camera movement helpers");
65 println!("\n CAMERA TYPES:");
66 println!(" • OrthographicCamera - 2D games, UI overlays");
67 println!(" camera.orthographic(left, right, bottom, top, near, far)");
68 println!(" • PerspectiveCamera - 3D scenes");
69 println!(" camera.perspective(fov, aspect, near, far)");
70 println!("\n Camera API Usage:");
71 println!(" let camera = Camera::new()");
72 println!(" .position(Vec3::new(0.0, 5.0, 10.0))");
73 println!(" .look_at(Vec3::ZERO)");
74 println!(" .perspective(60.0, aspect, 0.1, 100.0);");
75 println!(" let view_proj = camera.view_projection_matrix();");
76 println!("═══════════════════════════════════════════════════════\n");
77
78 tracing::info!("Camera demo initialized");
79
80 Box::new(CameraDemo {
81 _context: graphics_ctx,
82 window,
83 window_id,
84 })
85 });
86}29fn main() {
30 logging::init();
31
32 run_app(|ctx| {
33 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
34
35 let window = ctx
36 .create_window(WindowDescriptor {
37 title: "Render Graph Demo - Multi-Pass Rendering".to_string(),
38 size: Some(WinitPhysicalSize::new(1024.0, 768.0)),
39 ..Default::default()
40 })
41 .expect("Failed to create window");
42
43 let window = RenderableWindow::new_with_descriptor(
44 window,
45 graphics_ctx.clone(),
46 WindowContextDescriptor {
47 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
48 ..Default::default()
49 },
50 ).expect("Failed to create renderable window");
51
52 let window_id = window.id();
53
54 println!("\n═══════════════════════════════════════════════════════");
55 println!(" 🔀 RENDER GRAPH DEMO - Multi-Pass Rendering");
56 println!("═══════════════════════════════════════════════════════");
57 println!("\n RENDER GRAPH FEATURES:");
58 println!(" • Declarative pass definition");
59 println!(" • Automatic dependency resolution");
60 println!(" • Resource lifetime management");
61 println!(" • Parallel pass execution");
62 println!(" • Automatic optimization");
63 println!("\n EXAMPLE PIPELINE:");
64 println!(" 1. Shadow Pass → depth texture");
65 println!(" 2. Geometry Pass → color + normal + depth");
66 println!(" 3. Lighting Pass → lit scene");
67 println!(" 4. Post-Processing → bloom, tone mapping");
68 println!(" 5. UI Pass → final composite");
69 println!("\n Render Graph API Usage:");
70 println!(" let mut graph = RenderGraph::new();");
71 println!(" graph.add_pass(\"shadow\", shadow_pass_descriptor);");
72 println!(" graph.add_pass(\"geometry\", geometry_pass_descriptor);");
73 println!(" graph.add_dependency(\"lighting\", \"geometry\");");
74 println!(" graph.compile();");
75 println!(" graph.execute(&mut encoder);");
76 println!("═══════════════════════════════════════════════════════\n");
77
78 tracing::info!("Render graph demo initialized");
79
80 Box::new(RenderGraphDemo {
81 _context: graphics_ctx,
82 window,
83 window_id,
84 })
85 });
86}29fn main() {
30 logging::init();
31
32 run_app(|ctx| {
33 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
34
35 let window = ctx
36 .create_window(WindowDescriptor {
37 title: "Mesh Primitives Demo - Geometry API".to_string(),
38 size: Some(WinitPhysicalSize::new(1024.0, 768.0)),
39 ..Default::default()
40 })
41 .expect("Failed to create window");
42
43 let window = RenderableWindow::new_with_descriptor(
44 window,
45 graphics_ctx.clone(),
46 WindowContextDescriptor {
47 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
48 ..Default::default()
49 },
50 ).expect("Failed to create renderable window");
51
52 let window_id = window.id();
53
54 println!("\n═══════════════════════════════════════════════════════");
55 println!(" 📐 MESH PRIMITIVES DEMO - Geometry API");
56 println!("═══════════════════════════════════════════════════════");
57 println!("\n MESH API FEATURES:");
58 println!(" • MeshBuilder for custom geometry");
59 println!(" • Primitive generation (cube, sphere, plane, etc.)");
60 println!(" • Flexible vertex formats (Position, Normal, UV, Color)");
61 println!(" • Index buffer optimization");
62 println!(" • Instanced rendering support");
63 println!("\n EXAMPLE PRIMITIVES:");
64 println!(" • Cube - box with 24 vertices (6 faces × 4 vertices)");
65 println!(" • Sphere - tessellated sphere with UV mapping");
66 println!(" • Plane - quad with optional subdivisions");
67 println!(" • Cylinder - sides + caps");
68 println!(" • Custom - arbitrary vertex/index data");
69 println!("\n Mesh API Usage:");
70 println!(" let mesh = MeshBuilder::new()");
71 println!(" .with_positions(vertices)");
72 println!(" .with_normals(normals)");
73 println!(" .with_uvs(uvs)");
74 println!(" .with_indices(indices)");
75 println!(" .build(&ctx);");
76 println!(" mesh.draw(&mut pass);");
77 println!(" mesh.draw_instanced(&mut pass, instance_count);");
78 println!("═══════════════════════════════════════════════════════\n");
79
80 tracing::info!("Mesh primitives demo initialized");
81
82 Box::new(MeshPrimitivesDemo {
83 _context: graphics_ctx,
84 window,
85 window_id,
86 })
87 });
88}275fn main() {
276 logging::init();
277
278 run_app(|ctx| {
279 let tier_override = parse_tier();
280
281 // Use the capability API to configure GPU requirements.
282 // For auto-detect, request the best capability (graceful degradation).
283 // For a specific tier, require that tier's capability.
284 let descriptor = match tier_override {
285 None => GraphicsContextDescriptor::new()
286 .request_capability::<BestBatchCapability2D>(),
287 Some(RenderTier::Direct) => GraphicsContextDescriptor::new()
288 .require_capability::<DirectBatchCapability2D>(),
289 Some(RenderTier::Indirect) => GraphicsContextDescriptor::new()
290 .require_capability::<IndirectBatchCapability2D>(),
291 Some(RenderTier::Bindless) => GraphicsContextDescriptor::new()
292 .require_capability::<BindlessBatchCapability2D>(),
293 };
294 let graphics_ctx =
295 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
296 .expect("Failed to create graphics context");
297
298 let window = ctx
299 .create_window(WindowDescriptor {
300 title: "Batched Renderer Example".to_string(),
301 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
302 ..Default::default()
303 })
304 .expect("Failed to create window");
305
306 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
307
308 let renderable_window = RenderableWindow::new_with_descriptor(
309 window,
310 graphics_ctx.clone(),
311 WindowContextDescriptor {
312 format: Some(surface_format),
313 ..Default::default()
314 },
315 )
316 .expect("Failed to create renderable window");
317
318 let window_id = renderable_window.id();
319
320 let renderer = create_batch_renderer_2d(
321 graphics_ctx.clone(),
322 surface_format,
323 tier_override,
324 );
325
326 tracing::info!("Using render tier: {}", renderer.tier());
327
328 // Create initial depth buffer
329 let depth_texture = graphics_ctx
330 .device()
331 .create_texture(&wgpu::TextureDescriptor {
332 label: Some("example_depth"),
333 size: wgpu::Extent3d {
334 width: 1,
335 height: 1,
336 depth_or_array_layers: 1,
337 },
338 mip_level_count: 1,
339 sample_count: 1,
340 dimension: wgpu::TextureDimension::D2,
341 format: DEPTH_FORMAT,
342 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
343 view_formats: &[],
344 });
345 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
346
347 let mut windows = HashMap::new();
348 windows.insert(window_id, renderable_window);
349
350 Box::new(App {
351 context: graphics_ctx,
352 windows,
353 renderer,
354 depth_texture,
355 depth_view,
356 depth_width: 1,
357 depth_height: 1,
358 frame_count: 0,
359 })
360 });
361}Sourcepub fn id(&self) -> WindowId
pub fn id(&self) -> WindowId
Examples found in repository?
27fn main() {
28 logging::init();
29
30 run_app(|ctx| {
31 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
32
33 let mut windows = HashMap::new();
34
35 // Create 3 windows with different colors
36 let colors = [
37 wgpu::Color {
38 r: 0.8,
39 g: 0.2,
40 b: 0.2,
41 a: 1.0,
42 },
43 wgpu::Color {
44 r: 0.2,
45 g: 0.8,
46 b: 0.2,
47 a: 1.0,
48 },
49 wgpu::Color {
50 r: 0.2,
51 g: 0.2,
52 b: 0.8,
53 a: 1.0,
54 },
55 ];
56
57 for (i, color) in colors.iter().enumerate() {
58 let window = ctx
59 .create_window(WindowDescriptor {
60 title: format!("Window {} - Multi-Window Example", i + 1),
61 size: Some(WinitPhysicalSize::new(400.0, 300.0)),
62 ..Default::default()
63 })
64 .expect("Failed to create window");
65
66 let renderable_window = RenderableWindow::new_with_descriptor(
67 window,
68 graphics_ctx.clone(),
69 WindowContextDescriptor {
70 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
71 ..Default::default()
72 },
73 ).expect("Failed to create renderable window");
74
75 let window_id = renderable_window.id();
76 windows.insert(window_id, (renderable_window, *color));
77 }
78
79 Box::new(App {
80 windows,
81 })
82 });
83}More examples
36fn main() {
37 logging::init();
38
39 run_app(|ctx| {
40 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
41
42 let window = ctx
43 .create_window(WindowDescriptor {
44 title: "Performance Benchmark - Render Stress Test".to_string(),
45 size: Some(WinitPhysicalSize::new(1280.0, 720.0)),
46 ..Default::default()
47 })
48 .expect("Failed to create window");
49
50 let window = RenderableWindow::new_with_descriptor(
51 window,
52 graphics_ctx.clone(),
53 WindowContextDescriptor {
54 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
55 ..Default::default()
56 },
57 ).expect("Failed to create renderable window");
58
59 let window_id = window.id();
60
61 println!("\n═══════════════════════════════════════════════════════");
62 println!(" ⚡ PERFORMANCE BENCHMARK - Render Stress Test");
63 println!("═══════════════════════════════════════════════════════");
64 println!(" CONTROLS:");
65 println!(" [Space] Toggle rendering on/off");
66 println!(" [+/-] Increase/decrease object count");
67 println!(" Starting with 1000 objects");
68 println!("═══════════════════════════════════════════════════════\n");
69
70 Box::new(PerformanceBenchmark {
71 _context: graphics_ctx,
72 window,
73 window_id,
74 object_count: 1000,
75 rendering: true,
76 frame_count: 0,
77 last_fps_time: Instant::now(),
78 fps: 0.0,
79 last_frame_time: 0.0,
80 })
81 });
82}30fn main() {
31 logging::init();
32
33 run_app(|ctx| {
34 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
35
36 let window = ctx
37 .create_window(WindowDescriptor {
38 title: "Camera Demo - View & Projection".to_string(),
39 size: Some(WinitPhysicalSize::new(1024.0, 768.0)),
40 ..Default::default()
41 })
42 .expect("Failed to create window");
43
44 let window = RenderableWindow::new_with_descriptor(
45 window,
46 graphics_ctx.clone(),
47 WindowContextDescriptor {
48 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
49 ..Default::default()
50 },
51 ).expect("Failed to create renderable window");
52
53 let window_id = window.id();
54
55 println!("\n═══════════════════════════════════════════════════════");
56 println!(" 📹 CAMERA DEMO - View & Projection");
57 println!("═══════════════════════════════════════════════════════");
58 println!("\n CAMERA API FEATURES:");
59 println!(" • Orthographic cameras (2D, UI, isometric)");
60 println!(" • Perspective cameras (3D scenes)");
61 println!(" • View matrix (position, rotation, look-at)");
62 println!(" • Projection matrix (FOV, aspect, near/far planes)");
63 println!(" • Screen-to-world coordinate conversion");
64 println!(" • Camera movement helpers");
65 println!("\n CAMERA TYPES:");
66 println!(" • OrthographicCamera - 2D games, UI overlays");
67 println!(" camera.orthographic(left, right, bottom, top, near, far)");
68 println!(" • PerspectiveCamera - 3D scenes");
69 println!(" camera.perspective(fov, aspect, near, far)");
70 println!("\n Camera API Usage:");
71 println!(" let camera = Camera::new()");
72 println!(" .position(Vec3::new(0.0, 5.0, 10.0))");
73 println!(" .look_at(Vec3::ZERO)");
74 println!(" .perspective(60.0, aspect, 0.1, 100.0);");
75 println!(" let view_proj = camera.view_projection_matrix();");
76 println!("═══════════════════════════════════════════════════════\n");
77
78 tracing::info!("Camera demo initialized");
79
80 Box::new(CameraDemo {
81 _context: graphics_ctx,
82 window,
83 window_id,
84 })
85 });
86}29fn main() {
30 logging::init();
31
32 run_app(|ctx| {
33 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
34
35 let window = ctx
36 .create_window(WindowDescriptor {
37 title: "Render Graph Demo - Multi-Pass Rendering".to_string(),
38 size: Some(WinitPhysicalSize::new(1024.0, 768.0)),
39 ..Default::default()
40 })
41 .expect("Failed to create window");
42
43 let window = RenderableWindow::new_with_descriptor(
44 window,
45 graphics_ctx.clone(),
46 WindowContextDescriptor {
47 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
48 ..Default::default()
49 },
50 ).expect("Failed to create renderable window");
51
52 let window_id = window.id();
53
54 println!("\n═══════════════════════════════════════════════════════");
55 println!(" 🔀 RENDER GRAPH DEMO - Multi-Pass Rendering");
56 println!("═══════════════════════════════════════════════════════");
57 println!("\n RENDER GRAPH FEATURES:");
58 println!(" • Declarative pass definition");
59 println!(" • Automatic dependency resolution");
60 println!(" • Resource lifetime management");
61 println!(" • Parallel pass execution");
62 println!(" • Automatic optimization");
63 println!("\n EXAMPLE PIPELINE:");
64 println!(" 1. Shadow Pass → depth texture");
65 println!(" 2. Geometry Pass → color + normal + depth");
66 println!(" 3. Lighting Pass → lit scene");
67 println!(" 4. Post-Processing → bloom, tone mapping");
68 println!(" 5. UI Pass → final composite");
69 println!("\n Render Graph API Usage:");
70 println!(" let mut graph = RenderGraph::new();");
71 println!(" graph.add_pass(\"shadow\", shadow_pass_descriptor);");
72 println!(" graph.add_pass(\"geometry\", geometry_pass_descriptor);");
73 println!(" graph.add_dependency(\"lighting\", \"geometry\");");
74 println!(" graph.compile();");
75 println!(" graph.execute(&mut encoder);");
76 println!("═══════════════════════════════════════════════════════\n");
77
78 tracing::info!("Render graph demo initialized");
79
80 Box::new(RenderGraphDemo {
81 _context: graphics_ctx,
82 window,
83 window_id,
84 })
85 });
86}29fn main() {
30 logging::init();
31
32 run_app(|ctx| {
33 let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
34
35 let window = ctx
36 .create_window(WindowDescriptor {
37 title: "Mesh Primitives Demo - Geometry API".to_string(),
38 size: Some(WinitPhysicalSize::new(1024.0, 768.0)),
39 ..Default::default()
40 })
41 .expect("Failed to create window");
42
43 let window = RenderableWindow::new_with_descriptor(
44 window,
45 graphics_ctx.clone(),
46 WindowContextDescriptor {
47 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
48 ..Default::default()
49 },
50 ).expect("Failed to create renderable window");
51
52 let window_id = window.id();
53
54 println!("\n═══════════════════════════════════════════════════════");
55 println!(" 📐 MESH PRIMITIVES DEMO - Geometry API");
56 println!("═══════════════════════════════════════════════════════");
57 println!("\n MESH API FEATURES:");
58 println!(" • MeshBuilder for custom geometry");
59 println!(" • Primitive generation (cube, sphere, plane, etc.)");
60 println!(" • Flexible vertex formats (Position, Normal, UV, Color)");
61 println!(" • Index buffer optimization");
62 println!(" • Instanced rendering support");
63 println!("\n EXAMPLE PRIMITIVES:");
64 println!(" • Cube - box with 24 vertices (6 faces × 4 vertices)");
65 println!(" • Sphere - tessellated sphere with UV mapping");
66 println!(" • Plane - quad with optional subdivisions");
67 println!(" • Cylinder - sides + caps");
68 println!(" • Custom - arbitrary vertex/index data");
69 println!("\n Mesh API Usage:");
70 println!(" let mesh = MeshBuilder::new()");
71 println!(" .with_positions(vertices)");
72 println!(" .with_normals(normals)");
73 println!(" .with_uvs(uvs)");
74 println!(" .with_indices(indices)");
75 println!(" .build(&ctx);");
76 println!(" mesh.draw(&mut pass);");
77 println!(" mesh.draw_instanced(&mut pass, instance_count);");
78 println!("═══════════════════════════════════════════════════════\n");
79
80 tracing::info!("Mesh primitives demo initialized");
81
82 Box::new(MeshPrimitivesDemo {
83 _context: graphics_ctx,
84 window,
85 window_id,
86 })
87 });
88}275fn main() {
276 logging::init();
277
278 run_app(|ctx| {
279 let tier_override = parse_tier();
280
281 // Use the capability API to configure GPU requirements.
282 // For auto-detect, request the best capability (graceful degradation).
283 // For a specific tier, require that tier's capability.
284 let descriptor = match tier_override {
285 None => GraphicsContextDescriptor::new()
286 .request_capability::<BestBatchCapability2D>(),
287 Some(RenderTier::Direct) => GraphicsContextDescriptor::new()
288 .require_capability::<DirectBatchCapability2D>(),
289 Some(RenderTier::Indirect) => GraphicsContextDescriptor::new()
290 .require_capability::<IndirectBatchCapability2D>(),
291 Some(RenderTier::Bindless) => GraphicsContextDescriptor::new()
292 .require_capability::<BindlessBatchCapability2D>(),
293 };
294 let graphics_ctx =
295 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
296 .expect("Failed to create graphics context");
297
298 let window = ctx
299 .create_window(WindowDescriptor {
300 title: "Batched Renderer Example".to_string(),
301 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
302 ..Default::default()
303 })
304 .expect("Failed to create window");
305
306 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
307
308 let renderable_window = RenderableWindow::new_with_descriptor(
309 window,
310 graphics_ctx.clone(),
311 WindowContextDescriptor {
312 format: Some(surface_format),
313 ..Default::default()
314 },
315 )
316 .expect("Failed to create renderable window");
317
318 let window_id = renderable_window.id();
319
320 let renderer = create_batch_renderer_2d(
321 graphics_ctx.clone(),
322 surface_format,
323 tier_override,
324 );
325
326 tracing::info!("Using render tier: {}", renderer.tier());
327
328 // Create initial depth buffer
329 let depth_texture = graphics_ctx
330 .device()
331 .create_texture(&wgpu::TextureDescriptor {
332 label: Some("example_depth"),
333 size: wgpu::Extent3d {
334 width: 1,
335 height: 1,
336 depth_or_array_layers: 1,
337 },
338 mip_level_count: 1,
339 sample_count: 1,
340 dimension: wgpu::TextureDimension::D2,
341 format: DEPTH_FORMAT,
342 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
343 view_formats: &[],
344 });
345 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
346
347 let mut windows = HashMap::new();
348 windows.insert(window_id, renderable_window);
349
350 Box::new(App {
351 context: graphics_ctx,
352 windows,
353 renderer,
354 depth_texture,
355 depth_view,
356 depth_width: 1,
357 depth_height: 1,
358 frame_count: 0,
359 })
360 });
361}pub fn window(&self) -> &Window
Sourcepub fn context(&self) -> &WindowContext
pub fn context(&self) -> &WindowContext
Examples found in repository?
367 fn update(&mut self, _ctx: &mut astrelis_winit::app::AppCtx, _time: &astrelis_winit::FrameTime) {
368 let now = Instant::now();
369 let dt = now.duration_since(self.last_update).as_secs_f32();
370 self.last_update = now;
371
372 // Update animation
373 if self.animation.update(dt) {
374 // Frame changed - update vertex buffer with new UVs
375 let frame = self.animation.current_frame();
376 let uv = self.sprite_sheet.sprite_uv(frame);
377 let vertices = create_quad_vertices(uv.u_min, uv.v_min, uv.u_max, uv.v_max);
378
379 // Get context from first window
380 if let Some(window) = self.windows.values().next() {
381 window.context().graphics_context().queue().write_buffer(
382 &self.vertex_buffer,
383 0,
384 bytemuck::cast_slice(&vertices),
385 );
386 }
387 }
388 }pub fn context_mut(&mut self) -> &mut WindowContext
Sourcepub fn surface_format(&self) -> TextureFormat
pub fn surface_format(&self) -> TextureFormat
Get the surface texture format.
This is the format that render pipelines must use when rendering to this
window’s surface. Pass this to renderer constructors like
LineRenderer::new.
Sourcepub fn resized(&mut self, new_size: LogicalSize<u32>)
pub fn resized(&mut self, new_size: LogicalSize<u32>)
Handle window resize event (logical size).
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 }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 }444 fn render(
445 &mut self,
446 _ctx: &mut astrelis_winit::app::AppCtx,
447 window_id: WindowId,
448 events: &mut astrelis_winit::event::EventBatch,
449 ) {
450 let Some(window) = self.windows.get_mut(&window_id) else {
451 return;
452 };
453
454 // Handle resize
455 events.dispatch(|event| {
456 if let astrelis_winit::event::Event::WindowResized(size) = event {
457 window.resized(*size);
458 astrelis_winit::event::HandleStatus::consumed()
459 } else {
460 astrelis_winit::event::HandleStatus::ignored()
461 }
462 });
463
464 let mut frame = window.begin_drawing();
465
466 // Render with automatic scoping (no manual {} block needed)
467 frame.clear_and_render(
468 RenderTarget::Surface,
469 Color::rgb(0.05, 0.05, 0.08),
470 |pass| {
471 let pass = pass.wgpu_pass();
472 pass.set_pipeline(&self.pipeline);
473 pass.set_bind_group(0, &self.bind_group, &[]);
474 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
475 pass.draw(0..6, 0..1);
476 },
477 );
478
479 frame.finish();
480 }Sourcepub fn resized_physical(&mut self, new_size: PhysicalSize<u32>)
pub fn resized_physical(&mut self, new_size: PhysicalSize<u32>)
Handle window resize event (physical size).
Sourcepub fn physical_size(&self) -> PhysicalSize<u32>
pub fn physical_size(&self) -> PhysicalSize<u32>
Get the physical size of the window.
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 scale_factor(&self) -> ScaleFactor
pub fn scale_factor(&self) -> ScaleFactor
Get the scale factor.
Sourcepub fn set_gpu_profiler(&mut self, profiler: Arc<GpuFrameProfiler>)
pub fn set_gpu_profiler(&mut self, profiler: Arc<GpuFrameProfiler>)
Attach a GPU profiler to this window for automatic render pass profiling.
Once set, all frames created via begin_drawing
will automatically:
- Create GPU profiling scopes around render passes
- Resolve timestamp queries before command submission
- End the profiler frame after queue submit
§Example
let profiler = Arc::new(GpuFrameProfiler::new(&graphics_ctx)?);
window.set_gpu_profiler(profiler);
// Now all frames are automatically profiled:
let mut frame = window.begin_drawing();
frame.clear_and_render(RenderTarget::Surface, Color::BLACK, |pass| {
// GPU scope "main_pass" is automatically active
});
frame.finish(); // auto: resolve_queries -> submit -> end_frameSourcepub fn remove_gpu_profiler(&mut self) -> Option<Arc<GpuFrameProfiler>>
pub fn remove_gpu_profiler(&mut self) -> Option<Arc<GpuFrameProfiler>>
Remove the GPU profiler from this window.
Returns the profiler if one was attached.
Sourcepub fn gpu_profiler(&self) -> Option<&Arc<GpuFrameProfiler>>
pub fn gpu_profiler(&self) -> Option<&Arc<GpuFrameProfiler>>
Get a reference to the GPU profiler, if one is attached.
Methods from Deref<Target = WindowContext>§
Sourcepub fn resized(&mut self, new_size: LogicalSize<u32>)
pub fn resized(&mut self, new_size: LogicalSize<u32>)
Handle window resize event (logical size).
Sourcepub fn resized_physical(&mut self, new_size: PhysicalSize<u32>)
pub fn resized_physical(&mut self, new_size: PhysicalSize<u32>)
Handle window resize event (physical size).
pub fn window(&self) -> &Window
Sourcepub fn graphics_context(&self) -> &GraphicsContext
pub fn graphics_context(&self) -> &GraphicsContext
Examples found in repository?
367 fn update(&mut self, _ctx: &mut astrelis_winit::app::AppCtx, _time: &astrelis_winit::FrameTime) {
368 let now = Instant::now();
369 let dt = now.duration_since(self.last_update).as_secs_f32();
370 self.last_update = now;
371
372 // Update animation
373 if self.animation.update(dt) {
374 // Frame changed - update vertex buffer with new UVs
375 let frame = self.animation.current_frame();
376 let uv = self.sprite_sheet.sprite_uv(frame);
377 let vertices = create_quad_vertices(uv.u_min, uv.v_min, uv.u_max, uv.v_max);
378
379 // Get context from first window
380 if let Some(window) = self.windows.values().next() {
381 window.context().graphics_context().queue().write_buffer(
382 &self.vertex_buffer,
383 0,
384 bytemuck::cast_slice(&vertices),
385 );
386 }
387 }
388 }pub fn surface(&self) -> &Surface<'static>
pub fn surface_config(&self) -> &SurfaceConfiguration
Sourcepub fn surface_format(&self) -> TextureFormat
pub fn surface_format(&self) -> TextureFormat
Get the surface texture format.
This is the format that render pipelines must use when rendering to this
window’s surface. Pass this to renderer constructors like
LineRenderer::new.
Sourcepub fn logical_size(&self) -> LogicalSize<u32>
pub fn logical_size(&self) -> LogicalSize<u32>
Get the logical size of the window.
Sourcepub fn physical_size(&self) -> PhysicalSize<u32>
pub fn physical_size(&self) -> PhysicalSize<u32>
Get the physical size of the window.
Sourcepub fn logical_size_f32(&self) -> LogicalSize<f32>
pub fn logical_size_f32(&self) -> LogicalSize<f32>
Get the logical size as f32.
Sourcepub fn physical_size_f32(&self) -> PhysicalSize<f32>
pub fn physical_size_f32(&self) -> PhysicalSize<f32>
Get the physical size as f32.
Sourcepub fn reconfigure_surface(&mut self, config: SurfaceConfiguration)
pub fn reconfigure_surface(&mut self, config: SurfaceConfiguration)
Reconfigure the surface with a new configuration.
Trait Implementations§
Source§impl Deref for RenderableWindow
impl Deref for RenderableWindow
Source§impl DerefMut for RenderableWindow
impl DerefMut for RenderableWindow
Source§impl WindowBackend for RenderableWindow
impl WindowBackend for RenderableWindow
type FrameContext = FrameContext
type Error = GraphicsError
Source§fn try_begin_drawing(&mut self) -> Result<Self::FrameContext, Self::Error>
fn try_begin_drawing(&mut self) -> Result<Self::FrameContext, Self::Error>
Source§fn begin_drawing(&mut self) -> Self::FrameContext
fn begin_drawing(&mut self) -> Self::FrameContext
Auto Trait Implementations§
impl !Freeze for RenderableWindow
impl !RefUnwindSafe for RenderableWindow
impl Send for RenderableWindow
impl Sync for RenderableWindow
impl Unpin for RenderableWindow
impl !UnwindSafe for RenderableWindow
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