mirror of
https://github.com/servo/servo.git
synced 2025-06-21 15:49:04 +01:00
Added framebuffer and related attributes to XRWebGLLayer
This commit is contained in:
parent
dc1da02aa4
commit
aa0a72df0f
10 changed files with 158 additions and 46 deletions
|
@ -84,6 +84,8 @@ pub enum Error {
|
|||
InvalidModification,
|
||||
/// NotReadableError DOMException
|
||||
NotReadable,
|
||||
/// OperationError DOMException
|
||||
Operation,
|
||||
|
||||
/// TypeError JavaScript Error
|
||||
Type(String),
|
||||
|
@ -136,6 +138,7 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, resu
|
|||
Error::TypeMismatch => DOMErrorName::TypeMismatchError,
|
||||
Error::InvalidModification => DOMErrorName::InvalidModificationError,
|
||||
Error::NotReadable => DOMErrorName::NotReadableError,
|
||||
Error::Operation => DOMErrorName::OperationError,
|
||||
Error::Type(message) => {
|
||||
assert!(!JS_IsExceptionPending(cx));
|
||||
throw_type_error(cx, &message);
|
||||
|
|
|
@ -57,8 +57,8 @@ use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
|
|||
use encoding_rs::{Decoder, Encoding};
|
||||
use euclid::Length as EuclidLength;
|
||||
use euclid::{
|
||||
Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedRigidTransform3D,
|
||||
TypedScale, TypedSize2D, Vector2D,
|
||||
Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedRect,
|
||||
TypedRigidTransform3D, TypedScale, TypedSize2D, Vector2D,
|
||||
};
|
||||
use html5ever::buffer_queue::BufferQueue;
|
||||
use html5ever::{LocalName, Namespace, Prefix, QualName};
|
||||
|
@ -647,6 +647,13 @@ unsafe impl<U> JSTraceable for TypedSize2D<u32, U> {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<U> JSTraceable for TypedRect<i32, U> {
|
||||
#[inline]
|
||||
unsafe fn trace(&self, _trc: *mut JSTracer) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl JSTraceable for StyleLocked<FontFaceRule> {
|
||||
unsafe fn trace(&self, _trc: *mut JSTracer) {
|
||||
// Do nothing.
|
||||
|
|
|
@ -37,6 +37,7 @@ pub enum DOMErrorName {
|
|||
InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR,
|
||||
DataCloneError = DOMExceptionConstants::DATA_CLONE_ERR,
|
||||
NotReadableError = DOMExceptionConstants::NOT_READABLE_ERR,
|
||||
OperationError = DOMExceptionConstants::OPERATION_ERR,
|
||||
}
|
||||
|
||||
impl DOMErrorName {
|
||||
|
@ -64,6 +65,7 @@ impl DOMErrorName {
|
|||
"InvalidNodeTypeError" => Some(DOMErrorName::InvalidNodeTypeError),
|
||||
"DataCloneError" => Some(DOMErrorName::DataCloneError),
|
||||
"NotReadableError" => Some(DOMErrorName::NotReadableError),
|
||||
"OperationError" => Some(DOMErrorName::OperationError),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +109,9 @@ impl DOMException {
|
|||
},
|
||||
DOMErrorName::DataCloneError => "The object can not be cloned.",
|
||||
DOMErrorName::NotReadableError => "The I/O read operation failed.",
|
||||
DOMErrorName::OperationError => {
|
||||
"The operation failed for an operation-specific reason."
|
||||
},
|
||||
};
|
||||
|
||||
(
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
|||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::{TypedPoint2D, TypedRect, TypedSize2D};
|
||||
use euclid::{TypedRigidTransform3D, TypedRotation3D, TypedTransform3D, TypedVector3D};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use webxr_api::{MockDeviceMsg, View, Views};
|
||||
|
@ -71,13 +72,24 @@ pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<Views> {
|
|||
let offset_l = get_origin(&left.viewOffset)?.inverse();
|
||||
let offset_r = get_origin(&right.viewOffset)?.inverse();
|
||||
|
||||
let size_l = TypedSize2D::new(views[0].resolution.width, views[0].resolution.height);
|
||||
let size_r = TypedSize2D::new(views[1].resolution.width, views[1].resolution.height);
|
||||
|
||||
let origin_l = TypedPoint2D::new(0, 0);
|
||||
let origin_r = TypedPoint2D::new(size_l.width, 0);
|
||||
|
||||
let viewport_l = TypedRect::new(origin_l, size_l);
|
||||
let viewport_r = TypedRect::new(origin_r, size_r);
|
||||
|
||||
let left = View {
|
||||
projection: proj_l,
|
||||
transform: offset_l,
|
||||
viewport: viewport_l,
|
||||
};
|
||||
let right = View {
|
||||
projection: proj_r,
|
||||
transform: offset_r,
|
||||
viewport: viewport_r,
|
||||
};
|
||||
Ok(Views::Stereo(left, right))
|
||||
}
|
||||
|
|
|
@ -38,7 +38,10 @@ interface DOMException {
|
|||
const unsigned short TIMEOUT_ERR = 23;
|
||||
const unsigned short INVALID_NODE_TYPE_ERR = 24;
|
||||
const unsigned short DATA_CLONE_ERR = 25;
|
||||
// Only the first 25 errors are given codes in
|
||||
// https://heycam.github.io/webidl/#idl-DOMException
|
||||
const unsigned short NOT_READABLE_ERR = 26;
|
||||
const unsigned short OPERATION_ERR = 27;
|
||||
|
||||
// Error code as u16
|
||||
readonly attribute unsigned short code;
|
||||
|
|
|
@ -30,9 +30,9 @@ interface XRWebGLLayer : XRLayer {
|
|||
readonly attribute boolean stencil;
|
||||
readonly attribute boolean alpha;
|
||||
|
||||
// readonly attribute WebGLFramebuffer framebuffer;
|
||||
// readonly attribute unsigned long framebufferWidth;
|
||||
// readonly attribute unsigned long framebufferHeight;
|
||||
readonly attribute WebGLFramebuffer framebuffer;
|
||||
readonly attribute unsigned long framebufferWidth;
|
||||
readonly attribute unsigned long framebufferHeight;
|
||||
|
||||
// // Methods
|
||||
XRViewport? getViewport(XRView view);
|
||||
|
|
|
@ -103,7 +103,7 @@ impl XRSession {
|
|||
ret
|
||||
}
|
||||
|
||||
pub fn with_session<F: FnOnce(&Session)>(&self, with: F) {
|
||||
pub fn with_session<R, F: FnOnce(&Session) -> R>(&self, with: F) -> R {
|
||||
let session = self.session.borrow();
|
||||
with(&session)
|
||||
}
|
||||
|
|
|
@ -8,36 +8,26 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
|||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::TypedRect;
|
||||
use webxr_api::Viewport;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRViewport {
|
||||
reflector_: Reflector,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
viewport: TypedRect<i32, Viewport>,
|
||||
}
|
||||
|
||||
impl XRViewport {
|
||||
fn new_inherited(x: u32, y: u32, width: u32, height: u32) -> XRViewport {
|
||||
fn new_inherited(viewport: TypedRect<i32, Viewport>) -> XRViewport {
|
||||
XRViewport {
|
||||
reflector_: Reflector::new(),
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
viewport,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> DomRoot<XRViewport> {
|
||||
pub fn new(global: &GlobalScope, viewport: TypedRect<i32, Viewport>) -> DomRoot<XRViewport> {
|
||||
reflect_dom_object(
|
||||
Box::new(XRViewport::new_inherited(x, y, width, height)),
|
||||
Box::new(XRViewport::new_inherited(viewport)),
|
||||
global,
|
||||
XRViewportBinding::Wrap,
|
||||
)
|
||||
|
@ -47,21 +37,21 @@ impl XRViewport {
|
|||
impl XRViewportMethods for XRViewport {
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrviewport-x
|
||||
fn X(&self) -> i32 {
|
||||
self.x as i32
|
||||
self.viewport.origin.x
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrviewport-y
|
||||
fn Y(&self) -> i32 {
|
||||
self.y as i32
|
||||
self.viewport.origin.y
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrviewport-width
|
||||
fn Width(&self) -> i32 {
|
||||
self.width as i32
|
||||
self.viewport.size.width
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrviewport-height
|
||||
fn Height(&self) -> i32 {
|
||||
self.height as i32
|
||||
self.viewport.size.height
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue