Skip to content

Commit

Permalink
Only start WebGPU thread if an adapter is requested
Browse files Browse the repository at this point in the history
  • Loading branch information
Zakor Gyula committed Jan 13, 2020
1 parent f8c957d commit a751b1c
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 147 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 79 additions & 16 deletions components/constellation/constellation.rs
Expand Up @@ -173,7 +173,7 @@ use std::sync::Arc;
use std::thread;
use style_traits::viewport::ViewportConstraints;
use style_traits::CSSPixel;
use webgpu::WebGPU;
use webgpu::{WebGPU, WebGPURequest};
use webvr_traits::{WebVREvent, WebVRMsg};

type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, HistoryEntryReplacement)>;
Expand Down Expand Up @@ -242,6 +242,9 @@ struct BrowsingContextGroup {
/// share an event loop, since they can use `document.domain`
/// to become same-origin, at which point they can share DOM objects.
event_loops: HashMap<Host, Weak<EventLoop>>,

/// The set of all WebGPU channels in this BrowsingContextGroup.
webgpus: HashMap<Host, WebGPU>,
}

/// The `Constellation` itself. In the servo browser, there is one
Expand Down Expand Up @@ -450,10 +453,6 @@ pub struct Constellation<Message, LTF, STF> {
/// Entry point to create and get channels to a WebGLThread.
webgl_threads: Option<WebGLThreads>,

/// An IPC channel for the constellation to send messages to the
/// WebGPU threads.
webgpu: Option<WebGPU>,

/// A channel through which messages can be sent to the webvr thread.
webvr_chan: Option<IpcSender<WebVRMsg>>,

Expand Down Expand Up @@ -537,9 +536,6 @@ pub struct InitialConstellationState {
/// Entry point to create and get channels to a WebGLThread.
pub webgl_threads: Option<WebGLThreads>,

/// A channel to the WebGPU threads.
pub webgpu: Option<WebGPU>,

/// A channel to the webgl thread.
pub webvr_chan: Option<IpcSender<WebVRMsg>>,

Expand Down Expand Up @@ -973,7 +969,6 @@ where
(rng, prob)
}),
webgl_threads: state.webgl_threads,
webgpu: state.webgpu,
webvr_chan: state.webvr_chan,
webxr_registry: state.webxr_registry,
canvas_chan,
Expand Down Expand Up @@ -1230,7 +1225,6 @@ where
.webgl_threads
.as_ref()
.map(|threads| threads.pipeline()),
webgpu: self.webgpu.clone(),
webvr_chan: self.webvr_chan.clone(),
webxr_registry: self.webxr_registry.clone(),
player_context: self.player_context.clone(),
Expand Down Expand Up @@ -1945,9 +1939,65 @@ where
EmbedderMsg::MediaSessionEvent(event),
));
},
FromScriptMsg::RequestAdapter(sender, options, ids) => self
.handle_request_wgpu_adapter(
source_pipeline_id,
BrowsingContextId::from(source_top_ctx_id),
FromScriptMsg::RequestAdapter(sender, options, ids),
),
}
}

fn handle_request_wgpu_adapter(
&mut self,
source_pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId,
request: FromScriptMsg,
) {
let browsing_context_group_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(bc) => &bc.bc_group_id,
None => return warn!("Browsing context not found"),
};
let host = match self
.pipelines
.get(&source_pipeline_id)
.map(|pipeline| &pipeline.url)
{
Some(ref url) => match reg_host(&url) {
Some(host) => host,
None => return warn!("Invalid host url"),
},
None => return warn!("ScriptMsg from closed pipeline {:?}.", source_pipeline_id),
};
match self
.browsing_context_group_set
.get_mut(&browsing_context_group_id)
{
Some(browsing_context_group) => {
let adapter_request =
if let FromScriptMsg::RequestAdapter(sender, options, ids) = request {
WebGPURequest::RequestAdapter(sender, options, ids)
} else {
return warn!("Wrong message type in handle_request_wgpu_adapter");
};
let send = match browsing_context_group.webgpus.entry(host) {
Entry::Vacant(v) => v
.insert(match WebGPU::new() {
Some(webgpu) => webgpu,
None => return warn!("Failed to create new WebGPU thread"),
})
.0
.send(adapter_request),
Entry::Occupied(o) => o.get().0.send(adapter_request),
};
if send.is_err() {
return warn!("Failed to send request adapter message on WebGPU channel");
}
},
None => return warn!("Browsing context group not found"),
};
}

fn handle_request_from_layout(&mut self, message: FromLayoutMsg) {
debug!("Constellation got {:?} message", message);
match message {
Expand Down Expand Up @@ -2496,12 +2546,25 @@ where
}
}

if let Some(webgpu) = self.webgpu.as_ref() {
debug!("Exiting WebGPU thread.");
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
if let Err(e) = webgpu.exit(sender) {
warn!("Exit WebGPU Thread failed ({})", e);
}
debug!("Exiting WebGPU threads.");
let receivers = self
.browsing_context_group_set
.values()
.map(|browsing_context_group| {
browsing_context_group.webgpus.values().map(|webgpu| {
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
if let Err(e) = webgpu.exit(sender) {
warn!("Exit WebGPU Thread failed ({})", e);
None
} else {
Some(receiver)
}
})
})
.flatten()
.filter_map(|r| r);

for receiver in receivers {
if let Err(e) = receiver.recv() {
warn!("Failed to receive exit response from WebGPU ({})", e);
}
Expand Down
7 changes: 0 additions & 7 deletions components/constellation/pipeline.rs
Expand Up @@ -48,7 +48,6 @@ use std::process;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use webgpu::WebGPU;
use webvr_traits::WebVRMsg;

/// A `Pipeline` is the constellation's view of a `Document`. Each pipeline has an
Expand Down Expand Up @@ -194,9 +193,6 @@ pub struct InitialPipelineState {
/// A channel to the WebGL thread.
pub webgl_chan: Option<WebGLPipeline>,

/// A channel to the WebGPU threads.
pub webgpu: Option<WebGPU>,

/// A channel to the webvr thread.
pub webvr_chan: Option<IpcSender<WebVRMsg>>,

Expand Down Expand Up @@ -309,7 +305,6 @@ impl Pipeline {
webrender_document: state.webrender_document,
webgl_chan: state.webgl_chan,
webvr_chan: state.webvr_chan,
webgpu: state.webgpu,
webxr_registry: state.webxr_registry,
player_context: state.player_context,
};
Expand Down Expand Up @@ -516,7 +511,6 @@ pub struct UnprivilegedPipelineContent {
webrender_image_api_sender: net_traits::WebrenderIpcSender,
webrender_document: webrender_api::DocumentId,
webgl_chan: Option<WebGLPipeline>,
webgpu: Option<WebGPU>,
webvr_chan: Option<IpcSender<WebVRMsg>>,
webxr_registry: webxr_api::Registry,
player_context: WindowGLContext,
Expand Down Expand Up @@ -569,7 +563,6 @@ impl UnprivilegedPipelineContent {
pipeline_namespace_id: self.pipeline_namespace_id,
content_process_shutdown_chan: content_process_shutdown_chan,
webgl_chan: self.webgl_chan,
webgpu: self.webgpu,
webvr_chan: self.webvr_chan,
webxr_registry: self.webxr_registry,
webrender_document: self.webrender_document,
Expand Down
1 change: 1 addition & 0 deletions components/script/dom/bindings/trace.rs
Expand Up @@ -521,6 +521,7 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId);
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
unsafe_no_jsmanaged_fields!(RefCell<Option<WebGPU>>);
unsafe_no_jsmanaged_fields!(RefCell<Identities>);
unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter);
Expand Down
41 changes: 20 additions & 21 deletions components/script/dom/gpu.rs
Expand Up @@ -19,9 +19,10 @@ use dom_struct::dom_struct;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use js::jsapi::Heap;
use script_traits::ScriptMsg;
use std::rc::Rc;
use webgpu::wgpu;
use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUResponseResult};
use webgpu::{WebGPUResponse, WebGPUResponseResult};

#[dom_struct]
pub struct GPU {
Expand All @@ -38,10 +39,6 @@ impl GPU {
pub fn new(global: &GlobalScope) -> DomRoot<GPU> {
reflect_dom_object(Box::new(GPU::new_inherited()), global, GPUBinding::Wrap)
}

fn wgpu_channel(&self) -> Option<WebGPU> {
self.global().as_window().webgpu_channel()
}
}

pub trait AsyncWGPUListener {
Expand Down Expand Up @@ -114,7 +111,8 @@ impl GPUMethods for GPU {
options: &GPURequestAdapterOptions,
comp: InCompartment,
) -> Rc<Promise> {
let promise = Promise::new_in_current_compartment(&self.global(), comp);
let global = &self.global();
let promise = Promise::new_in_current_compartment(global, comp);
let sender = response_async(&promise, self);
let power_preference = match options.powerPreference {
Some(GPUPowerPreference::Low_power) => wgpu::instance::PowerPreference::LowPower,
Expand All @@ -123,31 +121,32 @@ impl GPUMethods for GPU {
},
None => wgpu::instance::PowerPreference::Default,
};
let ids = self.global().as_window().Navigator().create_adapter_ids();
let ids = global.as_window().Navigator().create_adapter_ids();

match self.wgpu_channel() {
Some(channel) => {
channel
.0
.send(WebGPURequest::RequestAdapter(
sender,
wgpu::instance::RequestAdapterOptions { power_preference },
ids,
))
.unwrap();
},
None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
};
let script_to_constellation_chan = global.script_to_constellation_chan();
if script_to_constellation_chan
.send(ScriptMsg::RequestAdapter(
sender,
wgpu::instance::RequestAdapterOptions { power_preference },
ids,
))
.is_err()
{
promise.reject_error(Error::Type(
"Failed to send adapter request to constellation...".to_owned(),
));
}
promise
}
}

impl AsyncWGPUListener for GPU {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
WebGPUResponse::RequestAdapter(name, adapter) => {
WebGPUResponse::RequestAdapter(name, adapter, channel) => {
let adapter = GPUAdapter::new(
&self.global(),
channel,
DOMString::from(format!("{} ({:?})", name, adapter.0.backend())),
Heap::default(),
adapter,
Expand Down
27 changes: 19 additions & 8 deletions components/script/dom/gpuadapter.rs
Expand Up @@ -23,11 +23,13 @@ use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use std::rc::Rc;
use webgpu::{wgpu, WebGPUAdapter, WebGPURequest, WebGPUResponse};
use webgpu::{wgpu, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};

#[dom_struct]
pub struct GPUAdapter {
reflector_: Reflector,
#[ignore_malloc_size_of = "channels are hard"]
channel: WebGPU,
name: DOMString,
#[ignore_malloc_size_of = "mozjs"]
extensions: Heap<*mut JSObject>,
Expand All @@ -36,12 +38,14 @@ pub struct GPUAdapter {

impl GPUAdapter {
pub fn new_inherited(
channel: WebGPU,
name: DOMString,
extensions: Heap<*mut JSObject>,
adapter: WebGPUAdapter,
) -> GPUAdapter {
GPUAdapter {
reflector_: Reflector::new(),
channel,
name,
extensions,
adapter,
Expand All @@ -50,12 +54,15 @@ impl GPUAdapter {

pub fn new(
global: &GlobalScope,
channel: WebGPU,
name: DOMString,
extensions: Heap<*mut JSObject>,
adapter: WebGPUAdapter,
) -> DomRoot<GPUAdapter> {
reflect_dom_object(
Box::new(GPUAdapter::new_inherited(name, extensions, adapter)),
Box::new(GPUAdapter::new_inherited(
channel, name, extensions, adapter,
)),
global,
GPUAdapterBinding::Wrap,
)
Expand Down Expand Up @@ -89,12 +96,15 @@ impl GPUAdapterMethods for GPUAdapter {
let id = window
.Navigator()
.create_device_id(self.adapter.0.backend());
match window.webgpu_channel() {
Some(thread) => thread
.0
.send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
.unwrap(),
None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
if self
.channel
.0
.send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
.is_err()
{
promise.reject_error(Error::Type(
"Failed to send RequestDevice message...".to_owned(),
));
}
} else {
promise.reject_error(Error::Type("No WebGPU thread...".to_owned()))
Expand All @@ -109,6 +119,7 @@ impl AsyncWGPUListener for GPUAdapter {
WebGPUResponse::RequestDevice(device_id, _descriptor) => {
let device = GPUDevice::new(
&self.global(),
self.channel.clone(),
&self,
Heap::default(),
Heap::default(),
Expand Down

0 comments on commit a751b1c

Please sign in to comment.