Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ui_render/src/render_pass.rs
9334 views
1
use core::ops::Range;
2
3
use super::{ImageNodeBindGroups, UiBatch, UiMeta, UiViewTarget};
4
5
use crate::UiCameraView;
6
use bevy_ecs::{
7
prelude::*,
8
system::{lifetimeless::*, SystemParamItem},
9
};
10
use bevy_math::FloatOrd;
11
use bevy_render::{
12
camera::ExtractedCamera,
13
diagnostic::RecordDiagnostics,
14
render_phase::*,
15
render_resource::{CachedRenderPipelineId, RenderPassDescriptor},
16
renderer::{RenderContext, ViewQuery},
17
sync_world::MainEntity,
18
view::*,
19
};
20
use tracing::error;
21
22
pub fn ui_pass(
23
world: &World,
24
view: ViewQuery<&UiCameraView>,
25
ui_view_query: Query<(&ExtractedView, &UiViewTarget)>,
26
ui_view_target_query: Query<(&ViewTarget, &ExtractedCamera)>,
27
transparent_render_phases: Res<ViewSortedRenderPhases<TransparentUi>>,
28
mut ctx: RenderContext,
29
) {
30
let ui_camera_view = view.into_inner();
31
let ui_view_entity = ui_camera_view.0;
32
33
let Ok((extracted_view, ui_view_target)) = ui_view_query.get(ui_view_entity) else {
34
return;
35
};
36
37
let Ok((target, camera)) = ui_view_target_query.get(ui_view_target.0) else {
38
return;
39
};
40
41
let Some(transparent_phase) =
42
transparent_render_phases.get(&extracted_view.retained_view_entity)
43
else {
44
return;
45
};
46
47
if transparent_phase.items.is_empty() {
48
return;
49
}
50
51
let diagnostics = ctx.diagnostic_recorder();
52
let diagnostics = diagnostics.as_deref();
53
54
let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {
55
label: Some("ui"),
56
color_attachments: &[Some(target.get_unsampled_color_attachment())],
57
depth_stencil_attachment: None,
58
timestamp_writes: None,
59
occlusion_query_set: None,
60
multiview_mask: None,
61
});
62
let pass_span = diagnostics.pass_span(&mut render_pass, "ui");
63
64
if let Some(viewport) = camera.viewport.as_ref() {
65
render_pass.set_camera_viewport(viewport);
66
}
67
68
if let Err(err) = transparent_phase.render(&mut render_pass, world, ui_view_entity) {
69
error!("Error encountered while rendering the ui phase {err:?}");
70
}
71
72
pass_span.end(&mut render_pass);
73
}
74
75
pub struct TransparentUi {
76
pub sort_key: FloatOrd,
77
pub entity: (Entity, MainEntity),
78
pub pipeline: CachedRenderPipelineId,
79
pub draw_function: DrawFunctionId,
80
pub batch_range: Range<u32>,
81
pub extra_index: PhaseItemExtraIndex,
82
pub index: usize,
83
pub indexed: bool,
84
}
85
86
impl PhaseItem for TransparentUi {
87
#[inline]
88
fn entity(&self) -> Entity {
89
self.entity.0
90
}
91
92
fn main_entity(&self) -> MainEntity {
93
self.entity.1
94
}
95
96
#[inline]
97
fn draw_function(&self) -> DrawFunctionId {
98
self.draw_function
99
}
100
101
#[inline]
102
fn batch_range(&self) -> &Range<u32> {
103
&self.batch_range
104
}
105
106
#[inline]
107
fn batch_range_mut(&mut self) -> &mut Range<u32> {
108
&mut self.batch_range
109
}
110
111
#[inline]
112
fn extra_index(&self) -> PhaseItemExtraIndex {
113
self.extra_index.clone()
114
}
115
116
#[inline]
117
fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
118
(&mut self.batch_range, &mut self.extra_index)
119
}
120
}
121
122
impl SortedPhaseItem for TransparentUi {
123
type SortKey = FloatOrd;
124
125
#[inline]
126
fn sort_key(&self) -> Self::SortKey {
127
self.sort_key
128
}
129
130
#[inline]
131
fn sort(items: &mut [Self]) {
132
items.sort_by_key(SortedPhaseItem::sort_key);
133
}
134
135
#[inline]
136
fn indexed(&self) -> bool {
137
self.indexed
138
}
139
}
140
141
impl CachedRenderPipelinePhaseItem for TransparentUi {
142
#[inline]
143
fn cached_pipeline(&self) -> CachedRenderPipelineId {
144
self.pipeline
145
}
146
}
147
148
pub type DrawUi = (
149
SetItemPipeline,
150
SetUiViewBindGroup<0>,
151
SetUiTextureBindGroup<1>,
152
DrawUiNode,
153
);
154
155
pub struct SetUiViewBindGroup<const I: usize>;
156
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
157
type Param = SRes<UiMeta>;
158
type ViewQuery = Read<ViewUniformOffset>;
159
type ItemQuery = ();
160
161
fn render<'w>(
162
_item: &P,
163
view_uniform: &'w ViewUniformOffset,
164
_entity: Option<()>,
165
ui_meta: SystemParamItem<'w, '_, Self::Param>,
166
pass: &mut TrackedRenderPass<'w>,
167
) -> RenderCommandResult {
168
let Some(view_bind_group) = ui_meta.into_inner().view_bind_group.as_ref() else {
169
return RenderCommandResult::Failure("view_bind_group not available");
170
};
171
pass.set_bind_group(I, view_bind_group, &[view_uniform.offset]);
172
RenderCommandResult::Success
173
}
174
}
175
pub struct SetUiTextureBindGroup<const I: usize>;
176
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {
177
type Param = SRes<ImageNodeBindGroups>;
178
type ViewQuery = ();
179
type ItemQuery = Read<UiBatch>;
180
181
#[inline]
182
fn render<'w>(
183
_item: &P,
184
_view: (),
185
batch: Option<&'w UiBatch>,
186
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
187
pass: &mut TrackedRenderPass<'w>,
188
) -> RenderCommandResult {
189
let image_bind_groups = image_bind_groups.into_inner();
190
let Some(batch) = batch else {
191
return RenderCommandResult::Skip;
192
};
193
194
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
195
RenderCommandResult::Success
196
}
197
}
198
199
pub struct DrawUiNode;
200
impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
201
type Param = SRes<UiMeta>;
202
type ViewQuery = ();
203
type ItemQuery = Read<UiBatch>;
204
205
#[inline]
206
fn render<'w>(
207
_item: &P,
208
_view: (),
209
batch: Option<&'w UiBatch>,
210
ui_meta: SystemParamItem<'w, '_, Self::Param>,
211
pass: &mut TrackedRenderPass<'w>,
212
) -> RenderCommandResult {
213
let Some(batch) = batch else {
214
return RenderCommandResult::Skip;
215
};
216
let ui_meta = ui_meta.into_inner();
217
let Some(vertices) = ui_meta.vertices.buffer() else {
218
return RenderCommandResult::Failure("missing vertices to draw ui");
219
};
220
let Some(indices) = ui_meta.indices.buffer() else {
221
return RenderCommandResult::Failure("missing indices to draw ui");
222
};
223
224
// Store the vertices
225
pass.set_vertex_buffer(0, vertices.slice(..));
226
// Define how to "connect" the vertices
227
pass.set_index_buffer(
228
indices.slice(..),
229
bevy_render::render_resource::IndexFormat::Uint32,
230
);
231
// Draw the vertices
232
pass.draw_indexed(batch.range.clone(), 0, 0..1);
233
RenderCommandResult::Success
234
}
235
}
236
237