bevy/crates/bevy_ui/src/render/render_pass.rs
Zachary Harrold d70595b667
Add core and alloc over std Lints (#15281)
# Objective

- Fixes #6370
- Closes #6581

## Solution

- Added the following lints to the workspace:
  - `std_instead_of_core`
  - `std_instead_of_alloc`
  - `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.

## Testing

- Ran CI locally

## Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

## Notes

- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00

242 lines
6.9 KiB
Rust

use core::ops::Range;
use super::{UiBatch, UiImageBindGroups, UiMeta};
use crate::DefaultCameraView;
use bevy_ecs::{
prelude::*,
system::{lifetimeless::*, SystemParamItem},
};
use bevy_math::FloatOrd;
use bevy_render::{
camera::ExtractedCamera,
render_graph::*,
render_phase::*,
render_resource::{CachedRenderPipelineId, RenderPassDescriptor},
renderer::*,
view::*,
};
use bevy_utils::tracing::error;
pub struct UiPassNode {
ui_view_query: QueryState<(&'static ViewTarget, &'static ExtractedCamera), With<ExtractedView>>,
default_camera_view_query: QueryState<&'static DefaultCameraView>,
}
impl UiPassNode {
pub fn new(world: &mut World) -> Self {
Self {
ui_view_query: world.query_filtered(),
default_camera_view_query: world.query(),
}
}
}
impl Node for UiPassNode {
fn update(&mut self, world: &mut World) {
self.ui_view_query.update_archetypes(world);
self.default_camera_view_query.update_archetypes(world);
}
fn run(
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let input_view_entity = graph.view_entity();
let Some(transparent_render_phases) =
world.get_resource::<ViewSortedRenderPhases<TransparentUi>>()
else {
return Ok(());
};
let Some(transparent_phase) = transparent_render_phases.get(&input_view_entity) else {
return Ok(());
};
let Ok((target, camera)) = self.ui_view_query.get_manual(world, input_view_entity) else {
return Ok(());
};
if transparent_phase.items.is_empty() {
return Ok(());
}
// use the "default" view entity if it is defined
let view_entity = if let Ok(default_view) = self
.default_camera_view_query
.get_manual(world, input_view_entity)
{
default_view.0
} else {
input_view_entity
};
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
label: Some("ui_pass"),
color_attachments: &[Some(target.get_unsampled_color_attachment())],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(viewport);
}
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {
error!("Error encountered while rendering the ui phase {err:?}");
}
Ok(())
}
}
pub struct TransparentUi {
pub sort_key: (FloatOrd, u32),
pub entity: Entity,
pub pipeline: CachedRenderPipelineId,
pub draw_function: DrawFunctionId,
pub batch_range: Range<u32>,
pub extra_index: PhaseItemExtraIndex,
}
impl PhaseItem for TransparentUi {
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.draw_function
}
#[inline]
fn batch_range(&self) -> &Range<u32> {
&self.batch_range
}
#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}
#[inline]
fn extra_index(&self) -> PhaseItemExtraIndex {
self.extra_index
}
#[inline]
fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
(&mut self.batch_range, &mut self.extra_index)
}
}
impl SortedPhaseItem for TransparentUi {
type SortKey = (FloatOrd, u32);
#[inline]
fn sort_key(&self) -> Self::SortKey {
self.sort_key
}
#[inline]
fn sort(items: &mut [Self]) {
items.sort_by_key(SortedPhaseItem::sort_key);
}
}
impl CachedRenderPipelinePhaseItem for TransparentUi {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.pipeline
}
}
pub type DrawUi = (
SetItemPipeline,
SetUiViewBindGroup<0>,
SetUiTextureBindGroup<1>,
DrawUiNode,
);
pub struct SetUiViewBindGroup<const I: usize>;
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
type Param = SRes<UiMeta>;
type ViewQuery = Read<ViewUniformOffset>;
type ItemQuery = ();
fn render<'w>(
_item: &P,
view_uniform: &'w ViewUniformOffset,
_entity: Option<()>,
ui_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
let Some(view_bind_group) = ui_meta.into_inner().view_bind_group.as_ref() else {
return RenderCommandResult::Failure("view_bind_group not available");
};
pass.set_bind_group(I, view_bind_group, &[view_uniform.offset]);
RenderCommandResult::Success
}
}
pub struct SetUiTextureBindGroup<const I: usize>;
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {
type Param = SRes<UiImageBindGroups>;
type ViewQuery = ();
type ItemQuery = Read<UiBatch>;
#[inline]
fn render<'w>(
_item: &P,
_view: (),
batch: Option<&'w UiBatch>,
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
let image_bind_groups = image_bind_groups.into_inner();
let Some(batch) = batch else {
return RenderCommandResult::Skip;
};
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
RenderCommandResult::Success
}
}
pub struct DrawUiNode;
impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
type Param = SRes<UiMeta>;
type ViewQuery = ();
type ItemQuery = Read<UiBatch>;
#[inline]
fn render<'w>(
_item: &P,
_view: (),
batch: Option<&'w UiBatch>,
ui_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
let Some(batch) = batch else {
return RenderCommandResult::Skip;
};
let ui_meta = ui_meta.into_inner();
let Some(vertices) = ui_meta.vertices.buffer() else {
return RenderCommandResult::Failure("missing vertices to draw ui");
};
let Some(indices) = ui_meta.indices.buffer() else {
return RenderCommandResult::Failure("missing indices to draw ui");
};
// Store the vertices
pass.set_vertex_buffer(0, vertices.slice(..));
// Define how to "connect" the vertices
pass.set_index_buffer(
indices.slice(..),
0,
bevy_render::render_resource::IndexFormat::Uint32,
);
// Draw the vertices
pass.draw_indexed(batch.range.clone(), 0, 0..1);
RenderCommandResult::Success
}
}