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
examples/advanced_renderer/src/main.rs
1use anyhow::Result;
2use std::sync::Arc;
3use strato_renderer::{
4 AllocationStrategy, IntegratedRenderer, RenderContext, RendererBuilder, RendererConfig,
5};
6use tracing::{error, info};
7use wgpu::*;
8use winit::{
9 event::{Event, WindowEvent},
10 event_loop::{ControlFlow, EventLoop},
11 window::{Window, WindowBuilder},
12};
13 
14/// Advanced renderer example demonstrating the complete wgpu system
15struct AdvancedRendererExample {
16 window: Arc<Window>,
17 surface: Surface<'static>,
18 surface_config: SurfaceConfiguration,
19 renderer: IntegratedRenderer,
20 
21 // Example resources
22 vertex_buffer: Option<strato_renderer::ResourceHandle>,
23 index_buffer: Option<strato_renderer::ResourceHandle>,
24 render_pipeline: Option<RenderPipeline>,
25 
26 // State
27 frame_count: u64,
28}
29 
30impl AdvancedRendererExample {
31 async fn new(window: Arc<Window>) -> Result<Self> {
32 info!("Initializing advanced renderer example");
33 
34 // Create surface
35 let instance = Instance::new(InstanceDescriptor {
36 backends: Backends::PRIMARY,
37 ..Default::default()
38 });
39 
40 let surface = instance.create_surface(window.clone())?;
41 
42 // Create renderer with performance configuration
43 let mut renderer = RendererBuilder::new()
44 .with_instance(instance)
45 .with_surface(&surface)
46 .with_profiling(true)
47 .with_detailed_profiling(true)
48 .with_memory_strategy(AllocationStrategy::Balanced)
49 .with_max_memory_pool_size(256 * 1024 * 1024) // 256MB
50 .with_preferred_adapter(PowerPreference::HighPerformance)
51 .with_validation(cfg!(debug_assertions))
52 .build()
53 .await?;
54 
55 // Configure surface
56 let adapter = renderer
57 .get_active_adapter()
58 .expect("Current adapter not found");
59 
60 let size = window.inner_size();
61 let surface_config = SurfaceConfiguration {
62 usage: TextureUsages::RENDER_ATTACHMENT,
63 format: surface.get_capabilities(adapter).formats[0],
64 width: size.width,
65 height: size.height,
66 present_mode: PresentMode::Fifo,
67 alpha_mode: CompositeAlphaMode::Auto,
68 view_formats: vec![],
69 desired_maximum_frame_latency: 2,
70 };
71 
72 surface.configure(&renderer.device().device, &surface_config);
73 
74 // Initialize renderer
75 renderer.initialize().await?;
76 
77 info!("Renderer initialized successfully");
78 info!("GPU: {}", renderer.get_device_info().device_name);
79 // info!("Backend: {:?}", renderer.get_device_info().backend);
80 
81 let mut example = Self {
82 window,
83 surface,
84 surface_config,
85 renderer,
86 vertex_buffer: None,
87 index_buffer: None,
88 render_pipeline: None,
89 frame_count: 0,
90 };
91 
92 // Create example resources
93 example.create_resources().await?;
94 
95 Ok(example)
96 }
97 
98 async fn create_resources(&mut self) -> Result<()> {
99 info!("Creating example resources");
100 
101 // Create vertex buffer
102 let vertices: &[f32] = &[
103 // Triangle vertices (position + color)
104 -0.5, -0.5, 1.0, 0.0, 0.0, // Bottom left - Red
105 0.5, -0.5, 0.0, 1.0, 0.0, // Bottom right - Green
106 0.0, 0.5, 0.0, 0.0, 1.0, // Top - Blue
107 ];
108 
109 let vertex_buffer = self.renderer.create_buffer(
110 (vertices.len() * std::mem::size_of::<f32>()) as u64,
111 BufferUsages::VERTEX | BufferUsages::COPY_DST,
112 )?;
113 
114 // Create index buffer
115 let indices: &[u16] = &[0, 1, 2];
116 let index_buffer = self.renderer.create_buffer(
117 (indices.len() * std::mem::size_of::<u16>()) as u64,
118 BufferUsages::INDEX | BufferUsages::COPY_DST,
119 )?;
120 
121 // Load shader
122 let path = std::path::PathBuf::from("examples/advanced_renderer/shaders/triangle.wgsl");
123 let stage = strato_renderer::shader::ShaderStage::Vertex;
124 let variant = strato_renderer::shader::ShaderVariant {
125 macros: vec![],
126 features: vec![],
127 optimization_level: 0,
128 };
129 
130 let shader = self.renderer.load_shader(&path, stage, variant)?;
131 
132 // Create render pipeline
133 let render_pipeline_desc = RenderPipelineDescriptor {
134 label: Some("Triangle Pipeline"),
135 layout: None,
136 vertex: VertexState {
137 module: &shader.module,
138 entry_point: "vs_main",
139 buffers: &[VertexBufferLayout {
140 array_stride: 5 * std::mem::size_of::<f32>() as BufferAddress,
141 step_mode: VertexStepMode::Vertex,
142 attributes: &[
143 VertexAttribute {
144 offset: 0,
145 shader_location: 0,
146 format: VertexFormat::Float32x2,
147 },
148 VertexAttribute {
149 offset: 2 * std::mem::size_of::<f32>() as BufferAddress,
150 shader_location: 1,
151 format: VertexFormat::Float32x3,
152 },
153 ],
154 }],
155 compilation_options: Default::default(),
156 },
157 fragment: Some(FragmentState {
158 module: &shader.module,
159 entry_point: "fs_main",
160 targets: &[Some(ColorTargetState {
161 format: self.surface_config.format,
162 blend: Some(BlendState::REPLACE),
163 write_mask: ColorWrites::ALL,
164 })],
165 compilation_options: Default::default(),
166 }),
167 primitive: PrimitiveState {
168 topology: PrimitiveTopology::TriangleList,
169 strip_index_format: None,
170 front_face: FrontFace::Ccw,
171 cull_mode: Some(Face::Back),
172 unclipped_depth: false,
173 polygon_mode: PolygonMode::Fill,
174 conservative: false,
175 },
176 depth_stencil: None,
177 multisample: MultisampleState {
178 count: 1,
179 mask: !0,
180 alpha_to_coverage_enabled: false,
181 },
182 multiview: None,
183 };
184 
185 let render_pipeline = self
186 .renderer
187 .device()
188 .device
189 .create_render_pipeline(&render_pipeline_desc);
190 self.render_pipeline = Some(render_pipeline);
191 
192 self.vertex_buffer = Some(vertex_buffer);
193 self.index_buffer = Some(index_buffer);
194 
195 info!("Resources created successfully");
196 Ok(())
197 }
198 
199 fn render(&mut self) -> Result<()> {
200 // Resolve resources first to ensure they live long enough for the render pass
201 let vertex_buffer_res = if let Some(handle) = self.vertex_buffer {
202 self.renderer.get_buffer(handle)
203 } else {
204 None
205 };
206 
207 let index_buffer_res = if let Some(handle) = self.index_buffer {
208 self.renderer.get_buffer(handle)
209 } else {
210 None
211 };
212 
213 // Begin frame
214 let mut render_context = self.renderer.begin_frame()?;
215 
216 // Get surface texture
217 let output = self.surface.get_current_texture()?;
218 let view = output
219 .texture
220 .create_view(&TextureViewDescriptor::default());
221 
222 // Begin render pass
223 let mut render_pass = render_context.begin_render_pass(&RenderPassDescriptor {
224 label: Some("Main Render Pass"),
225 color_attachments: &[Some(RenderPassColorAttachment {
226 view: &view,
227 resolve_target: None,
228 ops: Operations {
229 load: LoadOp::Clear(Color {
230 r: 0.1,
231 g: 0.2,
232 b: 0.3,
233 a: 1.0,
234 }),
235 store: StoreOp::Store,
236 },
237 })],
238 depth_stencil_attachment: None,
239 occlusion_query_set: None,
240 timestamp_writes: None,
241 });
242 
243 // Draw triangle
244 if let (Some(pipeline), Some(vb), Some(ib)) =
245 (&self.render_pipeline, &vertex_buffer_res, &index_buffer_res)
246 {
247 render_pass.set_pipeline(pipeline);
248 render_pass.set_vertex_buffer(0, vb.slice(..));
249 render_pass.set_index_buffer(ib.slice(..), IndexFormat::Uint16);
250 render_pass.draw_indexed(0..3, 0, 0..1);
251 }
252 
253 drop(render_pass);
254 render_context.end_render_pass();
255 
256 // End frame
257 self.renderer.end_frame(render_context)?;
258 
259 // Present
260 output.present();
261 
262 self.frame_count += 1;
263 
264 // Print stats every 60 frames
265 if self.frame_count % 60 == 0 {
266 let stats = self.renderer.get_stats();
267 info!(
268 "Frame {}: {:.2}ms avg, {}MB memory, {} resources",
269 stats.frame_count,
270 stats.average_frame_time * 1000.0,
271 stats.memory_usage / (1024 * 1024),
272 stats.active_resources
273 );
274 
275 if let Some(report) = self.renderer.get_performance_report() {
276 info!("Performance report: {:#?}", report);
277 }
278 }
279 
280 Ok(())
281 }
282 
283 fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) -> Result<()> {
284 if new_size.width > 0 && new_size.height > 0 {
285 self.surface_config.width = new_size.width;
286 self.surface_config.height = new_size.height;
287 self.surface
288 .configure(&self.renderer.device().device, &self.surface_config);
289 self.renderer.resize((new_size.width, new_size.height))?;
290 }
291 Ok(())
292 }
293}
294 
295async fn run() -> Result<()> {
296 // Initialize tracing
297 tracing_subscriber::fmt::init();
298 
299 info!("Starting advanced renderer example");
300 
301 // Create event loop and window
302 let event_loop = EventLoop::new()?;
303 let window = Arc::new(
304 WindowBuilder::new()
305 .with_title("Advanced wgpu Renderer Example")
306 .with_inner_size(winit::dpi::LogicalSize::new(800, 600))
307 .build(&event_loop)?,
308 );
309 
310 // Create example
311 let mut example = AdvancedRendererExample::new(window.clone()).await?;
312 
313 info!("Starting event loop");
314 
315 event_loop.run(move |event, elwt| {
316 elwt.set_control_flow(ControlFlow::Poll);
317 
318 match event {
319 Event::WindowEvent {
320 ref event,
321 window_id,
322 } if window_id == window.id() => match event {
323 WindowEvent::CloseRequested => {
324 info!("Close requested");
325 elwt.exit();
326 }
327 WindowEvent::Resized(physical_size) => {
328 if let Err(e) = example.resize(*physical_size) {
329 error!("Resize error: {}", e);
330 }
331 }
332 WindowEvent::RedrawRequested => {
333 if let Err(e) = example.render() {
334 error!("Render error: {}", e);
335 }
336 }
337 _ => {}
338 },
339 Event::AboutToWait => {
340 window.request_redraw();
341 }
342 _ => {}
343 }
344 })?;
345 
346 Ok(())
347}
348 
349#[tokio::main]
350async fn main() {
351 if let Err(e) = run().await {
352 error!("Application error: {}", e);
353 std::process::exit(1);
354 }
355}
356