Path: blob/main/crates/bevy_ui_render/src/render_pass.rs
6596 views
use core::ops::Range;12use super::{ImageNodeBindGroups, UiBatch, UiMeta, UiViewTarget};34use crate::UiCameraView;5use bevy_ecs::{6prelude::*,7system::{lifetimeless::*, SystemParamItem},8};9use bevy_math::FloatOrd;10use bevy_render::{11camera::ExtractedCamera,12diagnostic::RecordDiagnostics,13render_graph::*,14render_phase::*,15render_resource::{CachedRenderPipelineId, RenderPassDescriptor},16renderer::*,17sync_world::MainEntity,18view::*,19};20use tracing::error;2122pub struct UiPassNode {23ui_view_query: QueryState<(&'static ExtractedView, &'static UiViewTarget)>,24ui_view_target_query: QueryState<(&'static ViewTarget, &'static ExtractedCamera)>,25ui_camera_view_query: QueryState<&'static UiCameraView>,26}2728impl UiPassNode {29pub fn new(world: &mut World) -> Self {30Self {31ui_view_query: world.query_filtered(),32ui_view_target_query: world.query(),33ui_camera_view_query: world.query(),34}35}36}3738impl Node for UiPassNode {39fn update(&mut self, world: &mut World) {40self.ui_view_query.update_archetypes(world);41self.ui_view_target_query.update_archetypes(world);42self.ui_camera_view_query.update_archetypes(world);43}4445fn run(46&self,47graph: &mut RenderGraphContext,48render_context: &mut RenderContext,49world: &World,50) -> Result<(), NodeRunError> {51// Extract the UI view.52let input_view_entity = graph.view_entity();5354let Some(transparent_render_phases) =55world.get_resource::<ViewSortedRenderPhases<TransparentUi>>()56else {57return Ok(());58};5960// Query the UI view components.61let Ok((view, ui_view_target)) = self.ui_view_query.get_manual(world, input_view_entity)62else {63return Ok(());64};6566let Ok((target, camera)) = self67.ui_view_target_query68.get_manual(world, ui_view_target.0)69else {70return Ok(());71};7273let Some(transparent_phase) = transparent_render_phases.get(&view.retained_view_entity)74else {75return Ok(());76};7778if transparent_phase.items.is_empty() {79return Ok(());80}8182let diagnostics = render_context.diagnostic_recorder();8384// use the UI view entity if it is defined85let view_entity = if let Ok(ui_camera_view) = self86.ui_camera_view_query87.get_manual(world, input_view_entity)88{89ui_camera_view.090} else {91input_view_entity92};93let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {94label: Some("ui"),95color_attachments: &[Some(target.get_unsampled_color_attachment())],96depth_stencil_attachment: None,97timestamp_writes: None,98occlusion_query_set: None,99});100let pass_span = diagnostics.pass_span(&mut render_pass, "ui");101102if let Some(viewport) = camera.viewport.as_ref() {103render_pass.set_camera_viewport(viewport);104}105if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {106error!("Error encountered while rendering the ui phase {err:?}");107}108109pass_span.end(&mut render_pass);110111Ok(())112}113}114115pub struct TransparentUi {116pub sort_key: FloatOrd,117pub entity: (Entity, MainEntity),118pub pipeline: CachedRenderPipelineId,119pub draw_function: DrawFunctionId,120pub batch_range: Range<u32>,121pub extra_index: PhaseItemExtraIndex,122pub index: usize,123pub indexed: bool,124}125126impl PhaseItem for TransparentUi {127#[inline]128fn entity(&self) -> Entity {129self.entity.0130}131132fn main_entity(&self) -> MainEntity {133self.entity.1134}135136#[inline]137fn draw_function(&self) -> DrawFunctionId {138self.draw_function139}140141#[inline]142fn batch_range(&self) -> &Range<u32> {143&self.batch_range144}145146#[inline]147fn batch_range_mut(&mut self) -> &mut Range<u32> {148&mut self.batch_range149}150151#[inline]152fn extra_index(&self) -> PhaseItemExtraIndex {153self.extra_index.clone()154}155156#[inline]157fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {158(&mut self.batch_range, &mut self.extra_index)159}160}161162impl SortedPhaseItem for TransparentUi {163type SortKey = FloatOrd;164165#[inline]166fn sort_key(&self) -> Self::SortKey {167self.sort_key168}169170#[inline]171fn sort(items: &mut [Self]) {172items.sort_by_key(SortedPhaseItem::sort_key);173}174175#[inline]176fn indexed(&self) -> bool {177self.indexed178}179}180181impl CachedRenderPipelinePhaseItem for TransparentUi {182#[inline]183fn cached_pipeline(&self) -> CachedRenderPipelineId {184self.pipeline185}186}187188pub type DrawUi = (189SetItemPipeline,190SetUiViewBindGroup<0>,191SetUiTextureBindGroup<1>,192DrawUiNode,193);194195pub struct SetUiViewBindGroup<const I: usize>;196impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {197type Param = SRes<UiMeta>;198type ViewQuery = Read<ViewUniformOffset>;199type ItemQuery = ();200201fn render<'w>(202_item: &P,203view_uniform: &'w ViewUniformOffset,204_entity: Option<()>,205ui_meta: SystemParamItem<'w, '_, Self::Param>,206pass: &mut TrackedRenderPass<'w>,207) -> RenderCommandResult {208let Some(view_bind_group) = ui_meta.into_inner().view_bind_group.as_ref() else {209return RenderCommandResult::Failure("view_bind_group not available");210};211pass.set_bind_group(I, view_bind_group, &[view_uniform.offset]);212RenderCommandResult::Success213}214}215pub struct SetUiTextureBindGroup<const I: usize>;216impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {217type Param = SRes<ImageNodeBindGroups>;218type ViewQuery = ();219type ItemQuery = Read<UiBatch>;220221#[inline]222fn render<'w>(223_item: &P,224_view: (),225batch: Option<&'w UiBatch>,226image_bind_groups: SystemParamItem<'w, '_, Self::Param>,227pass: &mut TrackedRenderPass<'w>,228) -> RenderCommandResult {229let image_bind_groups = image_bind_groups.into_inner();230let Some(batch) = batch else {231return RenderCommandResult::Skip;232};233234pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);235RenderCommandResult::Success236}237}238239pub struct DrawUiNode;240impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {241type Param = SRes<UiMeta>;242type ViewQuery = ();243type ItemQuery = Read<UiBatch>;244245#[inline]246fn render<'w>(247_item: &P,248_view: (),249batch: Option<&'w UiBatch>,250ui_meta: SystemParamItem<'w, '_, Self::Param>,251pass: &mut TrackedRenderPass<'w>,252) -> RenderCommandResult {253let Some(batch) = batch else {254return RenderCommandResult::Skip;255};256let ui_meta = ui_meta.into_inner();257let Some(vertices) = ui_meta.vertices.buffer() else {258return RenderCommandResult::Failure("missing vertices to draw ui");259};260let Some(indices) = ui_meta.indices.buffer() else {261return RenderCommandResult::Failure("missing indices to draw ui");262};263264// Store the vertices265pass.set_vertex_buffer(0, vertices.slice(..));266// Define how to "connect" the vertices267pass.set_index_buffer(268indices.slice(..),2690,270bevy_render::render_resource::IndexFormat::Uint32,271);272// Draw the vertices273pass.draw_indexed(batch.range.clone(), 0, 0..1);274RenderCommandResult::Success275}276}277278279