diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | components/canvas/Cargo.toml | 3 | ||||
-rw-r--r-- | components/canvas/gl_context.rs | 13 | ||||
-rw-r--r-- | components/canvas/webgl_thread.rs | 25 | ||||
-rw-r--r-- | components/canvas_traits/Cargo.toml | 3 | ||||
-rw-r--r-- | components/canvas_traits/webgl.rs | 14 | ||||
-rw-r--r-- | components/script/Cargo.toml | 2 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 28 | ||||
-rw-r--r-- | components/script/lib.rs | 2 | ||||
-rw-r--r-- | components/servo/Cargo.toml | 5 | ||||
-rw-r--r-- | ports/libsimpleservo/Cargo.toml | 1 | ||||
-rw-r--r-- | ports/servo/Cargo.toml | 1 |
12 files changed, 82 insertions, 16 deletions
diff --git a/Cargo.lock b/Cargo.lock index 85859bf7c72..6d839d69c0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2981,6 +2981,7 @@ version = "0.0.1" dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "audio-video-metadata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "bluetooth_traits 0.0.1", diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index d65c1b4b110..4006947acf6 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -9,6 +9,9 @@ publish = false name = "canvas" path = "lib.rs" +[features] +webgl_backtrace = ["canvas_traits/webgl_backtrace"] + [dependencies] azure = {git = "https://github.com/servo/rust-azure"} canvas_traits = {path = "../canvas_traits"} diff --git a/components/canvas/gl_context.rs b/components/canvas/gl_context.rs index 00e3f3ba4a9..c90ecec9cca 100644 --- a/components/canvas/gl_context.rs +++ b/components/canvas/gl_context.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::webgl::{WebGLCommand, WebGLVersion}; +use canvas_traits::webgl::{WebGLCommand, WebGLVersion, WebGLCommandBacktrace}; use compositing::compositor_thread::{CompositorProxy, self}; use euclid::Size2D; use gleam::gl; @@ -144,13 +144,18 @@ impl GLContextWrapper { } } - pub fn apply_command(&self, cmd: WebGLCommand, state: &mut GLState) { + pub fn apply_command( + &self, + cmd: WebGLCommand, + backtrace: WebGLCommandBacktrace, + state: &mut GLState + ) { match *self { GLContextWrapper::Native(ref ctx) => { - WebGLImpl::apply(ctx, state, cmd); + WebGLImpl::apply(ctx, state, cmd, backtrace); } GLContextWrapper::OSMesa(ref ctx) => { - WebGLImpl::apply(ctx, state, cmd); + WebGLImpl::apply(ctx, state, cmd, backtrace); } } } diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 9256692599a..4a2466d64e3 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -137,8 +137,8 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> { WebGLMsg::RemoveContext(ctx_id) => { self.remove_webgl_context(ctx_id); }, - WebGLMsg::WebGLCommand(ctx_id, command) => { - self.handle_webgl_command(ctx_id, command); + WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => { + self.handle_webgl_command(ctx_id, command, backtrace); }, WebGLMsg::WebVRCommand(ctx_id, command) => { self.handle_webvr_command(ctx_id, command); @@ -164,10 +164,15 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> { } /// Handles a WebGLCommand for a specific WebGLContext - fn handle_webgl_command(&mut self, context_id: WebGLContextId, command: WebGLCommand) { + fn handle_webgl_command( + &mut self, + context_id: WebGLContextId, + command: WebGLCommand, + backtrace: WebGLCommandBacktrace, + ) { let data = Self::make_current_if_needed_mut(context_id, &mut self.contexts, &mut self.bound_context_id); if let Some(data) = data { - data.ctx.apply_command(command, &mut data.state); + data.ctx.apply_command(command, backtrace, &mut data.state); } } @@ -670,7 +675,8 @@ impl WebGLImpl { pub fn apply<Native: NativeGLContextMethods>( ctx: &GLContext<Native>, state: &mut GLState, - command: WebGLCommand + command: WebGLCommand, + _backtrace: WebGLCommandBacktrace, ) { match command { WebGLCommand::GetContextAttributes(ref sender) => @@ -1191,7 +1197,14 @@ impl WebGLImpl { // TODO: update test expectations in order to enable debug assertions let error = ctx.gl().get_error(); if error != gl::NO_ERROR { - error!("Last GL operation failed: {:?}", command) + error!("Last GL operation failed: {:?}", command); + #[cfg(feature = "webgl_backtrace")] + { + error!("Backtrace from failed WebGL API:\n{}", _backtrace.backtrace); + if let Some(backtrace) = _backtrace.js_backtrace { + error!("JS backtrace from failed WebGL API:\n{}", backtrace); + } + } } assert_eq!(error, gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error); } diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index b5599232b5c..187b46d617e 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -9,6 +9,9 @@ publish = false name = "canvas_traits" path = "lib.rs" +[features] +webgl_backtrace = [] + [dependencies] cssparser = "0.24.0" euclid = "0.19" diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 8f9f4e70a31..ad10ed7edd0 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -24,6 +24,14 @@ pub use ::webgl_channel::WebGLPipeline; /// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer. pub use ::webgl_channel::WebGLChan; +#[derive(Clone, Deserialize, Serialize)] +pub struct WebGLCommandBacktrace { + #[cfg(feature = "webgl_backtrace")] + pub backtrace: String, + #[cfg(feature = "webgl_backtrace")] + pub js_backtrace: Option<String>, +} + /// WebGL Message API #[derive(Deserialize, Serialize)] pub enum WebGLMsg { @@ -35,7 +43,7 @@ pub enum WebGLMsg { /// Drops a WebGLContext. RemoveContext(WebGLContextId), /// Runs a WebGLCommand in a specific WebGLContext. - WebGLCommand(WebGLContextId, WebGLCommand), + WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace), /// Runs a WebVRCommand in a specific WebGLContext. WebVRCommand(WebGLContextId, WebVRCommand), /// Locks a specific WebGLContext. Lock messages are used for a correct synchronization @@ -121,8 +129,8 @@ impl WebGLMsgSender { /// Send a WebGLCommand message #[inline] - pub fn send(&self, command: WebGLCommand) -> WebGLSendResult { - self.sender.send(WebGLMsg::WebGLCommand(self.ctx_id, command)) + pub fn send(&self, command: WebGLCommand, backtrace: WebGLCommandBacktrace) -> WebGLSendResult { + self.sender.send(WebGLMsg::WebGLCommand(self.ctx_id, command, backtrace)) } /// Send a WebVRCommand message diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 1c8feb0f17e..5ad8c3df8ff 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -16,6 +16,7 @@ debugmozjs = ['mozjs/debugmozjs'] unstable = [] unrooted_must_root_lint = ["script_plugins/unrooted_must_root_lint"] default = ["unrooted_must_root_lint"] +webgl_backtrace = ["backtrace", "canvas_traits/webgl_backtrace"] [build-dependencies] cmake = "0.1" @@ -29,6 +30,7 @@ tinyfiledialogs = "3.0" [dependencies] app_units = "0.7" audio-video-metadata = "0.1.4" +backtrace = {version = "0.3", optional = true} base64 = "0.6" bitflags = "1.0" bluetooth_traits = {path = "../bluetooth_traits"} diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 7367a38fdcf..754637ad52b 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -2,9 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "webgl_backtrace")] +use backtrace::Backtrace; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; use canvas_traits::canvas::{byte_swap, multiply_u8_pixel}; -use canvas_traits::webgl::{DOMToTextureCommand, Parameter}; +use canvas_traits::webgl::{DOMToTextureCommand, Parameter, WebGLCommandBacktrace}; use canvas_traits::webgl::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender}; use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender}; @@ -316,7 +318,7 @@ impl WebGLRenderingContext { #[inline] pub fn send_command(&self, command: WebGLCommand) { - self.webgl_sender.send(command).unwrap(); + self.webgl_sender.send(command, capture_webgl_backtrace(self)).unwrap(); } #[inline] @@ -1189,6 +1191,25 @@ impl WebGLRenderingContext { } } +#[cfg(not(feature = "webgl_backtrace"))] +#[inline] +pub fn capture_webgl_backtrace<T: DomObject>(_: &T) -> WebGLCommandBacktrace { + WebGLCommandBacktrace {} +} + +#[cfg(feature = "webgl_backtrace")] +#[cfg_attr(feature = "webgl_backtrace", allow(unsafe_code))] +pub fn capture_webgl_backtrace<T: DomObject>(obj: &T) -> WebGLCommandBacktrace { + let bt = Backtrace::new(); + unsafe { + capture_stack!(in(obj.global().get_cx()) let stack); + WebGLCommandBacktrace { + backtrace: format!("{:?}", bt), + js_backtrace: stack.and_then(|s| s.as_string(None)), + } + } +} + impl Drop for WebGLRenderingContext { fn drop(&mut self) { let _ = self.webgl_sender.send_remove(); @@ -1521,9 +1542,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let (sender, receiver) = webgl_channel().unwrap(); // If the send does not succeed, assume context lost + let backtrace = capture_webgl_backtrace(self); if self .webgl_sender - .send(WebGLCommand::GetContextAttributes(sender)) + .send(WebGLCommand::GetContextAttributes(sender), backtrace) .is_err() { return None; diff --git a/components/script/lib.rs b/components/script/lib.rs index f8341323466..66bc4ac40eb 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -19,6 +19,8 @@ extern crate app_units; extern crate audio_video_metadata; +#[cfg(feature = "webgl_backtrace")] +extern crate backtrace; extern crate base64; #[macro_use] extern crate bitflags; diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 423d6814810..ea0a3d1d3a2 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -24,6 +24,11 @@ unstable = [ "profile/unstable", "script/unstable", ] +webgl_backtrace = [ + "script/webgl_backtrace", + "canvas/webgl_backtrace", + "canvas_traits/webgl_backtrace", +] [dependencies] bluetooth_traits = {path = "../bluetooth_traits"} diff --git a/ports/libsimpleservo/Cargo.toml b/ports/libsimpleservo/Cargo.toml index 6cb4d4f6c3c..75cde40fd23 100644 --- a/ports/libsimpleservo/Cargo.toml +++ b/ports/libsimpleservo/Cargo.toml @@ -42,3 +42,4 @@ debugmozjs = ["libservo/debugmozjs"] unstable = ["libservo/unstable"] googlevr = ["libservo/googlevr"] oculusvr = ["libservo/oculusvr"] +webgl_backtrace = ["libservo/webgl_backtrace"]
\ No newline at end of file diff --git a/ports/servo/Cargo.toml b/ports/servo/Cargo.toml index a31f6306514..e128738b365 100644 --- a/ports/servo/Cargo.toml +++ b/ports/servo/Cargo.toml @@ -30,6 +30,7 @@ webdriver = ["libservo/webdriver"] energy-profiling = ["libservo/energy-profiling"] debugmozjs = ["libservo/debugmozjs"] unstable = ["libservo/unstable"] +webgl_backtrace = ["libservo/webgl_backtrace"] [target.'cfg(not(target_os = "android"))'.dependencies] backtrace = "0.3" |