With the latest performance fixes on master, there is an issue with creating meshes in stages that happen after mesh_resource_provider_system. I've debugged it and reduced it to this sample case (from my actual code which hits this).
This code will panic on bevy master:
With: thread 'main' panicked at 'Attribute Vertex_Position is required by shader, but not supplied by mesh. Either remove the attribute from the shader or supply the attribute (Vertex_Position) to the mesh. ', crates\bevy_render\src\pipeline\pipeline_compiler.rs:223:17
use bevy::prelude::*;
fn main() {
App::build()
.add_plugins(DefaultPlugins)
// add_stage ends up adding it last in the stage order?
.add_stage("panic_due_to_stage_order")
.add_system_to_stage("panic_due_to_stage_order", panic_due_to_stage_order)
.run();
}
fn panic_due_to_stage_order(commands: &mut Commands, mut materials: ResMut<Assets<ColorMaterial>>) {
commands.spawn(SpriteBundle {
material: materials.add(ColorMaterial::color(Color::RED)),
..Default::default()
});
}
The issue is that in the new optimized mesh_resource_provider_system implementation we are using Changed\<> to detect when we need to initialize the render_pipeline for the mesh. Unfortunately, the mesh has not yet been flagged for Changed at the time the mesh_resource_provider_system runs and Changed gets reset every frame.
Ideally it shouldn't matter at what stage you spawn your entity/components.
Some half-baked ideas on how to fix this in bevy (obviously without reverting the perf improvement):
I'd like to contribute a fix to resolve this, if we can figure out what's a good way to fix this... Perhaps there's a trivial way I am not seeing!
Ideally it shouldn't matter at what stage you spawn your entity/components.
I don't think I agree. The whole point of stages is to be able to make different assertions about what has been done and what hasn't been done. I personally think it is 100% ok to say "meshes should be spawned before POST_UPDATE". The UPDATE stage is where app logic is supposed to go (and spawning entities is "app logic"). You can always create new stages directly after the UPDATE stage.
Ah in that case if we take that stance (which seems reasonable), it seems like we need some way to make this failure feel less like undefined behavior (an assertion that happens a lot sooner)? In this case, the failure ends up happening pretty far down the line and takes a lot of digging to correlate to stage order.
I think the "give someone a helpful error if they insert logic into the wrong stage" problem is a bit of a rabbit hole:
Id rather just have a rule of thumb that "app logic goes in UPDATE". everything else is undefined behavior.
Gotcha, you've convinced me