docs: elevate critical WHY explanations to callout blocks
This commit is contained in:
@@ -159,23 +159,17 @@ impl ApplicationHandler<()> for App {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Why `spawn_blocking`:** The display server event loop must run to completion
|
> **WHY: `spawn_blocking` for winit**
|
||||||
and cannot be interrupted. If we ran `run_app()` on the tokio runtime thread,
|
>
|
||||||
no other async tasks could execute. By spawning it on a blocking thread, the
|
> The display server event loop must run to completion and cannot be interrupted. If we ran `run_app()` on the tokio runtime thread, no other async tasks could execute. By spawning it on a blocking thread, the tokio runtime remains free for GPU queries, driver I/O, and future background tasks.
|
||||||
tokio runtime remains free for GPU queries, driver I/O, and future background
|
|
||||||
tasks.
|
|
||||||
|
|
||||||
**Why `Handle::block_on`:** wgpu's `request_adapter` and `request_device` query
|
> **WHY: `Handle::block_on` for async GPU init**
|
||||||
the driver over async D-Bus/Wayland/Vulkan entrypoints. These futures must be
|
>
|
||||||
polled by a runtime executor. `block_on` attaches temporarily to the runtime
|
> wgpu's `request_adapter` and `request_device` query the driver over async D-Bus/Wayland/Vulkan entrypoints. These futures must be polled by a runtime executor. `block_on` attaches temporarily to the runtime thread via its handle, polls the future to completion (~50ms), then returns the result.
|
||||||
thread via its handle, polls the future to completion (~50ms), then returns the
|
|
||||||
result.
|
|
||||||
|
|
||||||
**Why `ControlFlow::Poll`:** winit supports `ControlFlow::Poll` (continuous
|
> **WHY: `ControlFlow::Poll` for the render loop**
|
||||||
redraw) and `ControlFlow::Wait` (idle until next event). A graphics application
|
>
|
||||||
needs a steady render loop. `Poll` tells winit to keep firing `RedrawRequested`
|
> winit supports `ControlFlow::Poll` (continuous redraw) and `ControlFlow::Wait` (idle until next event). A graphics application needs a steady render loop. `Poll` tells winit to keep firing `RedrawRequested` events. We re-queue ourselves inside the handler via `window.request_redraw()`, matching the wgpu swapchain presentation rhythm.
|
||||||
events. We re-queue ourselves inside the handler via `window.request_redraw()`,
|
|
||||||
matching the wgpu swapchain presentation rhythm.
|
|
||||||
|
|
||||||
**Why `request_redraw()`:** After presenting a frame to the display, we ask
|
**Why `request_redraw()`:** After presenting a frame to the display, we ask
|
||||||
winit to schedule the next `RedrawRequested` frame. This creates an explicit
|
winit to schedule the next `RedrawRequested` frame. This creates an explicit
|
||||||
@@ -556,12 +550,9 @@ weights. At each vertex, the value is exact. Inside the triangle, it is the
|
|||||||
weighted blend of all three vertex values. The fragment shader receives a
|
weighted blend of all three vertex values. The fragment shader receives a
|
||||||
different `vertex_color` for every pixel, without any manual interpolation code.
|
different `vertex_color` for every pixel, without any manual interpolation code.
|
||||||
|
|
||||||
> **Key insight #2 — THE LOCATIONS MUST MATCH:** `shader_location: 0` in
|
> **WHY: `@location` must match between Rust and WGSL**
|
||||||
> Rust's `VertexAttribute` MUST equal `@location(0)` in WGSL's parameter
|
>
|
||||||
> annotation. If they differ, the shader reads from the wrong memory offset
|
> `shader_location: 0` in Rust's `VertexAttribute` MUST equal `@location(0)` in WGSL's parameter annotation. If they differ, the shader reads from the wrong memory offset and produces garbage. This is not a type error or a runtime panic — it is silent data corruption. The GPU reads whatever bytes live at the mismatched offset and interprets them as floats.
|
||||||
> and produces garbage. This is not a type error or a runtime panic — it is
|
|
||||||
> silent data corruption. The GPU reads whatever bytes live at the mismatched
|
|
||||||
> offset and interprets them as floats.
|
|
||||||
|
|
||||||
**`@vertex fn vs_main(...)`** — `@vertex` declares this function as the vertex
|
**`@vertex fn vs_main(...)`** — `@vertex` declares this function as the vertex
|
||||||
shader entry point. The function is invoked once per vertex in the draw call.
|
shader entry point. The function is invoked once per vertex in the draw call.
|
||||||
@@ -674,18 +665,9 @@ struct Vertex {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- **`#[repr(C)]`** — Forces the Rust compiler to lay out the struct fields in
|
> **WHY: `#[repr(C)]` + bytemuck for GPU data layout**
|
||||||
declaration order with no padding reordering. Without this, Rust is free to
|
>
|
||||||
reorder fields for optimal alignment, which would break the byte layout the
|
> `#[repr(C)]` forces the Rust compiler to lay out the struct fields in declaration order with no padding reordering. Without this, Rust is free to reorder fields for optimal alignment, which would break the byte layout the shader expects. `bytemuck::Pod` ("Plain Old Data") guarantees the struct has no padding holes, no destructors, and a trivial memory representation. wgpu requires all vertex types to be Pod so they can be safely transmuted to bytes. `bytemuck::Zeroable` guarantees that initializing the struct's memory to all-zero bytes produces a valid instance. Required because `Pod` alone does not guarantee zero is a valid discriminant for enums or optional types. Combined with Pod, it enables `bytemuck::cast_slice` to convert between `&[Vertex]` and `&[u8]` without an unsafe block.
|
||||||
shader expects.
|
|
||||||
- **`bytemuck::Pod`** — "Plain Old Data." Guarantees the struct has no padding
|
|
||||||
holes, no destructors, and a trivial memory representation. wgpu requires
|
|
||||||
all vertex types to be Pod so they can be safely transmuted to bytes.
|
|
||||||
- **`bytemuck::Zeroable`** — Guarantees that initializing the struct's memory
|
|
||||||
to all-zero bytes produces a valid instance. Required because `Pod` alone
|
|
||||||
does not guarantee zero is a valid discriminant for enums or optional types.
|
|
||||||
Combined with Pod, it enables `bytemuck::cast_slice` to convert between
|
|
||||||
`&[Vertex]` and `&[u8]` without a `unsafe` block.
|
|
||||||
|
|
||||||
### Vertex Data
|
### Vertex Data
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user