mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Give inline sessions the correct projection matrices
This commit is contained in:
parent
a1c1a16e98
commit
8aaa8493a7
4 changed files with 108 additions and 27 deletions
|
@ -61,7 +61,7 @@ use cssparser::RGBA;
|
|||
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
|
||||
use embedder_traits::{EventLoopWaker, MediaMetadata};
|
||||
use encoding_rs::{Decoder, Encoding};
|
||||
use euclid::default::{Point2D, Rect, Rotation3D, Transform2D, Transform3D};
|
||||
use euclid::default::{Point2D, Rect, Rotation3D, Transform2D};
|
||||
use euclid::Length as EuclidLength;
|
||||
use html5ever::buffer_queue::BufferQueue;
|
||||
use html5ever::{LocalName, Namespace, Prefix, QualName};
|
||||
|
@ -534,7 +534,7 @@ unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
|
|||
unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
|
||||
unsafe_no_jsmanaged_fields!(Timespec);
|
||||
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
|
||||
unsafe_no_jsmanaged_fields!(Rotation3D<f64>, Transform2D<f32>, Transform3D<f64>);
|
||||
unsafe_no_jsmanaged_fields!(Rotation3D<f64>, Transform2D<f32>);
|
||||
unsafe_no_jsmanaged_fields!(Point2D<f32>, Rect<Au>);
|
||||
unsafe_no_jsmanaged_fields!(Rect<f32>);
|
||||
unsafe_no_jsmanaged_fields!(CascadeData);
|
||||
|
@ -665,6 +665,20 @@ unsafe impl<T, U> JSTraceable for euclid::RigidTransform3D<f64, T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<T, U> JSTraceable for euclid::Transform3D<f32, T, U> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, _trc: *mut JSTracer) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T, U> JSTraceable for euclid::Transform3D<f64, T, U> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, _trc: *mut JSTracer) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> JSTraceable for EuclidLength<u64, T> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, _trc: *mut JSTracer) {
|
||||
|
|
|
@ -40,7 +40,7 @@ use crate::dom::xrspace::XRSpace;
|
|||
use crate::dom::xrwebgllayer::XRWebGLLayer;
|
||||
use crate::task_source::TaskSource;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::RigidTransform3D;
|
||||
use euclid::{Rect, RigidTransform3D, Transform3D};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use profile_traits::ipc;
|
||||
|
@ -48,8 +48,8 @@ use std::cell::Cell;
|
|||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use webxr_api::{
|
||||
self, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind, Session,
|
||||
Visibility,
|
||||
self, util, Display, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind,
|
||||
Session, View, Viewer, Visibility,
|
||||
};
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -65,6 +65,8 @@ pub struct XRSession {
|
|||
frame_requested: Cell<bool>,
|
||||
pending_render_state: MutNullableDom<XRRenderState>,
|
||||
active_render_state: MutDom<XRRenderState>,
|
||||
/// Cached projection matrix for inline sessions
|
||||
inline_projection_matrix: DomRefCell<Transform3D<f32, Viewer, Display>>,
|
||||
|
||||
next_raf_id: Cell<i32>,
|
||||
#[ignore_malloc_size_of = "closures are hard"]
|
||||
|
@ -100,6 +102,7 @@ impl XRSession {
|
|||
frame_requested: Cell::new(false),
|
||||
pending_render_state: MutNullableDom::new(None),
|
||||
active_render_state: MutDom::new(render_state),
|
||||
inline_projection_matrix: Default::default(),
|
||||
|
||||
next_raf_id: Cell::new(0),
|
||||
raf_callback_list: DomRefCell::new(vec![]),
|
||||
|
@ -140,6 +143,10 @@ impl XRSession {
|
|||
self.ended.get()
|
||||
}
|
||||
|
||||
pub fn is_immersive(&self) -> bool {
|
||||
self.mode != XRSessionMode::Inline
|
||||
}
|
||||
|
||||
fn setup_raf_loop(&self) {
|
||||
assert!(
|
||||
self.raf_sender.borrow().is_none(),
|
||||
|
@ -304,9 +311,12 @@ impl XRSession {
|
|||
self.active_render_state.set(&pending);
|
||||
// Step 6-7: XXXManishearth handle inlineVerticalFieldOfView
|
||||
|
||||
// XXXManishearth handle inline sessions and composition disabled flag
|
||||
let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id());
|
||||
self.session.borrow_mut().set_swap_chain(swap_chain_id);
|
||||
if self.is_immersive() {
|
||||
let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id());
|
||||
self.session.borrow_mut().set_swap_chain(swap_chain_id);
|
||||
} else {
|
||||
self.update_inline_projection_matrix()
|
||||
}
|
||||
}
|
||||
|
||||
for event in frame.events.drain(..) {
|
||||
|
@ -339,8 +349,10 @@ impl XRSession {
|
|||
self.outside_raf.set(true);
|
||||
|
||||
frame.set_active(false);
|
||||
base_layer.swap_buffers();
|
||||
self.session.borrow_mut().render_animation_frame();
|
||||
if self.is_immersive() {
|
||||
base_layer.swap_buffers();
|
||||
self.session.borrow_mut().render_animation_frame();
|
||||
}
|
||||
self.request_new_xr_frame();
|
||||
|
||||
// If the canvas element is attached to the DOM, it is now dirty,
|
||||
|
@ -351,6 +363,44 @@ impl XRSession {
|
|||
.upcast::<Node>()
|
||||
.dirty(NodeDamage::OtherNodeDamage);
|
||||
}
|
||||
|
||||
fn update_inline_projection_matrix(&self) {
|
||||
debug_assert!(!self.is_immersive());
|
||||
let render_state = self.active_render_state.get();
|
||||
let size = if let Some(base) = render_state.GetBaseLayer() {
|
||||
base.size()
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let mut clip_planes = util::ClipPlanes::default();
|
||||
let near = *render_state.DepthNear() as f32;
|
||||
let far = *render_state.DepthFar() as f32;
|
||||
clip_planes.update(near, far);
|
||||
let top = *render_state.InlineVerticalFieldOfView() / 2.;
|
||||
let top = near * top.tan() as f32;
|
||||
let bottom = top;
|
||||
let left = top * size.width as f32 / size.height as f32;
|
||||
let right = left;
|
||||
let matrix = util::frustum_to_projection_matrix(left, right, top, bottom, clip_planes);
|
||||
*self.inline_projection_matrix.borrow_mut() = matrix;
|
||||
}
|
||||
|
||||
/// Constructs a View suitable for inline sessions using the inlineVerticalFieldOfView and canvas size
|
||||
pub fn inline_view(&self) -> View<Viewer> {
|
||||
debug_assert!(!self.is_immersive());
|
||||
let size = self
|
||||
.active_render_state
|
||||
.get()
|
||||
.GetBaseLayer()
|
||||
.expect("Must never construct views when base layer is not set")
|
||||
.size();
|
||||
View {
|
||||
// Inline views have no offset
|
||||
transform: RigidTransform3D::identity(),
|
||||
projection: *self.inline_projection_matrix.borrow(),
|
||||
viewport: Rect::from_size(size.to_i32()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XRSessionMethods for XRSession {
|
||||
|
|
|
@ -42,7 +42,13 @@ impl XRViewerPose {
|
|||
) -> DomRoot<XRViewerPose> {
|
||||
rooted_vec!(let mut views);
|
||||
session.with_session(|s| match s.views() {
|
||||
Views::Inline => unimplemented!(),
|
||||
Views::Inline => views.push(XRView::new(
|
||||
global,
|
||||
session,
|
||||
&session.inline_view(),
|
||||
XREye::None,
|
||||
&pose,
|
||||
)),
|
||||
Views::Mono(view) => {
|
||||
views.push(XRView::new(global, session, &view, XREye::None, &pose))
|
||||
},
|
||||
|
|
|
@ -20,10 +20,10 @@ use crate::dom::xrview::XRView;
|
|||
use crate::dom::xrviewport::XRViewport;
|
||||
use canvas_traits::webgl::WebGLFramebufferId;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::default::Size2D;
|
||||
use euclid::Size2D;
|
||||
use std::convert::TryInto;
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
use webxr_api::Views;
|
||||
use webxr_api::{Viewport, Views};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRWebGLLayer {
|
||||
|
@ -33,7 +33,7 @@ pub struct XRWebGLLayer {
|
|||
stencil: bool,
|
||||
alpha: bool,
|
||||
#[ignore_malloc_size_of = "ids don't malloc"]
|
||||
swap_chain_id: WebXRSwapChainId,
|
||||
swap_chain_id: Option<WebXRSwapChainId>,
|
||||
context: Dom<WebGLRenderingContext>,
|
||||
session: Dom<XRSession>,
|
||||
/// If none, this is an inline session (the composition disabled flag is true)
|
||||
|
@ -42,7 +42,7 @@ pub struct XRWebGLLayer {
|
|||
|
||||
impl XRWebGLLayer {
|
||||
pub fn new_inherited(
|
||||
swap_chain_id: WebXRSwapChainId,
|
||||
swap_chain_id: Option<WebXRSwapChainId>,
|
||||
session: &XRSession,
|
||||
context: &WebGLRenderingContext,
|
||||
init: &XRWebGLLayerInit,
|
||||
|
@ -63,7 +63,7 @@ impl XRWebGLLayer {
|
|||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
swap_chain_id: WebXRSwapChainId,
|
||||
swap_chain_id: Option<WebXRSwapChainId>,
|
||||
session: &XRSession,
|
||||
context: &WebGLRenderingContext,
|
||||
init: &XRWebGLLayerInit,
|
||||
|
@ -89,6 +89,7 @@ impl XRWebGLLayer {
|
|||
context: &WebGLRenderingContext,
|
||||
init: &XRWebGLLayerInit,
|
||||
) -> Fallible<DomRoot<Self>> {
|
||||
let framebuffer;
|
||||
// Step 2
|
||||
if session.is_ended() {
|
||||
return Err(Error::InvalidState);
|
||||
|
@ -97,9 +98,15 @@ impl XRWebGLLayer {
|
|||
// XXXManishearth step 4: check XR compat flag for immersive sessions
|
||||
|
||||
// Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context."
|
||||
let size = session.with_session(|session| session.recommended_framebuffer_resolution());
|
||||
let (swap_chain_id, framebuffer) =
|
||||
WebGLFramebuffer::maybe_new_webxr(session, context, size).ok_or(Error::Operation)?;
|
||||
let (swap_chain_id, framebuffer) = if session.is_immersive() {
|
||||
let size = session.with_session(|session| session.recommended_framebuffer_resolution());
|
||||
let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, context, size)
|
||||
.ok_or(Error::Operation)?;
|
||||
framebuffer = fb;
|
||||
(Some(swap_chain_id), Some(&*framebuffer))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
// Step 9.3. "Allocate and initialize resources compatible with session’s XR device,
|
||||
// including GPU accessible memory buffers, as required to support the compositing of layer."
|
||||
|
@ -117,12 +124,13 @@ impl XRWebGLLayer {
|
|||
session,
|
||||
context,
|
||||
init,
|
||||
Some(&framebuffer),
|
||||
framebuffer,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn swap_chain_id(&self) -> WebXRSwapChainId {
|
||||
self.swap_chain_id
|
||||
.expect("swap_chain_id must not be called for inline sessions")
|
||||
}
|
||||
|
||||
pub fn session(&self) -> &XRSession {
|
||||
|
@ -133,19 +141,22 @@ impl XRWebGLLayer {
|
|||
if let WebGLFramebufferId::Opaque(id) = self
|
||||
.framebuffer
|
||||
.as_ref()
|
||||
.expect("Must have framebuffer")
|
||||
.expect("swap_buffers must not be called for inline sessions")
|
||||
.id()
|
||||
{
|
||||
self.context.swap_buffers(Some(id));
|
||||
}
|
||||
}
|
||||
|
||||
fn size(&self) -> Size2D<i32> {
|
||||
if let Some(framebuffer) = self.framebuffer {
|
||||
pub fn size(&self) -> Size2D<u32, Viewport> {
|
||||
if let Some(framebuffer) = self.framebuffer.as_ref() {
|
||||
let size = framebuffer.size().unwrap_or((0, 0));
|
||||
Size2D::new(size.0, size.1)
|
||||
Size2D::new(
|
||||
size.0.try_into().unwrap_or(0),
|
||||
size.1.try_into().unwrap_or(0),
|
||||
)
|
||||
} else {
|
||||
self.context.Canvas().get_size()
|
||||
Size2D::from_untyped(self.context.Canvas().get_size())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,12 +194,12 @@ impl XRWebGLLayerMethods for XRWebGLLayer {
|
|||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth
|
||||
fn FramebufferWidth(&self) -> u32 {
|
||||
self.size().width.try_into().unwrap_or(0)
|
||||
self.size().width
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight
|
||||
fn FramebufferHeight(&self) -> u32 {
|
||||
self.size().height.try_into().unwrap_or(0)
|
||||
self.size().height
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue