Eliminate Per-Frame Allocation in Rendering Loop
We resolved **Issue 4.3 (Severe Per-Frame Allocation in Rendering
Loop)** by removing the intermediate `MeshData` structure and storing
`macroquad::prelude::Mesh` directly in
[`DrawCommand::Mesh`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs).
[`DrawCommand`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs)
- Dropped `Clone` and `Debug` derives from
[`Turtle`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs#L58)
and
[`DrawCommand`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs#L351),
accommodating Macroquad's `Mesh` which does not implement these
traits.
- Changed
[`DrawCommand::Mesh`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs#L353)
to the tuple variant `DrawCommand::Mesh(macroquad::prelude::Mesh)`.
- Deleted `struct MeshData` and its `to_mesh` method.
[`tessellation.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs)
- Renamed `build_mesh_data` to
[`build_mesh`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L35)
returning `macroquad::prelude::Mesh { vertices, indices, texture: None
}` directly.
- Updated
[`tessellate_polygon`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L71),
[`tessellate_multi_contour`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L116),
[`tessellate_stroke`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L214),
[`tessellate_circle`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L259),
and
[`tessellate_arc`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tessellation.rs#L308)
to return `Result<Mesh, Box<dyn std::error::Error>>`.
[`drawing.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs)
- In the main drawing loop
([`drawing.rs:36-38`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L36-L38)):
```rust
DrawCommand::Mesh(mesh) => {
draw_mesh(mesh);
}
```
Now borrows `&Mesh` directly from the command vector with **0 heap
allocations and 0 vector clones per frame**.
- Updated fill preview ([line
228](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L228)),
tween arc/center indicators ([lines 309,
329](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L309)),
and turtle shape drawing ([line
349](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs#L349))
to pass `&mesh` directly to `draw_mesh(&mesh)` without vector cloning.
[`execution.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs)
- Updated
[`commands.push(DrawCommand::Mesh(mesh))`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs#L135)
and
[`tessellate_command`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs#L337).
- Updated
[`test_forward_left_forward`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/execution.rs#L487)
to instantiate `mut state` directly without dummy cloning.
---
```bash
cargo test --lib
```
Output:
```
running 10 tests
test circle_geometry::tests::test_circle_left_geometry ... ok
test circle_geometry::tests::test_circle_right_geometry ... ok
test general::angle::tests::degrees_to_radians_roundtrip ... ok
test general::angle::tests::from_integer ... ok
test execution::tests::test_forward_left_forward ... ok
test general::angle::tests::negation ... ok
test tweening::tests::test_animated_mode_pops_to_current_tween ... ok
test tweening::tests::test_instant_mode_drains_queue ... ok
test
tweening::tests::test_instant_mode_respects_batch_limit_and_retains_pending
... ok
test tweening::tests::test_streaming_append_commands_does_not_accumulate
... ok
test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered
out; finished in 0.00s
```
All targets verified with `cargo check --all-targets` and `cargo clippy
--lib`.
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
//! This module provides helper functions to tessellate paths using Lyon,
|
||||
//! which replaces the manual triangulation with GPU-optimized tessellation.
|
||||
|
||||
use crate::state::MeshData;
|
||||
use lyon::math::{point, Point};
|
||||
use lyon::path::{LineCap, LineJoin, Path};
|
||||
use lyon::tessellation::{
|
||||
@@ -31,13 +30,13 @@ pub(crate) struct SimpleVertex {
|
||||
pub(crate) position: [f32; 2],
|
||||
}
|
||||
|
||||
/// Build mesh data from Lyon tessellation
|
||||
/// Build mesh from Lyon tessellation
|
||||
#[must_use]
|
||||
pub(crate) fn build_mesh_data(
|
||||
pub(crate) fn build_mesh(
|
||||
vertices: &[SimpleVertex],
|
||||
indices: &[u16],
|
||||
color: Color,
|
||||
) -> MeshData {
|
||||
) -> Mesh {
|
||||
let verts: Vec<Vertex> = vertices
|
||||
.iter()
|
||||
.map(|v| Vertex {
|
||||
@@ -53,9 +52,10 @@ pub(crate) fn build_mesh_data(
|
||||
})
|
||||
.collect();
|
||||
|
||||
MeshData {
|
||||
Mesh {
|
||||
vertices: verts,
|
||||
indices: indices.to_vec(),
|
||||
texture: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ pub(crate) fn build_mesh_data(
|
||||
pub(crate) fn tessellate_polygon(
|
||||
vertices: &[Vec2],
|
||||
color: Color,
|
||||
) -> Result<MeshData, Box<dyn std::error::Error>> {
|
||||
) -> Result<Mesh, Box<dyn std::error::Error>> {
|
||||
if vertices.is_empty() {
|
||||
return Err("No vertices provided".into());
|
||||
}
|
||||
@@ -96,7 +96,7 @@ pub(crate) fn tessellate_polygon(
|
||||
}),
|
||||
)?;
|
||||
|
||||
Ok(build_mesh_data(
|
||||
Ok(build_mesh(
|
||||
&geometry.vertices,
|
||||
&geometry.indices,
|
||||
color,
|
||||
@@ -114,7 +114,7 @@ pub(crate) fn tessellate_polygon(
|
||||
pub(crate) fn tessellate_multi_contour(
|
||||
contours: &[Vec<Vec2>],
|
||||
color: Color,
|
||||
) -> Result<MeshData, Box<dyn std::error::Error>> {
|
||||
) -> Result<Mesh, Box<dyn std::error::Error>> {
|
||||
if contours.is_empty() {
|
||||
return Err("No contours provided".into());
|
||||
}
|
||||
@@ -195,7 +195,7 @@ pub(crate) fn tessellate_multi_contour(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(build_mesh_data(
|
||||
Ok(build_mesh(
|
||||
&geometry.vertices,
|
||||
&geometry.indices,
|
||||
color,
|
||||
@@ -212,7 +212,7 @@ pub(crate) fn tessellate_stroke(
|
||||
color: Color,
|
||||
width: f32,
|
||||
closed: bool,
|
||||
) -> Result<MeshData, Box<dyn std::error::Error>> {
|
||||
) -> Result<Mesh, Box<dyn std::error::Error>> {
|
||||
if vertices.is_empty() {
|
||||
return Err("No vertices provided".into());
|
||||
}
|
||||
@@ -241,7 +241,7 @@ pub(crate) fn tessellate_stroke(
|
||||
}),
|
||||
)?;
|
||||
|
||||
Ok(build_mesh_data(
|
||||
Ok(build_mesh(
|
||||
&geometry.vertices,
|
||||
&geometry.indices,
|
||||
color,
|
||||
@@ -259,7 +259,7 @@ pub(crate) fn tessellate_circle(
|
||||
color: Color,
|
||||
filled: bool,
|
||||
stroke_width: f32,
|
||||
) -> Result<MeshData, Box<dyn std::error::Error>> {
|
||||
) -> Result<Mesh, Box<dyn std::error::Error>> {
|
||||
let mut builder = Path::builder();
|
||||
builder.add_circle(to_lyon_point(center), radius, lyon::path::Winding::Positive);
|
||||
let path = builder.build();
|
||||
@@ -286,7 +286,7 @@ pub(crate) fn tessellate_circle(
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(build_mesh_data(
|
||||
Ok(build_mesh(
|
||||
&geometry.vertices,
|
||||
&geometry.indices,
|
||||
color,
|
||||
@@ -308,7 +308,7 @@ pub(crate) fn tessellate_arc(
|
||||
stroke_width: f32,
|
||||
segments: usize,
|
||||
direction: crate::circle_geometry::CircleDirection,
|
||||
) -> Result<MeshData, Box<dyn std::error::Error>> {
|
||||
) -> Result<Mesh, Box<dyn std::error::Error>> {
|
||||
use crate::circle_geometry::arc_points;
|
||||
|
||||
let start_angle = start_angle_degrees.to_radians();
|
||||
@@ -352,7 +352,7 @@ pub(crate) fn tessellate_arc(
|
||||
}),
|
||||
)?;
|
||||
|
||||
Ok(build_mesh_data(
|
||||
Ok(build_mesh(
|
||||
&geometry.vertices,
|
||||
&geometry.indices,
|
||||
color,
|
||||
|
||||
Reference in New Issue
Block a user