Path: blob/main/crates/bevy_ui_render/src/render_pass.rs
9334 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_phase::*,14render_resource::{CachedRenderPipelineId, RenderPassDescriptor},15renderer::{RenderContext, ViewQuery},16sync_world::MainEntity,17view::*,18};19use tracing::error;2021pub fn ui_pass(22world: &World,23view: ViewQuery<&UiCameraView>,24ui_view_query: Query<(&ExtractedView, &UiViewTarget)>,25ui_view_target_query: Query<(&ViewTarget, &ExtractedCamera)>,26transparent_render_phases: Res<ViewSortedRenderPhases<TransparentUi>>,27mut ctx: RenderContext,28) {29let ui_camera_view = view.into_inner();30let ui_view_entity = ui_camera_view.0;3132let Ok((extracted_view, ui_view_target)) = ui_view_query.get(ui_view_entity) else {33return;34};3536let Ok((target, camera)) = ui_view_target_query.get(ui_view_target.0) else {37return;38};3940let Some(transparent_phase) =41transparent_render_phases.get(&extracted_view.retained_view_entity)42else {43return;44};4546if transparent_phase.items.is_empty() {47return;48}4950let diagnostics = ctx.diagnostic_recorder();51let diagnostics = diagnostics.as_deref();5253let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {54label: Some("ui"),55color_attachments: &[Some(target.get_unsampled_color_attachment())],56depth_stencil_attachment: None,57timestamp_writes: None,58occlusion_query_set: None,59multiview_mask: None,60});61let pass_span = diagnostics.pass_span(&mut render_pass, "ui");6263if let Some(viewport) = camera.viewport.as_ref() {64render_pass.set_camera_viewport(viewport);65}6667if let Err(err) = transparent_phase.render(&mut render_pass, world, ui_view_entity) {68error!("Error encountered while rendering the ui phase {err:?}");69}7071pass_span.end(&mut render_pass);72}7374pub struct TransparentUi {75pub sort_key: FloatOrd,76pub entity: (Entity, MainEntity),77pub pipeline: CachedRenderPipelineId,78pub draw_function: DrawFunctionId,79pub batch_range: Range<u32>,80pub extra_index: PhaseItemExtraIndex,81pub index: usize,82pub indexed: bool,83}8485impl PhaseItem for TransparentUi {86#[inline]87fn entity(&self) -> Entity {88self.entity.089}9091fn main_entity(&self) -> MainEntity {92self.entity.193}9495#[inline]96fn draw_function(&self) -> DrawFunctionId {97self.draw_function98}99100#[inline]101fn batch_range(&self) -> &Range<u32> {102&self.batch_range103}104105#[inline]106fn batch_range_mut(&mut self) -> &mut Range<u32> {107&mut self.batch_range108}109110#[inline]111fn extra_index(&self) -> PhaseItemExtraIndex {112self.extra_index.clone()113}114115#[inline]116fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {117(&mut self.batch_range, &mut self.extra_index)118}119}120121impl SortedPhaseItem for TransparentUi {122type SortKey = FloatOrd;123124#[inline]125fn sort_key(&self) -> Self::SortKey {126self.sort_key127}128129#[inline]130fn sort(items: &mut [Self]) {131items.sort_by_key(SortedPhaseItem::sort_key);132}133134#[inline]135fn indexed(&self) -> bool {136self.indexed137}138}139140impl CachedRenderPipelinePhaseItem for TransparentUi {141#[inline]142fn cached_pipeline(&self) -> CachedRenderPipelineId {143self.pipeline144}145}146147pub type DrawUi = (148SetItemPipeline,149SetUiViewBindGroup<0>,150SetUiTextureBindGroup<1>,151DrawUiNode,152);153154pub struct SetUiViewBindGroup<const I: usize>;155impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {156type Param = SRes<UiMeta>;157type ViewQuery = Read<ViewUniformOffset>;158type ItemQuery = ();159160fn render<'w>(161_item: &P,162view_uniform: &'w ViewUniformOffset,163_entity: Option<()>,164ui_meta: SystemParamItem<'w, '_, Self::Param>,165pass: &mut TrackedRenderPass<'w>,166) -> RenderCommandResult {167let Some(view_bind_group) = ui_meta.into_inner().view_bind_group.as_ref() else {168return RenderCommandResult::Failure("view_bind_group not available");169};170pass.set_bind_group(I, view_bind_group, &[view_uniform.offset]);171RenderCommandResult::Success172}173}174pub struct SetUiTextureBindGroup<const I: usize>;175impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {176type Param = SRes<ImageNodeBindGroups>;177type ViewQuery = ();178type ItemQuery = Read<UiBatch>;179180#[inline]181fn render<'w>(182_item: &P,183_view: (),184batch: Option<&'w UiBatch>,185image_bind_groups: SystemParamItem<'w, '_, Self::Param>,186pass: &mut TrackedRenderPass<'w>,187) -> RenderCommandResult {188let image_bind_groups = image_bind_groups.into_inner();189let Some(batch) = batch else {190return RenderCommandResult::Skip;191};192193pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);194RenderCommandResult::Success195}196}197198pub struct DrawUiNode;199impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {200type Param = SRes<UiMeta>;201type ViewQuery = ();202type ItemQuery = Read<UiBatch>;203204#[inline]205fn render<'w>(206_item: &P,207_view: (),208batch: Option<&'w UiBatch>,209ui_meta: SystemParamItem<'w, '_, Self::Param>,210pass: &mut TrackedRenderPass<'w>,211) -> RenderCommandResult {212let Some(batch) = batch else {213return RenderCommandResult::Skip;214};215let ui_meta = ui_meta.into_inner();216let Some(vertices) = ui_meta.vertices.buffer() else {217return RenderCommandResult::Failure("missing vertices to draw ui");218};219let Some(indices) = ui_meta.indices.buffer() else {220return RenderCommandResult::Failure("missing indices to draw ui");221};222223// Store the vertices224pass.set_vertex_buffer(0, vertices.slice(..));225// Define how to "connect" the vertices226pass.set_index_buffer(227indices.slice(..),228bevy_render::render_resource::IndexFormat::Uint32,229);230// Draw the vertices231pass.draw_indexed(batch.range.clone(), 0, 0..1);232RenderCommandResult::Success233}234}235236237