diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 14 | ||||
-rw-r--r-- | components/script/dom/document.rs | 24 | ||||
-rw-r--r-- | components/script/dom/performanceresourcetiming.rs | 3 | ||||
-rw-r--r-- | components/script/dom/webgl2renderingcontext.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webgl_validations/tex_image_2d.rs | 4 | ||||
-rw-r--r-- | components/script/dom/webglframebuffer.rs | 143 | ||||
-rw-r--r-- | components/script/dom/webglprogram.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webglrenderbuffer.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 98 | ||||
-rw-r--r-- | components/script/dom/webgltexture.rs | 75 | ||||
-rw-r--r-- | components/script/dom/webgluniformlocation.rs | 10 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 31 | ||||
-rw-r--r-- | components/script/dom/xrwebgllayer.rs | 126 |
13 files changed, 282 insertions, 252 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 4b79bc7085b..7869d1499ac 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -47,11 +47,10 @@ use canvas_traits::canvas::{ use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; use canvas_traits::webgl::WebGLVertexArrayId; use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat}; -use canvas_traits::webgl::{GLFormats, GLLimits, WebGLQueryId, WebGLSamplerId}; -use canvas_traits::webgl::{ - WebGLBufferId, WebGLChan, WebGLContextId, WebGLContextShareMode, WebGLError, -}; +use canvas_traits::webgl::{GLLimits, WebGLQueryId, WebGLSamplerId}; +use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextId, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId}; +use canvas_traits::webgl::{WebGLOpaqueFramebufferId, WebGLTransparentFramebufferId}; use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender}; use canvas_traits::webgl::{WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion}; use content_security_policy::CspList; @@ -147,6 +146,7 @@ use time::{Duration, Timespec}; use uuid::Uuid; use webrender_api::{DocumentId, ImageKey, RenderApiSender}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; +use webxr_api::SwapChainId as WebXRSwapChainId; /// A trait to allow tracing (only) DOM objects. pub unsafe trait JSTraceable { @@ -451,7 +451,7 @@ unsafe_no_jsmanaged_fields!(StorageType); unsafe_no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle); unsafe_no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); unsafe_no_jsmanaged_fields!(RepetitionStyle); -unsafe_no_jsmanaged_fields!(WebGLError, GLFormats, GLLimits, GlType); +unsafe_no_jsmanaged_fields!(WebGLError, GLLimits, GlType); unsafe_no_jsmanaged_fields!(TimeProfilerChan); unsafe_no_jsmanaged_fields!(MemProfilerChan); unsafe_no_jsmanaged_fields!(PseudoElement); @@ -486,8 +486,9 @@ unsafe_no_jsmanaged_fields!(DocumentId); unsafe_no_jsmanaged_fields!(ImageKey); unsafe_no_jsmanaged_fields!(WebGLBufferId); unsafe_no_jsmanaged_fields!(WebGLChan); -unsafe_no_jsmanaged_fields!(WebGLContextShareMode); unsafe_no_jsmanaged_fields!(WebGLFramebufferId); +unsafe_no_jsmanaged_fields!(WebGLOpaqueFramebufferId); +unsafe_no_jsmanaged_fields!(WebGLTransparentFramebufferId); unsafe_no_jsmanaged_fields!(WebGLMsgSender); unsafe_no_jsmanaged_fields!(WebGLPipeline); unsafe_no_jsmanaged_fields!(WebGLProgramId); @@ -500,6 +501,7 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId); unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); +unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); unsafe_no_jsmanaged_fields!( diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index fd5994925c1..0efb0856098 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -98,6 +98,7 @@ use crate::dom::treewalker::TreeWalker; use crate::dom::uievent::UIEvent; use crate::dom::virtualmethods::vtable_for; use crate::dom::webglcontextevent::WebGLContextEvent; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::wheelevent::WheelEvent; use crate::dom::window::{ReflowReason, Window}; use crate::dom::windowproxy::WindowProxy; @@ -109,7 +110,7 @@ use crate::stylesheet_set::StylesheetSetRef; use crate::task::TaskBox; use crate::task_source::{TaskSource, TaskSourceName}; use crate::timers::OneshotTimerCallback; -use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg}; +use canvas_traits::webgl::{self, SwapChainId, WebGLContextId, WebGLMsg}; use content_security_policy::{self as csp, CspList}; use cookie::Cookie; use devtools_traits::ScriptToDevtoolsControlMsg; @@ -399,7 +400,7 @@ pub struct Document { /// hosting the media controls UI. media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>, /// List of all WebGL context IDs that need flushing. - dirty_webgl_contexts: DomRefCell<HashSet<WebGLContextId>>, + dirty_webgl_contexts: DomRefCell<HashMap<WebGLContextId, Dom<WebGLRenderingContext>>>, /// https://html.spec.whatwg.org/multipage/#concept-document-csp-list #[ignore_malloc_size_of = "Defined in rust-content-security-policy"] csp_list: DomRefCell<Option<CspList>>, @@ -2486,15 +2487,26 @@ impl Document { } } - pub fn add_dirty_canvas(&self, context_id: WebGLContextId) { - self.dirty_webgl_contexts.borrow_mut().insert(context_id); + pub fn add_dirty_canvas(&self, context: &WebGLRenderingContext) { + self.dirty_webgl_contexts + .borrow_mut() + .entry(context.context_id()) + .or_insert_with(|| Dom::from_ref(context)); } pub fn flush_dirty_canvases(&self) { - let dirty_context_ids: Vec<_> = self.dirty_webgl_contexts.borrow_mut().drain().collect(); + let dirty_context_ids: Vec<_> = self + .dirty_webgl_contexts + .borrow_mut() + .drain() + .filter(|(_, context)| context.onscreen()) + .map(|(id, _)| SwapChainId::Context(id)) + .collect(); + if dirty_context_ids.is_empty() { return; } + let (sender, receiver) = webgl::webgl_channel().unwrap(); self.window .webgl_chan() @@ -2797,7 +2809,7 @@ impl Document { shadow_roots: DomRefCell::new(HashSet::new()), shadow_roots_styles_changed: Cell::new(false), media_controls: DomRefCell::new(HashMap::new()), - dirty_webgl_contexts: DomRefCell::new(HashSet::new()), + dirty_webgl_contexts: DomRefCell::new(HashMap::new()), csp_list: DomRefCell::new(None), } } diff --git a/components/script/dom/performanceresourcetiming.rs b/components/script/dom/performanceresourcetiming.rs index 735d13a31f4..586515d4365 100644 --- a/components/script/dom/performanceresourcetiming.rs +++ b/components/script/dom/performanceresourcetiming.rs @@ -55,7 +55,6 @@ pub struct PerformanceResourceTiming { decoded_body_size: u64, //size in octets } -// TODO(#21255): duration // TODO(#21269): next_hop // TODO(#21264): worker_start // TODO(#21258): fetch_start @@ -115,7 +114,7 @@ impl PerformanceResourceTiming { DOMString::from(url.into_string()), DOMString::from("resource"), resource_timing.start_time as f64, - 0., + resource_timing.response_end as f64 - resource_timing.start_time as f64, ), initiator_type: initiator_type, next_hop: next_hop, diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 63cfd0bc530..4c7d9fb857a 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -1426,6 +1426,6 @@ impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingConte #[allow(unsafe_code)] unsafe fn canvas_data_source(&self) -> HTMLCanvasDataSource { let this = &*self.unsafe_get(); - HTMLCanvasDataSource::WebGL((*this.base.to_layout().unsafe_get()).layout_handle()) + (*this.base.to_layout().unsafe_get()).layout_handle() } } diff --git a/components/script/dom/webgl_validations/tex_image_2d.rs b/components/script/dom/webgl_validations/tex_image_2d.rs index 329ffd10349..fc5919132cf 100644 --- a/components/script/dom/webgl_validations/tex_image_2d.rs +++ b/components/script/dom/webgl_validations/tex_image_2d.rs @@ -613,7 +613,7 @@ impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> { compression, } = self.compression_validator.validate()?; - let tex_info = texture.image_info_for_target(&target, level); + let tex_info = texture.image_info_for_target(&target, level).unwrap(); // GL_INVALID_VALUE is generated if: // - xoffset or yoffset is less than 0 @@ -630,7 +630,7 @@ impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> { // GL_INVALID_OPERATION is generated if format does not match // internal_format. - if compression.format != tex_info.internal_format().unwrap() { + if compression.format != tex_info.internal_format() { context.webgl_error(InvalidOperation); return Err(TexImageValidationError::TextureFormatMismatch); } diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 3a31e99be33..df9e194962e 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -8,15 +8,20 @@ use crate::dom::bindings::codegen::Bindings::WebGLFramebufferBinding; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::webglobject::WebGLObject; use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webgltexture::WebGLTexture; +use crate::dom::xrsession::XRSession; use canvas_traits::webgl::{webgl_channel, WebGLError, WebGLResult}; -use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId}; +use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest}; +use canvas_traits::webgl::{WebGLFramebufferId, WebGLOpaqueFramebufferId}; use dom_struct::dom_struct; +use euclid::Size2D; use std::cell::Cell; +use webxr_api::SwapChainId as WebXRSwapChainId; +use webxr_api::Viewport; pub enum CompleteForRendering { Complete, @@ -92,6 +97,9 @@ pub struct WebGLFramebuffer { stencil: DomRefCell<Option<WebGLFramebufferAttachment>>, depthstencil: DomRefCell<Option<WebGLFramebufferAttachment>>, is_initialized: Cell<bool>, + // Framebuffers for XR keep a reference to the XR session. + // https://github.com/immersive-web/webxr/issues/856 + xr_session: MutNullableDom<XRSession>, } impl WebGLFramebuffer { @@ -108,16 +116,37 @@ impl WebGLFramebuffer { stencil: DomRefCell::new(None), depthstencil: DomRefCell::new(None), is_initialized: Cell::new(false), + xr_session: Default::default(), } } pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::CreateFramebuffer(sender)); - receiver - .recv() - .unwrap() - .map(|id| WebGLFramebuffer::new(context, id)) + let id = receiver.recv().unwrap()?; + let framebuffer = WebGLFramebuffer::new(context, WebGLFramebufferId::Transparent(id)); + Some(framebuffer) + } + + // TODO: depth, stencil and alpha + // https://github.com/servo/servo/issues/24498 + pub fn maybe_new_webxr( + session: &XRSession, + context: &WebGLRenderingContext, + size: Size2D<i32, Viewport>, + ) -> Option<(WebXRSwapChainId, DomRoot<Self>)> { + let (sender, receiver) = webgl_channel().unwrap(); + let _ = context + .webgl_sender() + .send_create_webxr_swap_chain(size.to_untyped(), sender); + let swap_chain_id = receiver.recv().unwrap()?; + let framebuffer_id = + WebGLFramebufferId::Opaque(WebGLOpaqueFramebufferId::WebXR(swap_chain_id)); + let framebuffer = WebGLFramebuffer::new(context, framebuffer_id); + framebuffer.size.set(Some((size.width, size.height))); + framebuffer.status.set(constants::FRAMEBUFFER_COMPLETE); + framebuffer.xr_session.set(Some(session)); + Some((swap_chain_id, framebuffer)) } pub fn new(context: &WebGLRenderingContext, id: WebGLFramebufferId) -> DomRoot<Self> { @@ -134,11 +163,25 @@ impl WebGLFramebuffer { self.id } + fn is_in_xr_session(&self) -> bool { + self.xr_session.get().is_some() + } + + pub fn validate_transparent(&self) -> WebGLResult<()> { + if self.is_in_xr_session() { + Err(WebGLError::InvalidOperation) + } else { + Ok(()) + } + } + pub fn bind(&self, target: u32) { - // Update the framebuffer status on binding. It may have - // changed if its attachments were resized or deleted while - // we've been unbound. - self.update_status(); + if !self.is_in_xr_session() { + // Update the framebuffer status on binding. It may have + // changed if its attachments were resized or deleted while + // we've been unbound. + self.update_status(); + } self.target.set(Some(target)); self.upcast::<WebGLObject>() @@ -221,12 +264,16 @@ impl WebGLFramebuffer { Some(WebGLFramebufferAttachment::Texture { texture: ref att_tex, level, - }) => { - let info = att_tex.image_info_at_face(0, level as u32); - ( - info.internal_format().map(|t| t.as_gl_constant()), + }) => match att_tex.image_info_at_face(0, level as u32) { + Some(info) => ( + Some(info.internal_format().as_gl_constant()), Some((info.width() as i32, info.height() as i32)), - ) + ), + None => { + self.status + .set(constants::FRAMEBUFFER_INCOMPLETE_ATTACHMENT); + return; + }, }, None => (None, None), }; @@ -267,7 +314,17 @@ impl WebGLFramebuffer { } pub fn check_status(&self) -> u32 { - return self.status.get(); + // For opaque framebuffers, check to see if the XR session is currently processing an rAF + // https://immersive-web.github.io/webxr/#opaque-framebuffer + if let Some(xr_session) = self.xr_session.get() { + if xr_session.is_outside_raf() { + constants::FRAMEBUFFER_UNSUPPORTED + } else { + constants::FRAMEBUFFER_COMPLETE + } + } else { + self.status.get() + } } pub fn check_status_for_rendering(&self) -> CompleteForRendering { @@ -276,6 +333,12 @@ impl WebGLFramebuffer { return CompleteForRendering::Incomplete; } + // XR framebuffers are complete inside an rAF + // https://github.com/immersive-web/webxr/issues/854 + if self.xr_session.get().is_some() { + return CompleteForRendering::Complete; + } + if self.color.borrow().is_none() { return CompleteForRendering::MissingColorAttachment; } @@ -309,6 +372,10 @@ impl WebGLFramebuffer { } pub fn renderbuffer(&self, attachment: u32, rb: Option<&WebGLRenderbuffer>) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let binding = self .attachment_binding(attachment) .ok_or(WebGLError::InvalidEnum)?; @@ -337,7 +404,7 @@ impl WebGLFramebuffer { )); if rb.is_none() { - self.detach_binding(binding, attachment); + self.detach_binding(binding, attachment)?; } self.update_status(); @@ -349,14 +416,19 @@ impl WebGLFramebuffer { &self, binding: &DomRefCell<Option<WebGLFramebufferAttachment>>, attachment: u32, - ) { + ) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + if let Some(att) = &*binding.borrow() { att.detach(); } *binding.borrow_mut() = None; if INTERESTING_ATTACHMENT_POINTS.contains(&attachment) { - self.reattach_depth_stencil(); + self.reattach_depth_stencil()?; } + Ok(()) } fn attachment_binding( @@ -372,7 +444,11 @@ impl WebGLFramebuffer { } } - fn reattach_depth_stencil(&self) { + fn reattach_depth_stencil(&self) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let reattach = |attachment: &WebGLFramebufferAttachment, attachment_point| { let context = self.upcast::<WebGLObject>().context(); match *attachment { @@ -411,6 +487,7 @@ impl WebGLFramebuffer { if let Some(ref depth_stencil) = *self.depthstencil.borrow() { reattach(depth_stencil, constants::DEPTH_STENCIL_ATTACHMENT); } + Ok(()) } pub fn attachment(&self, attachment: u32) -> Option<WebGLFramebufferAttachmentRoot> { @@ -428,6 +505,10 @@ impl WebGLFramebuffer { texture: Option<&WebGLTexture>, level: i32, ) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let binding = self .attachment_binding(attachment) .ok_or(WebGLError::InvalidEnum)?; @@ -498,7 +579,7 @@ impl WebGLFramebuffer { )); if texture.is_none() { - self.detach_binding(binding, attachment); + self.detach_binding(binding, attachment)?; } self.update_status(); @@ -563,7 +644,11 @@ impl WebGLFramebuffer { } } - pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) { + pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let mut depth_or_stencil_updated = false; self.with_matching_renderbuffers(rb, |att, name| { depth_or_stencil_updated |= INTERESTING_ATTACHMENT_POINTS.contains(&name); @@ -575,11 +660,16 @@ impl WebGLFramebuffer { }); if depth_or_stencil_updated { - self.reattach_depth_stencil(); + self.reattach_depth_stencil()?; } + Ok(()) } - pub fn detach_texture(&self, texture: &WebGLTexture) { + pub fn detach_texture(&self, texture: &WebGLTexture) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let mut depth_or_stencil_updated = false; self.with_matching_textures(texture, |att, name| { depth_or_stencil_updated |= INTERESTING_ATTACHMENT_POINTS.contains(&name); @@ -591,8 +681,9 @@ impl WebGLFramebuffer { }); if depth_or_stencil_updated { - self.reattach_depth_stencil(); + self.reattach_depth_stencil()?; } + Ok(()) } pub fn invalidate_renderbuffer(&self, rb: &WebGLRenderbuffer) { @@ -615,7 +706,7 @@ impl WebGLFramebuffer { impl Drop for WebGLFramebuffer { fn drop(&mut self) { - self.delete(true); + let _ = self.delete(true); } } diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index bf198e5382c..6863bc89e53 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -392,10 +392,12 @@ impl WebGLProgram { sender, )); let location = receiver.recv().unwrap(); + let context_id = self.upcast::<WebGLObject>().context().context_id(); Ok(Some(WebGLUniformLocation::new( self.global().as_window(), location, + context_id, self.id, self.link_generation.get(), size, diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs index 07afdbccb44..ca75f83c336 100644 --- a/components/script/dom/webglrenderbuffer.rs +++ b/components/script/dom/webglrenderbuffer.rs @@ -106,7 +106,7 @@ impl WebGLRenderbuffer { let currently_bound_framebuffer = self.upcast::<WebGLObject>().context().bound_framebuffer(); if let Some(fb) = currently_bound_framebuffer { - fb.detach_renderbuffer(self); + let _ = fb.detach_renderbuffer(self); } let context = self.upcast::<WebGLObject>().context(); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index f19664ad0ad..b5faecc7371 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -54,11 +54,11 @@ use crate::script_runtime::JSContext as SafeJSContext; use backtrace::Backtrace; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::{ - webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLFormats, GLLimits, - GlType, Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, - WebGLCommandBacktrace, WebGLContextId, WebGLContextShareMode, WebGLError, - WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult, - WebGLSLVersion, WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, + webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLLimits, GlType, + Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, + WebGLCommandBacktrace, WebGLContextId, WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, + WebGLMsgSender, WebGLOpaqueFramebufferId, WebGLProgramId, WebGLResult, WebGLSLVersion, + WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, }; use dom_struct::dom_struct; use embedder_traits::EventLoopWaker; @@ -81,6 +81,7 @@ use std::cell::Cell; use std::cmp; use std::ptr::{self, NonNull}; use std::rc::Rc; +use webxr_api::SwapChainId as WebXRSwapChainId; // From the GLES 2.0.25 spec, page 85: // @@ -130,10 +131,9 @@ pub struct WebGLRenderingContext { webgl_sender: WebGLMessageSender, #[ignore_malloc_size_of = "Defined in webrender"] webrender_image: webrender_api::ImageKey, - share_mode: WebGLContextShareMode, webgl_version: WebGLVersion, glsl_version: WebGLSLVersion, - #[ignore_malloc_size_of = "Defined in offscreen_gl_context"] + #[ignore_malloc_size_of = "Defined in surfman"] limits: GLLimits, canvas: Dom<HTMLCanvasElement>, #[ignore_malloc_size_of = "Defined in canvas_traits"] @@ -160,7 +160,6 @@ pub struct WebGLRenderingContext { current_vao: MutNullableDom<WebGLVertexArrayObjectOES>, textures: Textures, api_type: GlType, - framebuffer_format: GLFormats, } impl WebGLRenderingContext { @@ -195,7 +194,6 @@ impl WebGLRenderingContext { window.get_event_loop_waker(), ), webrender_image: ctx_data.image_key, - share_mode: ctx_data.share_mode, webgl_version, glsl_version: ctx_data.glsl_version, limits: ctx_data.limits, @@ -220,7 +218,6 @@ impl WebGLRenderingContext { current_vao: Default::default(), textures: Textures::new(max_combined_texture_image_units), api_type: ctx_data.api_type, - framebuffer_format: ctx_data.framebuffer_format, } }) } @@ -292,7 +289,7 @@ impl WebGLRenderingContext { self.send_command(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3)); // Bound texture must not change when the canvas is resized. - // Right now offscreen_gl_context generates a new FBO and the bound texture is changed + // Right now surfman generates a new FBO and the bound texture is changed // in order to create a new render to texture attachment. // Send a command to re-bind the TEXTURE_2D, if any. if let Some(texture) = self @@ -308,7 +305,7 @@ impl WebGLRenderingContext { } // Bound framebuffer must not change when the canvas is resized. - // Right now offscreen_gl_context generates a new FBO on resize. + // Right now surfman generates a new FBO on resize. // Send a command to re-bind the framebuffer, if any. if let Some(fbo) = self.bound_framebuffer.get() { let id = WebGLFramebufferBindingRequest::Explicit(fbo.id()); @@ -324,6 +321,10 @@ impl WebGLRenderingContext { self.webgl_sender.context_id() } + pub fn onscreen(&self) -> bool { + self.canvas.upcast::<Node>().is_connected() + } + #[inline] pub fn send_command(&self, command: WebGLCommand) { self.webgl_sender @@ -337,6 +338,10 @@ impl WebGLRenderingContext { .send(command, capture_webgl_backtrace(self)); } + pub fn swap_buffers(&self, id: Option<WebGLOpaqueFramebufferId>) { + let _ = self.webgl_sender.send_swap_buffers(id); + } + #[inline] pub fn send_vr_command(&self, command: WebVRCommand) { self.webgl_sender.send_vr(command).unwrap(); @@ -438,13 +443,12 @@ impl WebGLRenderingContext { } let target = TexImageTarget::Texture2D; - let info = texture.image_info_for_target(&target, 0); - if info.is_initialized() { + if let Some(info) = texture.image_info_for_target(&target, 0) { self.validate_filterable_texture( &texture, target, 0, - info.internal_format().unwrap_or(TexFormat::RGBA), + info.internal_format(), Size2D::new(info.width(), info.height()), info.data_type().unwrap_or(TexDataType::UnsignedByte), ); @@ -462,7 +466,7 @@ impl WebGLRenderingContext { .dirty(NodeDamage::OtherNodeDamage); let document = document_from_node(&*self.canvas); - document.add_dirty_canvas(self.context_id()); + document.add_dirty_canvas(self); } fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) { @@ -746,7 +750,10 @@ impl WebGLRenderingContext { pixels: TexPixels, ) { // We have already validated level - let image_info = texture.image_info_for_target(&target, level); + let image_info = match texture.image_info_for_target(&target, level) { + Some(info) => info, + None => return self.webgl_error(InvalidOperation), + }; // GL_INVALID_VALUE is generated if: // - xoffset or yoffset is less than 0 @@ -761,9 +768,7 @@ impl WebGLRenderingContext { } // NB: format and internal_format must match. - if format != image_info.internal_format().unwrap() || - data_type != image_info.data_type().unwrap() - { + if format != image_info.internal_format() || data_type != image_info.data_type().unwrap() { return self.webgl_error(InvalidOperation); } @@ -810,8 +815,9 @@ impl WebGLRenderingContext { receiver.recv().unwrap() } - pub fn layout_handle(&self) -> webrender_api::ImageKey { - self.webrender_image + pub(crate) fn layout_handle(&self) -> HTMLCanvasDataSource { + let image_key = self.webrender_image; + HTMLCanvasDataSource::WebGL(image_key) } // https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/ @@ -1086,17 +1092,9 @@ impl WebGLRenderingContext { self.bound_framebuffer.get() } - pub fn bound_renderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> { - self.bound_renderbuffer.get() - } - pub fn extension_manager(&self) -> &WebGLExtensions { &self.extension_manager } - - pub fn formats(&self) -> &GLFormats { - &self.framebuffer_format - } } #[cfg(not(feature = "webgl_backtrace"))] @@ -1921,9 +1919,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => { TexFormat::from_gl_constant(rb.internal_format()) }, - Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => { - texture.image_info_for_target(&target, 0).internal_format() - }, + Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => texture + .image_info_for_target(&target, 0) + .map(|info| info.internal_format()), None => None, }, None => { @@ -2022,7 +2020,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(_) => return, }; - let image_info = texture.image_info_for_target(&target, level); + let image_info = match texture.image_info_for_target(&target, level) { + Some(info) => info, + None => return self.webgl_error(InvalidOperation), + }; // GL_INVALID_VALUE is generated if: // - xoffset or yoffset is less than 0 @@ -2225,6 +2226,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6 fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) { if let Some(framebuffer) = framebuffer { + // https://immersive-web.github.io/webxr/#opaque-framebuffer + // Can opaque framebuffers be deleted? + // https://github.com/immersive-web/webxr/issues/855 + handle_potential_webgl_error!(self, framebuffer.validate_transparent(), return); handle_potential_webgl_error!(self, self.validate_ownership(framebuffer), return); handle_object_deletion!( self, @@ -2384,7 +2389,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { pname: u32, ) -> JSVal { // Check if currently bound framebuffer is non-zero as per spec. - if self.bound_framebuffer.get().is_none() { + if let Some(fb) = self.bound_framebuffer.get() { + // Opaque framebuffers cannot have their attachments inspected + // https://immersive-web.github.io/webxr/#opaque-framebuffer + handle_potential_webgl_error!(self, fb.validate_transparent(), return NullValue()); + } else { self.webgl_error(InvalidOperation); return NullValue(); } @@ -2487,6 +2496,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 fn GetRenderbufferParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal { + // We do not check to see if the renderbuffer came from an opaque framebuffer + // https://github.com/immersive-web/webxr/issues/862 let target_matches = target == constants::RENDERBUFFER; let pname_matches = match pname { @@ -3477,6 +3488,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if program.is_deleted() || !program.is_linked() || + self.context_id() != location.context_id() || program.id() != location.program_id() || program.link_generation() != location.link_generation() { @@ -4153,7 +4165,7 @@ pub trait LayoutCanvasWebGLRenderingContextHelpers { impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGLRenderingContext> { #[allow(unsafe_code)] unsafe fn canvas_data_source(&self) -> HTMLCanvasDataSource { - HTMLCanvasDataSource::WebGL((*self.unsafe_get()).layout_handle()) + (*self.unsafe_get()).layout_handle() } } @@ -4347,7 +4359,7 @@ impl TexPixels { } #[derive(JSTraceable)] -pub(crate) struct WebGLCommandSender { +pub struct WebGLCommandSender { sender: WebGLChan, waker: Option<Box<dyn EventLoopWaker>>, } @@ -4410,6 +4422,18 @@ impl WebGLMessageSender { self.wake_after_send(|| self.sender.send_vr(command)) } + pub fn send_swap_buffers(&self, id: Option<WebGLOpaqueFramebufferId>) -> WebGLSendResult { + self.wake_after_send(|| self.sender.send_swap_buffers(id)) + } + + pub fn send_create_webxr_swap_chain( + &self, + size: Size2D<i32>, + sender: WebGLSender<Option<WebXRSwapChainId>>, + ) -> WebGLSendResult { + self.wake_after_send(|| self.sender.send_create_webxr_swap_chain(size, sender)) + } + pub fn send_resize( &self, size: Size2D<u32>, diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index e4a18b519a3..f7d52c8708a 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -40,7 +40,7 @@ pub struct WebGLTexture { is_deleted: Cell<bool>, /// Stores information about mipmap levels and cubemap faces. #[ignore_malloc_size_of = "Arrays are cumbersome"] - image_info_array: DomRefCell<[ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>, + image_info_array: DomRefCell<[Option<ImageInfo>; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>, /// Face count can only be 1 or 6 face_count: Cell<u8>, base_mipmap_level: u32, @@ -64,7 +64,7 @@ impl WebGLTexture { base_mipmap_level: 0, min_filter: Cell::new(constants::NEAREST_MIPMAP_LINEAR), mag_filter: Cell::new(constants::LINEAR), - image_info_array: DomRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]), + image_info_array: DomRefCell::new([None; MAX_LEVEL_COUNT * MAX_FACE_COUNT]), attached_to_dom: Cell::new(false), attached_framebuffer: Default::default(), } @@ -135,8 +135,7 @@ impl WebGLTexture { width: width, height: height, depth: depth, - internal_format: Some(internal_format), - is_initialized: true, + internal_format: internal_format, data_type: data_type, }; @@ -159,10 +158,7 @@ impl WebGLTexture { }, }; - let base_image_info = self.base_image_info(); - if !base_image_info.is_initialized() { - return Err(WebGLError::InvalidOperation); - } + let base_image_info = self.base_image_info().ok_or(WebGLError::InvalidOperation)?; let is_cubic = target == constants::TEXTURE_CUBE_MAP; if is_cubic && !self.is_cube_complete() { @@ -210,7 +206,7 @@ impl WebGLTexture { let currently_bound_framebuffer = self.upcast::<WebGLObject>().context().bound_framebuffer(); if let Some(fb) = currently_bound_framebuffer { - fb.detach_texture(self); + let _ = fb.detach_texture(self); } let cmd = WebGLCommand::DeleteTexture(self.id); @@ -308,10 +304,9 @@ impl WebGLTexture { } pub fn populate_mip_chain(&self, first_level: u32, last_level: u32) -> WebGLResult<()> { - let base_image_info = self.image_info_at_face(0, first_level); - if !base_image_info.is_initialized() { - return Err(WebGLError::InvalidOperation); - } + let base_image_info = self + .image_info_at_face(0, first_level) + .ok_or(WebGLError::InvalidOperation)?; let mut ref_width = base_image_info.width; let mut ref_height = base_image_info.height; @@ -333,7 +328,6 @@ impl WebGLTexture { height: ref_height, depth: 0, internal_format: base_image_info.internal_format, - is_initialized: base_image_info.is_initialized(), data_type: base_image_info.data_type, }; @@ -345,19 +339,19 @@ impl WebGLTexture { fn is_cube_complete(&self) -> bool { debug_assert_eq!(self.face_count.get(), 6); - let image_info = self.base_image_info(); - if !image_info.is_defined() { - return false; - } + let image_info = match self.base_image_info() { + Some(info) => info, + None => return false, + }; let ref_width = image_info.width; let ref_format = image_info.internal_format; for face in 0..self.face_count.get() { - let current_image_info = self.image_info_at_face(face, self.base_mipmap_level); - if !current_image_info.is_defined() { - return false; - } + let current_image_info = match self.image_info_at_face(face, self.base_mipmap_level) { + Some(info) => info, + None => return false, + }; // Compares height with width to enforce square dimensions if current_image_info.internal_format != ref_format || @@ -383,12 +377,12 @@ impl WebGLTexture { } } - pub fn image_info_for_target(&self, target: &TexImageTarget, level: u32) -> ImageInfo { + pub fn image_info_for_target(&self, target: &TexImageTarget, level: u32) -> Option<ImageInfo> { let face_index = self.face_index_for_target(&target); self.image_info_at_face(face_index, level) } - pub fn image_info_at_face(&self, face: u8, level: u32) -> ImageInfo { + pub fn image_info_at_face(&self, face: u8, level: u32) -> Option<ImageInfo> { let pos = (level * self.face_count.get() as u32) + face as u32; self.image_info_array.borrow()[pos as usize] } @@ -402,10 +396,10 @@ impl WebGLTexture { fn set_image_infos_at_level_and_face(&self, level: u32, face: u8, image_info: ImageInfo) { debug_assert!(face < self.face_count.get()); let pos = (level * self.face_count.get() as u32) + face as u32; - self.image_info_array.borrow_mut()[pos as usize] = image_info; + self.image_info_array.borrow_mut()[pos as usize] = Some(image_info); } - fn base_image_info(&self) -> ImageInfo { + fn base_image_info(&self) -> Option<ImageInfo> { assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT); self.image_info_at_face(0, self.base_mipmap_level) @@ -435,23 +429,11 @@ pub struct ImageInfo { width: u32, height: u32, depth: u32, - internal_format: Option<TexFormat>, - is_initialized: bool, + internal_format: TexFormat, data_type: Option<TexDataType>, } impl ImageInfo { - fn new() -> ImageInfo { - ImageInfo { - width: 0, - height: 0, - depth: 0, - internal_format: None, - is_initialized: false, - data_type: None, - } - } - pub fn width(&self) -> u32 { self.width } @@ -460,7 +442,7 @@ impl ImageInfo { self.height } - pub fn internal_format(&self) -> Option<TexFormat> { + pub fn internal_format(&self) -> TexFormat { self.internal_format } @@ -474,14 +456,6 @@ impl ImageInfo { self.depth.is_power_of_two() } - pub fn is_initialized(&self) -> bool { - self.is_initialized - } - - fn is_defined(&self) -> bool { - self.internal_format.is_some() - } - fn get_max_mimap_levels(&self) -> u32 { let largest = cmp::max(cmp::max(self.width, self.height), self.depth); if largest == 0 { @@ -492,10 +466,7 @@ impl ImageInfo { } fn is_compressed_format(&self) -> bool { - match self.internal_format { - Some(format) => format.is_compressed(), - None => false, - } + self.internal_format.is_compressed() } } diff --git a/components/script/dom/webgluniformlocation.rs b/components/script/dom/webgluniformlocation.rs index bf142480dc7..5bdc661f17a 100644 --- a/components/script/dom/webgluniformlocation.rs +++ b/components/script/dom/webgluniformlocation.rs @@ -7,6 +7,7 @@ use crate::dom::bindings::codegen::Bindings::WebGLUniformLocationBinding; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::window::Window; +use canvas_traits::webgl::WebGLContextId; use canvas_traits::webgl::WebGLProgramId; use dom_struct::dom_struct; @@ -14,6 +15,7 @@ use dom_struct::dom_struct; pub struct WebGLUniformLocation { reflector_: Reflector, id: i32, + context_id: WebGLContextId, program_id: WebGLProgramId, link_generation: u64, size: Option<i32>, @@ -23,6 +25,7 @@ pub struct WebGLUniformLocation { impl WebGLUniformLocation { fn new_inherited( id: i32, + context_id: WebGLContextId, program_id: WebGLProgramId, link_generation: u64, size: Option<i32>, @@ -31,6 +34,7 @@ impl WebGLUniformLocation { Self { reflector_: Reflector::new(), id, + context_id, program_id, link_generation, size, @@ -41,6 +45,7 @@ impl WebGLUniformLocation { pub fn new( window: &Window, id: i32, + context_id: WebGLContextId, program_id: WebGLProgramId, link_generation: u64, size: Option<i32>, @@ -49,6 +54,7 @@ impl WebGLUniformLocation { reflect_dom_object( Box::new(Self::new_inherited( id, + context_id, program_id, link_generation, size, @@ -67,6 +73,10 @@ impl WebGLUniformLocation { self.program_id } + pub fn context_id(&self) -> WebGLContextId { + self.context_id + } + pub fn link_generation(&self) -> u64 { self.link_generation } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 41f8392acfb..6fbdc592b0e 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -6,7 +6,6 @@ use crate::compartments::InCompartment; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods; -use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; @@ -30,7 +29,6 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::node::Node; use crate::dom::node::NodeDamage; use crate::dom::promise::Promise; -use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot; use crate::dom::xrframe::XRFrame; use crate::dom::xrinputsourcearray::XRInputSourceArray; use crate::dom::xrinputsourceevent::XRInputSourceEvent; @@ -41,7 +39,6 @@ use crate::dom::xrspace::XRSpace; use crate::dom::xrwebgllayer::XRWebGLLayer; use crate::task_source::TaskSource; use dom_struct::dom_struct; -use euclid::default::Size2D; use euclid::RigidTransform3D; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; @@ -77,6 +74,9 @@ pub struct XRSession { end_promises: DomRefCell<Vec<Rc<Promise>>>, /// https://immersive-web.github.io/webxr/#ended ended: Cell<bool>, + /// Opaque framebuffers need to know the session is "outside of a requestAnimationFrame" + /// https://immersive-web.github.io/webxr/#opaque-framebuffer + outside_raf: Cell<bool>, } impl XRSession { @@ -102,6 +102,7 @@ impl XRSession { input_sources: Dom::from_ref(input_sources), end_promises: DomRefCell::new(vec![]), ended: Cell::new(false), + outside_raf: Cell::new(true), } } @@ -169,6 +170,10 @@ impl XRSession { self.session.borrow_mut().request_animation_frame(sender); } + pub fn is_outside_raf(&self) -> bool { + self.outside_raf.get() + } + fn attach_event_handler(&self) { let this = Trusted::new(self); let global = self.global(); @@ -276,6 +281,8 @@ impl XRSession { /// https://immersive-web.github.io/webxr/#xr-animation-frame fn raf_callback(&self, (time, mut frame): (f64, Frame)) { + debug!("WebXR RAF callback"); + // Step 1 if let Some(pending) = self.pending_render_state.take() { // https://immersive-web.github.io/webxr/#apply-the-pending-render-state @@ -285,19 +292,8 @@ impl XRSession { // Step 6-7: XXXManishearth handle inlineVerticalFieldOfView // XXXManishearth handle inline sessions and composition disabled flag - if let Some(layer) = pending.GetBaseLayer() { - let attachment = layer.framebuffer().attachment(constants::COLOR_ATTACHMENT0); - if let Some(WebGLFramebufferAttachmentRoot::Texture(texture)) = attachment { - let context = layer.Context().context_id().0; - let texture_id = texture.id().get(); - if let Some((width, height)) = layer.framebuffer().size() { - let size = Size2D::new(width, height); - self.session - .borrow_mut() - .set_texture(context, texture_id, size); - } - } - } + let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id()); + self.session.borrow_mut().set_swap_chain(swap_chain_id); } for event in frame.events.drain(..) { @@ -321,13 +317,16 @@ impl XRSession { frame.set_animation_frame(true); // Step 8 + self.outside_raf.set(false); for (_, callback) in callbacks.drain(..) { if let Some(callback) = callback { let _ = callback.Call__(Finite::wrap(time), &frame, ExceptionHandling::Report); } } + self.outside_raf.set(true); frame.set_active(false); + base_layer.swap_buffers(); self.session.borrow_mut().render_animation_frame(); self.request_new_xr_frame(); diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index f637f4ee96e..44bc10868b6 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -2,27 +2,26 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; 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, Reflector, DomObject}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; 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::xrsession::XRSession; use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; +use canvas_traits::webgl::WebGLFramebufferId; use dom_struct::dom_struct; -use js::rust::CustomAutoRooter; use std::convert::TryInto; +use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::Views; #[dom_struct] @@ -32,6 +31,8 @@ pub struct XRWebGLLayer { depth: bool, stencil: bool, alpha: bool, + #[ignore_malloc_size_of = "ids don't malloc"] + swap_chain_id: WebXRSwapChainId, context: Dom<WebGLRenderingContext>, session: Dom<XRSession>, framebuffer: Dom<WebGLFramebuffer>, @@ -39,6 +40,7 @@ pub struct XRWebGLLayer { impl XRWebGLLayer { pub fn new_inherited( + swap_chain_id: WebXRSwapChainId, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, @@ -50,6 +52,7 @@ impl XRWebGLLayer { depth: init.depth, stencil: init.stencil, alpha: init.alpha, + swap_chain_id, context: Dom::from_ref(context), session: Dom::from_ref(session), framebuffer: Dom::from_ref(framebuffer), @@ -58,6 +61,7 @@ impl XRWebGLLayer { pub fn new( global: &GlobalScope, + swap_chain_id: WebXRSwapChainId, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, @@ -65,6 +69,7 @@ impl XRWebGLLayer { ) -> DomRoot<XRWebGLLayer> { reflect_dom_object( Box::new(XRWebGLLayer::new_inherited( + swap_chain_id, session, context, init, @@ -89,108 +94,16 @@ impl XRWebGLLayer { // XXXManishearth step 3: throw error if context is lost // XXXManishearth step 4: check XR compat flag for immersive sessions - let cx = global.get_cx(); - let old_fbo = context.bound_framebuffer(); - let old_rbo = context.bound_renderbuffer(); - let old_texture = context - .textures() - .active_texture_for_image_target(TexImageTarget::Texture2D); - - // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with - // context and layerInit’s depth, stencil, and alpha values." - let framebuffer = context.CreateFramebuffer().ok_or(Error::Operation)?; + // 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)?; // 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." - // Create a new texture with size given by the session's recommended resolution - let texture = context.CreateTexture().ok_or(Error::Operation)?; - let render_buffer = context.CreateRenderbuffer().ok_or(Error::Operation)?; - let resolution = session.with_session(|s| s.recommended_framebuffer_resolution()); - let mut pixels = CustomAutoRooter::new(None); - let mut clear_bits = constants::COLOR_BUFFER_BIT; - - let formats = context.formats(); - - context.BindTexture(constants::TEXTURE_2D, Some(&texture)); - let sc = context.TexImage2D( - constants::TEXTURE_2D, - 0, - formats.texture_format, - resolution.width, - resolution.height, - 0, - formats.texture_format, - formats.texture_type, - 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, - ); - - // Create backing store and bind a renderbuffer if requested - if init.depth || init.stencil { - let (internal_format, attachment) = if init.depth && init.stencil { - clear_bits |= constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT; - ( - constants::DEPTH_STENCIL, - constants::DEPTH_STENCIL_ATTACHMENT, - ) - } else if init.depth { - clear_bits |= constants::DEPTH_BUFFER_BIT; - (constants::DEPTH_COMPONENT16, constants::DEPTH_ATTACHMENT) - } else { - clear_bits |= constants::STENCIL_BUFFER_BIT; - (constants::STENCIL_INDEX8, constants::STENCIL_ATTACHMENT) - }; - context.BindRenderbuffer(constants::RENDERBUFFER, Some(&render_buffer)); - context.RenderbufferStorage( - constants::RENDERBUFFER, - internal_format, - resolution.width, - resolution.height, - ); - context.FramebufferRenderbuffer( - constants::FRAMEBUFFER, - attachment, - constants::RENDERBUFFER, - Some(&render_buffer), - ); - } - - context.initialize_framebuffer(clear_bits); - - // Restore the WebGL state while complaining about global mutable state - let fb_status = context.CheckFramebufferStatus(constants::FRAMEBUFFER); - let gl_status = context.GetError(); - context.BindTexture(constants::TEXTURE_2D, old_texture.as_ref().map(|t| &**t)); - context.BindFramebuffer(constants::FRAMEBUFFER, old_fbo.as_ref().map(|f| &**f)); - context.BindRenderbuffer(constants::RENDERBUFFER, old_rbo.as_ref().map(|f| &**f)); - // Step 9.4: "If layer’s resources were unable to be created for any reason, // throw an OperationError and abort these steps." - if let Err(err) = sc { - error!("TexImage2D error {:?} while creating XR context", err); - return Err(Error::Operation); - } - if fb_status != constants::FRAMEBUFFER_COMPLETE { - error!( - "Framebuffer error {:x} while creating XR context", - fb_status - ); - return Err(Error::Operation); - } - if gl_status != constants::NO_ERROR { - error!("GL error {:x} while creating XR context", gl_status); - return Err(Error::Operation); - } // Ensure that we finish setting up this layer before continuing. context.Finish(); @@ -198,6 +111,7 @@ impl XRWebGLLayer { // Step 10. "Return layer." Ok(XRWebGLLayer::new( &global.global(), + swap_chain_id, session, context, init, @@ -205,12 +119,18 @@ impl XRWebGLLayer { )) } + pub fn swap_chain_id(&self) -> WebXRSwapChainId { + self.swap_chain_id + } + pub fn session(&self) -> &XRSession { &self.session } - pub fn framebuffer(&self) -> &WebGLFramebuffer { - &self.framebuffer + pub fn swap_buffers(&self) { + if let WebGLFramebufferId::Opaque(id) = self.framebuffer.id() { + self.context.swap_buffers(Some(id)); + } } } |