Repository: bevyengine/bevy
File: crates/bevy_render/src/lib.rs (Rust)

Code before:
                debug_flags: self.debug_flags,
            },
            StoragePlugin,
            GpuReadbackPlugin::default(),
            OcclusionCullingPlugin,
            #[cfg(feature = "tracing-tracy")]
            diagnostic::RenderDiagnosticsPlugin,
        ));

        let asset_server = app.world().resource::<AssetServer>().clone();
        app.init_resource::<RenderAssetBytesPerFrame>()
            .init_resource::<RenderErrorHandler>();
        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
            render_app.init_resource::<RenderAssetBytesPerFrameLimiter>();
            render_app.init_resource::<renderer::PendingCommandBuffers>();
            render_app.insert_resource(asset_server);
            render_app.insert_resource(RenderState::Initializing);
            render_app.add_systems(
                ExtractSchedule,
                (
                    extract_render_asset_bytes_per_frame,
                    PipelineCache::extract_shaders,
                ),
            );

            render_app.init_schedule(RenderStartup);
            render_app.update_schedule = Some(RenderRecovery.intern());
            render_app.add_systems(
                RenderRecovery,
                (run_render_schedule.run_if(renderer_is_ready), send_time).chain(),
            );
            render_app.add_systems(
                Render,
                (
                    (PipelineCache::process_pipeline_queue_system, render_system)
                        .chain()
                        .in_set(RenderSystems::Render),
                    reset_render_asset_bytes_per_frame.in_set(RenderSystems::Cleanup),
                ),
            );
        }
    }

    fn ready(&self, app: &App) -> bool {
        // This is a little tricky. `FutureRenderResources` is added in `build`, which runs synchronously before `ready`.
        // It is only added if there is a wgpu backend and thus the renderer can be created.
        // Hence, if we try and get the resource and it is not present, that means we are ready, because we dont need it.
        // On the other hand, if the resource is present, then we try and lock on it. The lock can fail, in which case
        // we currently can assume that means the `FutureRenderResources` is in the act of being populated, because
        // that is the only other place the lock may be held. If it is being populated, we can assume we're ready. This
        // happens via the `and_then` falling through to the same `unwrap_or(true)` case as when there's no resource.

Review comment (refactor):
There's a small footgun here: if any of the plugins that are added above insert systems into this schedule they will be removed, because this overwrites the implicit schedule that they create. That's the reason `Render::base_schedule()` is currently added inside `ExtractPlugin`.

I made `add_schedule` print a warning though, and we're planning to move `ExtractPlugin` to `bevy_extract`, when that happens we'll have a better place to put this. So it might be fine for now.

Code after:
                debug_flags: self.debug_flags,
            },
            StoragePlugin,
            GpuReadbackPlugin::default(),
            OcclusionCullingPlugin,
            #[cfg(feature = "tracing-tracy")]
            diagnostic::RenderDiagnosticsPlugin,
        ));

        let asset_server = app.world().resource::<AssetServer>().clone();
        app.init_resource::<RenderAssetBytesPerFrame>()
            .init_resource::<RenderErrorHandler>();
        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
            render_app.init_resource::<RenderAssetBytesPerFrameLimiter>();
            render_app.init_resource::<renderer::PendingCommandBuffers>();
            render_app.insert_resource(asset_server);
            render_app.insert_resource(RenderState::Initializing);
            render_app.add_systems(
                ExtractSchedule,
                (
                    extract_render_asset_bytes_per_frame,
                    PipelineCache::extract_shaders,
                ),
            );

            render_app.add_schedule(RenderGraph::base_schedule());

            render_app.init_schedule(RenderStartup);
            render_app.update_schedule = Some(RenderRecovery.intern());
            render_app.add_systems(
                RenderRecovery,
                (run_render_schedule.run_if(renderer_is_ready), send_time).chain(),
            );
            render_app.add_systems(
                Render,
                (
                    (PipelineCache::process_pipeline_queue_system, render_system)
                        .chain()
                        .in_set(RenderSystems::Render),
                    reset_render_asset_bytes_per_frame.in_set(RenderSystems::Cleanup),
                ),
            );
        }
    }

    fn ready(&self, app: &App) -> bool {
        // This is a little tricky. `FutureRenderResources` is added in `build`, which runs synchronously before `ready`.
        // It is only added if there is a wgpu backend and thus the renderer can be created.
        // Hence, if we try and get the resource and it is not present, that means we are ready, because we dont need it.
        // On the other hand, if the resource is present, then we try and lock on it. The lock can fail, in which case
        // we currently can assume that means the `FutureRenderResources` is in the act of being populated, because