diff options
Diffstat (limited to 'components/script/dom/xrwebgllayer.rs')
-rw-r--r-- | components/script/dom/xrwebgllayer.rs | 126 |
1 files changed, 109 insertions, 17 deletions
diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 16653383a0b..a2a7c93f37c 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -6,10 +6,15 @@ use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethod use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextBinding::WebGLRenderingContextMethods; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; +use crate::dom::bindings::error::Error; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; +use crate::dom::webgl_validations::types::TexImageTarget; +use crate::dom::webglframebuffer::WebGLFramebuffer; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::window::Window; use crate::dom::xrlayer::XRLayer; @@ -17,6 +22,9 @@ use crate::dom::xrsession::XRSession; use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; use dom_struct::dom_struct; +use js::rust::CustomAutoRooter; +use std::convert::TryInto; +use webxr_api::Views; #[dom_struct] pub struct XRWebGLLayer { @@ -27,6 +35,7 @@ pub struct XRWebGLLayer { alpha: bool, context: Dom<WebGLRenderingContext>, session: Dom<XRSession>, + framebuffer: Dom<WebGLFramebuffer>, } impl XRWebGLLayer { @@ -34,6 +43,7 @@ impl XRWebGLLayer { session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, + framebuffer: &WebGLFramebuffer, ) -> XRWebGLLayer { XRWebGLLayer { xrlayer: XRLayer::new_inherited(), @@ -43,6 +53,7 @@ impl XRWebGLLayer { alpha: init.alpha, context: Dom::from_ref(context), session: Dom::from_ref(session), + framebuffer: Dom::from_ref(framebuffer), } } @@ -51,21 +62,82 @@ impl XRWebGLLayer { session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, + framebuffer: &WebGLFramebuffer, ) -> DomRoot<XRWebGLLayer> { reflect_dom_object( - Box::new(XRWebGLLayer::new_inherited(session, context, init)), + Box::new(XRWebGLLayer::new_inherited( + session, + context, + init, + framebuffer, + )), global, XRWebGLLayerBinding::Wrap, ) } + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-xrwebgllayer pub fn Constructor( global: &Window, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, ) -> Fallible<DomRoot<Self>> { - Ok(XRWebGLLayer::new(&global.global(), session, context, init)) + let cx = global.get_cx(); + let old_fbo = context.bound_framebuffer(); + let old_texture = context + .textures() + .active_texture_for_image_target(TexImageTarget::Texture2D); + + // Step 8.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." + let framebuffer = context.CreateFramebuffer().ok_or(Error::Operation)?; + + // Step 8.3. "Allocate and initialize resources compatible with session’s XR device, + // including GPU accessible memory buffers, as required to support the compositing of layer." + + // Create a new texture with size given by the session's recommended resolution + let texture = context.CreateTexture().ok_or(Error::Operation)?; + let resolution = session.with_session(|s| s.recommended_framebuffer_resolution()); + let mut pixels = CustomAutoRooter::new(None); + context.BindTexture(constants::TEXTURE_2D, Some(&texture)); + let sc = context.TexImage2D( + constants::TEXTURE_2D, + 0, + constants::RGBA, + resolution.width, + resolution.height, + 0, + constants::RGBA, + constants::UNSIGNED_BYTE, + pixels.root(cx), + ); + + // Bind the new texture to the framebuffer + context.BindFramebuffer(constants::FRAMEBUFFER, Some(&framebuffer)); + context.FramebufferTexture2D( + constants::FRAMEBUFFER, + constants::COLOR_ATTACHMENT0, + constants::TEXTURE_2D, + Some(&texture), + 0, + ); + + // Restore the WebGL state while complaining about global mutable state + context.BindTexture(constants::TEXTURE_2D, old_texture.as_ref().map(|t| &**t)); + context.BindFramebuffer(constants::FRAMEBUFFER, old_fbo.as_ref().map(|f| &**f)); + + // Step 8.4: "If layer’s resources were unable to be created for any reason, + // throw an OperationError and abort these steps." + sc.or(Err(Error::Operation))?; + + // Step 9. "Return layer." + Ok(XRWebGLLayer::new( + &global.global(), + session, + context, + init, + &framebuffer, + )) } } @@ -95,28 +167,48 @@ impl XRWebGLLayerMethods for XRWebGLLayer { DomRoot::from_ref(&self.context) } + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebuffer + fn Framebuffer(&self) -> DomRoot<WebGLFramebuffer> { + DomRoot::from_ref(&self.framebuffer) + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth + fn FramebufferWidth(&self) -> u32 { + self.framebuffer + .size() + .unwrap_or((0, 0)) + .0 + .try_into() + .unwrap_or(0) + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight + fn FramebufferHeight(&self) -> u32 { + self.framebuffer + .size() + .unwrap_or((0, 0)) + .1 + .try_into() + .unwrap_or(0) + } + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport fn GetViewport(&self, view: &XRView) -> Option<DomRoot<XRViewport>> { if self.session != view.session() { return None; } - let size = self.context.size(); + let views = self.session.with_session(|s| s.views().clone()); - let x = if view.Eye() == XREye::Left { - 0 - } else { - size.width / 2 + let viewport = match (view.Eye(), views) { + (XREye::None, Views::Mono(view)) => view.viewport, + (XREye::Left, Views::Stereo(view, _)) => view.viewport, + (XREye::Right, Views::Stereo(_, view)) => view.viewport, + // The spec doesn't really say what to do in this case + // https://github.com/immersive-web/webxr/issues/769 + _ => return None, }; - // XXXManishearth this assumes the WebVR default of canvases being cut in half - // which need not be generally true for all devices, and will not work in - // inline VR mode - Some(XRViewport::new( - &self.global(), - x, - 0, - size.width / 2, - size.height, - )) + + Some(XRViewport::new(&self.global(), viewport)) } } |