mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #23777 - jdm:webgl-main-thread, r=asajeffrey
Support running WebGL in its own thread or on the main thread. This is the final missing piece to support WebGL in ANGLE on Windows. ANGLE doesn't support multiple GL contexts on separate threads using the same underlying Direct3d device, so we need to process all GL operations for WebGL on the same thread as the compositor. These changes try to retain enough flexibility to support both approaches so we can get WebGL working on Windows ASAP. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #23697 - [x] There are tests for these changes <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23777) <!-- Reviewable:end -->
This commit is contained in:
commit
8ec28978cd
164 changed files with 3105 additions and 552 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -395,6 +395,7 @@ dependencies = [
|
||||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"canvas_traits 0.0.1",
|
"canvas_traits 0.0.1",
|
||||||
"cssparser 0.25.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cssparser 0.25.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"embedder_traits 0.0.1",
|
||||||
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -21,6 +21,7 @@ azure = {git = "https://github.com/servo/rust-azure", optional = true}
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
canvas_traits = {path = "../canvas_traits"}
|
canvas_traits = {path = "../canvas_traits"}
|
||||||
cssparser = "0.25"
|
cssparser = "0.25"
|
||||||
|
embedder_traits = {path = "../embedder_traits"}
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
gleam = "0.6.7"
|
gleam = "0.6.7"
|
||||||
|
|
|
@ -3,15 +3,19 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::gl_context::GLContextFactory;
|
use crate::gl_context::GLContextFactory;
|
||||||
use crate::webgl_thread::WebGLThread;
|
use crate::webgl_thread::{TexturesMap, WebGLMainThread, WebGLThread, WebGLThreadInit};
|
||||||
use canvas_traits::webgl::webgl_channel;
|
use canvas_traits::webgl::webgl_channel;
|
||||||
use canvas_traits::webgl::DOMToTextureCommand;
|
use canvas_traits::webgl::DOMToTextureCommand;
|
||||||
use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver};
|
use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver};
|
||||||
use canvas_traits::webgl::{WebGLSender, WebVRCommand, WebVRRenderHandler};
|
use canvas_traits::webgl::{WebGLSender, WebVRRenderHandler};
|
||||||
|
use embedder_traits::EventLoopWaker;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use servo_config::pref;
|
use servo_config::pref;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::default::Default;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
|
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
|
||||||
|
@ -19,37 +23,70 @@ use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry
|
||||||
/// WebGL Threading API entry point that lives in the constellation.
|
/// WebGL Threading API entry point that lives in the constellation.
|
||||||
pub struct WebGLThreads(WebGLSender<WebGLMsg>);
|
pub struct WebGLThreads(WebGLSender<WebGLMsg>);
|
||||||
|
|
||||||
|
pub enum ThreadMode {
|
||||||
|
MainThread(Box<dyn EventLoopWaker>),
|
||||||
|
OffThread(Rc<dyn gl::Gl>),
|
||||||
|
}
|
||||||
|
|
||||||
impl WebGLThreads {
|
impl WebGLThreads {
|
||||||
/// Creates a new WebGLThreads object
|
/// Creates a new WebGLThreads object
|
||||||
pub fn new(
|
pub fn new(
|
||||||
gl_factory: GLContextFactory,
|
gl_factory: GLContextFactory,
|
||||||
webrender_gl: Rc<dyn gl::Gl>,
|
|
||||||
webrender_api_sender: webrender_api::RenderApiSender,
|
webrender_api_sender: webrender_api::RenderApiSender,
|
||||||
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
|
mode: ThreadMode,
|
||||||
) -> (
|
) -> (
|
||||||
WebGLThreads,
|
WebGLThreads,
|
||||||
|
Option<WebGLMainThread>,
|
||||||
Box<dyn WebrenderExternalImageApi>,
|
Box<dyn WebrenderExternalImageApi>,
|
||||||
Option<Box<dyn webrender::OutputImageHandler>>,
|
Option<Box<dyn webrender::OutputImageHandler>>,
|
||||||
) {
|
) {
|
||||||
|
let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
|
||||||
// This implementation creates a single `WebGLThread` for all the pipelines.
|
// This implementation creates a single `WebGLThread` for all the pipelines.
|
||||||
let channel = WebGLThread::start(
|
let init = WebGLThreadInit {
|
||||||
gl_factory,
|
gl_factory,
|
||||||
webrender_api_sender,
|
webrender_api_sender,
|
||||||
webvr_compositor.map(|c| WebVRRenderWrapper(c)),
|
webvr_compositor,
|
||||||
external_images,
|
external_images,
|
||||||
);
|
sender: sender.clone(),
|
||||||
|
receiver,
|
||||||
|
};
|
||||||
|
|
||||||
let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) {
|
let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) {
|
||||||
Some(Box::new(OutputHandler::new(
|
Some(Box::new(match mode {
|
||||||
webrender_gl.clone(),
|
ThreadMode::MainThread(..) => OutputHandler::new_main_thread(),
|
||||||
channel.clone(),
|
ThreadMode::OffThread(ref webrender_gl) => {
|
||||||
)))
|
OutputHandler::new_off_thread(webrender_gl.clone(), sender.clone())
|
||||||
|
},
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let external = WebGLExternalImages::new(webrender_gl, channel.clone());
|
|
||||||
|
let (external, webgl_thread) = match mode {
|
||||||
|
ThreadMode::MainThread(event_loop_waker) => {
|
||||||
|
let textures = Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
let thread_data =
|
||||||
|
WebGLThread::run_on_current_thread(init, event_loop_waker, textures.clone());
|
||||||
(
|
(
|
||||||
WebGLThreads(channel),
|
WebGLExternalImages::new_main_thread(textures),
|
||||||
|
Some(thread_data),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
ThreadMode::OffThread(webrender_gl) => {
|
||||||
|
WebGLThread::run_on_own_thread(init);
|
||||||
|
(
|
||||||
|
WebGLExternalImages::new_off_thread(webrender_gl, sender.clone()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
WebGLThreads(sender),
|
||||||
|
webgl_thread,
|
||||||
Box::new(external),
|
Box::new(external),
|
||||||
output_handler.map(|b| b as Box<_>),
|
output_handler.map(|b| b as Box<_>),
|
||||||
)
|
)
|
||||||
|
@ -70,7 +107,8 @@ impl WebGLThreads {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
|
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
|
||||||
struct WebGLExternalImages {
|
enum WebGLExternalImages {
|
||||||
|
OffThread {
|
||||||
webrender_gl: Rc<dyn gl::Gl>,
|
webrender_gl: Rc<dyn gl::Gl>,
|
||||||
webgl_channel: WebGLSender<WebGLMsg>,
|
webgl_channel: WebGLSender<WebGLMsg>,
|
||||||
// Used to avoid creating a new channel on each received WebRender request.
|
// Used to avoid creating a new channel on each received WebRender request.
|
||||||
|
@ -78,61 +116,79 @@ struct WebGLExternalImages {
|
||||||
WebGLSender<(u32, Size2D<i32>, usize)>,
|
WebGLSender<(u32, Size2D<i32>, usize)>,
|
||||||
WebGLReceiver<(u32, Size2D<i32>, usize)>,
|
WebGLReceiver<(u32, Size2D<i32>, usize)>,
|
||||||
),
|
),
|
||||||
|
},
|
||||||
|
MainThread {
|
||||||
|
textures: TexturesMap,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebGLExternalImages {
|
impl WebGLExternalImages {
|
||||||
fn new(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
|
fn new_off_thread(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
|
||||||
Self {
|
WebGLExternalImages::OffThread {
|
||||||
webrender_gl,
|
webrender_gl,
|
||||||
webgl_channel: channel,
|
webgl_channel: channel,
|
||||||
lock_channel: webgl_channel().unwrap(),
|
lock_channel: webgl_channel().unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_main_thread(textures: TexturesMap) -> Self {
|
||||||
|
WebGLExternalImages::MainThread { textures }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebrenderExternalImageApi for WebGLExternalImages {
|
impl WebrenderExternalImageApi for WebGLExternalImages {
|
||||||
fn lock(&mut self, id: u64) -> (u32, Size2D<i32>) {
|
fn lock(&mut self, id: u64) -> (u32, Size2D<i32>) {
|
||||||
|
match *self {
|
||||||
|
WebGLExternalImages::OffThread {
|
||||||
|
ref webgl_channel,
|
||||||
|
ref webrender_gl,
|
||||||
|
ref lock_channel,
|
||||||
|
} => {
|
||||||
// WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue.
|
// WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue.
|
||||||
// The WebGLMsg::Lock message inserts a fence in the WebGL command queue.
|
// The WebGLMsg::Lock message inserts a fence in the WebGL command queue.
|
||||||
self.webgl_channel
|
webgl_channel
|
||||||
.send(WebGLMsg::Lock(
|
.send(WebGLMsg::Lock(
|
||||||
WebGLContextId(id as usize),
|
WebGLContextId(id as usize),
|
||||||
self.lock_channel.0.clone(),
|
lock_channel.0.clone(),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (image_id, size, gl_sync) = self.lock_channel.1.recv().unwrap();
|
let (image_id, size, gl_sync) = lock_channel.1.recv().unwrap();
|
||||||
// The next glWaitSync call is run on the WR thread and it's used to synchronize the two
|
// The next glWaitSync call is run on the WR thread and it's used to synchronize the two
|
||||||
// flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture.
|
// flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture.
|
||||||
// glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem.
|
// glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem.
|
||||||
self.webrender_gl
|
webrender_gl.wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED);
|
||||||
.wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED);
|
|
||||||
(image_id, size)
|
(image_id, size)
|
||||||
|
},
|
||||||
|
|
||||||
|
WebGLExternalImages::MainThread { ref textures } => {
|
||||||
|
let textures = textures.borrow();
|
||||||
|
let entry = textures
|
||||||
|
.get(&WebGLContextId(id as usize))
|
||||||
|
.expect("no texture entry???");
|
||||||
|
(entry.0, entry.1)
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock(&mut self, id: u64) {
|
fn unlock(&mut self, id: u64) {
|
||||||
self.webgl_channel
|
match *self {
|
||||||
|
WebGLExternalImages::OffThread {
|
||||||
|
ref webgl_channel, ..
|
||||||
|
} => {
|
||||||
|
webgl_channel
|
||||||
.send(WebGLMsg::Unlock(WebGLContextId(id as usize)))
|
.send(WebGLMsg::Unlock(WebGLContextId(id as usize)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
},
|
||||||
|
|
||||||
|
WebGLExternalImages::MainThread { .. } => {},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper to send WebVR commands used in `WebGLThread`.
|
|
||||||
struct WebVRRenderWrapper(Box<dyn WebVRRenderHandler>);
|
|
||||||
|
|
||||||
impl WebVRRenderHandler for WebVRRenderWrapper {
|
|
||||||
fn handle(
|
|
||||||
&mut self,
|
|
||||||
gl: &dyn gl::Gl,
|
|
||||||
command: WebVRCommand,
|
|
||||||
texture: Option<(u32, Size2D<i32>)>,
|
|
||||||
) {
|
|
||||||
self.0.handle(gl, command, texture);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// struct used to implement DOMToTexture feature and webrender::OutputImageHandler trait.
|
/// struct used to implement DOMToTexture feature and webrender::OutputImageHandler trait.
|
||||||
type OutputHandlerData = Option<(u32, Size2D<i32>)>;
|
type OutputHandlerData = Option<(u32, Size2D<i32>)>;
|
||||||
struct OutputHandler {
|
enum OutputHandler {
|
||||||
|
OffThread {
|
||||||
webrender_gl: Rc<dyn gl::Gl>,
|
webrender_gl: Rc<dyn gl::Gl>,
|
||||||
webgl_channel: WebGLSender<WebGLMsg>,
|
webgl_channel: WebGLSender<WebGLMsg>,
|
||||||
// Used to avoid creating a new channel on each received WebRender request.
|
// Used to avoid creating a new channel on each received WebRender request.
|
||||||
|
@ -141,17 +197,23 @@ struct OutputHandler {
|
||||||
WebGLReceiver<OutputHandlerData>,
|
WebGLReceiver<OutputHandlerData>,
|
||||||
),
|
),
|
||||||
sync_objects: FnvHashMap<webrender_api::PipelineId, gl::GLsync>,
|
sync_objects: FnvHashMap<webrender_api::PipelineId, gl::GLsync>,
|
||||||
|
},
|
||||||
|
MainThread,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputHandler {
|
impl OutputHandler {
|
||||||
fn new(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
|
fn new_off_thread(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
|
||||||
Self {
|
OutputHandler::OffThread {
|
||||||
webrender_gl,
|
webrender_gl,
|
||||||
webgl_channel: channel,
|
webgl_channel: channel,
|
||||||
lock_channel: webgl_channel().unwrap(),
|
lock_channel: webgl_channel().unwrap(),
|
||||||
sync_objects: Default::default(),
|
sync_objects: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_main_thread() -> Self {
|
||||||
|
OutputHandler::MainThread
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bridge between the WR frame outputs and WebGL to implement DOMToTexture synchronization.
|
/// Bridge between the WR frame outputs and WebGL to implement DOMToTexture synchronization.
|
||||||
|
@ -160,29 +222,49 @@ impl webrender::OutputImageHandler for OutputHandler {
|
||||||
&mut self,
|
&mut self,
|
||||||
id: webrender_api::PipelineId,
|
id: webrender_api::PipelineId,
|
||||||
) -> Option<(u32, webrender_api::units::FramebufferIntSize)> {
|
) -> Option<(u32, webrender_api::units::FramebufferIntSize)> {
|
||||||
|
match *self {
|
||||||
|
OutputHandler::OffThread {
|
||||||
|
ref webrender_gl,
|
||||||
|
ref lock_channel,
|
||||||
|
ref webgl_channel,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
// Insert a fence in the WR command queue
|
// Insert a fence in the WR command queue
|
||||||
let gl_sync = self
|
let gl_sync = webrender_gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
.webrender_gl
|
|
||||||
.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
||||||
// The lock command adds a WaitSync call on the WebGL command flow.
|
// The lock command adds a WaitSync call on the WebGL command flow.
|
||||||
let command = DOMToTextureCommand::Lock(id, gl_sync as usize, self.lock_channel.0.clone());
|
let command =
|
||||||
self.webgl_channel
|
DOMToTextureCommand::Lock(id, gl_sync as usize, lock_channel.0.clone());
|
||||||
|
webgl_channel
|
||||||
.send(WebGLMsg::DOMToTextureCommand(command))
|
.send(WebGLMsg::DOMToTextureCommand(command))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.lock_channel.1.recv().unwrap().map(|(tex_id, size)| {
|
lock_channel.1.recv().unwrap().map(|(tex_id, size)| {
|
||||||
(
|
(
|
||||||
tex_id,
|
tex_id,
|
||||||
webrender_api::units::FramebufferIntSize::new(size.width, size.height),
|
webrender_api::units::FramebufferIntSize::new(size.width, size.height),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
OutputHandler::MainThread => unimplemented!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock(&mut self, id: webrender_api::PipelineId) {
|
fn unlock(&mut self, id: webrender_api::PipelineId) {
|
||||||
if let Some(gl_sync) = self.sync_objects.remove(&id) {
|
match *self {
|
||||||
|
OutputHandler::OffThread {
|
||||||
|
ref webrender_gl,
|
||||||
|
ref mut sync_objects,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if let Some(gl_sync) = sync_objects.remove(&id) {
|
||||||
// Flush the Sync object into the GPU's command queue to guarantee that it it's signaled.
|
// Flush the Sync object into the GPU's command queue to guarantee that it it's signaled.
|
||||||
self.webrender_gl.flush();
|
webrender_gl.flush();
|
||||||
// Mark the sync object for deletion.
|
// Mark the sync object for deletion.
|
||||||
self.webrender_gl.delete_sync(gl_sync);
|
webrender_gl.delete_sync(gl_sync);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
OutputHandler::MainThread => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
mod inprocess;
|
mod inprocess;
|
||||||
pub use self::inprocess::WebGLThreads;
|
pub use self::inprocess::{ThreadMode, WebGLThreads};
|
||||||
|
|
|
@ -5,21 +5,27 @@
|
||||||
use super::gl_context::{map_attrs_to_script_attrs, GLContextFactory, GLContextWrapper};
|
use super::gl_context::{map_attrs_to_script_attrs, GLContextFactory, GLContextWrapper};
|
||||||
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
|
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
|
||||||
use canvas_traits::webgl::*;
|
use canvas_traits::webgl::*;
|
||||||
|
use embedder_traits::EventLoopWaker;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use half::f16;
|
use half::f16;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::{self, IpcSender, OpaqueIpcMessage};
|
||||||
|
use ipc_channel::router::ROUTER;
|
||||||
use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods};
|
use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods};
|
||||||
use pixels::{self, PixelFormat};
|
use pixels::{self, PixelFormat};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
||||||
|
|
||||||
/// WebGL Threading API entry point that lives in the constellation.
|
/// WebGL Threading API entry point that lives in the constellation.
|
||||||
/// It allows to get a WebGLThread handle for each script pipeline.
|
/// It allows to get a WebGLThread handle for each script pipeline.
|
||||||
pub use crate::webgl_mode::WebGLThreads;
|
pub use crate::webgl_mode::{ThreadMode, WebGLThreads};
|
||||||
|
|
||||||
struct GLContextData {
|
struct GLContextData {
|
||||||
ctx: GLContextWrapper,
|
ctx: GLContextWrapper,
|
||||||
|
@ -50,7 +56,7 @@ impl Default for GLState {
|
||||||
|
|
||||||
/// A WebGLThread manages the life cycle and message multiplexing of
|
/// A WebGLThread manages the life cycle and message multiplexing of
|
||||||
/// a set of WebGLContexts living in the same thread.
|
/// a set of WebGLContexts living in the same thread.
|
||||||
pub struct WebGLThread<VR: WebVRRenderHandler + 'static> {
|
pub(crate) struct WebGLThread {
|
||||||
/// Factory used to create a new GLContext shared with the WR/Main thread.
|
/// Factory used to create a new GLContext shared with the WR/Main thread.
|
||||||
gl_factory: GLContextFactory,
|
gl_factory: GLContextFactory,
|
||||||
/// Channel used to generate/update or delete `webrender_api::ImageKey`s.
|
/// Channel used to generate/update or delete `webrender_api::ImageKey`s.
|
||||||
|
@ -62,20 +68,74 @@ pub struct WebGLThread<VR: WebVRRenderHandler + 'static> {
|
||||||
/// Current bound context.
|
/// Current bound context.
|
||||||
bound_context_id: Option<WebGLContextId>,
|
bound_context_id: Option<WebGLContextId>,
|
||||||
/// Handler user to send WebVR commands.
|
/// Handler user to send WebVR commands.
|
||||||
webvr_compositor: Option<VR>,
|
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
||||||
/// Texture ids and sizes used in DOM to texture outputs.
|
/// Texture ids and sizes used in DOM to texture outputs.
|
||||||
dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>,
|
dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>,
|
||||||
/// List of registered webrender external images.
|
/// List of registered webrender external images.
|
||||||
/// We use it to get an unique ID for new WebGLContexts.
|
/// We use it to get an unique ID for new WebGLContexts.
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
|
/// The receiver that will be used for processing WebGL messages.
|
||||||
|
receiver: WebGLReceiver<WebGLMsg>,
|
||||||
|
/// The receiver that should be used to send WebGL messages for processing.
|
||||||
|
sender: WebGLSender<WebGLMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
/// A map of GL contexts to backing textures and their sizes.
|
||||||
pub fn new(
|
/// Only used for accessing this information when the WebGL processing is run
|
||||||
gl_factory: GLContextFactory,
|
/// on the main thread and the compositor needs access to this information
|
||||||
webrender_api_sender: webrender_api::RenderApiSender,
|
/// synchronously.
|
||||||
webvr_compositor: Option<VR>,
|
pub(crate) type TexturesMap = Rc<RefCell<HashMap<WebGLContextId, (u32, Size2D<i32>)>>>;
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum EventLoop {
|
||||||
|
Blocking,
|
||||||
|
Nonblocking,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The data required to initialize an instance of the WebGLThread type.
|
||||||
|
pub(crate) struct WebGLThreadInit {
|
||||||
|
pub gl_factory: GLContextFactory,
|
||||||
|
pub webrender_api_sender: webrender_api::RenderApiSender,
|
||||||
|
pub webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
|
||||||
|
pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||||
|
pub sender: WebGLSender<WebGLMsg>,
|
||||||
|
pub receiver: WebGLReceiver<WebGLMsg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The extra data required to run an instance of WebGLThread when it is
|
||||||
|
/// not running in its own thread.
|
||||||
|
pub struct WebGLMainThread {
|
||||||
|
thread_data: WebGLThread,
|
||||||
|
shut_down: bool,
|
||||||
|
textures: TexturesMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebGLMainThread {
|
||||||
|
/// Synchronously process all outstanding WebGL messages.
|
||||||
|
pub fn process(&mut self) {
|
||||||
|
if self.shut_down {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any context could be current when we start.
|
||||||
|
self.thread_data.bound_context_id = None;
|
||||||
|
self.shut_down = !self
|
||||||
|
.thread_data
|
||||||
|
.process(EventLoop::Nonblocking, Some(self.textures.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebGLThread {
|
||||||
|
/// Create a new instance of WebGLThread.
|
||||||
|
pub(crate) fn new(
|
||||||
|
WebGLThreadInit {
|
||||||
|
gl_factory,
|
||||||
|
webrender_api_sender,
|
||||||
|
webvr_compositor,
|
||||||
|
external_images,
|
||||||
|
sender,
|
||||||
|
receiver,
|
||||||
|
}: WebGLThreadInit,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
WebGLThread {
|
WebGLThread {
|
||||||
gl_factory,
|
gl_factory,
|
||||||
|
@ -86,49 +146,80 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
webvr_compositor,
|
webvr_compositor,
|
||||||
dom_outputs: Default::default(),
|
dom_outputs: Default::default(),
|
||||||
external_images,
|
external_images,
|
||||||
|
sender,
|
||||||
|
receiver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `WebGLThread` and returns a Sender to
|
/// Perform all initialization required to run an instance of WebGLThread
|
||||||
/// communicate with it.
|
/// concurrently on the current thread. Returns a `WebGLMainThread` instance
|
||||||
pub fn start(
|
/// that can be used to process any outstanding WebGL messages at any given
|
||||||
gl_factory: GLContextFactory,
|
/// point in time.
|
||||||
webrender_api_sender: webrender_api::RenderApiSender,
|
pub(crate) fn run_on_current_thread(
|
||||||
webvr_compositor: Option<VR>,
|
mut init: WebGLThreadInit,
|
||||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
event_loop_waker: Box<dyn EventLoopWaker>,
|
||||||
) -> WebGLSender<WebGLMsg> {
|
textures: TexturesMap,
|
||||||
let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
|
) -> WebGLMainThread {
|
||||||
let result = sender.clone();
|
if let WebGLReceiver::Ipc(ref mut receiver) = init.receiver {
|
||||||
thread::Builder::new()
|
// Interpose a new channel in between the existing WebGL channel endpoints.
|
||||||
.name("WebGLThread".to_owned())
|
// This will bounce all WebGL messages through the router thread adding a small
|
||||||
.spawn(move || {
|
// delay, but this will also ensure that the main thread will wake up and
|
||||||
let mut renderer = WebGLThread::new(
|
// process the WebGL message when it arrives.
|
||||||
gl_factory,
|
let (from_router_sender, from_router_receiver) = ipc::channel::<WebGLMsg>().unwrap();
|
||||||
webrender_api_sender,
|
let old_receiver = mem::replace(receiver, from_router_receiver);
|
||||||
webvr_compositor,
|
ROUTER.add_route(
|
||||||
external_images,
|
old_receiver.to_opaque(),
|
||||||
|
Box::new(move |msg: OpaqueIpcMessage| {
|
||||||
|
let _ = from_router_sender.send(msg.to().unwrap());
|
||||||
|
event_loop_waker.wake();
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
let webgl_chan = WebGLChan(sender);
|
}
|
||||||
loop {
|
|
||||||
let msg = receiver.recv().unwrap();
|
WebGLMainThread {
|
||||||
let exit = renderer.handle_msg(msg, &webgl_chan);
|
thread_data: WebGLThread::new(init),
|
||||||
if exit {
|
textures,
|
||||||
return;
|
shut_down: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform all initialization required to run an instance of WebGLThread
|
||||||
|
/// in parallel on its own dedicated thread.
|
||||||
|
pub(crate) fn run_on_own_thread(init: WebGLThreadInit) {
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("WebGL thread".to_owned())
|
||||||
|
.spawn(move || {
|
||||||
|
let mut data = WebGLThread::new(init);
|
||||||
|
data.process(EventLoop::Blocking, None);
|
||||||
})
|
})
|
||||||
.expect("Thread spawning failed");
|
.expect("Thread spawning failed");
|
||||||
|
}
|
||||||
|
|
||||||
result
|
fn process(&mut self, loop_type: EventLoop, textures: Option<TexturesMap>) -> bool {
|
||||||
|
let webgl_chan = WebGLChan(self.sender.clone());
|
||||||
|
while let Ok(msg) = match loop_type {
|
||||||
|
EventLoop::Blocking => self.receiver.recv(),
|
||||||
|
EventLoop::Nonblocking => self.receiver.try_recv(),
|
||||||
|
} {
|
||||||
|
let exit = self.handle_msg(msg, &webgl_chan, textures.as_ref());
|
||||||
|
if exit {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a generic WebGLMsg message
|
/// Handles a generic WebGLMsg message
|
||||||
#[inline]
|
fn handle_msg(
|
||||||
fn handle_msg(&mut self, msg: WebGLMsg, webgl_chan: &WebGLChan) -> bool {
|
&mut self,
|
||||||
|
msg: WebGLMsg,
|
||||||
|
webgl_chan: &WebGLChan,
|
||||||
|
textures: Option<&TexturesMap>,
|
||||||
|
) -> bool {
|
||||||
trace!("processing {:?}", msg);
|
trace!("processing {:?}", msg);
|
||||||
match msg {
|
match msg {
|
||||||
WebGLMsg::CreateContext(version, size, attributes, result_sender) => {
|
WebGLMsg::CreateContext(version, size, attributes, result_sender) => {
|
||||||
let result = self.create_webgl_context(version, size, attributes);
|
let result = self.create_webgl_context(version, size, attributes, textures);
|
||||||
result_sender
|
result_sender
|
||||||
.send(result.map(|(id, limits, share_mode)| {
|
.send(result.map(|(id, limits, share_mode)| {
|
||||||
let data = Self::make_current_if_needed(
|
let data = Self::make_current_if_needed(
|
||||||
|
@ -173,10 +264,10 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
WebGLMsg::ResizeContext(ctx_id, size, sender) => {
|
WebGLMsg::ResizeContext(ctx_id, size, sender) => {
|
||||||
self.resize_webgl_context(ctx_id, size, sender);
|
self.resize_webgl_context(ctx_id, size, sender, textures);
|
||||||
},
|
},
|
||||||
WebGLMsg::RemoveContext(ctx_id) => {
|
WebGLMsg::RemoveContext(ctx_id) => {
|
||||||
self.remove_webgl_context(ctx_id);
|
self.remove_webgl_context(ctx_id, textures);
|
||||||
},
|
},
|
||||||
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
||||||
self.handle_webgl_command(ctx_id, command, backtrace);
|
self.handle_webgl_command(ctx_id, command, backtrace);
|
||||||
|
@ -296,6 +387,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
version: WebGLVersion,
|
version: WebGLVersion,
|
||||||
size: Size2D<u32>,
|
size: Size2D<u32>,
|
||||||
attributes: GLContextAttributes,
|
attributes: GLContextAttributes,
|
||||||
|
textures: Option<&TexturesMap>,
|
||||||
) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> {
|
) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> {
|
||||||
// Creating a new GLContext may make the current bound context_id dirty.
|
// Creating a new GLContext may make the current bound context_id dirty.
|
||||||
// Clear it to ensure that make_current() is called in subsequent commands.
|
// Clear it to ensure that make_current() is called in subsequent commands.
|
||||||
|
@ -332,6 +424,11 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(ref textures) = textures {
|
||||||
|
textures.borrow_mut().insert(id, (texture_id, size));
|
||||||
|
}
|
||||||
|
|
||||||
self.cached_context_info.insert(
|
self.cached_context_info.insert(
|
||||||
id,
|
id,
|
||||||
WebGLContextInfo {
|
WebGLContextInfo {
|
||||||
|
@ -354,6 +451,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
context_id: WebGLContextId,
|
context_id: WebGLContextId,
|
||||||
size: Size2D<u32>,
|
size: Size2D<u32>,
|
||||||
sender: WebGLSender<Result<(), String>>,
|
sender: WebGLSender<Result<(), String>>,
|
||||||
|
textures: Option<&TexturesMap>,
|
||||||
) {
|
) {
|
||||||
let data = Self::make_current_if_needed_mut(
|
let data = Self::make_current_if_needed_mut(
|
||||||
context_id,
|
context_id,
|
||||||
|
@ -378,6 +476,13 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
// Update webgl texture size. Texture id may change too.
|
// Update webgl texture size. Texture id may change too.
|
||||||
info.texture_id = texture_id;
|
info.texture_id = texture_id;
|
||||||
info.size = real_size;
|
info.size = real_size;
|
||||||
|
|
||||||
|
if let Some(ref textures) = textures {
|
||||||
|
textures
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(context_id, (texture_id, real_size));
|
||||||
|
}
|
||||||
|
|
||||||
// Update WR image if needed. Resize image updates are only required for SharedTexture mode.
|
// Update WR image if needed. Resize image updates are only required for SharedTexture mode.
|
||||||
// Readback mode already updates the image every frame to send the raw pixels.
|
// Readback mode already updates the image every frame to send the raw pixels.
|
||||||
// See `handle_update_wr_image`.
|
// See `handle_update_wr_image`.
|
||||||
|
@ -403,7 +508,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a WebGLContext and releases attached resources.
|
/// Removes a WebGLContext and releases attached resources.
|
||||||
fn remove_webgl_context(&mut self, context_id: WebGLContextId) {
|
fn remove_webgl_context(&mut self, context_id: WebGLContextId, textures: Option<&TexturesMap>) {
|
||||||
// Release webrender image keys.
|
// Release webrender image keys.
|
||||||
if let Some(info) = self.cached_context_info.remove(&context_id) {
|
if let Some(info) = self.cached_context_info.remove(&context_id) {
|
||||||
let mut txn = webrender_api::Transaction::new();
|
let mut txn = webrender_api::Transaction::new();
|
||||||
|
@ -422,6 +527,10 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
// Release GL context.
|
// Release GL context.
|
||||||
self.contexts.remove(&context_id);
|
self.contexts.remove(&context_id);
|
||||||
|
|
||||||
|
if let Some(ref textures) = textures {
|
||||||
|
textures.borrow_mut().remove(&context_id);
|
||||||
|
}
|
||||||
|
|
||||||
// Removing a GLContext may make the current bound context_id dirty.
|
// Removing a GLContext may make the current bound context_id dirty.
|
||||||
self.bound_context_id = None;
|
self.bound_context_id = None;
|
||||||
}
|
}
|
||||||
|
@ -729,12 +838,12 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<VR: WebVRRenderHandler + 'static> Drop for WebGLThread<VR> {
|
impl Drop for WebGLThread {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Call remove_context functions in order to correctly delete WebRender image keys.
|
// Call remove_context functions in order to correctly delete WebRender image keys.
|
||||||
let context_ids: Vec<WebGLContextId> = self.contexts.keys().map(|id| *id).collect();
|
let context_ids: Vec<WebGLContextId> = self.contexts.keys().map(|id| *id).collect();
|
||||||
for id in context_ids {
|
for id in context_ids {
|
||||||
self.remove_webgl_context(id);
|
self.remove_webgl_context(id, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,13 @@ where
|
||||||
WebGLReceiver::Mpsc(ref receiver) => receiver.recv().map_err(|_| ()),
|
WebGLReceiver::Mpsc(ref receiver) => receiver.recv().map_err(|_| ()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_recv(&self) -> Result<T, ()> {
|
||||||
|
match *self {
|
||||||
|
WebGLReceiver::Ipc(ref receiver) => receiver.try_recv().map_err(|_| ()),
|
||||||
|
WebGLReceiver::Mpsc(ref receiver) => receiver.try_recv().map_err(|_| ()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()>
|
pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()>
|
||||||
|
|
|
@ -47,6 +47,10 @@ impl<T> WebGLReceiver<T> {
|
||||||
pub fn recv(&self) -> Result<T, mpsc::RecvError> {
|
pub fn recv(&self) -> Result<T, mpsc::RecvError> {
|
||||||
self.0.recv()
|
self.0.recv()
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
|
||||||
|
self.0.try_recv()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()> {
|
pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()> {
|
||||||
|
|
|
@ -112,7 +112,7 @@ use compositing::compositor_thread::Msg as ToCompositorMsg;
|
||||||
use compositing::SendableFrameTree;
|
use compositing::SendableFrameTree;
|
||||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||||
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
|
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
|
||||||
use embedder_traits::{Cursor, EmbedderMsg, EmbedderProxy};
|
use embedder_traits::{Cursor, EmbedderMsg, EmbedderProxy, EventLoopWaker};
|
||||||
use euclid::{default::Size2D as UntypedSize2D, Scale, Size2D};
|
use euclid::{default::Size2D as UntypedSize2D, Scale, Size2D};
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use gfx_traits::Epoch;
|
use gfx_traits::Epoch;
|
||||||
|
@ -416,6 +416,9 @@ pub struct Constellation<Message, LTF, STF> {
|
||||||
|
|
||||||
/// Application window's GL Context for Media player
|
/// Application window's GL Context for Media player
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
|
|
||||||
|
/// Mechanism to force the compositor to process events.
|
||||||
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State needed to construct a constellation.
|
/// State needed to construct a constellation.
|
||||||
|
@ -469,6 +472,9 @@ pub struct InitialConstellationState {
|
||||||
|
|
||||||
/// Application window's GL Context for Media player
|
/// Application window's GL Context for Media player
|
||||||
pub player_context: WindowGLContext,
|
pub player_context: WindowGLContext,
|
||||||
|
|
||||||
|
/// Mechanism to force the compositor to process events.
|
||||||
|
pub event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data needed for webdriver
|
/// Data needed for webdriver
|
||||||
|
@ -767,6 +773,7 @@ where
|
||||||
enable_canvas_antialiasing,
|
enable_canvas_antialiasing,
|
||||||
glplayer_threads: state.glplayer_threads,
|
glplayer_threads: state.glplayer_threads,
|
||||||
player_context: state.player_context,
|
player_context: state.player_context,
|
||||||
|
event_loop_waker: state.event_loop_waker,
|
||||||
};
|
};
|
||||||
|
|
||||||
constellation.run();
|
constellation.run();
|
||||||
|
@ -1009,6 +1016,7 @@ where
|
||||||
webvr_chan: self.webvr_chan.clone(),
|
webvr_chan: self.webvr_chan.clone(),
|
||||||
webxr_registry: self.webxr_registry.clone(),
|
webxr_registry: self.webxr_registry.clone(),
|
||||||
player_context: self.player_context.clone(),
|
player_context: self.player_context.clone(),
|
||||||
|
event_loop_waker: self.event_loop_waker.as_ref().map(|w| (*w).clone_box()),
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipeline = match result {
|
let pipeline = match result {
|
||||||
|
|
|
@ -11,6 +11,7 @@ use compositing::CompositionPipeline;
|
||||||
use compositing::CompositorProxy;
|
use compositing::CompositorProxy;
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
|
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
|
||||||
|
use embedder_traits::EventLoopWaker;
|
||||||
use euclid::{Scale, Size2D};
|
use euclid::{Scale, Size2D};
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
|
@ -195,6 +196,9 @@ pub struct InitialPipelineState {
|
||||||
|
|
||||||
/// Application window's GL Context for Media player
|
/// Application window's GL Context for Media player
|
||||||
pub player_context: WindowGLContext,
|
pub player_context: WindowGLContext,
|
||||||
|
|
||||||
|
/// Mechanism to force the compositor to process events.
|
||||||
|
pub event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NewPipeline {
|
pub struct NewPipeline {
|
||||||
|
@ -327,7 +331,11 @@ impl Pipeline {
|
||||||
let register = state
|
let register = state
|
||||||
.background_monitor_register
|
.background_monitor_register
|
||||||
.expect("Couldn't start content, no background monitor has been initiated");
|
.expect("Couldn't start content, no background monitor has been initiated");
|
||||||
unprivileged_pipeline_content.start_all::<Message, LTF, STF>(false, register);
|
unprivileged_pipeline_content.start_all::<Message, LTF, STF>(
|
||||||
|
false,
|
||||||
|
register,
|
||||||
|
state.event_loop_waker,
|
||||||
|
);
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -524,6 +532,7 @@ impl UnprivilegedPipelineContent {
|
||||||
self,
|
self,
|
||||||
wait_for_completion: bool,
|
wait_for_completion: bool,
|
||||||
background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
|
background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
|
||||||
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
) where
|
) where
|
||||||
LTF: LayoutThreadFactory<Message = Message>,
|
LTF: LayoutThreadFactory<Message = Message>,
|
||||||
STF: ScriptThreadFactory<Message = Message>,
|
STF: ScriptThreadFactory<Message = Message>,
|
||||||
|
@ -566,6 +575,7 @@ impl UnprivilegedPipelineContent {
|
||||||
webrender_api_sender: self.webrender_api_sender.clone(),
|
webrender_api_sender: self.webrender_api_sender.clone(),
|
||||||
layout_is_busy: layout_thread_busy_flag.clone(),
|
layout_is_busy: layout_thread_busy_flag.clone(),
|
||||||
player_context: self.player_context.clone(),
|
player_context: self.player_context.clone(),
|
||||||
|
event_loop_waker,
|
||||||
},
|
},
|
||||||
self.load_data.clone(),
|
self.load_data.clone(),
|
||||||
self.opts.profile_script_events,
|
self.opts.profile_script_events,
|
||||||
|
|
|
@ -54,6 +54,7 @@ use canvas_traits::webgl::{WebGLShaderId, WebGLTextureId, WebGLVersion, WebGLVer
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use cssparser::RGBA;
|
use cssparser::RGBA;
|
||||||
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
|
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
|
||||||
|
use embedder_traits::EventLoopWaker;
|
||||||
use encoding_rs::{Decoder, Encoding};
|
use encoding_rs::{Decoder, Encoding};
|
||||||
use euclid::default::{Point2D, Rect, Rotation3D, Transform2D, Transform3D};
|
use euclid::default::{Point2D, Rect, Rotation3D, Transform2D, Transform3D};
|
||||||
use euclid::Length as EuclidLength;
|
use euclid::Length as EuclidLength;
|
||||||
|
@ -146,7 +147,7 @@ pub unsafe trait JSTraceable {
|
||||||
unsafe fn trace(&self, trc: *mut JSTracer);
|
unsafe fn trace(&self, trc: *mut JSTracer);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(Box<dyn TaskBox>);
|
unsafe_no_jsmanaged_fields!(Box<dyn TaskBox>, Box<dyn EventLoopWaker>);
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(CSSError);
|
unsafe_no_jsmanaged_fields!(CSSError);
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,11 @@ use crate::dom::vreyeparameters::VREyeParameters;
|
||||||
use crate::dom::vrframedata::VRFrameData;
|
use crate::dom::vrframedata::VRFrameData;
|
||||||
use crate::dom::vrpose::VRPose;
|
use crate::dom::vrpose::VRPose;
|
||||||
use crate::dom::vrstageparameters::VRStageParameters;
|
use crate::dom::vrstageparameters::VRStageParameters;
|
||||||
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
use crate::dom::webglrenderingcontext::{WebGLMessageSender, WebGLRenderingContext};
|
||||||
use crate::script_runtime::CommonScriptMsg;
|
use crate::script_runtime::CommonScriptMsg;
|
||||||
use crate::script_runtime::ScriptThreadEventCategory::WebVREvent;
|
use crate::script_runtime::ScriptThreadEventCategory::WebVREvent;
|
||||||
use crate::task_source::{TaskSource, TaskSourceName};
|
use crate::task_source::{TaskSource, TaskSourceName};
|
||||||
use canvas_traits::webgl::{webgl_channel, WebGLMsgSender, WebGLReceiver, WebVRCommand};
|
use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand};
|
||||||
use crossbeam_channel::{unbounded, Sender};
|
use crossbeam_channel::{unbounded, Sender};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
@ -102,7 +102,7 @@ struct VRRAFUpdate {
|
||||||
depth_near: f64,
|
depth_near: f64,
|
||||||
depth_far: f64,
|
depth_far: f64,
|
||||||
/// WebGL API sender
|
/// WebGL API sender
|
||||||
api_sender: Option<WebGLMsgSender>,
|
api_sender: Option<WebGLMessageSender>,
|
||||||
/// Number uniquely identifying the WebGL context
|
/// Number uniquely identifying the WebGL context
|
||||||
/// so that we may setup/tear down VR compositors as things change
|
/// so that we may setup/tear down VR compositors as things change
|
||||||
context_id: usize,
|
context_id: usize,
|
||||||
|
@ -583,7 +583,7 @@ impl VRDisplay {
|
||||||
.fire(self.global().upcast::<EventTarget>());
|
.fire(self.global().upcast::<EventTarget>());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn api_sender(&self) -> Option<WebGLMsgSender> {
|
fn api_sender(&self) -> Option<WebGLMessageSender> {
|
||||||
self.layer_ctx.get().map(|c| c.webgl_sender())
|
self.layer_ctx.get().map(|c| c.webgl_sender())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,12 +54,13 @@ use backtrace::Backtrace;
|
||||||
use canvas_traits::webgl::WebGLError::*;
|
use canvas_traits::webgl::WebGLError::*;
|
||||||
use canvas_traits::webgl::{
|
use canvas_traits::webgl::{
|
||||||
webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLLimits, GlType,
|
webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLLimits, GlType,
|
||||||
Parameter, TexDataType, TexFormat, TexParameter, WebGLCommand, WebGLCommandBacktrace,
|
Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand,
|
||||||
WebGLContextShareMode, WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender,
|
WebGLCommandBacktrace, WebGLContextId, WebGLContextShareMode, WebGLError,
|
||||||
WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender, WebGLVersion, WebVRCommand,
|
WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult,
|
||||||
YAxisTreatment,
|
WebGLSLVersion, WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment,
|
||||||
};
|
};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use embedder_traits::EventLoopWaker;
|
||||||
use euclid::default::{Point2D, Rect, Size2D};
|
use euclid::default::{Point2D, Rect, Size2D};
|
||||||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||||
use js::jsapi::{JSContext, JSObject, Type};
|
use js::jsapi::{JSContext, JSObject, Type};
|
||||||
|
@ -79,6 +80,7 @@ use std::cell::Cell;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use webrender_api::ImageKey;
|
||||||
|
|
||||||
// From the GLES 2.0.25 spec, page 85:
|
// From the GLES 2.0.25 spec, page 85:
|
||||||
//
|
//
|
||||||
|
@ -135,7 +137,7 @@ bitflags! {
|
||||||
pub struct WebGLRenderingContext {
|
pub struct WebGLRenderingContext {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
#[ignore_malloc_size_of = "Channels are hard"]
|
#[ignore_malloc_size_of = "Channels are hard"]
|
||||||
webgl_sender: WebGLMsgSender,
|
webgl_sender: WebGLMessageSender,
|
||||||
#[ignore_malloc_size_of = "Defined in webrender"]
|
#[ignore_malloc_size_of = "Defined in webrender"]
|
||||||
webrender_image: Cell<Option<webrender_api::ImageKey>>,
|
webrender_image: Cell<Option<webrender_api::ImageKey>>,
|
||||||
share_mode: WebGLContextShareMode,
|
share_mode: WebGLContextShareMode,
|
||||||
|
@ -197,7 +199,10 @@ impl WebGLRenderingContext {
|
||||||
let max_combined_texture_image_units = ctx_data.limits.max_combined_texture_image_units;
|
let max_combined_texture_image_units = ctx_data.limits.max_combined_texture_image_units;
|
||||||
Self {
|
Self {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
webgl_sender: ctx_data.sender,
|
webgl_sender: WebGLMessageSender::new(
|
||||||
|
ctx_data.sender,
|
||||||
|
window.get_event_loop_waker(),
|
||||||
|
),
|
||||||
webrender_image: Cell::new(None),
|
webrender_image: Cell::new(None),
|
||||||
share_mode: ctx_data.share_mode,
|
share_mode: ctx_data.share_mode,
|
||||||
webgl_version,
|
webgl_version,
|
||||||
|
@ -319,7 +324,7 @@ impl WebGLRenderingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webgl_sender(&self) -> WebGLMsgSender {
|
pub(crate) fn webgl_sender(&self) -> WebGLMessageSender {
|
||||||
self.webgl_sender.clone()
|
self.webgl_sender.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4288,3 +4293,92 @@ impl TexPixels {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(JSTraceable)]
|
||||||
|
pub(crate) struct WebGLCommandSender {
|
||||||
|
sender: WebGLChan,
|
||||||
|
waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebGLCommandSender {
|
||||||
|
pub fn new(sender: WebGLChan, waker: Option<Box<dyn EventLoopWaker>>) -> WebGLCommandSender {
|
||||||
|
WebGLCommandSender { sender, waker }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self, msg: WebGLMsg) -> WebGLSendResult {
|
||||||
|
let result = self.sender.send(msg);
|
||||||
|
if let Some(ref waker) = self.waker {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
pub(crate) struct WebGLMessageSender {
|
||||||
|
sender: WebGLMsgSender,
|
||||||
|
#[ignore_malloc_size_of = "traits are cumbersome"]
|
||||||
|
waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for WebGLMessageSender {
|
||||||
|
fn clone(&self) -> WebGLMessageSender {
|
||||||
|
WebGLMessageSender {
|
||||||
|
sender: self.sender.clone(),
|
||||||
|
waker: self.waker.as_ref().map(|w| (*w).clone_box()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebGLMessageSender {
|
||||||
|
fn wake_after_send<F: FnOnce() -> WebGLSendResult>(&self, f: F) -> WebGLSendResult {
|
||||||
|
let result = f();
|
||||||
|
if let Some(ref waker) = self.waker {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
sender: WebGLMsgSender,
|
||||||
|
waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
|
) -> WebGLMessageSender {
|
||||||
|
WebGLMessageSender { sender, waker }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn context_id(&self) -> WebGLContextId {
|
||||||
|
self.sender.context_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self, msg: WebGLCommand, backtrace: WebGLCommandBacktrace) -> WebGLSendResult {
|
||||||
|
self.wake_after_send(|| self.sender.send(msg, backtrace))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_vr(&self, command: WebVRCommand) -> WebGLSendResult {
|
||||||
|
self.wake_after_send(|| self.sender.send_vr(command))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_resize(
|
||||||
|
&self,
|
||||||
|
size: Size2D<u32>,
|
||||||
|
sender: WebGLSender<Result<(), String>>,
|
||||||
|
) -> WebGLSendResult {
|
||||||
|
self.wake_after_send(|| self.sender.send_resize(size, sender))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_remove(&self) -> WebGLSendResult {
|
||||||
|
self.wake_after_send(|| self.sender.send_remove())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_update_wr_image(&self, sender: WebGLSender<ImageKey>) -> WebGLSendResult {
|
||||||
|
self.wake_after_send(|| self.sender.send_update_wr_image(sender))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult {
|
||||||
|
self.wake_after_send(|| self.sender.send_dom_to_texture(command))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn webxr_external_image_api(&self) -> impl webxr_api::WebGLExternalImageApi {
|
||||||
|
self.sender.webxr_external_image_api()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ use crate::dom::promise::Promise;
|
||||||
use crate::dom::screen::Screen;
|
use crate::dom::screen::Screen;
|
||||||
use crate::dom::storage::Storage;
|
use crate::dom::storage::Storage;
|
||||||
use crate::dom::testrunner::TestRunner;
|
use crate::dom::testrunner::TestRunner;
|
||||||
|
use crate::dom::webglrenderingcontext::WebGLCommandSender;
|
||||||
use crate::dom::windowproxy::WindowProxy;
|
use crate::dom::windowproxy::WindowProxy;
|
||||||
use crate::dom::worklet::Worklet;
|
use crate::dom::worklet::Worklet;
|
||||||
use crate::dom::workletglobalscope::WorkletGlobalScopeType;
|
use crate::dom::workletglobalscope::WorkletGlobalScopeType;
|
||||||
|
@ -73,7 +74,7 @@ use crossbeam_channel::{unbounded, Sender, TryRecvError};
|
||||||
use cssparser::{Parser, ParserInput, SourceLocation};
|
use cssparser::{Parser, ParserInput, SourceLocation};
|
||||||
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use embedder_traits::EmbedderMsg;
|
use embedder_traits::{EmbedderMsg, EventLoopWaker};
|
||||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
||||||
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
|
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
|
||||||
use ipc_channel::ipc::{channel, IpcSender};
|
use ipc_channel::ipc::{channel, IpcSender};
|
||||||
|
@ -326,6 +327,10 @@ pub struct Window {
|
||||||
/// Window's GL context from application
|
/// Window's GL context from application
|
||||||
#[ignore_malloc_size_of = "defined in script_thread"]
|
#[ignore_malloc_size_of = "defined in script_thread"]
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
|
|
||||||
|
/// A mechanism to force the compositor to process events.
|
||||||
|
#[ignore_malloc_size_of = "traits are cumbersome"]
|
||||||
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
@ -432,8 +437,10 @@ impl Window {
|
||||||
self.current_viewport.clone().get()
|
self.current_viewport.clone().get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webgl_chan(&self) -> Option<WebGLChan> {
|
pub(crate) fn webgl_chan(&self) -> Option<WebGLCommandSender> {
|
||||||
self.webgl_chan.clone()
|
self.webgl_chan
|
||||||
|
.as_ref()
|
||||||
|
.map(|chan| WebGLCommandSender::new(chan.clone(), self.get_event_loop_waker()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
|
pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
|
||||||
|
@ -498,6 +505,10 @@ impl Window {
|
||||||
pub fn get_player_context(&self) -> WindowGLContext {
|
pub fn get_player_context(&self) -> WindowGLContext {
|
||||||
self.player_context.clone()
|
self.player_context.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_event_loop_waker(&self) -> Option<Box<dyn EventLoopWaker>> {
|
||||||
|
self.event_loop_waker.as_ref().map(|w| (*w).clone_box())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#atob
|
// https://html.spec.whatwg.org/multipage/#atob
|
||||||
|
@ -2087,6 +2098,7 @@ impl Window {
|
||||||
replace_surrogates: bool,
|
replace_surrogates: bool,
|
||||||
user_agent: Cow<'static, str>,
|
user_agent: Cow<'static, str>,
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
let layout_rpc: Box<dyn LayoutRPC + Send> = {
|
let layout_rpc: Box<dyn LayoutRPC + Send> = {
|
||||||
let (rpc_send, rpc_recv) = unbounded();
|
let (rpc_send, rpc_recv) = unbounded();
|
||||||
|
@ -2169,6 +2181,7 @@ impl Window {
|
||||||
userscripts_path,
|
userscripts_path,
|
||||||
replace_surrogates,
|
replace_surrogates,
|
||||||
player_context,
|
player_context,
|
||||||
|
event_loop_waker,
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
||||||
|
|
|
@ -93,7 +93,7 @@ use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||||
use devtools_traits::CSSError;
|
use devtools_traits::CSSError;
|
||||||
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
|
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
|
||||||
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
|
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
|
||||||
use embedder_traits::EmbedderMsg;
|
use embedder_traits::{EmbedderMsg, EventLoopWaker};
|
||||||
use euclid::default::{Point2D, Rect};
|
use euclid::default::{Point2D, Rect};
|
||||||
use euclid::Vector2D;
|
use euclid::Vector2D;
|
||||||
use headers::ReferrerPolicy as ReferrerPolicyHeader;
|
use headers::ReferrerPolicy as ReferrerPolicyHeader;
|
||||||
|
@ -684,6 +684,9 @@ pub struct ScriptThread {
|
||||||
|
|
||||||
/// Application window's GL Context for Media player
|
/// Application window's GL Context for Media player
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
|
|
||||||
|
/// A mechanism to force the compositor's event loop to process events.
|
||||||
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In the event of thread panic, all data on the stack runs its destructor. However, there
|
/// In the event of thread panic, all data on the stack runs its destructor. However, there
|
||||||
|
@ -1314,6 +1317,7 @@ impl ScriptThread {
|
||||||
replace_surrogates,
|
replace_surrogates,
|
||||||
user_agent,
|
user_agent,
|
||||||
player_context: state.player_context,
|
player_context: state.player_context,
|
||||||
|
event_loop_waker: state.event_loop_waker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3142,6 +3146,7 @@ impl ScriptThread {
|
||||||
self.replace_surrogates,
|
self.replace_surrogates,
|
||||||
self.user_agent.clone(),
|
self.user_agent.clone(),
|
||||||
self.player_context.clone(),
|
self.player_context.clone(),
|
||||||
|
self.event_loop_waker.as_ref().map(|w| (*w).clone_box()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize the browsing context for the window.
|
// Initialize the browsing context for the window.
|
||||||
|
|
|
@ -24,7 +24,7 @@ use bluetooth_traits::BluetoothRequest;
|
||||||
use canvas_traits::webgl::WebGLPipeline;
|
use canvas_traits::webgl::WebGLPipeline;
|
||||||
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
||||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::{Cursor, EventLoopWaker};
|
||||||
use euclid::{
|
use euclid::{
|
||||||
default::{Point2D, Rect},
|
default::{Point2D, Rect},
|
||||||
Length, Scale, Size2D, Vector2D,
|
Length, Scale, Size2D, Vector2D,
|
||||||
|
@ -666,6 +666,8 @@ pub struct InitialScriptState {
|
||||||
pub layout_is_busy: Arc<AtomicBool>,
|
pub layout_is_busy: Arc<AtomicBool>,
|
||||||
/// Application window's GL Context for Media player
|
/// Application window's GL Context for Media player
|
||||||
pub player_context: WindowGLContext,
|
pub player_context: WindowGLContext,
|
||||||
|
/// Mechanism to force the compositor to process events.
|
||||||
|
pub event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait allows creating a `ScriptThread` without depending on the `script`
|
/// This trait allows creating a `ScriptThread` without depending on the `script`
|
||||||
|
|
|
@ -60,9 +60,9 @@ layout_thread_2020 = {path = "../layout_thread_2020", optional = true}
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
media = {path = "../media"}
|
media = {path = "../media"}
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
offscreen_gl_context = "0.23"
|
|
||||||
net = {path = "../net"}
|
net = {path = "../net"}
|
||||||
net_traits = {path = "../net_traits"}
|
net_traits = {path = "../net_traits"}
|
||||||
|
offscreen_gl_context = "0.23"
|
||||||
profile = {path = "../profile"}
|
profile = {path = "../profile"}
|
||||||
profile_traits = {path = "../profile_traits"}
|
profile_traits = {path = "../profile_traits"}
|
||||||
script = {path = "../script"}
|
script = {path = "../script"}
|
||||||
|
|
|
@ -65,7 +65,7 @@ fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) {}
|
||||||
use bluetooth::BluetoothThreadFactory;
|
use bluetooth::BluetoothThreadFactory;
|
||||||
use bluetooth_traits::BluetoothRequest;
|
use bluetooth_traits::BluetoothRequest;
|
||||||
use canvas::gl_context::{CloneableDispatcher, GLContextFactory};
|
use canvas::gl_context::{CloneableDispatcher, GLContextFactory};
|
||||||
use canvas::webgl_thread::WebGLThreads;
|
use canvas::webgl_thread::{ThreadMode, WebGLMainThread, WebGLThreads};
|
||||||
use compositing::compositor_thread::{
|
use compositing::compositor_thread::{
|
||||||
CompositorProxy, CompositorReceiver, InitialCompositorState, Msg,
|
CompositorProxy, CompositorReceiver, InitialCompositorState, Msg,
|
||||||
};
|
};
|
||||||
|
@ -117,6 +117,7 @@ use std::rc::Rc;
|
||||||
use webrender::{RendererKind, ShaderPrecacheFlags};
|
use webrender::{RendererKind, ShaderPrecacheFlags};
|
||||||
use webrender_traits::{WebrenderExternalImageHandlers, WebrenderImageHandlerType};
|
use webrender_traits::{WebrenderExternalImageHandlers, WebrenderImageHandlerType};
|
||||||
use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread};
|
use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread};
|
||||||
|
use webvr_traits::WebVRMsg;
|
||||||
|
|
||||||
pub use gleam::gl;
|
pub use gleam::gl;
|
||||||
pub use keyboard_types;
|
pub use keyboard_types;
|
||||||
|
@ -226,6 +227,7 @@ pub struct Servo<Window: WindowMethods + 'static + ?Sized> {
|
||||||
embedder_receiver: EmbedderReceiver,
|
embedder_receiver: EmbedderReceiver,
|
||||||
embedder_events: Vec<(Option<BrowserId>, EmbedderMsg)>,
|
embedder_events: Vec<(Option<BrowserId>, EmbedderMsg)>,
|
||||||
profiler_enabled: bool,
|
profiler_enabled: bool,
|
||||||
|
webgl_thread_data: Option<WebGLMainThread>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -384,11 +386,93 @@ where
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (webvr_chan, webvr_constellation_sender, webvr_compositor) =
|
||||||
|
if let Some(services) = webvr_services {
|
||||||
|
// WebVR initialization
|
||||||
|
let (mut handler, sender) = WebVRCompositorHandler::new();
|
||||||
|
let (webvr_thread, constellation_sender) = WebVRThread::spawn(sender, services);
|
||||||
|
handler.set_webvr_thread_sender(webvr_thread.clone());
|
||||||
|
(
|
||||||
|
Some(webvr_thread),
|
||||||
|
Some(constellation_sender),
|
||||||
|
Some(handler),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
// GLContext factory used to create WebGL Contexts
|
||||||
|
let gl_factory = if opts.should_use_osmesa() {
|
||||||
|
GLContextFactory::current_osmesa_handle()
|
||||||
|
} else {
|
||||||
|
let dispatcher =
|
||||||
|
Box::new(MainThreadDispatcher::new(compositor_proxy.clone())) as Box<_>;
|
||||||
|
GLContextFactory::current_native_handle(dispatcher, window.gl().get_type())
|
||||||
|
};
|
||||||
|
|
||||||
|
let (external_image_handlers, external_images) = WebrenderExternalImageHandlers::new();
|
||||||
|
let mut external_image_handlers = Box::new(external_image_handlers);
|
||||||
|
|
||||||
|
let run_webgl_on_main_thread =
|
||||||
|
cfg!(windows) || std::env::var("SERVO_WEBGL_MAIN_THREAD").is_ok();
|
||||||
|
|
||||||
|
// Initialize WebGL Thread entry point.
|
||||||
|
let webgl_result = gl_factory.map(|factory| {
|
||||||
|
let (webgl_threads, thread_data, image_handler, output_handler) = WebGLThreads::new(
|
||||||
|
factory,
|
||||||
|
webrender_api_sender.clone(),
|
||||||
|
webvr_compositor.map(|c| c as Box<_>),
|
||||||
|
external_images.clone(),
|
||||||
|
if run_webgl_on_main_thread {
|
||||||
|
ThreadMode::MainThread(embedder.create_event_loop_waker())
|
||||||
|
} else {
|
||||||
|
ThreadMode::OffThread(window.gl())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set webrender external image handler for WebGL textures
|
||||||
|
external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
|
||||||
|
|
||||||
|
// Set DOM to texture handler, if enabled.
|
||||||
|
if let Some(output_handler) = output_handler {
|
||||||
|
webrender.set_output_image_handler(output_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
(webgl_threads, thread_data)
|
||||||
|
});
|
||||||
|
let (webgl_threads, webgl_thread_data) = match webgl_result {
|
||||||
|
Some((a, b)) => (Some(a), b),
|
||||||
|
None => (None, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let glplayer_threads = match window.get_gl_context() {
|
||||||
|
GlContext::Unknown => None,
|
||||||
|
_ => {
|
||||||
|
let (glplayer_threads, image_handler) = GLPlayerThreads::new(external_images);
|
||||||
|
external_image_handlers
|
||||||
|
.set_handler(image_handler, WebrenderImageHandlerType::Media);
|
||||||
|
Some(glplayer_threads)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let player_context = WindowGLContext {
|
let player_context = WindowGLContext {
|
||||||
gl_context: window.get_gl_context(),
|
gl_context: window.get_gl_context(),
|
||||||
native_display: window.get_native_display(),
|
native_display: window.get_native_display(),
|
||||||
gl_api: window.get_gl_api(),
|
gl_api: window.get_gl_api(),
|
||||||
glplayer_chan: None,
|
glplayer_chan: glplayer_threads.as_ref().map(GLPlayerThreads::pipeline),
|
||||||
|
};
|
||||||
|
|
||||||
|
webrender.set_external_image_handler(external_image_handlers);
|
||||||
|
|
||||||
|
// When webgl execution occurs on the main thread, and the script thread
|
||||||
|
// lives in the same process, then the script thread needs the ability to
|
||||||
|
// wake up the main thread's event loop when webgl commands need processing.
|
||||||
|
// When there are multiple processes, this is handled automatically by
|
||||||
|
// the IPC receiving handler instead.
|
||||||
|
let event_loop_waker = if run_webgl_on_main_thread && !opts.multiprocess {
|
||||||
|
Some(embedder.create_event_loop_waker())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the constellation, which maintains the engine
|
// Create the constellation, which maintains the engine
|
||||||
|
@ -403,13 +487,15 @@ where
|
||||||
mem_profiler_chan.clone(),
|
mem_profiler_chan.clone(),
|
||||||
debugger_chan,
|
debugger_chan,
|
||||||
devtools_chan,
|
devtools_chan,
|
||||||
&mut webrender,
|
|
||||||
webrender_document,
|
webrender_document,
|
||||||
webrender_api_sender,
|
webrender_api_sender,
|
||||||
window.gl(),
|
|
||||||
webvr_services,
|
|
||||||
webxr_main_thread.registry(),
|
webxr_main_thread.registry(),
|
||||||
player_context,
|
player_context,
|
||||||
|
webgl_threads,
|
||||||
|
webvr_chan,
|
||||||
|
webvr_constellation_sender,
|
||||||
|
glplayer_threads,
|
||||||
|
event_loop_waker,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send the constellation's swmanager sender to service worker manager thread
|
// Send the constellation's swmanager sender to service worker manager thread
|
||||||
|
@ -450,6 +536,7 @@ where
|
||||||
embedder_receiver: embedder_receiver,
|
embedder_receiver: embedder_receiver,
|
||||||
embedder_events: Vec::new(),
|
embedder_events: Vec::new(),
|
||||||
profiler_enabled: false,
|
profiler_enabled: false,
|
||||||
|
webgl_thread_data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,6 +728,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_events(&mut self, events: Vec<WindowEvent>) {
|
pub fn handle_events(&mut self, events: Vec<WindowEvent>) {
|
||||||
|
if let Some(ref mut webgl_thread) = self.webgl_thread_data {
|
||||||
|
webgl_thread.process();
|
||||||
|
}
|
||||||
|
|
||||||
if self.compositor.receive_messages() {
|
if self.compositor.receive_messages() {
|
||||||
self.receive_messages();
|
self.receive_messages();
|
||||||
}
|
}
|
||||||
|
@ -715,13 +806,15 @@ fn create_constellation(
|
||||||
mem_profiler_chan: mem::ProfilerChan,
|
mem_profiler_chan: mem::ProfilerChan,
|
||||||
debugger_chan: Option<debugger::Sender>,
|
debugger_chan: Option<debugger::Sender>,
|
||||||
devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
||||||
webrender: &mut webrender::Renderer,
|
|
||||||
webrender_document: webrender_api::DocumentId,
|
webrender_document: webrender_api::DocumentId,
|
||||||
webrender_api_sender: webrender_api::RenderApiSender,
|
webrender_api_sender: webrender_api::RenderApiSender,
|
||||||
window_gl: Rc<dyn gl::Gl>,
|
|
||||||
webvr_services: Option<VRServiceManager>,
|
|
||||||
webxr_registry: webxr_api::Registry,
|
webxr_registry: webxr_api::Registry,
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
|
webgl_threads: Option<WebGLThreads>,
|
||||||
|
webvr_chan: Option<IpcSender<WebVRMsg>>,
|
||||||
|
webvr_constellation_sender: Option<Sender<Sender<ConstellationMsg>>>,
|
||||||
|
glplayer_threads: Option<GLPlayerThreads>,
|
||||||
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
) -> (Sender<ConstellationMsg>, SWManagerSenders) {
|
) -> (Sender<ConstellationMsg>, SWManagerSenders) {
|
||||||
// Global configuration options, parsed from the command line.
|
// Global configuration options, parsed from the command line.
|
||||||
let opts = opts::get();
|
let opts = opts::get();
|
||||||
|
@ -745,69 +838,6 @@ fn create_constellation(
|
||||||
|
|
||||||
let resource_sender = public_resource_threads.sender();
|
let resource_sender = public_resource_threads.sender();
|
||||||
|
|
||||||
let (webvr_chan, webvr_constellation_sender, webvr_compositor) =
|
|
||||||
if let Some(services) = webvr_services {
|
|
||||||
// WebVR initialization
|
|
||||||
let (mut handler, sender) = WebVRCompositorHandler::new();
|
|
||||||
let (webvr_thread, constellation_sender) = WebVRThread::spawn(sender, services);
|
|
||||||
handler.set_webvr_thread_sender(webvr_thread.clone());
|
|
||||||
(
|
|
||||||
Some(webvr_thread),
|
|
||||||
Some(constellation_sender),
|
|
||||||
Some(handler),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(None, None, None)
|
|
||||||
};
|
|
||||||
|
|
||||||
// GLContext factory used to create WebGL Contexts
|
|
||||||
let gl_factory = if opts.should_use_osmesa() {
|
|
||||||
GLContextFactory::current_osmesa_handle()
|
|
||||||
} else {
|
|
||||||
let dispatcher = Box::new(MainThreadDispatcher::new(compositor_proxy.clone())) as Box<_>;
|
|
||||||
GLContextFactory::current_native_handle(dispatcher, window_gl.get_type())
|
|
||||||
};
|
|
||||||
|
|
||||||
let (external_image_handlers, external_images) = WebrenderExternalImageHandlers::new();
|
|
||||||
let mut external_image_handlers = Box::new(external_image_handlers);
|
|
||||||
|
|
||||||
// Initialize WebGL Thread entry point.
|
|
||||||
let webgl_threads = gl_factory.map(|factory| {
|
|
||||||
let (webgl_threads, image_handler, output_handler) = WebGLThreads::new(
|
|
||||||
factory,
|
|
||||||
window_gl,
|
|
||||||
webrender_api_sender.clone(),
|
|
||||||
webvr_compositor.map(|c| c as Box<_>),
|
|
||||||
external_images.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set webrender external image handler for WebGL textures
|
|
||||||
external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
|
|
||||||
|
|
||||||
// Set DOM to texture handler, if enabled.
|
|
||||||
if let Some(output_handler) = output_handler {
|
|
||||||
webrender.set_output_image_handler(output_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
webgl_threads
|
|
||||||
});
|
|
||||||
|
|
||||||
let glplayer_threads = match player_context.gl_context {
|
|
||||||
GlContext::Unknown => None,
|
|
||||||
_ => {
|
|
||||||
let (glplayer_threads, image_handler) = GLPlayerThreads::new(external_images);
|
|
||||||
external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::Media);
|
|
||||||
Some(glplayer_threads)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
webrender.set_external_image_handler(external_image_handlers);
|
|
||||||
|
|
||||||
let player_context = WindowGLContext {
|
|
||||||
glplayer_chan: glplayer_threads.as_ref().map(|threads| threads.pipeline()),
|
|
||||||
..player_context
|
|
||||||
};
|
|
||||||
|
|
||||||
let initial_state = InitialConstellationState {
|
let initial_state = InitialConstellationState {
|
||||||
compositor_proxy,
|
compositor_proxy,
|
||||||
embedder_proxy,
|
embedder_proxy,
|
||||||
|
@ -826,6 +856,7 @@ fn create_constellation(
|
||||||
webxr_registry,
|
webxr_registry,
|
||||||
glplayer_threads,
|
glplayer_threads,
|
||||||
player_context,
|
player_context,
|
||||||
|
event_loop_waker,
|
||||||
};
|
};
|
||||||
let (constellation_chan, from_swmanager_sender) = Constellation::<
|
let (constellation_chan, from_swmanager_sender) = Constellation::<
|
||||||
script_layout_interface::message::Msg,
|
script_layout_interface::message::Msg,
|
||||||
|
@ -930,7 +961,8 @@ pub fn run_content_process(token: String) {
|
||||||
layout_thread::LayoutThread,
|
layout_thread::LayoutThread,
|
||||||
script::script_thread::ScriptThread>(
|
script::script_thread::ScriptThread>(
|
||||||
true,
|
true,
|
||||||
background_hang_monitor_register
|
background_hang_monitor_register,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ linux-rel-css:
|
||||||
- ./mach build --release --with-debug-assertions -p servo
|
- ./mach build --release --with-debug-assertions -p servo
|
||||||
- ./mach test-wpt --release --processes 24 --total-chunks 2 --this-chunk 2 --log-raw test-wpt.log --log-errorsummary wpt-errorsummary.log --always-succeed
|
- ./mach test-wpt --release --processes 24 --total-chunks 2 --this-chunk 2 --log-raw test-wpt.log --log-errorsummary wpt-errorsummary.log --always-succeed
|
||||||
- ./mach filter-intermittents wpt-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-wpt-errorsummary.log --tracker-api default --reporter-api default
|
- ./mach filter-intermittents wpt-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-wpt-errorsummary.log --tracker-api default --reporter-api default
|
||||||
|
- env SERVO_WEBGL_MAIN_THREAD=1 ./mach test-wpt --release --processes 24 --log-raw test-wpt-webgl.log --log-errorsummary webgl-errorsummary.log --always-succeed tests/wpt/webgl/tests/conformance
|
||||||
|
- ./mach filter-intermittents webgl-errorsummary.log --log-intermittents webgl-intermittents.log --log-filteredsummary filtered-webgl-errorsummary.log --tracker-api default --reporter-api default
|
||||||
- bash ./etc/ci/lockfile_changed.sh
|
- bash ./etc/ci/lockfile_changed.sh
|
||||||
- ./etc/ci/clean_build_artifacts.sh
|
- ./etc/ci/clean_build_artifacts.sh
|
||||||
|
|
||||||
|
|
|
@ -7,27 +7,36 @@
|
||||||
|
|
||||||
use glutin;
|
use glutin;
|
||||||
use servo::embedder_traits::EventLoopWaker;
|
use servo::embedder_traits::EventLoopWaker;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::thread;
|
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
pub struct EventsLoop(Option<glutin::EventsLoop>);
|
#[allow(dead_code)]
|
||||||
|
enum EventLoop {
|
||||||
|
/// A real Glutin windowing event loop.
|
||||||
|
Glutin(Option<glutin::EventsLoop>),
|
||||||
|
/// A fake event loop which contains a signalling flag used to ensure
|
||||||
|
/// that pending events get processed in a timely fashion, and a condition
|
||||||
|
/// variable to allow waiting on that flag changing state.
|
||||||
|
Headless(Arc<(Mutex<bool>, Condvar)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventsLoop(EventLoop);
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
// Ideally, we could use the winit event loop in both modes,
|
// Ideally, we could use the winit event loop in both modes,
|
||||||
// but on Linux, the event loop requires a X11 server.
|
// but on Linux, the event loop requires a X11 server.
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
|
pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
|
||||||
Rc::new(RefCell::new(EventsLoop(Some(glutin::EventsLoop::new()))))
|
Rc::new(RefCell::new(EventsLoop(EventLoop::Glutin(Some(glutin::EventsLoop::new())))))
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
|
pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
|
||||||
let events_loop = if headless {
|
let events_loop = if headless {
|
||||||
None
|
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
|
||||||
} else {
|
} else {
|
||||||
Some(glutin::EventsLoop::new())
|
EventLoop::Glutin(Some(glutin::EventsLoop::new()))
|
||||||
};
|
};
|
||||||
Rc::new(RefCell::new(EventsLoop(events_loop)))
|
Rc::new(RefCell::new(EventsLoop(events_loop)))
|
||||||
}
|
}
|
||||||
|
@ -35,39 +44,79 @@ impl EventsLoop {
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
|
pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
|
||||||
if let Some(ref events_loop) = self.0 {
|
match self.0 {
|
||||||
|
EventLoop::Glutin(ref events_loop) => {
|
||||||
|
let events_loop = events_loop
|
||||||
|
.as_ref()
|
||||||
|
.expect("Can't create waker for unavailable event loop.");
|
||||||
Box::new(HeadedEventLoopWaker::new(&events_loop))
|
Box::new(HeadedEventLoopWaker::new(&events_loop))
|
||||||
} else {
|
},
|
||||||
Box::new(HeadlessEventLoopWaker)
|
EventLoop::Headless(ref data) =>
|
||||||
|
Box::new(HeadlessEventLoopWaker(data.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn as_winit(&self) -> &glutin::EventsLoop {
|
pub fn as_winit(&self) -> &glutin::EventsLoop {
|
||||||
&self.0.as_ref().expect("Can't access winit event loop while using the fake headless event loop")
|
match self.0 {
|
||||||
|
EventLoop::Glutin(Some(ref event_loop)) => event_loop,
|
||||||
|
EventLoop::Glutin(None) | EventLoop::Headless(..) =>
|
||||||
|
panic!("Can't access winit event loop while using the fake headless event loop"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn take(&mut self) -> Option<glutin::EventsLoop> {
|
pub fn take(&mut self) -> Option<glutin::EventsLoop> {
|
||||||
self.0.take()
|
match self.0 {
|
||||||
|
EventLoop::Glutin(ref mut event_loop) => event_loop.take(),
|
||||||
|
EventLoop::Headless(..) => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
|
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
|
||||||
if let Some(ref mut events_loop) = self.0 {
|
match self.0 {
|
||||||
events_loop.poll_events(callback);
|
EventLoop::Glutin(Some(ref mut events_loop)) => events_loop.poll_events(callback),
|
||||||
} else {
|
EventLoop::Glutin(None) => (),
|
||||||
self.sleep();
|
EventLoop::Headless(ref data) => {
|
||||||
|
// This is subtle - the use of the event loop in App::run_loop
|
||||||
|
// optionally calls run_forever, then always calls poll_events.
|
||||||
|
// If our signalling flag is true before we call run_forever,
|
||||||
|
// we don't want to reset it before poll_events is called or
|
||||||
|
// we'll end up sleeping even though there are events waiting
|
||||||
|
// to be handled. We compromise by only resetting the flag here
|
||||||
|
// in poll_events, so that both poll_events and run_forever can
|
||||||
|
// check it first and avoid sleeping unnecessarily.
|
||||||
|
self.sleep(&data.0, &data.1);
|
||||||
|
*data.0.lock().unwrap() = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow {
|
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow {
|
||||||
if let Some(ref mut events_loop) = self.0 {
|
match self.0 {
|
||||||
|
EventLoop::Glutin(ref mut events_loop) => {
|
||||||
|
let events_loop = events_loop
|
||||||
|
.as_mut()
|
||||||
|
.expect("Can't run an unavailable event loop.");
|
||||||
events_loop.run_forever(callback);
|
events_loop.run_forever(callback);
|
||||||
} else {
|
}
|
||||||
loop {
|
EventLoop::Headless(ref data) => {
|
||||||
self.sleep();
|
let &(ref flag, ref condvar) = &**data;
|
||||||
|
while { !*flag.lock().unwrap() } {
|
||||||
|
self.sleep(flag, condvar);
|
||||||
if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break {
|
if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn sleep(&self) {
|
}
|
||||||
thread::sleep(time::Duration::from_millis(5));
|
fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) {
|
||||||
|
// To avoid sleeping when we should be processing events, do two things:
|
||||||
|
// * before sleeping, check whether our signalling flag has been set
|
||||||
|
// * wait on a condition variable with a maximum timeout, to allow
|
||||||
|
// being woken up by any signals that occur while sleeping.
|
||||||
|
let guard = lock.lock().unwrap();
|
||||||
|
if *guard {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let _ = condvar.wait_timeout(
|
||||||
|
guard, time::Duration::from_millis(5)
|
||||||
|
).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +143,19 @@ impl EventLoopWaker for HeadedEventLoopWaker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HeadlessEventLoopWaker;
|
struct HeadlessEventLoopWaker(Arc<(Mutex<bool>, Condvar)>);
|
||||||
impl EventLoopWaker for HeadlessEventLoopWaker {
|
impl EventLoopWaker for HeadlessEventLoopWaker {
|
||||||
fn wake(&self) {}
|
fn wake(&self) {
|
||||||
fn clone_box(&self) -> Box<dyn EventLoopWaker> { Box::new(HeadlessEventLoopWaker) }
|
// Set the signalling flag and notify the condition variable.
|
||||||
|
// This ensures that any sleep operation is interrupted,
|
||||||
|
// and any non-sleeping operation will have a change to check
|
||||||
|
// the flag before going to sleep.
|
||||||
|
let (ref flag, ref condvar) = *self.0;
|
||||||
|
let mut flag = flag.lock().unwrap();
|
||||||
|
*flag = true;
|
||||||
|
condvar.notify_all();
|
||||||
|
}
|
||||||
|
fn clone_box(&self) -> Box<dyn EventLoopWaker> {
|
||||||
|
Box::new(HeadlessEventLoopWaker(self.0.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize};
|
||||||
use servo_media::player::context as MediaPlayerCtxt;
|
use servo_media::player::context as MediaPlayerCtxt;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
use std::cell::RefCell;
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -28,8 +30,8 @@ use std::rc::Rc;
|
||||||
struct HeadlessContext {
|
struct HeadlessContext {
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
_context: osmesa_sys::OSMesaContext,
|
context: osmesa_sys::OSMesaContext,
|
||||||
_buffer: Vec<u32>,
|
buffer: RefCell<Vec<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||||
|
@ -51,30 +53,17 @@ impl HeadlessContext {
|
||||||
attribs.push(3);
|
attribs.push(3);
|
||||||
attribs.push(0);
|
attribs.push(0);
|
||||||
|
|
||||||
let share = share.map_or(ptr::null_mut(), |share| share._context as *mut _);
|
let share = share.map_or(ptr::null_mut(), |share| share.context as *mut _);
|
||||||
|
|
||||||
let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) };
|
let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) };
|
||||||
|
|
||||||
assert!(!context.is_null());
|
assert!(!context.is_null());
|
||||||
|
|
||||||
let mut buffer = vec![0; (width * height) as usize];
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let ret = osmesa_sys::OSMesaMakeCurrent(
|
|
||||||
context,
|
|
||||||
buffer.as_mut_ptr() as *mut _,
|
|
||||||
gl::UNSIGNED_BYTE,
|
|
||||||
width as i32,
|
|
||||||
height as i32,
|
|
||||||
);
|
|
||||||
assert_ne!(ret, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
HeadlessContext {
|
HeadlessContext {
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
_context: context,
|
context: context,
|
||||||
_buffer: buffer,
|
buffer: RefCell::new(vec![0; (width * height) as usize]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +185,23 @@ impl WindowMethods for Window {
|
||||||
self.animation_state.set(state);
|
self.animation_state.set(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_for_composite(&self) { }
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
fn prepare_for_composite(&self) {
|
||||||
|
unsafe {
|
||||||
|
let mut buffer = self.context.buffer.borrow_mut();
|
||||||
|
let ret = osmesa_sys::OSMesaMakeCurrent(
|
||||||
|
self.context.context,
|
||||||
|
buffer.as_mut_ptr() as *mut _,
|
||||||
|
gl::UNSIGNED_BYTE,
|
||||||
|
self.context.width as i32,
|
||||||
|
self.context.height as i32,
|
||||||
|
);
|
||||||
|
assert_ne!(ret, 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||||
|
fn prepare_for_composite(&self) {}
|
||||||
|
|
||||||
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
|
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
|
||||||
MediaPlayerCtxt::GlContext::Unknown
|
MediaPlayerCtxt::GlContext::Unknown
|
||||||
|
|
|
@ -251,7 +251,9 @@ impl ServoGlue {
|
||||||
debug!("perform_updates");
|
debug!("perform_updates");
|
||||||
let events = mem::replace(&mut self.events, Vec::new());
|
let events = mem::replace(&mut self.events, Vec::new());
|
||||||
self.servo.handle_events(events);
|
self.servo.handle_events(events);
|
||||||
self.handle_servo_events()
|
let r = self.handle_servo_events();
|
||||||
|
debug!("done perform_updates");
|
||||||
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In batch mode, Servo won't call perform_updates automatically.
|
/// In batch mode, Servo won't call perform_updates automatically.
|
||||||
|
@ -628,7 +630,7 @@ impl WindowMethods for ServoWindowCallbacks {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_animation_state(&self, state: AnimationState) {
|
fn set_animation_state(&self, state: AnimationState) {
|
||||||
debug!("WindowMethods::set_animation_state");
|
debug!("WindowMethods::set_animation_state: {:?}", state);
|
||||||
self.host_callbacks
|
self.host_callbacks
|
||||||
.on_animating_changed(state == AnimationState::Animating);
|
.on_animating_changed(state == AnimationState::Animating);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>Test that contexts are freed and garbage collected reasonably</title>
|
<title>Test that contexts are freed and garbage collected reasonably</title>
|
||||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||||
<script src=/resources/testharness.js></script>
|
<script src=/resources/testharness.js></script>
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL Context Release Test</title>
|
<title>WebGL Context Release Test</title>
|
||||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||||
<script src=/resources/testharness.js></script>
|
<script src=/resources/testharness.js></script>
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>Driver Bug - temp experssions should not crash</title>
|
<title>Driver Bug - temp experssions should not crash</title>
|
||||||
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
|
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
|
||||||
<script src=/resources/testharness.js></script>
|
<script src=/resources/testharness.js></script>
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL Conformance Tests - Non Reserved Words</title>
|
<title>WebGL GLSL Conformance Tests - Non Reserved Words</title>
|
||||||
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
|
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
|
||||||
<link rel="stylesheet" href="../../../resources/glsl-feature-tests.css"/>
|
<link rel="stylesheet" href="../../../resources/glsl-feature-tests.css"/>
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: abs_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: abs_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: all_001_to_004.html</title>
|
<title>WebGL GLSL conformance test: all_001_to_004.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: any_001_to_004.html</title>
|
<title>WebGL GLSL conformance test: any_001_to_004.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: array_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: array_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: atan_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: atan_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: atan_009_to_012.html</title>
|
<title>WebGL GLSL conformance test: atan_009_to_012.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: biConstants_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: biConstants_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: biConstants_009_to_016.html</title>
|
<title>WebGL GLSL conformance test: biConstants_009_to_016.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: biuDepthRange_001_to_002.html</title>
|
<title>WebGL GLSL conformance test: biuDepthRange_001_to_002.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: build_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_009_to_016.html</title>
|
<title>WebGL GLSL conformance test: build_009_to_016.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_017_to_024.html</title>
|
<title>WebGL GLSL conformance test: build_017_to_024.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_025_to_032.html</title>
|
<title>WebGL GLSL conformance test: build_025_to_032.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_033_to_040.html</title>
|
<title>WebGL GLSL conformance test: build_033_to_040.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_041_to_048.html</title>
|
<title>WebGL GLSL conformance test: build_041_to_048.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_049_to_056.html</title>
|
<title>WebGL GLSL conformance test: build_049_to_056.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_057_to_064.html</title>
|
<title>WebGL GLSL conformance test: build_057_to_064.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_065_to_072.html</title>
|
<title>WebGL GLSL conformance test: build_065_to_072.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_073_to_080.html</title>
|
<title>WebGL GLSL conformance test: build_073_to_080.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_081_to_088.html</title>
|
<title>WebGL GLSL conformance test: build_081_to_088.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_089_to_096.html</title>
|
<title>WebGL GLSL conformance test: build_089_to_096.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_097_to_104.html</title>
|
<title>WebGL GLSL conformance test: build_097_to_104.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_105_to_112.html</title>
|
<title>WebGL GLSL conformance test: build_105_to_112.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_113_to_120.html</title>
|
<title>WebGL GLSL conformance test: build_113_to_120.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_121_to_128.html</title>
|
<title>WebGL GLSL conformance test: build_121_to_128.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_129_to_136.html</title>
|
<title>WebGL GLSL conformance test: build_129_to_136.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_137_to_144.html</title>
|
<title>WebGL GLSL conformance test: build_137_to_144.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_145_to_152.html</title>
|
<title>WebGL GLSL conformance test: build_145_to_152.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_153_to_160.html</title>
|
<title>WebGL GLSL conformance test: build_153_to_160.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_161_to_168.html</title>
|
<title>WebGL GLSL conformance test: build_161_to_168.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_169_to_176.html</title>
|
<title>WebGL GLSL conformance test: build_169_to_176.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: build_177_to_178.html</title>
|
<title>WebGL GLSL conformance test: build_177_to_178.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: built_in_varying_array_out_of_bounds_001_to_001.html</title>
|
<title>WebGL GLSL conformance test: built_in_varying_array_out_of_bounds_001_to_001.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: ceil_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: ceil_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: clamp_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: clamp_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: control_flow_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: control_flow_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: control_flow_009_to_010.html</title>
|
<title>WebGL GLSL conformance test: control_flow_009_to_010.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: cos_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: cos_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: cross_001_to_002.html</title>
|
<title>WebGL GLSL conformance test: cross_001_to_002.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: default_001_to_001.html</title>
|
<title>WebGL GLSL conformance test: default_001_to_001.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: degrees_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: degrees_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: discard_001_to_002.html</title>
|
<title>WebGL GLSL conformance test: discard_001_to_002.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: distance_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: distance_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: dot_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: dot_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: equal_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: equal_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: equal_009_to_012.html</title>
|
<title>WebGL GLSL conformance test: equal_009_to_012.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: exp_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: exp_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: exp_009_to_012.html</title>
|
<title>WebGL GLSL conformance test: exp_009_to_012.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: exp2_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: exp2_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: exp2_009_to_012.html</title>
|
<title>WebGL GLSL conformance test: exp2_009_to_012.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: faceforward_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: faceforward_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: floor_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: floor_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: fract_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: fract_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: functions_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_009_to_016.html</title>
|
<title>WebGL GLSL conformance test: functions_009_to_016.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_017_to_024.html</title>
|
<title>WebGL GLSL conformance test: functions_017_to_024.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_025_to_032.html</title>
|
<title>WebGL GLSL conformance test: functions_025_to_032.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_033_to_040.html</title>
|
<title>WebGL GLSL conformance test: functions_033_to_040.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_041_to_048.html</title>
|
<title>WebGL GLSL conformance test: functions_041_to_048.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_049_to_056.html</title>
|
<title>WebGL GLSL conformance test: functions_049_to_056.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_057_to_064.html</title>
|
<title>WebGL GLSL conformance test: functions_057_to_064.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_065_to_072.html</title>
|
<title>WebGL GLSL conformance test: functions_065_to_072.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_073_to_080.html</title>
|
<title>WebGL GLSL conformance test: functions_073_to_080.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_081_to_088.html</title>
|
<title>WebGL GLSL conformance test: functions_081_to_088.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_089_to_096.html</title>
|
<title>WebGL GLSL conformance test: functions_089_to_096.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_097_to_104.html</title>
|
<title>WebGL GLSL conformance test: functions_097_to_104.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_105_to_112.html</title>
|
<title>WebGL GLSL conformance test: functions_105_to_112.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_113_to_120.html</title>
|
<title>WebGL GLSL conformance test: functions_113_to_120.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: functions_121_to_126.html</title>
|
<title>WebGL GLSL conformance test: functions_121_to_126.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: gl_FragCoord_001_to_003.html</title>
|
<title>WebGL GLSL conformance test: gl_FragCoord_001_to_003.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: gl_FrontFacing_001_to_001.html</title>
|
<title>WebGL GLSL conformance test: gl_FrontFacing_001_to_001.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: greaterThan_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: greaterThan_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: greaterThanEqual_001_to_008.html</title>
|
<title>WebGL GLSL conformance test: greaterThanEqual_001_to_008.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>WebGL GLSL conformance test: inversesqrt_001_to_006.html</title>
|
<title>WebGL GLSL conformance test: inversesqrt_001_to_006.html</title>
|
||||||
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
<link rel="stylesheet" href="../../../../resources/js-test-style.css" />
|
||||||
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
<link rel="stylesheet" href="../../../../resources/ogles-tests.css" />
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue