Added framebuffer and related attributes to XRWebGLLayer

This commit is contained in:
Alan Jeffrey 2019-07-17 18:09:15 -05:00
parent dc1da02aa4
commit aa0a72df0f
10 changed files with 158 additions and 46 deletions

View file

@ -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);

View file

@ -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.

View file

@ -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."
},
};
(

View file

@ -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))
}

View file

@ -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;

View file

@ -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);

View file

@ -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)
}

View file

@ -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
}
}

View file

@ -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 layers 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 sessions 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 layers 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))
}
}