mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Support for webxr layer management
This commit is contained in:
parent
af110ac21f
commit
349619ed2d
34 changed files with 949 additions and 642 deletions
|
@ -2,6 +2,8 @@
|
|||
* 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::inheritance::Castable;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextBinding::WebGL2RenderingContextMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit;
|
||||
|
@ -13,17 +15,24 @@ 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::webglframebuffer::WebGLFramebuffer;
|
||||
use crate::dom::webglobject::WebGLObject;
|
||||
use crate::dom::webgltexture::WebGLTexture;
|
||||
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl2renderingcontext::WebGL2RenderingContext;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::xrframe::XRFrame;
|
||||
use crate::dom::xrsession::XRSession;
|
||||
use crate::dom::xrview::XRView;
|
||||
use crate::dom::xrviewport::XRViewport;
|
||||
use canvas_traits::webgl::WebGLFramebufferId;
|
||||
use canvas_traits::webgl::WebGLContextId;
|
||||
use canvas_traits::webgl::WebGLCommand;
|
||||
use canvas_traits::webgl::WebGLTextureId;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::{Rect, Size2D};
|
||||
use std::convert::TryInto;
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
use webxr_api::ContextId as WebXRContextId;
|
||||
use webxr_api::LayerId;
|
||||
use webxr_api::LayerInit;
|
||||
use webxr_api::Viewport;
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
|
@ -33,6 +42,28 @@ pub enum RenderingContext {
|
|||
WebGL2(Dom<WebGL2RenderingContext>),
|
||||
}
|
||||
|
||||
impl RenderingContext {
|
||||
fn context_id(&self) -> WebGLContextId {
|
||||
match self {
|
||||
RenderingContext::WebGL1(ref ctx) => ctx.context_id(),
|
||||
RenderingContext::WebGL2(ref ctx) => ctx.base_context().context_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a XRWebGLLayerInit> for LayerInit {
|
||||
fn from(init: &'a XRWebGLLayerInit) -> LayerInit {
|
||||
LayerInit::WebGLLayer {
|
||||
alpha: init.alpha,
|
||||
antialias: init.antialias,
|
||||
depth: init.depth,
|
||||
stencil: init.stencil,
|
||||
framebuffer_scale_factor: *init.framebufferScaleFactor as f32,
|
||||
ignore_depth_values: init.ignoreDepthValues,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRWebGLLayer {
|
||||
reflector_: Reflector,
|
||||
|
@ -40,21 +71,22 @@ pub struct XRWebGLLayer {
|
|||
depth: bool,
|
||||
stencil: bool,
|
||||
alpha: bool,
|
||||
#[ignore_malloc_size_of = "ids don't malloc"]
|
||||
swap_chain_id: Option<WebXRSwapChainId>,
|
||||
context: RenderingContext,
|
||||
session: Dom<XRSession>,
|
||||
/// If none, this is an inline session (the composition disabled flag is true)
|
||||
framebuffer: Option<Dom<WebGLFramebuffer>>,
|
||||
/// If none, this is an inline session (the composition disabled flag is true)
|
||||
#[ignore_malloc_size_of = "Layer ids don't heap-allocate"]
|
||||
layer_id: Option<LayerId>,
|
||||
}
|
||||
|
||||
impl XRWebGLLayer {
|
||||
pub fn new_inherited(
|
||||
swap_chain_id: Option<WebXRSwapChainId>,
|
||||
session: &XRSession,
|
||||
context: XRWebGLRenderingContext,
|
||||
init: &XRWebGLLayerInit,
|
||||
framebuffer: Option<&WebGLFramebuffer>,
|
||||
layer_id: Option<LayerId>,
|
||||
) -> XRWebGLLayer {
|
||||
XRWebGLLayer {
|
||||
reflector_: Reflector::new(),
|
||||
|
@ -62,7 +94,7 @@ impl XRWebGLLayer {
|
|||
depth: init.depth,
|
||||
stencil: init.stencil,
|
||||
alpha: init.alpha,
|
||||
swap_chain_id,
|
||||
layer_id,
|
||||
context: match context {
|
||||
XRWebGLRenderingContext::WebGLRenderingContext(ctx) => {
|
||||
RenderingContext::WebGL1(Dom::from_ref(&*ctx))
|
||||
|
@ -78,19 +110,19 @@ impl XRWebGLLayer {
|
|||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
swap_chain_id: Option<WebXRSwapChainId>,
|
||||
session: &XRSession,
|
||||
context: XRWebGLRenderingContext,
|
||||
init: &XRWebGLLayerInit,
|
||||
framebuffer: Option<&WebGLFramebuffer>,
|
||||
layer_id: Option<LayerId>,
|
||||
) -> DomRoot<XRWebGLLayer> {
|
||||
reflect_dom_object(
|
||||
Box::new(XRWebGLLayer::new_inherited(
|
||||
swap_chain_id,
|
||||
session,
|
||||
context,
|
||||
init,
|
||||
framebuffer,
|
||||
layer_id,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
|
@ -104,7 +136,6 @@ impl XRWebGLLayer {
|
|||
context: XRWebGLRenderingContext,
|
||||
init: &XRWebGLLayerInit,
|
||||
) -> Fallible<DomRoot<Self>> {
|
||||
let framebuffer;
|
||||
// Step 2
|
||||
if session.is_ended() {
|
||||
return Err(Error::InvalidState);
|
||||
|
@ -112,27 +143,29 @@ impl XRWebGLLayer {
|
|||
// XXXManishearth step 3: throw error if context is lost
|
||||
// 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 (swap_chain_id, framebuffer) = if session.is_immersive() {
|
||||
let size = session.with_session(|session| {
|
||||
session
|
||||
.recommended_framebuffer_resolution()
|
||||
.expect("immersive session must have viewports")
|
||||
});
|
||||
let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, &context, size)
|
||||
let (framebuffer, layer_id) = if session.is_immersive() {
|
||||
// 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())
|
||||
.ok_or(Error::Operation)?;
|
||||
framebuffer = fb;
|
||||
(Some(swap_chain_id), Some(&*framebuffer))
|
||||
let 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."
|
||||
let context_id = WebXRContextId::from(context.context_id());
|
||||
let layer_init = LayerInit::from(init);
|
||||
let layer_id = session
|
||||
.with_session(|session| session.create_layer(context_id, layer_init))
|
||||
.map_err(|_| Error::Operation)?;
|
||||
|
||||
// Step 9.4: "If layer’s resources were unable to be created for any reason,
|
||||
// throw an OperationError and abort these steps."
|
||||
(Some(framebuffer), Some(layer_id))
|
||||
} 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."
|
||||
|
||||
// Step 9.4: "If layer’s resources were unable to be created for any reason,
|
||||
// throw an OperationError and abort these steps."
|
||||
|
||||
// Ensure that we finish setting up this layer before continuing.
|
||||
match context {
|
||||
XRWebGLRenderingContext::WebGLRenderingContext(ref ctx) => ctx.Finish(),
|
||||
|
@ -142,37 +175,26 @@ impl XRWebGLLayer {
|
|||
// Step 10. "Return layer."
|
||||
Ok(XRWebGLLayer::new(
|
||||
&global.global(),
|
||||
swap_chain_id,
|
||||
session,
|
||||
context,
|
||||
init,
|
||||
framebuffer,
|
||||
framebuffer.as_deref(),
|
||||
layer_id,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn swap_chain_id(&self) -> WebXRSwapChainId {
|
||||
self.swap_chain_id
|
||||
.expect("swap_chain_id must not be called for inline sessions")
|
||||
pub fn layer_id(&self) -> Option<LayerId> {
|
||||
self.layer_id
|
||||
}
|
||||
|
||||
pub fn context_id(&self) -> WebGLContextId {
|
||||
self.context.context_id()
|
||||
}
|
||||
|
||||
pub fn session(&self) -> &XRSession {
|
||||
&self.session
|
||||
}
|
||||
|
||||
pub fn swap_buffers(&self) {
|
||||
if let WebGLFramebufferId::Opaque(id) = self
|
||||
.framebuffer
|
||||
.as_ref()
|
||||
.expect("swap_buffers must not be called for inline sessions")
|
||||
.id()
|
||||
{
|
||||
match self.context {
|
||||
RenderingContext::WebGL1(ref ctx) => ctx.swap_buffers(Some(id)),
|
||||
RenderingContext::WebGL2(ref ctx) => ctx.base_context().swap_buffers(Some(id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Size2D<u32, Viewport> {
|
||||
if let Some(framebuffer) = self.framebuffer.as_ref() {
|
||||
let size = framebuffer.size().unwrap_or((0, 0));
|
||||
|
@ -188,6 +210,52 @@ impl XRWebGLLayer {
|
|||
Size2D::from_untyped(size)
|
||||
}
|
||||
}
|
||||
|
||||
fn texture_target(&self) -> u32 {
|
||||
if cfg!(target_os = "macos") {
|
||||
sparkle::gl::TEXTURE_RECTANGLE
|
||||
} else {
|
||||
sparkle::gl::TEXTURE_2D
|
||||
}
|
||||
}
|
||||
|
||||
pub fn begin_frame(&self, frame: &XRFrame) -> Option<()> {
|
||||
debug!("XRWebGLLayer begin frame");
|
||||
let framebuffer = self.framebuffer.as_ref()?;
|
||||
let context = framebuffer.upcast::<WebGLObject>().context();
|
||||
let sub_images = frame.get_sub_images(self.layer_id?)?;
|
||||
// TODO: Cache this texture
|
||||
let color_texture_id =
|
||||
WebGLTextureId::maybe_new(sub_images.sub_image.as_ref()?.color_texture)?;
|
||||
let color_texture = WebGLTexture::new(context, color_texture_id);
|
||||
let target = self.texture_target();
|
||||
// TODO: rebind the current bindings
|
||||
context.send_command(WebGLCommand::BindTexture(target, Some(color_texture_id)));
|
||||
framebuffer.bind(constants::FRAMEBUFFER);
|
||||
framebuffer
|
||||
.texture2d_even_if_opaque(
|
||||
constants::COLOR_ATTACHMENT0,
|
||||
self.texture_target(),
|
||||
Some(&color_texture),
|
||||
0,
|
||||
)
|
||||
.ok()?;
|
||||
// TODO: depth/stencil
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn end_frame(&self, _frame: &XRFrame) -> Option<()> {
|
||||
debug!("XRWebGLLayer end frame");
|
||||
// TODO: invalidate the old texture
|
||||
let framebuffer = self.framebuffer.as_ref()?;
|
||||
// TODO: rebind the current bindings
|
||||
framebuffer.bind(constants::FRAMEBUFFER);
|
||||
framebuffer
|
||||
.texture2d_even_if_opaque(constants::COLOR_ATTACHMENT0, self.texture_target(), None, 0)
|
||||
.ok()?;
|
||||
framebuffer.upcast::<WebGLObject>().context().Flush();
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl XRWebGLLayerMethods for XRWebGLLayer {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue