# DRAFT — Frame Loop ## The "Frame Loop" (preparing the draw) To display something, you must follow an immutable cycle called the **Frame Lifetime**. In your Renderer (or a dedicated method of Context), you will need to: 1. **Acquire a surface texture** — ask the surface for the Back Buffer texture (where you'll draw). 2. **Create a texture view** — WGPU doesn't draw directly on the texture, but on a "view" into that texture. 3. **Create a command encoder** — this is the notebook where you write your orders ("clear screen", "draw triangle", "finalize"). 4. **Submit commands** — send this notebook to the GPU via the Queue. ### Why this is the logical next step Because without this, your `configure` call does nothing. You've reserved space on the GPU; now you need to learn how to "grasp" it to work on it. Here is the skeleton of this cycle that you should implement: ```rust // In your Renderer (or Context) pub fn render(&self) -> Result<(), WsgError> { // 1. Acquire the texture to draw on let frame = self.surface.get_current_texture() .map_err(|_| WsgError::SurfaceIncompatible)?; // 2. Create the view (the "channel" to the texture) let view = frame.texture.create_view(&wgpu::TextureViewDescriptor::default()); // 3. Create the command encoder let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"), }); // --- This is where we'll draw later --- { let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color::BLUE), // Blue background for testing store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, }); } // 4. Submit and present self.queue.submit(std::iter::once(encoder.finish())); frame.present(); Ok(()) } ``` ### Why this separation is vital You'll notice that the `{ let _render_pass ... }` block is delimited by braces. This is very important in Rust: `render_pass` must be dropped before calling `encoder.finish()`. If you forget this, your program will crash because you'd be submitting orders while the "notebook" is still being written. ## Persistent vs. Per-Frame Resources | Element | Lifetime | Why? | |---------|----------|------| | `SurfaceConfiguration` | Persistent | Only changes on resize | | `RenderPipeline` | Persistent | Very expensive to create (shader compilation) | | Buffers (Vertex/Index) | Persistent | Geometry data doesn't change every frame | | `CommandEncoder` | Frame | Temporary "notebook" for frame commands | | `TextureView` | Frame | View into the active Swapchain texture |