//! # Frame Module //! //! Defines `Frame`, a per-frame RAII wrapper around the surface texture and its TextureView. //! A Frame exists only for the duration of a single rendering pass — it is acquired at the start //! of each frame loop iteration via Context::begin_frame() or Frame::try_new(), used by Renderer //! to write draw commands into the TextureView, then dropped after Renderer::present() submits it. //! //! ## Interaction with Other Modules //! - **context**: provides the Surface from which Frame acquires the current texture. //! - **renderer**: passes Frame's TextureView to render() as the color attachment target. //! - **error**: does not use errors directly; Frame::new() panics on acquisition failure while //! Frame::try_new() returns Option for graceful recovery. pub struct Frame { /// The GPU surface texture representing the current display buffer to be presented. pub surface_texture: wgpu::SurfaceTexture, /// A read-only view into surface_texture, used as the RenderPass color attachment during rendering. pub view: wgpu::TextureView, } impl Frame { /// Acquires the next surface texture and creates a TextureView over it. /// Called by the orchestrator (main.rs) at the start of each frame loop iteration. /// Panics if the surface cannot be acquired (e.g., lost, occluded). For non-panicking /// alternatives, use try_new(). Internal steps: 1) get_current_texture() → 2) match Success/Suboptimal → 3) create_view. pub fn new(surface: &wgpu::Surface) -> Self { // In wgpu 30, get_current_texture() returns CurrentSurfaceTexture enum directly (not Result). // All variants are matched to provide explicit error handling instead of panicking — // see Context::begin_frame() for the detailed variant mapping. match surface.get_current_texture() { // On Success or Suboptimal, we acquire the SurfaceTexture and create its TextureView wgpu::CurrentSurfaceTexture::Success(frame) | wgpu::CurrentSurfaceTexture::Suboptimal(frame) => { let view = frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); Self { surface_texture: frame, view, } } // Panicking on failure here is intentional — Frame must exist for rendering to proceed. // Callers should use try_new() if they prefer Option-based error recovery. other => panic!("Failed to acquire texture: {:?}", other), } } /// Presents the rendered frame by submitting the acquired surface texture to the GPU queue. /// The frame must have been obtained via new() or try_new(); calling present() twice on the same /// texture is undefined behavior. Called after Renderer::render(). pub fn present(self, queue: &wgpu::Queue) { queue.present(self.surface_texture); } /// Attempts to acquire the next surface texture without panicking. /// Returns Some(Frame) on success (Success/Suboptimal) or None on any error variant. /// Called when graceful frame skipping is preferred over crashing. pub fn try_new(surface: &wgpu::Surface) -> Option { match surface.get_current_texture() { wgpu::CurrentSurfaceTexture::Success(frame) | wgpu::CurrentSurfaceTexture::Suboptimal(frame) => { let view = frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); Some(Self { surface_texture: frame, view, }) } _ => None, } } /// Returns a reference to the TextureView used as the RenderPass color attachment. /// Called by Renderer::render() to pass the view into begin_render_pass(). pub fn view(&self) -> &wgpu::TextureView { &self.view } }