correct pipelining

This commit is contained in:
awtterpip
2024-07-03 19:37:40 -05:00
parent c2a0d786b9
commit 3264bb9605
17 changed files with 660 additions and 720 deletions

View File

@@ -1,6 +1,3 @@
use bevy::app::MainScheduleOrder;
use bevy::ecs::schedule::ScheduleLabel;
use bevy::ecs::system::RunSystemOnce;
use bevy::prelude::*;
use bevy::render::extract_resource::ExtractResourcePlugin;
use bevy::render::renderer::RenderAdapter;
@@ -10,48 +7,38 @@ use bevy::render::renderer::RenderInstance;
use bevy::render::renderer::RenderQueue;
use bevy::render::settings::RenderCreation;
use bevy::render::MainWorld;
use bevy::render::Render;
use bevy::render::RenderApp;
use bevy::render::RenderPlugin;
use bevy::render::RenderSet;
use bevy::transform::TransformSystem;
use bevy::winit::UpdateMode;
use bevy::winit::WinitSettings;
use bevy_xr::session::session_running;
use bevy_xr::session::status_equals;
use bevy_xr::session::BeginXrSession;
use bevy_xr::session::CreateXrSession;
use bevy_xr::session::DestroyXrSession;
use bevy_xr::session::EndXrSession;
use bevy_xr::session::XrSessionExiting;
use bevy_xr::session::XrStatus;
use bevy_xr::session::XrStatusChanged;
use bevy_xr::session::*;
use crate::error::OxrError;
use crate::features::overlay::OxrOverlaySessionEvent;
use crate::graphics::*;
use crate::openxr::exts::OxrEnabledExtensions;
use crate::resources::*;
use crate::session::OxrSession;
use crate::session::OxrSessionCreateNextChain;
use crate::session::OxrSessionStatusEvent;
use crate::types::*;
use super::exts::OxrEnabledExtensions;
pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool {
started.is_some_and(|started| started.0)
}
pub fn should_run_frame_loop(
started: Option<Res<OxrSessionStarted>>,
state: Option<Res<XrState>>,
) -> bool {
started.is_some_and(|started| started.0)
&& state.is_some_and(|state| *state != XrState::Stopping)
}
pub fn should_render(frame_state: Option<Res<OxrFrameState>>) -> bool {
frame_state.is_some_and(|frame_state| frame_state.should_render)
}
/// TODO!() better name pls
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
pub struct OxrLast;
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
pub struct OxrHandleEvents;
pub struct OxrInitPlugin {
/// Information about the app this is being used to build.
pub app_info: AppInfo,
@@ -88,9 +75,6 @@ impl Default for OxrInitPlugin {
}
}
#[derive(Component)]
pub struct OxrTrackingRoot;
impl Plugin for OxrInitPlugin {
fn build(&self, app: &mut App) {
match self.init_xr() {
@@ -101,103 +85,70 @@ impl Plugin for OxrInitPlugin {
session_create_info,
enabled_exts,
)) => {
app.insert_resource(enabled_exts);
app.add_plugins((
RenderPlugin {
render_creation: RenderCreation::manual(
device.into(),
RenderQueue(queue.into()),
RenderAdapterInfo(adapter_info),
RenderAdapter(adapter.into()),
RenderInstance(wgpu_instance.into()),
),
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
},
ExtractResourcePlugin::<OxrCleanupSession>::default(),
ExtractResourcePlugin::<XrStatus>::default(),
ExtractResourcePlugin::<OxrSessionStarted>::default(),
))
.init_schedule(OxrLast)
.add_systems(
OxrLast,
(
reset_per_frame_resources,
poll_events,
create_xr_session
.run_if(on_event::<CreateXrSession>())
.run_if(status_equals(XrStatus::Available)),
begin_xr_session
.run_if(on_event::<BeginXrSession>())
.run_if(status_equals(XrStatus::Ready)),
end_xr_session
.run_if(on_event::<EndXrSession>())
.run_if(status_equals(XrStatus::Running)),
destroy_xr_session
.run_if(on_event::<DestroyXrSession>())
.run_if(status_equals(XrStatus::Exiting)),
app.insert_resource(enabled_exts)
.add_plugins((
RenderPlugin {
render_creation: RenderCreation::manual(
device.into(),
RenderQueue(queue.into()),
RenderAdapterInfo(adapter_info),
RenderAdapter(adapter.into()),
RenderInstance(wgpu_instance.into()),
),
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
},
ExtractResourcePlugin::<OxrSessionStarted>::default(),
))
.add_systems(
XrFirst,
poll_events
.before(XrHandleEvents)
.run_if(not(state_equals(XrState::Unavailable))),
)
.chain()
.in_set(OxrHandleEvents),
)
.add_systems(XrSessionExiting, destroy_xr_session)
.add_systems(
PostUpdate,
update_root_transform.after(TransformSystem::TransformPropagate),
)
.insert_resource(instance.clone())
.insert_resource(system_id)
.insert_resource(XrStatus::Available)
.insert_resource(WinitSettings {
focused_mode: UpdateMode::Continuous,
unfocused_mode: UpdateMode::Continuous,
})
.init_resource::<OxrCleanupSession>()
.init_resource::<OxrRootTransform>()
.insert_non_send_resource(session_create_info)
.configure_sets(OxrLast, OxrHandleEvents);
.add_systems(XrCreateSession, create_xr_session)
.add_systems(XrDestroySession, destroy_xr_session)
.add_systems(XrBeginSession, begin_xr_session)
.add_systems(XrEndSession, end_xr_session)
.add_systems(XrRequestExit, request_exit_xr_session)
.insert_resource(instance.clone())
.insert_resource(system_id)
.insert_resource(XrState::Available)
.insert_resource(WinitSettings {
focused_mode: UpdateMode::Continuous,
unfocused_mode: UpdateMode::Continuous,
})
.insert_resource(OxrSessionStarted(false))
.insert_non_send_resource(session_create_info)
.init_non_send_resource::<OxrSessionCreateNextChain>();
app.world
.resource_mut::<MainScheduleOrder>()
.insert_after(Last, OxrLast);
.spawn((TransformBundle::default(), XrTrackingRoot));
app.world
.spawn((TransformBundle::default(), OxrTrackingRoot));
.resource_mut::<Events<XrStateChanged>>()
.send(XrStateChanged(XrState::Available));
let render_app = app.sub_app_mut(RenderApp);
render_app
.add_systems(
Render,
destroy_xr_session_render
.run_if(resource_equals(OxrCleanupSession(true)))
.after(RenderSet::Cleanup),
)
.add_systems(
ExtractSchedule,
transfer_xr_resources.run_if(not(session_running)),
)
.add_systems(ExtractSchedule, transfer_xr_resources)
.insert_resource(instance)
.insert_resource(system_id)
.init_resource::<OxrRootTransform>()
.init_resource::<OxrCleanupSession>();
.insert_resource(XrState::Available)
.insert_resource(OxrSessionStarted(false));
}
Err(e) => {
error!("Failed to initialize openxr: {e}");
app.add_plugins(RenderPlugin::default())
.insert_resource(XrStatus::Unavailable);
.insert_resource(XrState::Unavailable);
}
};
app.insert_resource(OxrSessionStarted(false));
}
}
pub fn update_root_transform(
mut root_transform: ResMut<OxrRootTransform>,
root: Query<&GlobalTransform, With<OxrTrackingRoot>>,
) {
let transform = root.single();
root_transform.0 = *transform;
fn finish(&self, app: &mut App) {
app.sub_app_mut(RenderApp)
.add_systems(XrDestroySession, destroy_xr_session);
}
}
impl OxrInitPlugin {
@@ -291,6 +242,63 @@ impl OxrInitPlugin {
}
}
/// Polls any OpenXR events and handles them accordingly
pub fn poll_events(
instance: Res<OxrInstance>,
mut status: ResMut<XrState>,
mut changed_event: EventWriter<XrStateChanged>,
mut overlay_writer: Option<ResMut<Events<OxrOverlaySessionEvent>>>,
) {
let _span = info_span!("xr_poll_events");
let mut buffer = Default::default();
while let Some(event) = instance
.poll_event(&mut buffer)
.expect("Failed to poll event")
{
use openxr::Event::*;
match event {
SessionStateChanged(state) => {
use openxr::SessionState;
let state = state.state();
info!("entered XR state {:?}", state);
let new_status = match state {
SessionState::IDLE => XrState::Idle,
SessionState::READY => XrState::Ready,
SessionState::SYNCHRONIZED | SessionState::VISIBLE | SessionState::FOCUSED => {
XrState::Running
}
SessionState::STOPPING => XrState::Stopping,
SessionState::EXITING => XrState::Exiting {
should_restart: false,
},
SessionState::LOSS_PENDING => XrState::Exiting {
should_restart: true,
},
_ => unreachable!(),
};
changed_event.send(XrStateChanged(new_status));
*status = new_status;
}
InstanceLossPending(_) => {}
EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()),
MainSessionVisibilityChangedEXTX(d) => {
if let Some(writer) = overlay_writer.as_mut() {
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
visible: d.visible(),
flags: d.flags(),
});
} else {
warn!("Overlay Event Recieved without the OverlayPlugin being added!");
}
}
_ => {}
}
}
}
fn init_xr_session(
device: &wgpu::Device,
instance: &OxrInstance,
@@ -426,6 +434,49 @@ fn init_xr_session(
))
}
pub fn create_xr_session(world: &mut World) {
let mut chain = world
.remove_non_send_resource::<OxrSessionCreateNextChain>()
.unwrap();
let device = world.resource::<RenderDevice>();
let instance = world.resource::<OxrInstance>();
let create_info = world.non_send_resource::<SessionConfigInfo>();
let system_id = world.resource::<OxrSystemId>();
match init_xr_session(
device.wgpu_device(),
&instance,
**system_id,
&mut chain,
create_info.clone(),
) {
Ok((session, frame_waiter, frame_stream, swapchain, images, graphics_info)) => {
world.insert_resource(session.clone());
world.insert_resource(frame_waiter);
world.insert_resource(images.clone());
world.insert_resource(graphics_info.clone());
world.insert_resource(OxrRenderResources {
session,
frame_stream,
swapchain,
images,
graphics_info,
});
}
Err(e) => error!("Failed to initialize XrSession: {e}"),
}
world.insert_non_send_resource(chain);
}
pub fn destroy_xr_session(world: &mut World) {
world.remove_resource::<OxrSession>();
world.remove_resource::<OxrFrameWaiter>();
world.remove_resource::<OxrFrameStream>();
world.remove_resource::<OxrSwapchain>();
world.remove_resource::<OxrSwapchainImages>();
world.remove_resource::<OxrGraphicsInfo>();
world.insert_resource(XrState::Available);
}
pub fn begin_xr_session(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
let _span = info_span!("xr_begin_session");
session
@@ -436,10 +487,14 @@ pub fn begin_xr_session(session: Res<OxrSession>, mut session_started: ResMut<Ox
pub fn end_xr_session(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
let _span = info_span!("xr_end_session");
session.request_exit().expect("Failed to end session");
session.end().expect("Failed to end session");
session_started.0 = false;
}
pub fn request_exit_xr_session(session: Res<OxrSession>) {
session.request_exit().expect("Failed to request exit");
}
/// This is used solely to transport resources from the main world to the render world.
#[derive(Resource)]
struct OxrRenderResources {
@@ -450,38 +505,6 @@ struct OxrRenderResources {
graphics_info: OxrGraphicsInfo,
}
pub fn create_xr_session(
device: Res<RenderDevice>,
instance: Res<OxrInstance>,
create_info: NonSend<SessionConfigInfo>,
system_id: Res<OxrSystemId>,
mut chain: NonSendMut<OxrSessionCreateNextChain>,
mut commands: Commands,
) {
match init_xr_session(
device.wgpu_device(),
&instance,
**system_id,
&mut chain,
create_info.clone(),
) {
Ok((session, frame_waiter, frame_stream, swapchain, images, graphics_info)) => {
commands.insert_resource(session.clone());
commands.insert_resource(frame_waiter);
commands.insert_resource(images.clone());
commands.insert_resource(graphics_info.clone());
commands.insert_resource(OxrRenderResources {
session,
frame_stream,
swapchain,
images,
graphics_info,
});
}
Err(e) => error!("Failed to initialize XrSession: {e}"),
}
}
/// This system transfers important render resources from the main world to the render world when a session is created.
pub fn transfer_xr_resources(mut commands: Commands, mut world: ResMut<MainWorld>) {
let Some(OxrRenderResources {
@@ -501,86 +524,3 @@ pub fn transfer_xr_resources(mut commands: Commands, mut world: ResMut<MainWorld
commands.insert_resource(images);
commands.insert_resource(graphics_info);
}
/// Polls any OpenXR events and handles them accordingly
pub fn poll_events(
instance: Res<OxrInstance>,
mut status: ResMut<XrStatus>,
mut changed_event: EventWriter<XrStatusChanged>,
mut session_status_events: EventWriter<OxrSessionStatusEvent>,
mut overlay_writer: Option<ResMut<Events<OxrOverlaySessionEvent>>>,
) {
let _span = info_span!("xr_poll_events");
let mut buffer = Default::default();
while let Some(event) = instance
.poll_event(&mut buffer)
.expect("Failed to poll event")
{
use openxr::Event::*;
match event {
SessionStateChanged(state) => {
use openxr::SessionState;
let state = state.state();
info!("entered XR state {:?}", state);
let new_status = match state {
SessionState::IDLE => {
if *status == XrStatus::Available {
session_status_events.send(OxrSessionStatusEvent::Created);
}
XrStatus::Idle
}
SessionState::READY => XrStatus::Ready,
SessionState::SYNCHRONIZED | SessionState::VISIBLE | SessionState::FOCUSED => {
XrStatus::Running
}
SessionState::STOPPING => XrStatus::Stopping,
SessionState::EXITING | SessionState::LOSS_PENDING => {
session_status_events.send(OxrSessionStatusEvent::AboutToBeDestroyed);
XrStatus::Exiting
}
_ => unreachable!(),
};
changed_event.send(XrStatusChanged(new_status));
*status = new_status;
}
InstanceLossPending(_) => {}
EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()),
MainSessionVisibilityChangedEXTX(d) => {
if let Some(writer) = overlay_writer.as_mut() {
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
visible: d.visible(),
flags: d.flags(),
});
} else {
warn!("Overlay Event Recieved without the OverlayPlugin being added!");
}
}
_ => {}
}
}
}
pub fn reset_per_frame_resources(mut cleanup: ResMut<OxrCleanupSession>) {
**cleanup = false;
}
pub fn destroy_xr_session(mut commands: Commands) {
commands.remove_resource::<OxrFrameWaiter>();
commands.remove_resource::<OxrSwapchainImages>();
commands.remove_resource::<OxrGraphicsInfo>();
}
pub fn destroy_xr_session_render(world: &mut World) {
world.remove_resource::<OxrSwapchain>();
world.remove_resource::<OxrFrameStream>();
world.remove_resource::<OxrSwapchainImages>();
world.remove_resource::<OxrGraphicsInfo>();
world.run_system_once(apply_deferred);
world.run_schedule(XrSessionExiting);
world.run_system_once(apply_deferred);
world.remove_resource::<OxrSession>();
world.insert_resource(OxrSessionStarted(false));
}