PERFORMANCE TESTING SUITE
TYPES OF FUNCTIONS:
1. CPU NATIVE FUNCTIONS / PROCESSES
2. GPU NATIVE RENDER FUNCTIONS / PROCESSES (WHICH IS DONE BY BEVY)
- Should be run locally by maintainers before raising/merging PR.
Notes: External libraries also degrade sometimes in performance. We also need to have that in account.
CRATE: processing_render
TL;DR: processing_render is mostly CPU-heavy in the parts that generate and prepare render data: tessellation, mesh generation, geometry mutation, shader/material setup, command flushing, and buffer/image conversion. These CPU-side generators are the most likely areas contributors will modify, so V1 should focus on deterministic CPU benchmarks for those hot paths.
For GPU benchmarking, we should measure the complete rendering pipeline rather than isolated snippets, because actual GPU work is mostly executed inside Bevy/wgpu. A full render benchmark harness can be added in V2 for frame time, GPU compute dispatch, readback, particles, and end-to-end scene rendering.
processing_render/src/render
⇒ Prepares the data required for rendering. CPU computations to prepare data-structures that are rendered by Bevy.
CPU processes
processing_render/src/render/primitive
processing_render/src/render/primitive/mod.rs
This has the code for generating Mesh with Tessellators. These mostly contains CPU intensive calculations that forms the base that gets rendered.
CPU intensive fns: tessellate_path(...)
Key terms:
Tessellator (github)
Tessellators such as the ones provided by lyon take complex shapes as input and generate geometry made of triangles that can be easily consumed by graphics APIs such as OpenGL, Vulkan or D3D.
TessellationMode:
pub enum TessellationMode {
Fill, // fill the inside of the shape.
Stroke(f32), // draw only the outline/border of the shape.
}
Mesh
Mesh is the renderable geometry object.
Path
A Lyon Path is a data structure from the Rust lyon crate that describes a 2D vector shape.
pub struct Path {
points: Box<[Point]>,
verbs: Box<[Verb]>,
num_attributes: usize,
}
pub struct Point2D<T, U> {
pub x: T,
pub y: T,
#[doc(hidden)]
pub _unit: PhantomData<U>,
}
pub(crate) enum Verb {
LineTo,
QuadraticTo,
CubicTo,
Begin,
Close,
End,
}
Example:
Let's say points:
(0, 0)
(100, 0)
(100, 50)
(0, 50)
Let's say verbs
MoveTo
LineTo
LineTo
LineTo
Close
This means:
Start at (0,0)
Draw line to (100,0)
Draw line to (100,50)
Draw line to (0,50)
Close the shape
processing_render/src/render/primitive/arc.rs
builds arc paths for fill/stroke modes and tessellates them into Bevy mesh geometry.
CPU intensive fns: arc_path(...), tessellate_path(...) being called from arc_stroke(...) and arc_fill(...)
processing_render/src/render/primitive/curves.rs
curve paths and stroke-tessellates them into Bevy mesh geometry.
CPU intensive: builder.cubic_bezier_to(...) tessellate_path(...)
processing_render/src/render/primitive/ellipse.rs
ellipse.rs builds an ellipse as four cubic Bézier curve segments and tessellates it into Bevy mesh geometry.
CPU intensive fns: ellipse_path(...) b.cubic_bezier_to(...) tessellate_path(...)
processing_render/src/render/primitive/line.rs
line.rs builds a simple two-point line path and stroke-tessellates it into Bevy mesh geometry.
Usually not CPU intensive
processing_render/src/render/primitive/quad.rs
quad.rs draws quadrilaterals by directly writing filled quad mesh data, or by path-tessellating the quad outline for strokes.
CPU intensive: simple_quad(...) quad_path(...) only if Stroke mode is used
processing_render/src/render/primitive/rect.rs
rect.rs draws rectangles by directly writing simple filled rectangle mesh data, or by building/tessellating a Lyon path for strokes and rounded corners.
CPU intensive: simple_rect(...), Intensive in Stroke mode, or when it has round corners
processing_render/src/render/primitive/shape.rs
shape.rs implements beginShape()/vertex()/endShape() support by collecting custom shape vertices
CPU intensive:
build_polygon_fill(...) build_polygon_stroke(...) tessellate_path(...) build_polygon_path(...) expand_curve_vertices(...) flush_curve_points(...) build_direct_fill(...)
processing_render/src/render/primitive/shape3d.rs
shape3d.rs creates reusable Bevy Mesh objects for built-in 3D primitives like box, sphere, cylinder, cone, torus, capsule, grid, and plane.
CPU intensive:
sphere.mesh().uv(sectors, stacks)
cylinder.mesh().resolution(detail).build()
cone.mesh().resolution(detail).build()
torus.mesh().major_resolution(...).minor_resolution(...).build()
capsule.mesh().longitudes(detail).latitudes(...).build()
frustum.mesh().resolution(detail).build()
processing_render/src/render/primitive/triangle.rs
triangle.rs draws triangles by directly writing filled triangle mesh data, or by path-tessellating the triangle outline for strokes.
CPU intensive: Not so much, usually cheap
processing_render/src/render/transform.rs
The main responsibility of TransformStack is to keep track of the current transformation applied to everything you draw.
processing_render/src/render/mesh_builder.rs
This MeshBuilder is the adapter between Lyon tessellation and Bevy Mesh. convert Lyon's generated geometry into Bevy's mesh format. (Mostly an abstraction layer used else where, no heavy computations)
processing_render/src/render/material.rs
This file manages materials: color, texture, PBR lighting properties, custom materials, and blending. (Mostly book keeping and adapter fn)
processing_render/src/render/command.rs
Mostly helper fn for pushing Draw Commands in to CommandBuffer Queue
processing_render/src/render/mod.rs
Main orchestration layer. Module file for Flushes from Command Buffer and write to Render State, prepares renderable entities/assets, nothing is rendered yet.
processing_render/src/geometry
⇒ This file is for retained geometry. Meaning: unlike rect(), ellipse(), etc. which may generate fresh mesh data every frame, Geometry lets you create a mesh once, keep it as an asset, mutate it, and render/reuse it later.
CPU processes
processing_render/src/geometry/mod.rs
Module file for geometry. This module mostly makes use of render/primitive fns.
CPU intensive fns are : create_sphere() / create_grid() / create_box()
processing_render/src/geometry/attribute.rs
This file manages vertex attributes for retained Geometry meshes.
Vertex: A vertex is a single point in 2D or 3D space that forms the building block of a mesh. (Mostly book keeping). No CPU intensive calculations
processing_render/src/geometry/layout.rs
This file defines vertex layouts for retained Geometry. No CPU intensive tasks mostly book keeping.
processing_render/src/material
CPU processes
processing_render/src/material/mod.rs
material/mod.rs defines Processing's Bevy material plugin.
create_pbr / set_property / destroy
→ normal CPU-side material management
MaterialExtension methods
→ CPU-side render-pipeline callbacks triggered by Bevy
while preparing GPU pipelines/shaders
Actual GPU work
→ happens later inside Bevy/wgpu
CPU intensive: set_property(...) -> mat.shader.reflection().parameter(&name)
processing_render/src/material/custom.rs
create_shader / load_shader
→ CPU-heavy shader loading + WESL/WGSL compilation/parsing
create_custom / set_property / destroy_shader
→ normal CPU-side custom material/shader management
apply_reflect_field / find_param_containing_field
→ CPU-side reflection/property lookup helpers
prepare_asset
→ CPU-side render-asset preparation triggered by Bevy;
builds bind groups, material properties, shader references,
and pipeline metadata
extract_* / check_entities_needing_specialization
→ CPU-side Bevy render-world bookkeeping for changed/visible
custom materials
specialize
→ CPU-side render-pipeline callback triggered by
Bevy while preparing GPU pipeline variants
Actual GPU work
→ happens later inside Bevy/wgpu
CPU intensive: compile_shader(...) create_shader(...) load_shader(...)
create_custom(...) set_property(...) apply_reflect_field(...)find_param_containing_field(...)
Triggered by Bevy but CPU intensive
prepare_asset(...)
processing_render/src/material/pbr.rs
pbr.rs maps user-facing material property names like color, metallic, roughness, emissive, and texture into Bevy StandardMaterial fields.
No CPU intensive
processing_render/src/particles
CPU processes
processing_render/src/particles/kernels/mod.rs
particles/kernels/mod.rs registers built-in WGSL compute shader files for particle noise and transform kernels as embedded Bevy assets. Not CPU intensive
processing_render/src/particles/mod.rs
particles/mod.rs defines GPU-resident particle containers by allocating per-attribute GPU buffers, optionally seeding them from Geometry, and wiring particle rendering/compute plugins.
create / create_from_geometry
→ CPU-side particle container + GPU-buffer setup
make_buffer
→ CPU-side asset creation + GPU readback buffer allocation
through RenderDevice
attribute_values_to_bytes
→ CPU-side data conversion; can be expensive for large meshes
destroy
→ CPU-side cleanup of particle buffers/entities
Actual particle compute/rendering
→ happens later in Bevy/wgpu through compute kernels
and GpuInstanceBatchPlugin
CPU intensive:
create(...) create_from_geometry(...) make_buffer(...)
processing_render/src/particles/material.rs
particles/material.rs defines the particle material extension that binds a per-particle color buffer and uses a custom WGSL fragment shader for particle rendering. No CPU intensive, usually book-keeping
processing_render/src/particles/pack.rs
particles/pack.rs packs particle position/rotation/scale/dead buffers into Bevy's GPU instancing buffers using a compute pass before mesh preprocessing.
extract_particles_draws
→ CPU-side render-world extraction/bookkeeping
get_or_create_pipeline
→ CPU-side compute pipeline caching/specialization
prepare_pack_bind_groups
→ CPU-side GPU preparation: resolve buffers, create bind groups,
write uniforms
dispatch_pack
→ GPU dispatch trigger: begins compute pass and calls
dispatch_workgroups(...)
Actual GPU work
→ runs in pack.wgsl through Bevy/wgpu
CPU intensive: prepare_pack_bind_groups(...)
GPU triggering: pass.dispatch_workgroups(...);
GPU processes
processing_render/src/particles/kernels/noise.wgsl
noise.wgsl applies procedural 3D value-noise displacement to particle positions in parallel on the GPU.
GPU-intensive parts: value_noise(...), noise3(...)
processing_render/src/particles/kernels/transform.wgsl
transform.wgsl applies scale, optional axis-angle rotation, and translation to particle positions in parallel on the GPU.
GPU intensive parts: cos(angle) sin(angle) cross(axis, p) dot(axis, p)
processing_render/src/particles/pack.wgsl
pack.wgsl is the GPU compute shader that converts particle buffers into Bevy's per-instance mesh input/culling buffers triggered by processing_render/src/particles/pack.rs
GPU intensive: quat_to_basis(q)
rocessing_render/src/particles/pack.wgsl
particles.wgsl is a particle fragment shader that multiplies the material color by each particle's per-instance color before running Bevy PBR lighting/output.
GPU intensive: fragment(...)
processing_render/src/transform.rs
This file provides CPU-side helper APIs for mutating Bevy Transform components: position, rotation, scale, look-at, and reset.
CPU Processes
None
processing_render/src/time.rs
This file exposes Processing-style time helpers for frame count, delta time, and elapsed time using Bevy's Time resource.
CPU Processes
None
processing_render/src/surface.rs
surface.rs creates and manages Processing render surfaces: native windows, offscreen targets, resizing, pixel density, monitor placement, and window controls.
create_surface_* / spawn_surface
→ CPU-side native window/surface setup;
→ GPU surface/swapchain is created later by Bevy/wgpu
prepare_offscreen
→ CPU/memory-heavy for large surfaces because it
allocates pixel buffer: vec![0u8; width * height * pixel_size]
resize / set_pixel_density
→ CPU-side window metadata updates;
→ may trigger GPU swapchain/texture resize later in Bevy/wgpu
destroy
→ CPU-side ECS + asset cleanup
window property helpers
→ cheap CPU-side bookkeeping
CPU Processes
prepare_offscreen(...)
processing_render/src/sketch.rs
sketch.rs loads a user sketch source file, stores it as a Bevy Sketch asset, and detects hot-reload updates.
CPU Processes
None (Not Heavy)
processing_render/src/shader_value.rs
shader_value.rs defines a typed container for shader uniform/resource values and converts scalar/vector/matrix values to/from raw bytes for GPU buffer usage.
CPU Processes
None
processing_render/src/monitor.rs
monitor.rs exposes simple CPU-side helpers for listing monitors and reading monitor properties like size, scale factor, refresh rate, and name.
CPU Processes: None
processing_render/src/light.rs
light.rs creates Bevy directional, point, and spot light entities for a Processing graphics surface.
CPU heavy: None
processing_render/src/image.rs
image.rs creates, loads, resizes, updates, reads back, and destroys Processing image/texture assets backed by Bevy GPU images.
CPU Heavy
pixels_to_bytes(...)
bytes_to_pixels(...)
readback(...)
prepare_update_region(...)
resize(...)
create_readback_buffer(...)
GPU Triggers
render_queue.write_texture(...)
encoder.copy_texture_to_buffer(...)
render_queue.submit(...)
render_device.create_buffer(...)
processing_render/src/graphics.rs
graphics.rs creates and manages the Processing graphics context: camera/render target setup, draw command recording/flushing, 2D/3D projection modes, render layers, texture updates, and GPU readback.
CPU Heavy
create(...)
sync_to_surface(...)
readback_raw(...)
prepare_update_region(...)
warmup(...)
GPU Triggers
app.update()
encoder.copy_texture_to_buffer(...)
render_queue.submit(...)
render_queue.write_texture(...)
processing_render/src/gltf.rs
gltf.rs loads GLTF scenes, extracts named meshes/materials/cameras/lights, and adapts them into Processing/Bevy Geometry, materials, transforms, and render layers.
CPU
load(...)
compute_global_transform(...)
geometry(...)
material(...)
processing_render/src/compute.rs
compute.rs provides generic GPU compute support: creates shader buffers, builds compute pipelines from custom shaders, binds resources/uniforms, dispatches compute workgroups, and reads buffers back to CPU.
CPU
create_buffer(...)
create_buffer_with_data(...)
read_buffer_gpu(...)
create_compute(...)
set_compute_property(...)
dispatch(...)
processing_render/src/color.rs
color.rs defines Processing-style color modes/spaces and converts normalized or scaled color inputs into Bevy Color values.
CPU intensive: None
processing_render/src/camera.rs
camera.rs adds orbit/free/pan camera controls and updates camera transforms from mouse/input state.
CPU heavy: None
processing_render/src/lib.rs
public API
CPU
shader_create
shader_load
compute_create
geometry_sphere
geometry_grid
gltf_load
particles_emit
graphics_update
image_update
GPU
graphics_flush
graphics_present
graphics_readback
image_readback
buffer_read
compute_dispatch
particles_apply
particles_emit_gpu
PERFORMANCE TESTING SUITE
TYPES OF FUNCTIONS:
1. CPU NATIVE FUNCTIONS / PROCESSES
These can be done in gitHub actions CI/CD and locally
sphere_mesh()→ pure mesh generation cost (function)create_sphere()→ mesh generation + Bevy asset insertion + ECS entity creation (functionality)2. GPU NATIVE RENDER FUNCTIONS / PROCESSES (WHICH IS DONE BY BEVY)
Notes: External libraries also degrade sometimes in performance. We also need to have that in account.
CRATE:
processing_renderTL;DR:
processing_renderis mostly CPU-heavy in the parts that generate and prepare render data:tessellation,mesh generation,geometry mutation,shader/material setup,command flushing, andbuffer/image conversion. These CPU-side generators are the most likely areas contributors will modify, so V1 should focus on deterministic CPU benchmarks for those hot paths.For GPU benchmarking, we should measure the complete rendering pipeline rather than isolated snippets, because actual GPU work is mostly executed inside Bevy/wgpu. A full render benchmark harness can be added in V2 for frame time, GPU compute dispatch, readback, particles, and end-to-end scene rendering.
processing_render/src/renderprocessing_render/src/geometryprocessing_render/src/materialprocessing_render/src/particlesprocessing_render/src/transform.rsprocessing_render/src/time.rsprocessing_render/src/surface.rsprocessing_render/src/sketch.rsprocessing_render/src/shader_value.rsprocessing_render/src/monitor.rsprocessing_render/src/light.rsprocessing_render/src/image.rsprocessing_render/src/graphics.rsprocessing_render/src/gltf.rsprocessing_render/src/compute.rsprocessing_render/src/color.rsprocessing_render/src/camera.rsprocessing_render/src/lib.rs