1use super::WgpuWrapper;
2use crate::diagnostic::internal::DiagnosticsRecorder;
3use crate::render_phase::TrackedRenderPass;
4use crate::render_resource::{CommandEncoder, RenderPassDescriptor};
5use crate::renderer::RenderDevice;
6use bevy_derive::{Deref, DerefMut};
7use bevy_ecs::change_detection::Tick;
8use bevy_ecs::component::ComponentId;
9use bevy_ecs::prelude::*;
10use bevy_ecs::query::{FilteredAccessSet, QueryData, QueryFilter, QueryState};
11use bevy_ecs::system::{
12 Deferred, SystemBuffer, SystemMeta, SystemParam, SystemParamValidationError,
13};
14use bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell;
15use bevy_ecs::world::DeferredWorld;
16#[cfg(feature = "trace")]
17use bevy_log::info_span;
18use core::marker::PhantomData;
19use wgpu::CommandBuffer;
20
21#[derive(#[automatically_derived]
impl ::core::default::Default for PendingCommandBuffersInner {
#[inline]
fn default() -> PendingCommandBuffersInner {
PendingCommandBuffersInner {
buffers: ::core::default::Default::default(),
encoders: ::core::default::Default::default(),
}
}
}Default)]
22struct PendingCommandBuffersInner {
23 buffers: Vec<CommandBuffer>,
24 encoders: Vec<CommandEncoder>,
25}
26
27#[derive(impl bevy_ecs::resource::Resource for PendingCommandBuffers where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource)]
29pub struct PendingCommandBuffers(WgpuWrapper<PendingCommandBuffersInner>);
30
31impl Default for PendingCommandBuffers {
32 fn default() -> Self {
33 Self(WgpuWrapper::new(PendingCommandBuffersInner::default()))
34 }
35}
36
37impl PendingCommandBuffers {
38 pub fn push(&mut self, buffers: impl IntoIterator<Item = CommandBuffer>) {
39 self.0.buffers.extend(buffers);
40 }
41
42 pub fn push_encoder(&mut self, encoder: CommandEncoder) {
43 self.0.encoders.push(encoder);
44 }
45
46 pub fn take(&mut self) -> Vec<CommandBuffer> {
47 let encoders: Vec<_> = self.0.encoders.drain(..).collect();
48 for encoder in encoders {
49 self.0.buffers.push(encoder.finish());
50 }
51 core::mem::take(&mut self.0.buffers)
52 }
53
54 pub fn is_empty(&self) -> bool {
55 self.0.buffers.is_empty() && self.0.encoders.is_empty()
56 }
57
58 pub fn len(&self) -> usize {
59 self.0.buffers.len() + self.0.encoders.len()
60 }
61}
62
63#[derive(#[automatically_derived]
impl ::core::default::Default for RenderContextStateInner {
#[inline]
fn default() -> RenderContextStateInner {
RenderContextStateInner {
command_encoder: ::core::default::Default::default(),
command_buffers: ::core::default::Default::default(),
render_device: ::core::default::Default::default(),
}
}
}Default)]
64struct RenderContextStateInner {
65 command_encoder: Option<CommandEncoder>,
66 command_buffers: Vec<CommandBuffer>,
67 render_device: Option<RenderDevice>,
68}
69
70pub struct RenderContextState(WgpuWrapper<RenderContextStateInner>);
74
75impl Default for RenderContextState {
76 fn default() -> Self {
77 Self(WgpuWrapper::new(RenderContextStateInner::default()))
78 }
79}
80
81impl RenderContextState {
82 fn flush_encoder(&mut self) {
83 if let Some(encoder) = self.0.command_encoder.take() {
84 self.0.command_buffers.push(encoder.finish());
85 }
86 }
87
88 fn command_encoder(&mut self) -> &mut CommandEncoder {
89 let render_device = self
90 .0
91 .render_device
92 .clone()
93 .expect("RenderDevice must be set before accessing command_encoder");
94
95 self.0.command_encoder.get_or_insert_with(|| {
96 render_device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default())
97 })
98 }
99
100 pub fn finish(&mut self) -> Vec<CommandBuffer> {
101 self.flush_encoder();
102 core::mem::take(&mut self.0.command_buffers)
103 }
104}
105
106impl SystemBuffer for RenderContextState {
107 fn queue(&mut self, _system_meta: &SystemMeta, mut world: DeferredWorld) {
108 #[cfg(feature = "trace")]
109 let _span =
110 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("RenderContextState::apply",
"bevy_render::renderer::render_context",
::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("src/renderer/render_context.rs"),
::tracing_core::__macro_support::Option::Some(110u32),
::tracing_core::__macro_support::Option::Some("bevy_render::renderer::render_context"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("system")
}> =
::tracing::__macro_support::FieldName::new("system");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() } &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&_system_meta.name())
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
}info_span!("RenderContextState::apply", system = %_system_meta.name()).entered();
111
112 let inner = &mut *self.0;
113
114 if let Some(encoder) = inner.command_encoder.take() {
116 inner.command_buffers.push(encoder.finish());
117 }
118
119 if !inner.command_buffers.is_empty() {
120 let mut pending = world.resource_mut::<PendingCommandBuffers>();
121 pending.push(core::mem::take(&mut inner.command_buffers));
122 }
123
124 inner.render_device = None;
125 }
126}
127
128#[derive(const _: () =
{
type __StructFieldsAlias<'w, 's> =
(Deferred<'s, RenderContextState>, Res<'w, RenderDevice>,
Option<Res<'w, DiagnosticsRecorder>>);
#[doc(hidden)]
pub struct FetchState {
state: <__StructFieldsAlias<'static, 'static> as
bevy_ecs::system::SystemParam>::State,
}
unsafe impl bevy_ecs::system::SystemParam for RenderContext<'_, '_> {
type State = FetchState<>;
type Item<'w, 's> = RenderContext<'w, 's>;
fn init_state(world: &mut bevy_ecs::world::World) -> Self::State {
FetchState {
state: <__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::init_state(world),
}
}
fn init_access(state: &Self::State,
system_meta: &mut bevy_ecs::system::SystemMeta,
component_access_set: &mut bevy_ecs::query::FilteredAccessSet,
world: &mut bevy_ecs::world::World) {
<__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::init_access(&state.state,
system_meta, component_access_set, world);
}
fn apply(state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: &mut bevy_ecs::world::World) {
<__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::apply(&mut state.state,
system_meta, world);
}
fn queue(state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: bevy_ecs::world::DeferredWorld) {
<__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::queue(&mut state.state,
system_meta, world);
}
#[inline]
unsafe fn get_param<'w,
's>(state: &'s mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world:
bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell<'w>,
change_tick: bevy_ecs::change_detection::Tick)
->
::core::result::Result<Self::Item<'w, 's>,
bevy_ecs::system::SystemParamValidationError> {
let (fieldstate, fieldrender_device,
fielddiagnostics_recorder) = &mut state.state;
let fieldstate =
unsafe {
<Deferred<'s, RenderContextState> as
bevy_ecs::system::SystemParam>::get_param(fieldstate,
system_meta, world, change_tick)
}.map_err(|err|
bevy_ecs::system::SystemParamValidationError::new::<Self>(err.skipped,
err.message, "::state"))?;
let fieldrender_device =
unsafe {
<Res<'w, RenderDevice> as
bevy_ecs::system::SystemParam>::get_param(fieldrender_device,
system_meta, world, change_tick)
}.map_err(|err|
bevy_ecs::system::SystemParamValidationError::new::<Self>(err.skipped,
err.message, "::render_device"))?;
let fielddiagnostics_recorder =
unsafe {
<Option<Res<'w, DiagnosticsRecorder>> as
bevy_ecs::system::SystemParam>::get_param(fielddiagnostics_recorder,
system_meta, world, change_tick)
}.map_err(|err|
bevy_ecs::system::SystemParamValidationError::new::<Self>(err.skipped,
err.message, "::diagnostics_recorder"))?;
::core::result::Result::Ok(RenderContext {
state: fieldstate,
render_device: fieldrender_device,
diagnostics_recorder: fielddiagnostics_recorder,
})
}
}
unsafe impl<'w, 's> bevy_ecs::system::ReadOnlySystemParam for
RenderContext<'w, 's> where
Deferred<'s,
RenderContextState>: bevy_ecs::system::ReadOnlySystemParam,
Res<'w, RenderDevice>: bevy_ecs::system::ReadOnlySystemParam,
Option<Res<'w,
DiagnosticsRecorder>>: bevy_ecs::system::ReadOnlySystemParam {}
};SystemParam)]
132pub struct RenderContext<'w, 's> {
133 state: Deferred<'s, RenderContextState>,
134 render_device: Res<'w, RenderDevice>,
135 diagnostics_recorder: Option<Res<'w, DiagnosticsRecorder>>,
136}
137
138impl<'w, 's> RenderContext<'w, 's> {
139 fn ensure_device(&mut self) {
140 if self.state.0.render_device.is_none() {
141 self.state.0.render_device = Some(self.render_device.clone());
142 }
143 }
144
145 pub fn render_device(&self) -> &RenderDevice {
147 &self.render_device
148 }
149
150 pub fn diagnostic_recorder(&self) -> Option<Res<'w, DiagnosticsRecorder>> {
152 self.diagnostics_recorder.as_ref().map(Res::clone)
153 }
154
155 pub fn command_encoder(&mut self) -> &mut CommandEncoder {
157 self.ensure_device();
158 self.state.command_encoder()
159 }
160
161 pub fn begin_tracked_render_pass<'a>(
163 &'a mut self,
164 descriptor: RenderPassDescriptor<'_>,
165 ) -> TrackedRenderPass<'a> {
166 self.ensure_device();
167
168 let command_encoder = self.state.0.command_encoder.get_or_insert_with(|| {
169 self.render_device
170 .create_command_encoder(&wgpu::CommandEncoderDescriptor::default())
171 });
172
173 let render_pass = command_encoder.begin_render_pass(&descriptor);
174 TrackedRenderPass::new(&self.render_device, render_pass)
175 }
176
177 pub fn add_command_buffer(&mut self, command_buffer: CommandBuffer) {
179 self.state.flush_encoder();
180 self.state.0.command_buffers.push(command_buffer);
181 }
182}
183
184#[derive(const _: () =
{
type __StructFieldsAlias<'w, 's> =
(ResMut<'w, PendingCommandBuffers>, Res<'w, super::RenderQueue>);
#[doc(hidden)]
pub struct FetchState {
state: <__StructFieldsAlias<'static, 'static> as
bevy_ecs::system::SystemParam>::State,
}
unsafe impl bevy_ecs::system::SystemParam for FlushCommands<'_> {
type State = FetchState<>;
type Item<'w, 's> = FlushCommands<'w>;
fn init_state(world: &mut bevy_ecs::world::World) -> Self::State {
FetchState {
state: <__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::init_state(world),
}
}
fn init_access(state: &Self::State,
system_meta: &mut bevy_ecs::system::SystemMeta,
component_access_set: &mut bevy_ecs::query::FilteredAccessSet,
world: &mut bevy_ecs::world::World) {
<__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::init_access(&state.state,
system_meta, component_access_set, world);
}
fn apply(state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: &mut bevy_ecs::world::World) {
<__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::apply(&mut state.state,
system_meta, world);
}
fn queue(state: &mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world: bevy_ecs::world::DeferredWorld) {
<__StructFieldsAlias<'_, '_> as
bevy_ecs::system::SystemParam>::queue(&mut state.state,
system_meta, world);
}
#[inline]
unsafe fn get_param<'w,
's>(state: &'s mut Self::State,
system_meta: &bevy_ecs::system::SystemMeta,
world:
bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell<'w>,
change_tick: bevy_ecs::change_detection::Tick)
->
::core::result::Result<Self::Item<'w, 's>,
bevy_ecs::system::SystemParamValidationError> {
let (fieldpending, fieldqueue) = &mut state.state;
let fieldpending =
unsafe {
<ResMut<'w, PendingCommandBuffers> as
bevy_ecs::system::SystemParam>::get_param(fieldpending,
system_meta, world, change_tick)
}.map_err(|err|
bevy_ecs::system::SystemParamValidationError::new::<Self>(err.skipped,
err.message, "::pending"))?;
let fieldqueue =
unsafe {
<Res<'w, super::RenderQueue> as
bevy_ecs::system::SystemParam>::get_param(fieldqueue,
system_meta, world, change_tick)
}.map_err(|err|
bevy_ecs::system::SystemParamValidationError::new::<Self>(err.skipped,
err.message, "::queue"))?;
::core::result::Result::Ok(FlushCommands {
pending: fieldpending,
queue: fieldqueue,
})
}
}
unsafe impl<'w, 's> bevy_ecs::system::ReadOnlySystemParam for
FlushCommands<'w> where
ResMut<'w,
PendingCommandBuffers>: bevy_ecs::system::ReadOnlySystemParam,
Res<'w, super::RenderQueue>: bevy_ecs::system::ReadOnlySystemParam
{}
};SystemParam)]
188pub struct FlushCommands<'w> {
189 pending: ResMut<'w, PendingCommandBuffers>,
190 queue: Res<'w, super::RenderQueue>,
191}
192
193impl<'w> FlushCommands<'w> {
194 pub fn flush(&mut self) {
196 let buffers = self.pending.take();
197 if !buffers.is_empty() {
198 self.queue.submit(buffers);
199 }
200 }
201}
202
203#[derive(impl bevy_ecs::resource::Resource for CurrentView where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::fmt::Debug for CurrentView {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "CurrentView",
&&self.0)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for CurrentView {
#[inline]
fn clone(&self) -> CurrentView {
let _: ::core::clone::AssertParamIsClone<Entity>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CurrentView { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for CurrentView {
#[inline]
fn eq(&self, other: &CurrentView) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CurrentView {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Entity>;
}
}Eq, impl ::core::ops::Deref for CurrentView {
type Target = Entity;
fn deref(&self) -> &Self::Target { &self.0 }
}Deref, impl ::core::ops::DerefMut for CurrentView {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}DerefMut)]
205pub struct CurrentView(pub Entity);
206
207pub struct ViewQuery<'w, 's, D: QueryData, F: QueryFilter = ()> {
210 entity: Entity,
211 item: D::Item<'w, 's>,
212 _filter: PhantomData<F>,
213}
214
215impl<'w, 's, D: QueryData, F: QueryFilter> ViewQuery<'w, 's, D, F> {
216 #[inline]
217 pub fn entity(&self) -> Entity {
218 self.entity
219 }
220
221 #[inline]
222 pub fn into_inner(self) -> D::Item<'w, 's> {
223 self.item
224 }
225}
226
227pub struct ViewQueryState<D: QueryData, F: QueryFilter> {
228 resource_id: ComponentId,
229 query_state: QueryState<D, F>,
230}
231
232unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
235 for ViewQuery<'a, '_, D, F>
236{
237 type State = ViewQueryState<D, F>;
238 type Item<'w, 's> = ViewQuery<'w, 's, D, F>;
239
240 fn init_state(world: &mut World) -> Self::State {
241 ViewQueryState {
242 resource_id: world
243 .components_registrator()
244 .register_component::<CurrentView>(),
245 query_state: QueryState::new(world),
246 }
247 }
248
249 fn init_access(
250 state: &Self::State,
251 system_meta: &mut SystemMeta,
252 component_access_set: &mut FilteredAccessSet,
253 world: &mut World,
254 ) {
255 component_access_set.add_resource_read(state.resource_id);
256
257 <Query<'_, '_, D, F> as SystemParam>::init_access(
258 &state.query_state,
259 system_meta,
260 component_access_set,
261 world,
262 );
263 }
264
265 #[inline]
266 unsafe fn get_param<'w, 's>(
267 state: &'s mut Self::State,
268 _system_meta: &SystemMeta,
269 world: UnsafeWorldCell<'w>,
270 _change_tick: Tick,
271 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
272 let current_view = unsafe { world.get_resource::<CurrentView>() };
274
275 let Some(current_view) = current_view else {
276 return Err(SystemParamValidationError::skipped::<Self>(
277 "CurrentView resource not present",
278 ));
279 };
280
281 let entity = current_view.entity();
282
283 let item = unsafe { state.query_state.get_unchecked(world, entity) }.map_err(|_| {
286 SystemParamValidationError::skipped::<Self>("Current view entity does not match query")
287 })?;
288
289 Ok(ViewQuery {
290 entity,
291 item,
292 _filter: PhantomData,
293 })
294 }
295}
296
297unsafe impl<'w, 's, D: bevy_ecs::query::ReadOnlyQueryData + 'static, F: QueryFilter + 'static>
299 bevy_ecs::system::ReadOnlySystemParam for ViewQuery<'w, 's, D, F>
300{
301}