docs: fix SurfaceStatus API to match wgpu 29 CurrentSurfaceTexture
This commit is contained in:
@@ -921,7 +921,7 @@ wait for GPU completion.
|
|||||||
### Acquiring a Back Buffer from the Swapchain
|
### Acquiring a Back Buffer from the Swapchain
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let status = self.surface.get_current_texture();
|
let frame = self.surface.get_current_texture();
|
||||||
```
|
```
|
||||||
|
|
||||||
`get_current_texture()` is how you acquire a back buffer from the
|
`get_current_texture()` is how you acquire a back buffer from the
|
||||||
@@ -930,37 +930,58 @@ into for this frame. In a triple-buffered swapchain (`PresentMode::Mailbox`),
|
|||||||
there are up to two spare back buffers waiting for you. `get_current_texture()`
|
there are up to two spare back buffers waiting for you. `get_current_texture()`
|
||||||
hands you the next available one.
|
hands you the next available one.
|
||||||
|
|
||||||
In wgpu 29+, this method returns a `CurrentSurfaceTexture` **enum** — not a
|
In wgpu 29, this method returns `Result<SurfaceTexture, SurfaceError>`. On
|
||||||
`Result`. The swapchain can be in seven distinct states, and every state is a
|
success you receive a `SurfaceTexture` containing the back-buffer texture. On
|
||||||
valid, non-error condition:
|
failure you receive a `SurfaceError` describing what went wrong:
|
||||||
|
|
||||||
> **Key insight #5 — 7 swapchain states you must handle:** `Success(buf)` —
|
> **Key insight #5 — 4 surface error variants you must handle:** `Ok(texture)` —
|
||||||
> render normally. `Suboptimal(buf)` — render but reconfig is advisable.
|
> render normally. `SurfaceError::Timeout` — skip frame (GPU late).
|
||||||
> `Timeout` — skip frame (GPU late). `Occluded` — skip frame (window behind
|
> `SurfaceError::Outdated` — surface changed, reconfigure when possible.
|
||||||
> another). `Outdated` — `self.resize()` to reconfigure. `Lost` — skip frame
|
> `SurfaceError::Lost` — surface destroyed, cannot recover without re-init.
|
||||||
> (display server restarted). `Validation` — skip frame (API misuse; check
|
> `SurfaceError::OutOfMemory` — GPU memory exhausted, fatal.
|
||||||
> logs).
|
|
||||||
|
|
||||||
WHY `match` on 7 variants: `get_current_texture()` does not return a `Result`.
|
WHY `match` on the Result: `get_current_texture()` returns a `Result`, so you
|
||||||
All 7 states are valid and the match must be exhaustive. The Rust compiler
|
use standard Rust error handling. The happy path (`Ok`) extracts the
|
||||||
enforces this — you cannot miss a variant.
|
`SurfaceTexture`, and the error path (`Err`) matches on the specific
|
||||||
|
`SurfaceError` variant. The Rust compiler enforces exhaustive matching.
|
||||||
|
|
||||||
### The Complete `render` Implementation
|
### The Complete `render` Implementation
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn render(&mut self) {
|
fn render(&mut self) {
|
||||||
let status = self.surface.get_current_texture();
|
let frame = match self.surface.get_current_texture() {
|
||||||
|
Ok(frame) => frame,
|
||||||
|
Err(e) => {
|
||||||
|
match &e {
|
||||||
|
wgpu::SurfaceError::Timeout => {
|
||||||
|
log::warn!("Surface error: Timeout — skipping frame");
|
||||||
|
}
|
||||||
|
wgpu::SurfaceError::Outdated => {
|
||||||
|
log::warn!("Surface error: Outdated — resizing");
|
||||||
|
let size = wgpu::dpi::PhysicalSize {
|
||||||
|
width: self.config.width,
|
||||||
|
height: self.config.height,
|
||||||
|
};
|
||||||
|
self.resize(size);
|
||||||
|
}
|
||||||
|
wgpu::SurfaceError::Lost => {
|
||||||
|
log::error!("Surface error: Lost — cannot recover without re-creating State");
|
||||||
|
}
|
||||||
|
wgpu::SurfaceError::OutOfMemory => {
|
||||||
|
log::error!("Surface error: OutOfMemory — GPU memory exhausted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match status {
|
|
||||||
wgpu::SurfaceStatus::Success(surface_texture)
|
|
||||||
| wgpu::SurfaceStatus::Suboptimal(surface_texture) => {
|
|
||||||
// Drive GPU work: shader compilation, memory allocation, fence signaling
|
// Drive GPU work: shader compilation, memory allocation, fence signaling
|
||||||
if let Err(e) = self.device.poll(wgpu::PollType::Wait { submission_index: None, timeout: None }) {
|
if let Err(e) = self.device.poll(wgpu::PollType::Wait { submission_index: None, timeout: None }) {
|
||||||
log::error!("Device poll failed: {e}");
|
log::error!("Device poll failed: {e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture_view = surface_texture.texture.create_view(&Default::default());
|
let texture_view = frame.texture.create_view(&Default::default());
|
||||||
|
|
||||||
let mut encoder = self.device.create_command_encoder(
|
let mut encoder = self.device.create_command_encoder(
|
||||||
&wgpu::CommandEncoderDescriptor {
|
&wgpu::CommandEncoderDescriptor {
|
||||||
@@ -997,37 +1018,7 @@ fn render(&mut self) {
|
|||||||
} // render_pass drops here — render pass ends automatically
|
} // render_pass drops here — render pass ends automatically
|
||||||
|
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
surface_texture.present();
|
frame.present();
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::SurfaceStatus::Timeout => {
|
|
||||||
// GPU took too long to finish previous work. Skip this frame.
|
|
||||||
log::warn!("Surface status: Timeout — skipping frame");
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::SurfaceStatus::Occluded => {
|
|
||||||
// Window is fully occluded by another window. Skip rendering.
|
|
||||||
log::debug!("Surface status: Occluded — skipping frame");
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::SurfaceStatus::Outdated => {
|
|
||||||
// Swapchain resolution no longer matches window. Reconfigure.
|
|
||||||
log::warn!("Surface status: Outdated — resizing");
|
|
||||||
if let Some(window) = &self.window {
|
|
||||||
self.resize(window.inner_size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::SurfaceStatus::Lost => {
|
|
||||||
// Display server restarted or GPU lost. Fatal without re-init.
|
|
||||||
log::error!("Surface status: Lost — cannot recover without re-creating State");
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::SurfaceStatus::Validation { source, description } => {
|
|
||||||
// wgpu validated your descriptor and found it invalid.
|
|
||||||
log::error!("Surface validation: {source} — {description}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1165,22 +1156,19 @@ buffer from "render target" to "front buffer" on the next vsync.
|
|||||||
|
|
||||||
### Why the Match Arms Differ
|
### Why the Match Arms Differ
|
||||||
|
|
||||||
- **`Success` / `Suboptimal`** — both deliver a `SurfaceTexture` you can render
|
- **`Ok(frame)`** — the swapchain delivered a `SurfaceTexture` you can render
|
||||||
into. The difference: `Suboptimal` means the current swapchain configuration
|
into. Extract `frame.texture` to create a view, render, then call
|
||||||
is not ideal for the GPU (e.g., format mismatch). You render normally but
|
`frame.present()`.
|
||||||
should consider reconfiguring the surface during idle time.
|
- **`SurfaceError::Timeout`** — the GPU exceeded the wait threshold for a back
|
||||||
- **`Timeout`** — the GPU exceeded the wait threshold for a back buffer. Skip
|
buffer. Skip the frame. The GPU will catch up.
|
||||||
the frame. The GPU will catch up.
|
- **`SurfaceError::Outdated`** — the swapchain was created for a resolution
|
||||||
- **`Occluded`** — another fully covers your window. Skip rendering entirely —
|
that no longer matches the window. Reconfigure the surface to match the
|
||||||
the display server will not show your output. Saves GPU work.
|
current dimensions.
|
||||||
- **`Outdated`** — the swapchain was created for a resolution that no longer
|
- **`SurfaceError::Lost`** — the GPU or display server has been reset. Without
|
||||||
matches the window. Reconfigure the surface to match.
|
re-creating the device and surface, you cannot recover. In a real
|
||||||
- **`Lost`** — the GPU or display server has been reset. Without re-creating
|
application, you'd trigger a full re-initialization.
|
||||||
the device and surface, you cannot recover. In a real application, you'd
|
- **`SurfaceError::OutOfMemory`** — GPU memory is exhausted. This is a fatal
|
||||||
trigger a full re-initialization.
|
condition requiring process-level recovery.
|
||||||
- **`Validation`** — wgpu rejected the surface configuration due to API misuse.
|
|
||||||
Check logs for the description. This is a programming error, not a runtime
|
|
||||||
condition.
|
|
||||||
|
|
||||||
## S8: Handling Window Resize
|
## S8: Handling Window Resize
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user