Use surfman for managing GL surfaces

Co-authored-by: Alan Jeffrey <ajeffrey@mozilla.com>
Co-authored-by: Zakor Gyula <gyula.zakor@h-lab.eu>
Co-authored-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Patrick Walton 2019-10-15 12:57:00 -05:00 committed by Alan Jeffrey
parent 48d918dcde
commit a358bca766
52 changed files with 1929 additions and 2195 deletions

View file

@ -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>()
@ -267,7 +310,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 +329,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 +368,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 +400,7 @@ impl WebGLFramebuffer {
));
if rb.is_none() {
self.detach_binding(binding, attachment);
self.detach_binding(binding, attachment)?;
}
self.update_status();
@ -349,14 +412,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 +440,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 +483,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 +501,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 +575,7 @@ impl WebGLFramebuffer {
));
if texture.is_none() {
self.detach_binding(binding, attachment);
self.detach_binding(binding, attachment)?;
}
self.update_status();
@ -563,7 +640,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 +656,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 +677,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 +702,7 @@ impl WebGLFramebuffer {
impl Drop for WebGLFramebuffer {
fn drop(&mut self) {
self.delete(true);
let _ = self.delete(true);
}
}