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
6596 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_graph::*,
15
render_phase::*,
16
render_resource::{CachedRenderPipelineId, RenderPassDescriptor},
17
renderer::*,
18
sync_world::MainEntity,
19
view::*,
20
};
21
use tracing::error;
22
23
pub struct UiPassNode {
24
ui_view_query: QueryState<(&'static ExtractedView, &'static UiViewTarget)>,
25
ui_view_target_query: QueryState<(&'static ViewTarget, &'static ExtractedCamera)>,
26
ui_camera_view_query: QueryState<&'static UiCameraView>,
27
}
28
29
impl UiPassNode {
30
pub fn new(world: &mut World) -> Self {
31
Self {
32
ui_view_query: world.query_filtered(),
33
ui_view_target_query: world.query(),
34
ui_camera_view_query: world.query(),
35
}
36
}
37
}
38
39
impl Node for UiPassNode {
40
fn update(&mut self, world: &mut World) {
41
self.ui_view_query.update_archetypes(world);
42
self.ui_view_target_query.update_archetypes(world);
43
self.ui_camera_view_query.update_archetypes(world);
44
}
45
46
fn run(
47
&self,
48
graph: &mut RenderGraphContext,
49
render_context: &mut RenderContext,
50
world: &World,
51
) -> Result<(), NodeRunError> {
52
// Extract the UI view.
53
let input_view_entity = graph.view_entity();
54
55
let Some(transparent_render_phases) =
56
world.get_resource::<ViewSortedRenderPhases<TransparentUi>>()
57
else {
58
return Ok(());
59
};
60
61
// Query the UI view components.
62
let Ok((view, ui_view_target)) = self.ui_view_query.get_manual(world, input_view_entity)
63
else {
64
return Ok(());
65
};
66
67
let Ok((target, camera)) = self
68
.ui_view_target_query
69
.get_manual(world, ui_view_target.0)
70
else {
71
return Ok(());
72
};
73
74
let Some(transparent_phase) = transparent_render_phases.get(&view.retained_view_entity)
75
else {
76
return Ok(());
77
};
78
79
if transparent_phase.items.is_empty() {
80
return Ok(());
81
}
82
83
let diagnostics = render_context.diagnostic_recorder();
84
85
// use the UI view entity if it is defined
86
let view_entity = if let Ok(ui_camera_view) = self
87
.ui_camera_view_query
88
.get_manual(world, input_view_entity)
89
{
90
ui_camera_view.0
91
} else {
92
input_view_entity
93
};
94
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
95
label: Some("ui"),
96
color_attachments: &[Some(target.get_unsampled_color_attachment())],
97
depth_stencil_attachment: None,
98
timestamp_writes: None,
99
occlusion_query_set: None,
100
});
101
let pass_span = diagnostics.pass_span(&mut render_pass, "ui");
102
103
if let Some(viewport) = camera.viewport.as_ref() {
104
render_pass.set_camera_viewport(viewport);
105
}
106
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {
107
error!("Error encountered while rendering the ui phase {err:?}");
108
}
109
110
pass_span.end(&mut render_pass);
111
112
Ok(())
113
}
114
}
115
116
pub struct TransparentUi {
117
pub sort_key: FloatOrd,
118
pub entity: (Entity, MainEntity),
119
pub pipeline: CachedRenderPipelineId,
120
pub draw_function: DrawFunctionId,
121
pub batch_range: Range<u32>,
122
pub extra_index: PhaseItemExtraIndex,
123
pub index: usize,
124
pub indexed: bool,
125
}
126
127
impl PhaseItem for TransparentUi {
128
#[inline]
129
fn entity(&self) -> Entity {
130
self.entity.0
131
}
132
133
fn main_entity(&self) -> MainEntity {
134
self.entity.1
135
}
136
137
#[inline]
138
fn draw_function(&self) -> DrawFunctionId {
139
self.draw_function
140
}
141
142
#[inline]
143
fn batch_range(&self) -> &Range<u32> {
144
&self.batch_range
145
}
146
147
#[inline]
148
fn batch_range_mut(&mut self) -> &mut Range<u32> {
149
&mut self.batch_range
150
}
151
152
#[inline]
153
fn extra_index(&self) -> PhaseItemExtraIndex {
154
self.extra_index.clone()
155
}
156
157
#[inline]
158
fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
159
(&mut self.batch_range, &mut self.extra_index)
160
}
161
}
162
163
impl SortedPhaseItem for TransparentUi {
164
type SortKey = FloatOrd;
165
166
#[inline]
167
fn sort_key(&self) -> Self::SortKey {
168
self.sort_key
169
}
170
171
#[inline]
172
fn sort(items: &mut [Self]) {
173
items.sort_by_key(SortedPhaseItem::sort_key);
174
}
175
176
#[inline]
177
fn indexed(&self) -> bool {
178
self.indexed
179
}
180
}
181
182
impl CachedRenderPipelinePhaseItem for TransparentUi {
183
#[inline]
184
fn cached_pipeline(&self) -> CachedRenderPipelineId {
185
self.pipeline
186
}
187
}
188
189
pub type DrawUi = (
190
SetItemPipeline,
191
SetUiViewBindGroup<0>,
192
SetUiTextureBindGroup<1>,
193
DrawUiNode,
194
);
195
196
pub struct SetUiViewBindGroup<const I: usize>;
197
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
198
type Param = SRes<UiMeta>;
199
type ViewQuery = Read<ViewUniformOffset>;
200
type ItemQuery = ();
201
202
fn render<'w>(
203
_item: &P,
204
view_uniform: &'w ViewUniformOffset,
205
_entity: Option<()>,
206
ui_meta: SystemParamItem<'w, '_, Self::Param>,
207
pass: &mut TrackedRenderPass<'w>,
208
) -> RenderCommandResult {
209
let Some(view_bind_group) = ui_meta.into_inner().view_bind_group.as_ref() else {
210
return RenderCommandResult::Failure("view_bind_group not available");
211
};
212
pass.set_bind_group(I, view_bind_group, &[view_uniform.offset]);
213
RenderCommandResult::Success
214
}
215
}
216
pub struct SetUiTextureBindGroup<const I: usize>;
217
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {
218
type Param = SRes<ImageNodeBindGroups>;
219
type ViewQuery = ();
220
type ItemQuery = Read<UiBatch>;
221
222
#[inline]
223
fn render<'w>(
224
_item: &P,
225
_view: (),
226
batch: Option<&'w UiBatch>,
227
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
228
pass: &mut TrackedRenderPass<'w>,
229
) -> RenderCommandResult {
230
let image_bind_groups = image_bind_groups.into_inner();
231
let Some(batch) = batch else {
232
return RenderCommandResult::Skip;
233
};
234
235
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
236
RenderCommandResult::Success
237
}
238
}
239
240
pub struct DrawUiNode;
241
impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
242
type Param = SRes<UiMeta>;
243
type ViewQuery = ();
244
type ItemQuery = Read<UiBatch>;
245
246
#[inline]
247
fn render<'w>(
248
_item: &P,
249
_view: (),
250
batch: Option<&'w UiBatch>,
251
ui_meta: SystemParamItem<'w, '_, Self::Param>,
252
pass: &mut TrackedRenderPass<'w>,
253
) -> RenderCommandResult {
254
let Some(batch) = batch else {
255
return RenderCommandResult::Skip;
256
};
257
let ui_meta = ui_meta.into_inner();
258
let Some(vertices) = ui_meta.vertices.buffer() else {
259
return RenderCommandResult::Failure("missing vertices to draw ui");
260
};
261
let Some(indices) = ui_meta.indices.buffer() else {
262
return RenderCommandResult::Failure("missing indices to draw ui");
263
};
264
265
// Store the vertices
266
pass.set_vertex_buffer(0, vertices.slice(..));
267
// Define how to "connect" the vertices
268
pass.set_index_buffer(
269
indices.slice(..),
270
0,
271
bevy_render::render_resource::IndexFormat::Uint32,
272
);
273
// Draw the vertices
274
pass.draw_indexed(batch.range.clone(), 0, 0..1);
275
RenderCommandResult::Success
276
}
277
}
278
279