Implemented paint worklet rendering context.

This commit is contained in:
Alan Jeffrey 2017-06-09 12:47:39 -05:00
parent d47de6ccfc
commit 328fb25a65
15 changed files with 547 additions and 110 deletions

View file

@ -11,6 +11,7 @@
//! a backup thread, not on the primary worklet thread.
use app_units::Au;
use canvas_traits::CanvasData;
use dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials;
use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::codegen::Bindings::WorkletBinding::WorkletMethods;
@ -38,6 +39,7 @@ use dom::workletglobalscope::WorkletGlobalScopeType;
use dom::workletglobalscope::WorkletTask;
use dom_struct::dom_struct;
use euclid::Size2D;
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSGCParamKey;
use js::jsapi::JSTracer;
use js::jsapi::JS_GC;
@ -45,7 +47,6 @@ use js::jsapi::JS_GetGCParameter;
use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::IpcSend;
use net_traits::image::base::Image;
use net_traits::load_whole_resource;
use net_traits::request::Destination;
use net_traits::request::RequestInit;
@ -58,7 +59,6 @@ use script_runtime::new_rt_and_cx;
use script_thread::MainThreadScriptMsg;
use script_thread::Runnable;
use script_thread::ScriptThread;
use script_traits::PaintWorkletError;
use script_traits::PaintWorkletExecutor;
use servo_atoms::Atom;
use servo_rand;
@ -76,7 +76,6 @@ use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::thread;
use std::time::Duration;
use style::thread_state;
use swapper::Swapper;
use swapper::swapper;
@ -85,7 +84,6 @@ use uuid::Uuid;
// Magic numbers
const WORKLET_THREAD_POOL_SIZE: u32 = 3;
const MIN_GC_THRESHOLD: u32 = 1_000_000;
const PAINT_TIMEOUT_MILLISECONDS: u64 = 10;
#[dom_struct]
/// https://drafts.css-houdini.org/worklets/#worklet
@ -163,6 +161,7 @@ impl WorkletMethods for Worklet {
&promise);
// Step 5.
debug!("Returning promise.");
promise
}
}
@ -234,6 +233,17 @@ impl PendingTasksStruct {
/// The thread pool lives in the script thread, and is initialized
/// when a worklet adds a module. It is dropped when the script thread
/// is dropped, and asks each of the worklet threads to quit.
///
/// The layout thread can end up blocking on the primary worklet thread
/// (e.g. when invoking a paint callback), so it is important to avoid
/// deadlock by making sure the primary worklet thread doesn't end up
/// blocking waiting on layout. In particular, since the constellation
/// can block waiting on layout, this means the primary worklet thread
/// can't block waiting on the constellation. In general, the primary
/// worklet thread shouldn't perform any blocking operations. If a worklet
/// thread needs to do anything blocking, it should send a control
/// message, to make sure that the blocking operation is performed
/// by a backup thread, not by the primary thread.
#[derive(Clone, JSTraceable)]
pub struct WorkletThreadPool {
@ -551,6 +561,7 @@ impl WorkletThread {
match self.global_scopes.entry(worklet_id) {
hash_map::Entry::Occupied(entry) => Root::from_ref(entry.get()),
hash_map::Entry::Vacant(entry) => {
debug!("Creating new worklet global scope.");
let result = global_type.new(&self.runtime, pipeline_id, base_url, &self.global_init);
entry.insert(JS::from_ref(&*result));
result
@ -562,6 +573,7 @@ impl WorkletThread {
/// https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
fn fetch_and_invoke_a_worklet_script(&self,
global_scope: &WorkletGlobalScope,
pipeline_id: PipelineId,
origin: ImmutableOrigin,
script_url: ServoUrl,
credentials: RequestCredentials,
@ -612,7 +624,9 @@ impl WorkletThread {
debug!("Finished adding script.");
let old_counter = pending_tasks_struct.decrement_counter_by(1);
if old_counter == 1 {
// TODO: trigger a reflow?
debug!("Resolving promise.");
let msg = MainThreadScriptMsg::WorkletLoaded(pipeline_id);
self.script_sender.send(msg).expect("Worklet thread outlived script thread.");
self.run_in_script_thread(promise.resolve_runnable(()));
}
}
@ -638,6 +652,7 @@ impl WorkletThread {
global_type,
base_url);
self.fetch_and_invoke_a_worklet_script(&*global,
pipeline_id,
origin,
script_url,
credentials,
@ -678,13 +693,10 @@ impl PaintWorkletExecutor for WorkletExecutor {
/// https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image
fn draw_a_paint_image(&self,
name: Atom,
concrete_object_size: Size2D<Au>)
-> Result<Image, PaintWorkletError>
concrete_object_size: Size2D<Au>,
sender: IpcSender<CanvasData>)
{
let (sender, receiver) = mpsc::channel();
let task = WorkletTask::Paint(PaintWorkletTask::DrawAPaintImage(name, concrete_object_size, sender));
let timeout = Duration::from_millis(PAINT_TIMEOUT_MILLISECONDS);
self.schedule_a_worklet_task(task);
receiver.recv_timeout(timeout)?
}
}